/// <summary>
        /// Calcular Tangent y Binormal en base a los 3 vertices de un triangulo y la normal del primero de ellos
        /// Basado en: http://www.dhpoware.com/demos/d3d9NormalMapping.html
        /// </summary>
        public static void computeTangentBinormal(BumpMappingVertex v1, BumpMappingVertex v2, BumpMappingVertex v3, out Vector3 tangent, out Vector3 binormal)
        {
            // Given the 3 vertices (position and texture coordinates) of a triangle
            // calculate and return the triangle's tangent vector. The handedness of
            // the local coordinate system is stored in tangent.w. The bitangent is
            // then: float3 bitangent = cross(normal, tangent.xyz) * tangent.w.

            // Create 2 vectors in object space.
            //
            // edge1 is the vector from vertex positions v1 to v2.
            // edge2 is the vector from vertex positions v1 to v3.
            Vector3 edge1 = v2.Position - v1.Position;
            Vector3 edge2 = v3.Position - v1.Position;

            edge1.Normalize();
            edge2.Normalize();

            // Create 2 vectors in tangent (texture) space that point in the same
            // direction as edge1 and edge2 (in object space).
            //
            // texEdge1 is the vector from texture coordinates texCoord1 to texCoord2.
            // texEdge2 is the vector from texture coordinates texCoord1 to texCoord3.
            Vector2 texEdge1 = new Vector2(v2.Tu - v1.Tu, v2.Tv - v1.Tv);
            Vector2 texEdge2 = new Vector2(v3.Tu - v1.Tu, v3.Tv - v1.Tv);

            texEdge1.Normalize();
            texEdge2.Normalize();

            // These 2 sets of vectors form the following system of equations:
            //
            //  edge1 = (texEdge1.x * tangent) + (texEdge1.y * bitangent)
            //  edge2 = (texEdge2.x * tangent) + (texEdge2.y * bitangent)
            //
            // Using matrix notation this system looks like:
            //
            //  [ edge1 ]     [ texEdge1.x  texEdge1.y ]  [ tangent   ]
            //  [       ]  =  [                        ]  [           ]
            //  [ edge2 ]     [ texEdge2.x  texEdge2.y ]  [ bitangent ]
            //
            // The solution is:
            //
            //  [ tangent   ]        1     [ texEdge2.y  -texEdge1.y ]  [ edge1 ]
            //  [           ]  =  -------  [                         ]  [       ]
            //  [ bitangent ]      det A   [-texEdge2.x   texEdge1.x ]  [ edge2 ]
            //
            //  where:
            //        [ texEdge1.x  texEdge1.y ]
            //    A = [                        ]
            //        [ texEdge2.x  texEdge2.y ]
            //
            //    det A = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x)
            //
            // From this solution the tangent space basis vectors are:
            //
            //    tangent = (1 / det A) * ( texEdge2.y * edge1 - texEdge1.y * edge2)
            //  bitangent = (1 / det A) * (-texEdge2.x * edge1 + texEdge1.x * edge2)
            //     normal = cross(tangent, bitangent)

            float det = (texEdge1.X * texEdge2.Y) - (texEdge1.Y * texEdge2.X);

            if (FastMath.Abs(det) < 0.0001f)    // almost equal to zero
            {
                tangent.X = 1.0f;
                tangent.Y = 0.0f;
                tangent.Z = 0.0f;

                binormal.X = 0.0f;
                binormal.Y = 1.0f;
                binormal.Z = 0.0f;
            }
            else
            {
                det = 1.0f / det;

                tangent.X = (texEdge2.Y * edge1.X - texEdge1.Y * edge2.X) * det;
                tangent.Y = (texEdge2.Y * edge1.Y - texEdge1.Y * edge2.Y) * det;
                tangent.Z = (texEdge2.Y * edge1.Z - texEdge1.Y * edge2.Z) * det;
                //tangent.W = 0.0f;

                binormal.X = (-texEdge2.X * edge1.X + texEdge1.X * edge2.X) * det;
                binormal.Y = (-texEdge2.X * edge1.Y + texEdge1.X * edge2.Y) * det;
                binormal.Z = (-texEdge2.X * edge1.Z + texEdge1.X * edge2.Z) * det;

                tangent.Normalize();
                binormal.Normalize();
            }

            // Calculate the handedness of the local tangent space.
            // The bitangent vector is the cross product between the triangle face
            // normal vector and the calculated tangent vector. The resulting bitangent
            // vector should be the same as the bitangent vector calculated from the
            // set of linear equations above. If they point in different directions
            // then we need to invert the cross product calculated bitangent vector.
            Vector3 b = Vector3.Cross(v1.Normal, tangent);
            float   w = Vector3.Dot(b, binormal) < 0.0f ? -1.0f : 1.0f;

            binormal = b * w;
        }
        /// <summary>
        /// Calcular Tangent y Binormal en base a los 3 vertices de un triangulo y la normal del primero de ellos
        /// Basado en: http://www.dhpoware.com/demos/d3d9NormalMapping.html
        /// </summary>
        public static void computeTangentBinormal(BumpMappingVertex v1, BumpMappingVertex v2, BumpMappingVertex v3, out Vector3 tangent, out Vector3 binormal)
        {
            // Given the 3 vertices (position and texture coordinates) of a triangle
            // calculate and return the triangle's tangent vector. The handedness of
            // the local coordinate system is stored in tangent.w. The bitangent is
            // then: float3 bitangent = cross(normal, tangent.xyz) * tangent.w.

            // Create 2 vectors in object space.
            //
            // edge1 is the vector from vertex positions v1 to v2.
            // edge2 is the vector from vertex positions v1 to v3.
            Vector3 edge1 = v2.Position - v1.Position;
            Vector3 edge2 = v3.Position - v1.Position;
            edge1.Normalize();
            edge2.Normalize();

            // Create 2 vectors in tangent (texture) space that point in the same
            // direction as edge1 and edge2 (in object space).
            //
            // texEdge1 is the vector from texture coordinates texCoord1 to texCoord2.
            // texEdge2 is the vector from texture coordinates texCoord1 to texCoord3.
            Vector2 texEdge1 = new Vector2(v2.Tu - v1.Tu, v2.Tv - v1.Tv);
            Vector2 texEdge2 = new Vector2(v3.Tu - v1.Tu, v3.Tv - v1.Tv);
            texEdge1.Normalize();
            texEdge2.Normalize();

            // These 2 sets of vectors form the following system of equations:
            //
            //  edge1 = (texEdge1.x * tangent) + (texEdge1.y * bitangent)
            //  edge2 = (texEdge2.x * tangent) + (texEdge2.y * bitangent)
            //
            // Using matrix notation this system looks like:
            //
            //  [ edge1 ]     [ texEdge1.x  texEdge1.y ]  [ tangent   ]
            //  [       ]  =  [                        ]  [           ]
            //  [ edge2 ]     [ texEdge2.x  texEdge2.y ]  [ bitangent ]
            //
            // The solution is:
            //
            //  [ tangent   ]        1     [ texEdge2.y  -texEdge1.y ]  [ edge1 ]
            //  [           ]  =  -------  [                         ]  [       ]
            //  [ bitangent ]      det A   [-texEdge2.x   texEdge1.x ]  [ edge2 ]
            //
            //  where:
            //        [ texEdge1.x  texEdge1.y ]
            //    A = [                        ]
            //        [ texEdge2.x  texEdge2.y ]
            //
            //    det A = (texEdge1.x * texEdge2.y) - (texEdge1.y * texEdge2.x)
            //
            // From this solution the tangent space basis vectors are:
            //
            //    tangent = (1 / det A) * ( texEdge2.y * edge1 - texEdge1.y * edge2)
            //  bitangent = (1 / det A) * (-texEdge2.x * edge1 + texEdge1.x * edge2)
            //     normal = cross(tangent, bitangent)

            float det = (texEdge1.X * texEdge2.Y) - (texEdge1.Y * texEdge2.X);

            if (FastMath.Abs(det) < 0.0001f)    // almost equal to zero
            {
                tangent.X = 1.0f;
                tangent.Y = 0.0f;
                tangent.Z = 0.0f;

                binormal.X = 0.0f;
                binormal.Y = 1.0f;
                binormal.Z = 0.0f;
            }
            else
            {
                det = 1.0f / det;

                tangent.X = (texEdge2.Y * edge1.X - texEdge1.Y * edge2.X) * det;
                tangent.Y = (texEdge2.Y * edge1.Y - texEdge1.Y * edge2.Y) * det;
                tangent.Z = (texEdge2.Y * edge1.Z - texEdge1.Y * edge2.Z) * det;
                //tangent.W = 0.0f;

                binormal.X = (-texEdge2.X * edge1.X + texEdge1.X * edge2.X) * det;
                binormal.Y = (-texEdge2.X * edge1.Y + texEdge1.X * edge2.Y) * det;
                binormal.Z = (-texEdge2.X * edge1.Z + texEdge1.X * edge2.Z) * det;

                tangent.Normalize();
                binormal.Normalize();
            }

            // Calculate the handedness of the local tangent space.
            // The bitangent vector is the cross product between the triangle face
            // normal vector and the calculated tangent vector. The resulting bitangent
            // vector should be the same as the bitangent vector calculated from the
            // set of linear equations above. If they point in different directions
            // then we need to invert the cross product calculated bitangent vector.
            Vector3 b = Vector3.Cross(v1.Normal, tangent);
            float w = Vector3.Dot(b, binormal) < 0.0f ? -1.0f : 1.0f;
            binormal = b * w;
        }
        /// <summary>
        /// Crear un TgcMeshBumpMapping en base a un TgcMesh y su normalMap.
        /// Solo esta soportado un TgcMehs MeshRenderType = DiffuseMap
        /// </summary>
        public static TgcMeshBumpMapping fromTgcMesh(TgcMesh mesh, TgcTexture[] normalMaps)
        {
            if (mesh.RenderType != MeshRenderType.DIFFUSE_MAP)
            {
                throw new Exception("Solo esta soportado MeshRenderType = DiffuseMap");
            }


            //Obtener vertexBuffer original
            TgcSceneLoader.DiffuseMapVertex[] origVertexBuffer = (TgcSceneLoader.DiffuseMapVertex[])mesh.D3dMesh.LockVertexBuffer(
                typeof(TgcSceneLoader.DiffuseMapVertex), LockFlags.ReadOnly, mesh.D3dMesh.NumberVertices);
            mesh.D3dMesh.UnlockVertexBuffer();

            //Crear nuevo Mesh de DirectX
            int  triCount = origVertexBuffer.Length / 3;
            Mesh d3dMesh  = new Mesh(triCount, origVertexBuffer.Length, MeshFlags.Managed, BumpMappingVertexElements, GuiController.Instance.D3dDevice);

            //Calcular normales recorriendo los triangulos
            Vector3[] normals = new Vector3[origVertexBuffer.Length];
            for (int i = 0; i < normals.Length; i++)
            {
                normals[i] = new Vector3(0, 0, 0);
            }
            for (int i = 0; i < triCount; i++)
            {
                //Los 3 vertices del triangulo
                TgcSceneLoader.DiffuseMapVertex v1 = origVertexBuffer[i * 3];
                TgcSceneLoader.DiffuseMapVertex v2 = origVertexBuffer[i * 3 + 1];
                TgcSceneLoader.DiffuseMapVertex v3 = origVertexBuffer[i * 3 + 2];

                //Face-normal (left-handend)
                Vector3 a = v2.Position - v1.Position;
                Vector3 b = v3.Position - v1.Position;
                Vector3 n = Vector3.Cross(a, b);

                //Acumular normal del vertice segun todas sus Face-normal
                normals[i * 3]     += n;
                normals[i * 3 + 1] += n;
                normals[i * 3 + 2] += n;
            }

            //Normalizar normales
            for (int i = 0; i < normals.Length; i++)
            {
                normals[i] = Vector3.Normalize(normals[i]);
            }

            //Crear nuevo VertexBuffer
            using (VertexBuffer vb = d3dMesh.VertexBuffer)
            {
                //Iterar sobre triangulos
                GraphicsStream data = vb.Lock(0, 0, LockFlags.None);
                for (int i = 0; i < triCount; i++)
                {
                    //Vertices originales
                    TgcSceneLoader.DiffuseMapVertex vOrig1 = origVertexBuffer[i * 3];
                    TgcSceneLoader.DiffuseMapVertex vOrig2 = origVertexBuffer[i * 3 + 1];
                    TgcSceneLoader.DiffuseMapVertex vOrig3 = origVertexBuffer[i * 3 + 2];

                    //Nuevo vertice 1
                    BumpMappingVertex v1 = new BumpMappingVertex();
                    v1.Position = vOrig1.Position;
                    v1.Color    = vOrig1.Color;
                    v1.Tu       = vOrig1.Tu;
                    v1.Tv       = vOrig1.Tv;
                    v1.Normal   = normals[i * 3];

                    //Nuevo vertice 2
                    BumpMappingVertex v2 = new BumpMappingVertex();
                    v2.Position = vOrig2.Position;
                    v2.Color    = vOrig2.Color;
                    v2.Tu       = vOrig2.Tu;
                    v2.Tv       = vOrig2.Tv;
                    v2.Normal   = normals[i * 3 + 1];

                    //Nuevo vertice 3
                    BumpMappingVertex v3 = new BumpMappingVertex();
                    v3.Position = vOrig3.Position;
                    v3.Color    = vOrig3.Color;
                    v3.Tu       = vOrig3.Tu;
                    v3.Tv       = vOrig3.Tv;
                    v3.Normal   = normals[i * 3 + 2];

                    //Calcular tangente y binormal para todo el triangulo y cargarlas en cada vertice
                    Vector3 tangent;
                    Vector3 binormal;
                    TgcMeshBumpMapping.computeTangentBinormal(v1, v2, v3, out tangent, out binormal);
                    v1.Tangent  = tangent;
                    v1.Binormal = binormal;
                    v2.Tangent  = tangent;
                    v2.Binormal = binormal;
                    v3.Tangent  = tangent;
                    v3.Binormal = binormal;

                    //Cargar VertexBuffer
                    data.Write(v1);
                    data.Write(v2);
                    data.Write(v3);
                }

                vb.Unlock();
            }

            //Cargar IndexBuffer en forma plana
            using (IndexBuffer ib = d3dMesh.IndexBuffer)
            {
                short[] indices = new short[origVertexBuffer.Length];
                for (int i = 0; i < indices.Length; i++)
                {
                    indices[i] = (short)i;
                }
                ib.SetData(indices, 0, LockFlags.None);
            }

            //Clonar texturas y materials
            TgcTexture[] diffuseMaps = new TgcTexture[mesh.DiffuseMaps.Length];
            Material[]   materials   = new Material[mesh.Materials.Length];
            for (int i = 0; i < mesh.DiffuseMaps.Length; i++)
            {
                diffuseMaps[i] = mesh.DiffuseMaps[i].clone();
                materials[i]   = TgcD3dDevice.DEFAULT_MATERIAL;
            }

            //Cargar attributeBuffer
            if (diffuseMaps.Length > 1)
            {
                int[] origAttributeBuffer = mesh.D3dMesh.LockAttributeBufferArray(LockFlags.None);
                int[] newAttributeBuffer  = d3dMesh.LockAttributeBufferArray(LockFlags.None);
                Array.Copy(origAttributeBuffer, newAttributeBuffer, origAttributeBuffer.Length);
                mesh.D3dMesh.UnlockAttributeBuffer();
                d3dMesh.UnlockAttributeBuffer(newAttributeBuffer);
            }


            //Crear mesh de BumpMapping Mesh
            TgcMeshBumpMapping bumpMesh = new TgcMeshBumpMapping(d3dMesh, mesh.Name, mesh.RenderType);

            bumpMesh.diffuseMaps      = diffuseMaps;
            bumpMesh.materials        = materials;
            bumpMesh.normalMaps       = normalMaps;
            bumpMesh.layer            = mesh.Layer;
            bumpMesh.alphaBlendEnable = mesh.AlphaBlendEnable;
            bumpMesh.UserProperties   = mesh.UserProperties;
            bumpMesh.boundingBox      = mesh.BoundingBox.clone();
            bumpMesh.enabled          = true;

            return(bumpMesh);
        }
        /// <summary>
        /// Crear un TgcMeshBumpMapping en base a un TgcMesh y su normalMap.
        /// Solo esta soportado un TgcMehs MeshRenderType = DiffuseMap
        /// </summary>
        public static TgcMeshBumpMapping fromTgcMesh(TgcMesh mesh, TgcTexture[] normalMaps)
        {
            if (mesh.RenderType != MeshRenderType.DIFFUSE_MAP)
            {
                throw new Exception("Solo esta soportado MeshRenderType = DiffuseMap");
            }

            //Obtener vertexBuffer original
            TgcSceneLoader.DiffuseMapVertex[] origVertexBuffer = (TgcSceneLoader.DiffuseMapVertex[])mesh.D3dMesh.LockVertexBuffer(
                        typeof(TgcSceneLoader.DiffuseMapVertex), LockFlags.ReadOnly, mesh.D3dMesh.NumberVertices);
            mesh.D3dMesh.UnlockVertexBuffer();

            //Crear nuevo Mesh de DirectX
            int triCount = origVertexBuffer.Length / 3;
            Mesh d3dMesh = new Mesh(triCount, origVertexBuffer.Length, MeshFlags.Managed, BumpMappingVertexElements, GuiController.Instance.D3dDevice);

            //Calcular normales recorriendo los triangulos
            Vector3[] normals = new Vector3[origVertexBuffer.Length];
            for (int i = 0; i < normals.Length; i++)
            {
                normals[i] = new Vector3(0, 0, 0);
            }
            for (int i = 0; i < triCount; i++)
            {
                //Los 3 vertices del triangulo
                TgcSceneLoader.DiffuseMapVertex v1 = origVertexBuffer[i * 3];
                TgcSceneLoader.DiffuseMapVertex v2 = origVertexBuffer[i * 3 + 1];
                TgcSceneLoader.DiffuseMapVertex v3 = origVertexBuffer[i * 3 + 2];

                //Face-normal (left-handend)
                Vector3 a = v2.Position - v1.Position;
                Vector3 b = v3.Position - v1.Position;
                Vector3 n = Vector3.Cross(a, b);

                //Acumular normal del vertice segun todas sus Face-normal
                normals[i * 3] += n;
                normals[i * 3 + 1] += n;
                normals[i * 3 + 2] += n;
            }

            //Normalizar normales
            for (int i = 0; i < normals.Length; i++)
            {
                normals[i] = Vector3.Normalize(normals[i]);
            }

            //Crear nuevo VertexBuffer
            using (VertexBuffer vb = d3dMesh.VertexBuffer)
            {
                //Iterar sobre triangulos
                GraphicsStream data = vb.Lock(0, 0, LockFlags.None);
                for (int i = 0; i < triCount; i++)
                {
                    //Vertices originales
                    TgcSceneLoader.DiffuseMapVertex vOrig1 = origVertexBuffer[i * 3];
                    TgcSceneLoader.DiffuseMapVertex vOrig2 = origVertexBuffer[i * 3 + 1];
                    TgcSceneLoader.DiffuseMapVertex vOrig3 = origVertexBuffer[i * 3 + 2];

                    //Nuevo vertice 1
                    BumpMappingVertex v1 = new BumpMappingVertex();
                    v1.Position = vOrig1.Position;
                    v1.Color = vOrig1.Color;
                    v1.Tu = vOrig1.Tu;
                    v1.Tv = vOrig1.Tv;
                    v1.Normal = normals[i * 3];

                    //Nuevo vertice 2
                    BumpMappingVertex v2 = new BumpMappingVertex();
                    v2.Position = vOrig2.Position;
                    v2.Color = vOrig2.Color;
                    v2.Tu = vOrig2.Tu;
                    v2.Tv = vOrig2.Tv;
                    v2.Normal = normals[i * 3 + 1];

                    //Nuevo vertice 3
                    BumpMappingVertex v3 = new BumpMappingVertex();
                    v3.Position = vOrig3.Position;
                    v3.Color = vOrig3.Color;
                    v3.Tu = vOrig3.Tu;
                    v3.Tv = vOrig3.Tv;
                    v3.Normal = normals[i * 3 + 2];

                    //Calcular tangente y binormal para todo el triangulo y cargarlas en cada vertice
                    Vector3 tangent;
                    Vector3 binormal;
                    TgcMeshBumpMapping.computeTangentBinormal(v1, v2, v3, out tangent, out binormal);
                    v1.Tangent = tangent;
                    v1.Binormal = binormal;
                    v2.Tangent = tangent;
                    v2.Binormal = binormal;
                    v3.Tangent = tangent;
                    v3.Binormal = binormal;

                    //Cargar VertexBuffer
                    data.Write(v1);
                    data.Write(v2);
                    data.Write(v3);
                }

                vb.Unlock();
            }

            //Cargar IndexBuffer en forma plana
            using (IndexBuffer ib = d3dMesh.IndexBuffer)
            {
                short[] indices = new short[origVertexBuffer.Length];
                for (int i = 0; i < indices.Length; i++)
                {
                    indices[i] = (short)i;
                }
                ib.SetData(indices, 0, LockFlags.None);
            }

            //Clonar texturas y materials
            TgcTexture[] diffuseMaps = new TgcTexture[mesh.DiffuseMaps.Length];
            Material[] materials = new Material[mesh.Materials.Length];
            for (int i = 0; i < mesh.DiffuseMaps.Length; i++)
            {
                diffuseMaps[i] = mesh.DiffuseMaps[i].clone();
                materials[i] = TgcD3dDevice.DEFAULT_MATERIAL;
            }

            //Cargar attributeBuffer
            if (diffuseMaps.Length > 1)
            {
                int[] origAttributeBuffer = mesh.D3dMesh.LockAttributeBufferArray(LockFlags.None);
                int[] newAttributeBuffer = d3dMesh.LockAttributeBufferArray(LockFlags.None);
                Array.Copy(origAttributeBuffer, newAttributeBuffer, origAttributeBuffer.Length);
                mesh.D3dMesh.UnlockAttributeBuffer();
                d3dMesh.UnlockAttributeBuffer(newAttributeBuffer);
            }

            //Crear mesh de BumpMapping Mesh
            TgcMeshBumpMapping bumpMesh = new TgcMeshBumpMapping(d3dMesh, mesh.Name, mesh.RenderType);
            bumpMesh.diffuseMaps = diffuseMaps;
            bumpMesh.materials = materials;
            bumpMesh.normalMaps = normalMaps;
            bumpMesh.layer = mesh.Layer;
            bumpMesh.alphaBlendEnable = mesh.AlphaBlendEnable;
            bumpMesh.UserProperties = mesh.UserProperties;
            bumpMesh.boundingBox = mesh.BoundingBox.clone();
            bumpMesh.enabled = true;

            return bumpMesh;
        }