void AttachMirrorPlane(BabylonTexture babylonTexture, NovaObject novaObject)
        {
            // Mirror plane
            int f1, f2, f3;

            if (novaObject.Is32bits)
            {
                f1 = novaObject.Indices32[2];
                f2 = novaObject.Indices32[1];
                f3 = novaObject.Indices32[0];
            }
            else
            {
                f1 = novaObject.Indices[2];
                f2 = novaObject.Indices[1];
                f3 = novaObject.Indices[0];
            }
            Vector3 a = novaObject.PositionOnlyVertices[f1];
            Vector3 b = novaObject.PositionOnlyVertices[f2];
            Vector3 c = novaObject.PositionOnlyVertices[f3];

            var mainPlane = new Plane(a, b, c);

            Matrix matrix = Matrix.Invert(novaObject.WorldMatrix);
            matrix = Matrix.Transpose(matrix);
            Plane plane = Plane.Transform(mainPlane, matrix);

            babylonTexture.mirrorPlane = new[] { plane.Normal.X, plane.Normal.Y, plane.Normal.Z, plane.D };
        }
        void DumpTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
        {
            babylonTexture.level = texture.Level;
            babylonTexture.hasAlpha = texture.HasAlpha;
            babylonTexture.coordinatesMode = (int)texture.MapType;

            if (texture.LoadedTexture.IsCube)
            {
                DumpCubeTexture(texture, babylonTexture, babylonScene);
                return;
            }

            babylonTexture.name = texture.Name;
            babylonTexture.uOffset = texture.UOffset;
            babylonTexture.vOffset = texture.VOffset;
            babylonTexture.uScale = texture.UScale;
            babylonTexture.vScale = texture.VScale;
            babylonTexture.uAng = texture.UAng;
            babylonTexture.vAng = texture.VAng;
            babylonTexture.wAng = texture.WAng;
            switch (texture.UAddressMode)
            {
                case NovaTextureAddress.Wrap:
                    babylonTexture.wrapU = 1;
                    break;
                case NovaTextureAddress.Mirror:
                    babylonTexture.wrapU = 2;
                    break;
                case NovaTextureAddress.Clamp:
                    babylonTexture.wrapU = 0;
                    break;
            }
            switch (texture.VAddressMode)
            {
                case NovaTextureAddress.Wrap:
                    babylonTexture.wrapV = 1;
                    break;
                case NovaTextureAddress.Mirror:
                    babylonTexture.wrapV = 2;
                    break;
                case NovaTextureAddress.Clamp:
                    babylonTexture.wrapV = 0;
                    break;
            }
            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;

            DumpTextureAnimation(texture, babylonTexture);

            babylonTexture.name = CopyTexture(texture, babylonScene);
        }
        private void DumpCubeTexture(NovaTexture texture, BabylonTexture babylonTexture, BabylonScene babylonScene)
        {
            var textureFilename = Path.Combine(texture.LoadedTexture.Directory, texture.LoadedTexture.Filename);
            var baseName = Path.GetFileNameWithoutExtension(texture.LoadedTexture.Filename);

            babylonTexture.isCube = true;
            babylonTexture.name = baseName;

            baseName = Path.Combine(babylonScene.OutputPath, baseName);

            if (!File.Exists(textureFilename))
            {
                texture.LoadedTexture.SaveToDDS(false, textureFilename);
            }

            if (!alreadyExportedTextures.Contains(textureFilename))
            {
                alreadyExportedTextures.Add(textureFilename);

                // Use SharpDX to extract face images
                var form = new Form { ClientSize = new Size(64, 64) };
                var device = new Device(new Direct3D(), 0, DeviceType.Hardware, form.Handle,
                                        CreateFlags.HardwareVertexProcessing,
                                        new PresentParameters(form.ClientSize.Width, form.ClientSize.Height));

                var cubeTexture = CubeTexture.FromFile(device, textureFilename);

                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveX, 0))
                {
                    Surface.ToFile(surface, baseName + "_px.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveY, 0))
                {
                    Surface.ToFile(surface, baseName + "_py.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.PositiveZ, 0))
                {
                    Surface.ToFile(surface, baseName + "_pz.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeX, 0))
                {
                    Surface.ToFile(surface, baseName + "_nx.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeY, 0))
                {
                    Surface.ToFile(surface, baseName + "_ny.jpg", ImageFileFormat.Jpg);
                }
                using (var surface = cubeTexture.GetCubeMapSurface(CubeMapFace.NegativeZ, 0))
                {
                    Surface.ToFile(surface, baseName + "_nz.jpg", ImageFileFormat.Jpg);
                }

                cubeTexture.Dispose();
                device.Dispose();
                form.Dispose();
            }
        }
        private void DumpRenderTargetTexture(NovaTexture texture, BabylonTexture babylonTexture, int renderSize, float level, NovaMirroredObjectsList renderList)
        {
            babylonTexture.level = level;
            babylonTexture.hasAlpha = false;
            babylonTexture.coordinatesMode = (int)NovaTexture.NovaTextureMapType.Projection;

            babylonTexture.name = texture.Name;
            babylonTexture.uOffset = texture.UOffset;
            babylonTexture.vOffset = texture.VOffset;
            babylonTexture.uScale = texture.UScale;
            babylonTexture.vScale = texture.VScale;
            babylonTexture.uAng = texture.UAng;
            babylonTexture.vAng = texture.VAng;
            babylonTexture.wAng = texture.WAng;
            switch (texture.UAddressMode)
            {
                case NovaTextureAddress.Wrap:
                    babylonTexture.wrapU = 1;
                    break;
                case NovaTextureAddress.Mirror:
                    babylonTexture.wrapU = 2;
                    break;
                case NovaTextureAddress.Clamp:
                    babylonTexture.wrapU = 0;
                    break;
            }
            switch (texture.VAddressMode)
            {
                case NovaTextureAddress.Wrap:
                    babylonTexture.wrapV = 1;
                    break;
                case NovaTextureAddress.Mirror:
                    babylonTexture.wrapV = 2;
                    break;
                case NovaTextureAddress.Clamp:
                    babylonTexture.wrapV = 0;
                    break;
            }
            babylonTexture.coordinatesIndex = texture.MapCoordinateIndex;

            DumpTextureAnimation(texture, babylonTexture);

            babylonTexture.isRenderTarget = true;
            babylonTexture.renderTargetSize = renderSize;

            babylonTexture.renderList = renderList.Select(o => o.ID.ToString()).ToArray();
        }
        void DumpTextureAnimation(NovaTexture texture, BabylonTexture babylonTexture)
        {
            var animations = new List<BabylonAnimation>();

            DumpInterpolator("Texture UOffset", "uOffset", texture.UOffsetInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture VOffset", "vOffset", texture.VOffsetInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture UScale", "uScale", texture.UScaleInterpolator, texture.ParentScene, animations);
            DumpInterpolator("Texture VScale", "vScale", texture.VScaleInterpolator, texture.ParentScene, animations);

            babylonTexture.animations = animations.ToArray();
        }