public override bool Compile(GameAssetType gameAsset, Uri baseUri, BinaryAsset asset, XmlNode node, GameDefinition game,
                                     string trace, ref int position, out string ErrorDescription)
        {
            BinaryAsset w3dMeshPipelineVertexData = new BinaryAsset(0x1C);

            asset.SubAssets.Add(position, w3dMeshPipelineVertexData);
            position += 4;
            VertexData    vertexData = new VertexData();
            List <ushort> bones      = new List <ushort>();

            foreach (XmlNode childNode in node.ChildNodes)
            {
                switch (childNode.Name)
                {
                case "Vertices":
                    ++vertexData.VerticesCount;
                    List <Vector3> verticesList = new List <Vector3>();
                    if (vertexData.Vertices[0] == null)
                    {
                        vertexData.Vertices[0] = verticesList;
                    }
                    else
                    {
                        vertexData.Vertices[1] = verticesList;
                    }
                    foreach (XmlNode vertexNode in childNode.ChildNodes)
                    {
                        if (vertexNode.Name == "V")
                        {
                            Vector3 vertex = new Vector3();
                            vertex.X = float.Parse(vertexNode.Attributes.GetNamedItem("X").Value, NumberFormatInfo.InvariantInfo);
                            vertex.Y = float.Parse(vertexNode.Attributes.GetNamedItem("Y").Value, NumberFormatInfo.InvariantInfo);
                            vertex.Z = float.Parse(vertexNode.Attributes.GetNamedItem("Z").Value, NumberFormatInfo.InvariantInfo);
                            verticesList.Add(vertex);
                        }
                    }
                    break;

                case "Normals":
                    ++vertexData.NormalsCount;
                    List <Vector3> normalsList = new List <Vector3>();
                    if (vertexData.Normals[0] == null)
                    {
                        vertexData.Normals[0] = normalsList;
                    }
                    else
                    {
                        vertexData.Normals[1] = normalsList;
                    }
                    foreach (XmlNode normalNode in childNode.ChildNodes)
                    {
                        if (normalNode.Name == "N")
                        {
                            Vector3 normal = new Vector3();
                            normal.X = float.Parse(normalNode.Attributes.GetNamedItem("X").Value, NumberFormatInfo.InvariantInfo);
                            normal.Y = float.Parse(normalNode.Attributes.GetNamedItem("Y").Value, NumberFormatInfo.InvariantInfo);
                            normal.Z = float.Parse(normalNode.Attributes.GetNamedItem("Z").Value, NumberFormatInfo.InvariantInfo);
                            normalsList.Add(normal);
                        }
                    }
                    break;

                case "Tangents":
                    ++vertexData.TangentsCount;
                    List <Vector3> tangentsList = new List <Vector3>();
                    vertexData.Tangents = tangentsList;
                    foreach (XmlNode tangentNode in childNode.ChildNodes)
                    {
                        if (tangentNode.Name == "T")
                        {
                            Vector3 tangent = new Vector3();
                            tangent.X = float.Parse(tangentNode.Attributes.GetNamedItem("X").Value, NumberFormatInfo.InvariantInfo);
                            tangent.Y = float.Parse(tangentNode.Attributes.GetNamedItem("Y").Value, NumberFormatInfo.InvariantInfo);
                            tangent.Z = float.Parse(tangentNode.Attributes.GetNamedItem("Z").Value, NumberFormatInfo.InvariantInfo);
                            tangentsList.Add(tangent);
                        }
                    }
                    break;

                case "Binormals":
                    ++vertexData.BinormalsCount;
                    List <Vector3> binormalsList = new List <Vector3>();
                    vertexData.Binormals = binormalsList;
                    foreach (XmlNode binormalNode in childNode.ChildNodes)
                    {
                        if (binormalNode.Name == "B")
                        {
                            Vector3 binormal = new Vector3();
                            binormal.X = float.Parse(binormalNode.Attributes.GetNamedItem("X").Value, NumberFormatInfo.InvariantInfo);
                            binormal.Y = float.Parse(binormalNode.Attributes.GetNamedItem("Y").Value, NumberFormatInfo.InvariantInfo);
                            binormal.Z = float.Parse(binormalNode.Attributes.GetNamedItem("Z").Value, NumberFormatInfo.InvariantInfo);
                            binormalsList.Add(binormal);
                        }
                    }
                    break;

                case "VertexColors":
                    List <RGBAColor> colorList = new List <RGBAColor>();
                    vertexData.VertexColors = colorList;
                    foreach (XmlNode colorNode in childNode.ChildNodes)
                    {
                        if (colorNode.Name == "C")
                        {
                            RGBAColor color = new RGBAColor();
                            color.R = (byte)(float.Parse(colorNode.Attributes.GetNamedItem("R").Value, NumberFormatInfo.InvariantInfo) * 255);
                            color.G = (byte)(float.Parse(colorNode.Attributes.GetNamedItem("G").Value, NumberFormatInfo.InvariantInfo) * 255);
                            color.B = (byte)(float.Parse(colorNode.Attributes.GetNamedItem("B").Value, NumberFormatInfo.InvariantInfo) * 255);
                            color.A = (byte)(float.Parse(colorNode.Attributes.GetNamedItem("A").Value, NumberFormatInfo.InvariantInfo) * 255);
                            colorList.Add(color);
                        }
                    }
                    break;

                case "TexCoords":
                    List <Vector2> texcoordsList = new List <Vector2>();
                    vertexData.TexCoords.Add(texcoordsList);
                    foreach (XmlNode texcoordNode in childNode.ChildNodes)
                    {
                        if (texcoordNode.Name == "T")
                        {
                            Vector2 texcoord = new Vector2();
                            texcoord.X = float.Parse(texcoordNode.Attributes.GetNamedItem("X").Value, NumberFormatInfo.InvariantInfo);
                            texcoord.Y = 1 - float.Parse(texcoordNode.Attributes.GetNamedItem("Y").Value, NumberFormatInfo.InvariantInfo);
                            texcoordsList.Add(texcoord);
                        }
                    }
                    break;

                case "BoneInfluences":
                    ++vertexData.BoneInfluencesCount;
                    if (vertexData.BoneInfluences == null)
                    {
                        List <BoneInfluence> boneinfluenceList = new List <BoneInfluence>();
                        vertexData.BoneInfluences = boneinfluenceList;
                        foreach (XmlNode boneinfluenceNode in childNode.ChildNodes)
                        {
                            if (boneinfluenceNode.Name == "I")
                            {
                                BoneInfluence boneinfluence = new BoneInfluence();
                                ushort        bone          = ushort.Parse(boneinfluenceNode.Attributes.GetNamedItem("Bone").Value);
                                if (bones.Contains(bone))
                                {
                                    boneinfluence.Bones.R = (byte)bones.IndexOf(bone);
                                }
                                else
                                {
                                    boneinfluence.Bones.R = (byte)bones.Count;
                                    bones.Add(bone);
                                }
                                boneinfluence.Influences.X = float.Parse(boneinfluenceNode.Attributes.GetNamedItem("Weight").Value, NumberFormatInfo.InvariantInfo);
                                boneinfluenceList.Add(boneinfluence);
                            }
                        }
                    }
                    else
                    {
                        List <BoneInfluence> boneinfluenceList = vertexData.BoneInfluences;
                        int idx = 0;
                        foreach (XmlNode boneinfluenceNode in childNode.ChildNodes)
                        {
                            if (boneinfluenceNode.Name == "I")
                            {
                                ushort bone = ushort.Parse(boneinfluenceNode.Attributes.GetNamedItem("Bone").Value);
                                if (bones.Contains(bone))
                                {
                                    boneinfluenceList[idx].Bones.G = (byte)bones.IndexOf(bone);
                                }
                                else
                                {
                                    boneinfluenceList[idx].Bones.G = (byte)bones.Count;
                                    bones.Add(bone);
                                }
                                boneinfluenceList[idx].Influences.Y = float.Parse(boneinfluenceNode.Attributes.GetNamedItem("Weight").Value, NumberFormatInfo.InvariantInfo);
                                ++idx;
                            }
                        }
                    }
                    break;

                case "ShadeIndices":
                    // unused
                    break;
                }
            }
            FileHelper.SetInt(vertexData.Vertices[0].Count, 0x00, w3dMeshPipelineVertexData.Content);
            List <VertexElement> vertexElements = new List <VertexElement>();
            short vertexSize = 0;

            for (byte idx = 0; idx < vertexData.VerticesCount; ++idx)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.FLOAT3;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.POSITION;
                vertexElement.UsageIndex = idx;
                vertexElements.Add(vertexElement);
                vertexSize += 12;
            }
            for (byte idx = 0; idx < vertexData.NormalsCount; ++idx)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.FLOAT3;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.NORMAL;
                vertexElement.UsageIndex = idx;
                vertexElements.Add(vertexElement);
                vertexSize += 12;
            }
            VertexElement colorvertexElement = new VertexElement();

            colorvertexElement.Offset     = vertexSize;
            colorvertexElement.Type       = VertexElementType.D3DCOLOR;
            colorvertexElement.Method     = VertexElementMethod.DEFAULT;
            colorvertexElement.Usage      = VertexElementUsage.COLOR;
            colorvertexElement.UsageIndex = 0;
            vertexElements.Add(colorvertexElement);
            vertexSize += 4;
            for (byte idx = 0; idx < vertexData.TangentsCount; ++idx)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.FLOAT3;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.TANGENT;
                vertexElement.UsageIndex = idx;
                vertexElements.Add(vertexElement);
                vertexSize += 12;
            }
            for (byte idx = 0; idx < vertexData.BinormalsCount; ++idx)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.FLOAT3;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.BINORMAL;
                vertexElement.UsageIndex = idx;
                vertexElements.Add(vertexElement);
                vertexSize += 12;
            }
            for (byte idx = 0; idx < vertexData.TexCoords.Count; ++idx)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.FLOAT2;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.TEXCOORD;
                vertexElement.UsageIndex = idx;
                vertexElements.Add(vertexElement);
                vertexSize += 8;
            }
            if (vertexData.BoneInfluencesCount != 0)
            {
                VertexElement vertexElement = new VertexElement();
                vertexElement.Offset     = vertexSize;
                vertexElement.Type       = VertexElementType.D3DCOLOR;
                vertexElement.Method     = VertexElementMethod.DEFAULT;
                vertexElement.Usage      = VertexElementUsage.BLENDINDICES;
                vertexElement.UsageIndex = 0;
                vertexElements.Add(vertexElement);
                vertexSize += 4;
                foreach (BoneInfluence influence in vertexData.BoneInfluences)
                {
                    if (influence.Influences.X != 1 ||
                        (vertexData.BoneInfluencesCount == 2 && influence.Influences.Y != 1))
                    {
                        VertexElement influenceVertexElement = new VertexElement();
                        influenceVertexElement.Offset     = vertexSize;
                        influenceVertexElement.Type       = VertexElementType.FLOAT2;
                        influenceVertexElement.Method     = VertexElementMethod.DEFAULT;
                        influenceVertexElement.Usage      = VertexElementUsage.BLENDWEIGHT;
                        influenceVertexElement.UsageIndex = 0;
                        vertexElements.Add(influenceVertexElement);
                        vertexSize += 8;
                        break;
                    }
                }
            }
            vertexElements.Add(new VertexElement(true));
            FileHelper.SetInt(vertexSize, 0x04, w3dMeshPipelineVertexData.Content);
            BinaryAsset binaryVertexData = new BinaryAsset(vertexData.Vertices[0].Count * vertexSize);

            w3dMeshPipelineVertexData.SubAssets.Add(0x08, binaryVertexData);
            FileHelper.SetInt(vertexElements.Count << 3, 0x0C, w3dMeshPipelineVertexData.Content);
            BinaryAsset binaryVertexElementData = new BinaryAsset(vertexElements.Count << 3);

            w3dMeshPipelineVertexData.SubAssets.Add(0x10, binaryVertexElementData);
            for (int idx = 0; idx < vertexElements.Count; ++idx)
            {
                VertexElement vertexElement = vertexElements[idx];
                switch (vertexElement.Usage)
                {
                case VertexElementUsage.POSITION:
                    List <Vector3> verticesList = vertexData.Vertices[vertexElement.UsageIndex];
                    for (int idy = 0; idy < verticesList.Count; ++idy)
                    {
                        Array.Copy(verticesList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 12);
                    }
                    break;

                case VertexElementUsage.NORMAL:
                    List <Vector3> normalsList = vertexData.Normals[vertexElement.UsageIndex];
                    for (int idy = 0; idy < normalsList.Count; ++idy)
                    {
                        Array.Copy(normalsList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 12);
                    }
                    break;

                case VertexElementUsage.TANGENT:
                    List <Vector3> tangentsList = vertexData.Tangents;
                    for (int idy = 0; idy < tangentsList.Count; ++idy)
                    {
                        Array.Copy(tangentsList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 12);
                    }
                    break;

                case VertexElementUsage.BINORMAL:
                    List <Vector3> binormalsList = vertexData.Binormals;
                    for (int idy = 0; idy < binormalsList.Count; ++idy)
                    {
                        Array.Copy(binormalsList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 12);
                    }
                    break;

                case VertexElementUsage.COLOR:
                    List <RGBAColor> colorsList = vertexData.VertexColors;
                    if (colorsList != null)
                    {
                        for (int idy = 0; idy < colorsList.Count; ++idy)
                        {
                            Array.Copy(colorsList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 4);
                        }
                    }
                    else
                    {
                        int vertexCount = vertexData.Vertices[0].Count;
                        for (int idy = 0; idy < vertexCount; ++idy)
                        {
                            FileHelper.SetInt(-1, idy * vertexSize + vertexElement.Offset, binaryVertexData.Content);
                        }
                    }
                    break;

                case VertexElementUsage.TEXCOORD:
                    List <Vector2> texcoordList = vertexData.TexCoords[vertexElement.UsageIndex];
                    for (int idy = 0; idy < texcoordList.Count; ++idy)
                    {
                        Array.Copy(texcoordList[idy].binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 8);
                    }
                    break;

                case VertexElementUsage.BLENDINDICES:
                    List <BoneInfluence> blendindicesList = vertexData.BoneInfluences;
                    for (int idy = 0; idy < blendindicesList.Count; ++idy)
                    {
                        Array.Copy(blendindicesList[idy].Bones.binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 4);
                    }
                    break;

                case VertexElementUsage.BLENDWEIGHT:
                    List <BoneInfluence> blendweightList = vertexData.BoneInfluences;
                    for (int idy = 0; idy < blendweightList.Count; ++idy)
                    {
                        Array.Copy(blendweightList[idy].Influences.binary, 0, binaryVertexData.Content, idy * vertexSize + vertexElement.Offset, 8);
                    }
                    break;
                }
                Array.Copy(vertexElement.binary, 0, binaryVertexElementData.Content, idx << 3, 8);
            }
            BinaryAsset boneList = null;
            int         sageUnsignedShortCount = 2 - (bones.Count & 1);

            if (sageUnsignedShortCount == 2)
            {
                boneList = new BinaryAsset(bones.Count * 2);
            }
            else
            {
                boneList = new BinaryAsset((bones.Count + sageUnsignedShortCount) * 2);
            }
            for (int idx = 0; idx < bones.Count; ++idx)
            {
                FileHelper.SetUShort(bones[idx], idx * 2, boneList.Content);
            }
            FileHelper.SetInt(bones.Count, 0x14, w3dMeshPipelineVertexData.Content);
            w3dMeshPipelineVertexData.SubAssets.Add(0x18, boneList);
            foreach (BaseEntryType entry in gameAsset.Runtime.Entries)
            {
                if (entry.id == "VertexData")
                {
                    continue;
                }
                if (!entry.Compile(baseUri, asset, node, game, "W3DMesh", ref position, out ErrorDescription))
                {
                    return(false);
                }
            }
            ErrorDescription = string.Empty;
            return(true);
        }
 public BoneInfluence()
 {
     Bones      = new RGBAColor();
     Influences = new Vector2();
 }