Esempio n. 1
0
 public void addBoneAssignment(VertexBoneAssignment vertBoneAssign)
 {
     OgrePINVOKE.Mesh_addBoneAssignment(swigCPtr, VertexBoneAssignment.getCPtr(vertBoneAssign));
     if (OgrePINVOKE.SWIGPendingException.Pending)
     {
         throw OgrePINVOKE.SWIGPendingException.Retrieve();
     }
 }
Esempio n. 2
0
 /// <summary>
 ///    Assigns a vertex to a bone with a given weight, for skeletal animation.
 /// </summary>
 /// <remarks>
 ///    This method is only valid after setting the SkeletonName property.
 ///    You should not need to modify bone assignments during rendering (only the positions of bones)
 ///    and the engine reserves the right to do some internal data reformatting of this information,
 ///    depending on render system requirements.
 /// </remarks>
 /// <param name="boneAssignment"></param>
 public void AddBoneAssignment(VertexBoneAssignment boneAssignment)
 {
     if (!this.boneAssignmentList.ContainsKey(boneAssignment.vertexIndex))
     {
         this.boneAssignmentList[boneAssignment.vertexIndex] = new List <VertexBoneAssignment>();
     }
     this.boneAssignmentList[boneAssignment.vertexIndex].Add(boneAssignment);
     this.boneAssignmentsOutOfDate = true;
 }
Esempio n. 3
0
        protected void ReadVertexBoneAssigment(XmlNode node, SubMesh subMesh)
        {
            VertexBoneAssignment assignment = new VertexBoneAssignment();

            // read the data from the file
            assignment.vertexIndex = int.Parse(node.Attributes["vertexindex"].Value);
            assignment.boneIndex   = ushort.Parse(node.Attributes["boneindex"].Value);;
            assignment.weight      = float.Parse(node.Attributes["weight"].Value);;

            // add the assignment to the mesh
            subMesh.AddBoneAssignment(assignment);
        }
        public void SetPoints(List <Vector3> points, List <ColorEx> colors, List <VertexBoneAssignment> boneHandles)
        {
            // Preprocess the list of bone assignments so we get a list of
            // bone assignments for each vertex.
            List <List <VertexBoneAssignment> > boneAssignments = null;

            if (boneHandles != null)
            {
                Dictionary <int, List <VertexBoneAssignment> > dict = new Dictionary <int, List <VertexBoneAssignment> >();
                foreach (VertexBoneAssignment vba in boneHandles)
                {
                    List <VertexBoneAssignment> vbaList;
                    if (!dict.TryGetValue(vba.vertexIndex, out vbaList))
                    {
                        vbaList = new List <VertexBoneAssignment>();
                        dict[vba.vertexIndex] = vbaList;
                    }
                    vbaList.Add(vba);
                }
                // Construct the list of bone assignments for each vertex
                boneAssignments = new List <List <VertexBoneAssignment> >();
                for (int i = 0; i < points.Count; ++i)
                {
                    List <VertexBoneAssignment> vbaList;
                    if (!dict.TryGetValue(i, out vbaList))
                    {
                        vbaList = new List <VertexBoneAssignment>();
                    }
                    if (vbaList.Count > 4)
                    {
                        // only allowed to use 4 bone influences - trim the less important ones
                        vbaList.Sort(new VertexBoneAssignmentWeightComparer());
                        vbaList.RemoveRange(4, vbaList.Count - 4);
                    }
                    else
                    {
                        while (vbaList.Count < 4)
                        {
                            // Pad it out to 4 influences
                            VertexBoneAssignment vba = new VertexBoneAssignment();
                            vba.vertexIndex = i;
                            vba.boneIndex   = 0;
                            vba.weight      = 0;
                            vbaList.Add(vba);
                        }
                    }
                    boneAssignments.Add(vbaList);
                }
            }
            SetPointsImpl(points, colors, boneAssignments);
        }
 public static void CopyBoneAssignments(SubMesh dst, SubMesh src, Dictionary<uint, uint> vertexIdMap)
 {
     foreach (KeyValuePair<uint, uint> vertexMapping in vertexIdMap) {
         if (!src.BoneAssignmentList.ContainsKey((int)vertexMapping.Key))
             continue;
         List<VertexBoneAssignment> srcVbaList = src.BoneAssignmentList[(int)vertexMapping.Key];
         foreach (VertexBoneAssignment srcVba in srcVbaList) {
             Debug.Assert(srcVba.vertexIndex == (int)vertexMapping.Key);
             VertexBoneAssignment dstVba = new VertexBoneAssignment();
             dstVba.boneIndex = srcVba.boneIndex;
             dstVba.vertexIndex = (int)vertexMapping.Value;
             dstVba.weight = srcVba.weight;
             dst.AddBoneAssignment(dstVba);
         }
     }
 }
Esempio n. 6
0
 public static void CopyBoneAssignments(Mesh dst, Mesh src, Dictionary <uint, uint> vertexIdMap)
 {
     foreach (KeyValuePair <uint, uint> vertexMapping in vertexIdMap)
     {
         List <VertexBoneAssignment> srcVbaList = src.BoneAssignmentList[(int)vertexMapping.Key];
         foreach (VertexBoneAssignment srcVba in srcVbaList)
         {
             Debug.Assert(srcVba.vertexIndex == (int)vertexMapping.Key);
             VertexBoneAssignment dstVba = new VertexBoneAssignment();
             dstVba.boneIndex   = srcVba.boneIndex;
             dstVba.vertexIndex = (int)vertexMapping.Value;
             dstVba.weight      = srcVba.weight;
             dst.AddBoneAssignment(dstVba);
         }
     }
 }
        internal void RigidBindToBone(SubMesh subMesh, Bone bone)
        {
            m_Log.InfoFormat("Creating rigid binding from {0} to {1}", Id, bone.Name);

            for (int i = 0; i < subMesh.vertexData.vertexCount; ++i)
            {
                VertexBoneAssignment vba = new VertexBoneAssignment();

                vba.boneIndex = bone.Handle;

                vba.vertexIndex = i;

                vba.weight = 1.0f;

                subMesh.AddBoneAssignment(vba);
            }

            BoneAssignmentList = subMesh.BoneAssignmentList;
        }
Esempio n. 8
0
        protected XmlElement WriteVertexBoneAssignment(VertexBoneAssignment vba)
        {
            XmlElement   node = document.CreateElement("vertexboneassignment");
            XmlAttribute attr;

            attr       = document.CreateAttribute("vertexindex");
            attr.Value = vba.vertexIndex.ToString();
            node.Attributes.Append(attr);

            attr       = document.CreateAttribute("boneindex");
            attr.Value = vba.boneIndex.ToString();
            node.Attributes.Append(attr);

            attr       = document.CreateAttribute("weight");
            attr.Value = vba.weight.ToString();
            node.Attributes.Append(attr);

            return(node);
        }
        internal void WeightedBindToBones(SubMesh subMesh, List <VertexBoneAssignment> vbaList)
        {
            // Some of these vertices needed to be split into multiple vertices.
            // Rebuild the vertex bone assignment list, to have entries for our
            // new vertex ids instead.
            foreach (VertexBoneAssignment item in vbaList)
            {
                List <int> subMeshVertexIds = GetVertexIds(item.vertexIndex);

                if (null != subMeshVertexIds)
                {
                    foreach (int subVertexId in subMeshVertexIds)
                    {
                        VertexBoneAssignment vba = new VertexBoneAssignment(item);

                        vba.vertexIndex = subVertexId;

                        subMesh.AddBoneAssignment(vba);
                    }
                }
            }

            BoneAssignmentList = subMesh.BoneAssignmentList;
        }
Esempio n. 10
0
		/// <summary>
		///    Assigns a vertex to a bone with a given weight, for skeletal animation.
		/// </summary>
		/// <remarks>
		///    This method is only valid after setting the SkeletonName property.
		///    You should not need to modify bone assignments during rendering (only the positions of bones)
		///    and the engine reserves the right to do some internal data reformatting of this information,
		///    depending on render system requirements.
		/// </remarks>
		/// <param name="boneAssignment"></param>
		public void AddBoneAssignment( VertexBoneAssignment boneAssignment )
		{
			if ( !this.boneAssignmentList.ContainsKey( boneAssignment.vertexIndex ) )
			{
				this.boneAssignmentList[ boneAssignment.vertexIndex ] = new List<VertexBoneAssignment>();
			}
			this.boneAssignmentList[ boneAssignment.vertexIndex ].Add( boneAssignment );
			this.boneAssignmentsOutOfDate = true;
		}
Esempio n. 11
0
		protected void WriteMeshBoneAssignment( BinaryWriter writer, VertexBoneAssignment vba )
		{
			var start_offset = writer.Seek( 0, SeekOrigin.Current );
			WriteChunk( writer, MeshChunkID.MeshBoneAssignment, 0 );

			WriteUInt( writer, (uint)vba.vertexIndex );
			WriteUShort( writer, (ushort)vba.boneIndex );
			WriteFloat( writer, vba.weight );

			var end_offset = writer.Seek( 0, SeekOrigin.Current );
			writer.Seek( (int)start_offset, SeekOrigin.Begin );
			WriteChunk( writer, MeshChunkID.MeshBoneAssignment, (int)( end_offset - start_offset ) );
			writer.Seek( (int)end_offset, SeekOrigin.Begin );
		}
Esempio n. 12
0
		protected virtual void ReadSubMeshBoneAssignment( BinaryReader reader, SubMesh sub )
		{
			var assignment = new VertexBoneAssignment();

			// read the data from the file
			assignment.vertexIndex = ReadInt( reader );
			assignment.boneIndex = ReadUShort( reader );
			assignment.weight = ReadFloat( reader );

			// add the assignment to the mesh
			sub.AddBoneAssignment( assignment );
		}
        private LineRenderable CreateBoneLines(Skeleton skeleton)
        {
            List<Vector3> points = new List<Vector3>();
            List<ColorEx> colors = new List<ColorEx>();
            List<VertexBoneAssignment> vbas = new List<VertexBoneAssignment>();
            int vertexIndex = 0;
            VertexBoneAssignment vba;
            foreach (Bone bone in skeleton.Bones) {
                Matrix4 bindTransform = bone.BindDerivedInverseTransform.Inverse();
                Vector3 bonePosition = bindTransform.Translation;
                Bone parentBone = null;
                if (bone.Parent != null)
                    parentBone = bone.Parent as Bone;
                // If we have a parent bone, draw a line to the parent bone
                if (parentBone != null) {
                    points.Add(parentBone.BindDerivedInverseTransform.Inverse().Translation);
                    points.Add(bonePosition);
                    colors.Add(ColorEx.Cyan);
                    colors.Add(ColorEx.Cyan);
                    // Set up the vba for the bone base
                    vba = new VertexBoneAssignment();
                    vba.vertexIndex = vertexIndex++;
                    vba.weight = 1.0f;
                    vba.boneIndex = parentBone.Handle;
                    vbas.Add(vba);
                    // Set up the vba for the bone end
                    vba = new VertexBoneAssignment();
                    vba.vertexIndex = vertexIndex++;
                    vba.weight = 1.0f;
                    vba.boneIndex = bone.Handle;
                    vbas.Add(vba);
                }
                // Set up axis lines for this entry
                // X axis line
                points.Add(bonePosition);
                points.Add(bindTransform * (Vector3.UnitX * boneAxisLength));
                colors.Add(ColorEx.Red);
                colors.Add(ColorEx.Red);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
                // Y axis line
                points.Add(bonePosition);
                points.Add(bindTransform * (Vector3.UnitY * boneAxisLength));
                colors.Add(ColorEx.Blue);
                colors.Add(ColorEx.Blue);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
                // Z axis line
                points.Add(bonePosition);
                points.Add(bindTransform * (Vector3.UnitZ * boneAxisLength));
                colors.Add(ColorEx.Lime);
                colors.Add(ColorEx.Lime);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
                vba = new VertexBoneAssignment();
                vba.vertexIndex = vertexIndex++;
                vba.weight = 1.0f;
                vba.boneIndex = bone.Handle;
                vbas.Add(vba);
            }

            LineRenderable lines = new LineRenderable();
            lines.SetPoints(points, colors, vbas);
            lines.MaterialName = "MVSkinnedLines";
            lines.Skeleton = skeleton;
            return lines;
        }
Esempio n. 14
0
            private void ExportMesh(xxFrame meshParent, int indent)
            {
                string meshSpaces = GetStringSpaces(indent);
                xxMesh mesh = meshParent.Mesh;
                List<xxBone> boneList = mesh.BoneList;
                bool skinned = (boneList.Count > 0);
                for (int i = 0; i < mesh.SubmeshList.Count; i++)
                {
                    List<VertexBoneAssignment>[] boneAssignments = null;
                    if (skinned)
                    {
                        boneAssignments = new List<VertexBoneAssignment>[256];
                        for (int j = 0; j < boneAssignments.Length; j++)
                        {
                            boneAssignments[j] = new List<VertexBoneAssignment>();
                        }
                    }

                    writer.WriteLine(meshSpaces + "Mesh " + meshParent.Name + i + " {");
                    xxSubmesh submesh = mesh.SubmeshList[i];
                    List<xxFace> faceList = submesh.FaceList;
                    List<xxVertex> vertexList = submesh.VertexList;
                    writer.WriteLine(meshSpaces + " " + vertexList.Count + ";");
                    for (int j = 0; j < vertexList.Count; j++)
                    {
                        string s = meshSpaces + " ";
                        xxVertex vertex = vertexList[j];
                        Vector3 coords = vertex.Position;
                        coords[2] = -coords[2];

                        for (int k = 0; k < 3; k++)
                        {
                            s += coords[k].ToFloat6String() + ";";
                        }
                        if (j < (vertexList.Count - 1))
                        {
                            s += ",";
                        }
                        else
                        {
                            s += ";";
                        }
                        writer.WriteLine(s);

                        if (skinned)
                        {
                            float[] weights4 = vertex.Weights4(skinned);
                            byte[] boneIndices = vertex.BoneIndices;
                            for (int k = 0; k < boneIndices.Length; k++)
                            {
                                if ((boneIndices[k] != 0xFF) && (weights4[k] > 0))
                                {
                                    VertexBoneAssignment vba = new VertexBoneAssignment();
                                    vba.vertexIndex = j;
                                    vba.weight = weights4[k];
                                    boneAssignments[boneIndices[k]].Add(vba);
                                }
                            }
                        }
                    }
                    writer.WriteLine(meshSpaces + " " + faceList.Count + ";");
                    for (int j = 0; j < faceList.Count; j++)
                    {
                        string s = meshSpaces + " 3;";
                        xxFace face = faceList[j];
                        s += face.VertexIndices[0].ToString() + ",";
                        s += face.VertexIndices[2].ToString() + ",";
                        s += face.VertexIndices[1].ToString() + ";";
                        if (j < (faceList.Count - 1))
                        {
                            s += ",";
                        }
                        else
                        {
                            s += ";";
                        }
                        writer.WriteLine(s);
                    }
                    writer.WriteLine();

                    writer.WriteLine(meshSpaces + " MeshNormals {");
                    writer.WriteLine(meshSpaces + "  " + vertexList.Count + ";");
                    for (int j = 0; j < vertexList.Count; j++)
                    {
                        xxVertex vertex = vertexList[j];
                        Vector3 normal = vertex.Normal;
                        writer.Write(meshSpaces + "  " + normal[0].ToFloat6String() + ";" + normal[1].ToFloat6String() + ";" + (-normal[2]).ToFloat6String() + ";");
                        if (j < (vertexList.Count - 1))
                        {
                            writer.WriteLine(",");
                        }
                        else
                        {
                            writer.WriteLine(";");
                        }
                    }
                    writer.WriteLine(meshSpaces + "  " + faceList.Count + ";");
                    for (int j = 0; j < faceList.Count; j++)
                    {
                        xxFace face = faceList[j];
                        writer.Write(meshSpaces + "  3;" + face.VertexIndices[0] + "," + face.VertexIndices[2] + "," + face.VertexIndices[1] + ";");
                        if (j < (faceList.Count - 1))
                        {
                            writer.WriteLine(",");
                        }
                        else
                        {
                            writer.WriteLine(";");
                        }
                    }
                    writer.WriteLine(meshSpaces + " }");
                    writer.WriteLine();

                    writer.WriteLine(meshSpaces + " MeshTextureCoords {");
                    writer.WriteLine(meshSpaces + "  " + vertexList.Count + ";");
                    for (int j = 0; j < vertexList.Count; j++)
                    {
                        xxVertex vertex = vertexList[j];
                        float[] uv = vertex.UV;
                        writer.Write(meshSpaces + "  " + uv[0].ToFloat6String() + ";" + uv[1].ToFloat6String() + ";");
                        if (j < (vertexList.Count - 1))
                        {
                            writer.WriteLine(",");
                        }
                        else
                        {
                            writer.WriteLine(";");
                        }
                    }
                    writer.WriteLine(meshSpaces + " }");
                    writer.WriteLine();

                    int materialIdx = submesh.MaterialIndex;
                    if ((materialIdx >= 0) && (materialIdx < xxParser.MaterialList.Count))
                    {
                        writer.WriteLine(meshSpaces + " MeshMaterialList {");
                        writer.WriteLine(meshSpaces + "  1;");
                        writer.WriteLine(meshSpaces + "  " + faceList.Count + ";");
                        for (int j = 0; j < faceList.Count; j++)
                        {
                            writer.Write(meshSpaces + "  0");
                            if (j < (faceList.Count - 1))
                            {
                                writer.WriteLine(",");
                            }
                            else
                            {
                                writer.WriteLine(";");
                            }
                        }

                        xxMaterial mat = xxParser.MaterialList[materialIdx];
                        Color4 ambient = mat.Ambient;
                        Color4 specular = mat.Specular;
                        Color4 emissive = mat.Emissive;
                        writer.WriteLine();
                        writer.WriteLine(meshSpaces + "  Material " + mat.Name + " {");
                        writer.WriteLine(meshSpaces + "   " + ambient.Red.ToFloat6String() + ";" + ambient.Green.ToFloat6String() + ";" + ambient.Blue.ToFloat6String() + ";" + ambient.Alpha.ToFloat6String() + ";;");
                        writer.WriteLine(meshSpaces + "   " + mat.Power.ToFloat6String() + ";");
                        writer.WriteLine(meshSpaces + "   " + specular.Red.ToFloat6String() + ";" + specular.Green.ToFloat6String() + ";" + specular.Blue.ToFloat6String() + ";;");
                        writer.WriteLine(meshSpaces + "   " + emissive.Red.ToFloat6String() + ";" + emissive.Green.ToFloat6String() + ";" + emissive.Blue.ToFloat6String() + ";;");
                        xxMaterialTexture matTex = mat.Textures[0];
                        if (matTex.Name != String.Empty)
                        {
                            writer.WriteLine();
                            writer.WriteLine(meshSpaces + "   TextureFilename {");
                            writer.WriteLine(meshSpaces + "    \"" + matTex.Name + "\";");
                            writer.WriteLine(meshSpaces + "   }");

                            for (int j = 0; j < xxParser.TextureList.Count; j++)
                            {
                                xxTexture tex = xxParser.TextureList[j];
                                if (matTex.Name == tex.Name)
                                {
                                    if (!usedTextures.ContainsKey(tex.Name))
                                    {
                                        usedTextures.Add(tex.Name, tex);
                                    }
                                    break;
                                }
                            }
                        }
                        writer.WriteLine(meshSpaces + "  }");
                        writer.WriteLine(meshSpaces + " }" + Environment.NewLine);
                    }
                    else
                    {
                        Report.ReportLog("Warning: mesh " + meshParent.Name + " object " + i + " uses non-existant material index " + materialIdx);
                    }

                    if (skinned)
                    {
                        int numUsedBones = 0;
                        for (int j = 0; j < boneList.Count; j++)
                        {
                            xxBone bone = boneList[j];
                            if (boneAssignments[bone.Index].Count > 0)
                            {
                                numUsedBones++;
                            }
                        }

                        writer.WriteLine(meshSpaces + " XSkinMeshHeader {");
                        writer.WriteLine(meshSpaces + "  4;");
                        writer.WriteLine(meshSpaces + "  12;");
                        writer.WriteLine(meshSpaces + "  " + numUsedBones + ";");
                        writer.WriteLine(meshSpaces + " }");
                        writer.WriteLine();

                        for (int j = 0; j < boneList.Count; j++)
                        {
                            xxBone bone = boneList[j];
                            List<VertexBoneAssignment> boneAssignmentList = boneAssignments[bone.Index];
                            if (boneAssignmentList.Count <= 0)
                            {
                                continue;
                            }

                            writer.WriteLine(meshSpaces + " SkinWeights {");
                            writer.WriteLine(meshSpaces + "  \"" + bone.Name + "\";");
                            writer.WriteLine(meshSpaces + "  " + boneAssignmentList.Count + ";");

                            string vertexString = String.Empty;
                            string weightString = String.Empty;
                            for (int k = 0; k < boneAssignmentList.Count; k++)
                            {
                                vertexString += meshSpaces + "  " + boneAssignmentList[k].vertexIndex;
                                weightString += meshSpaces + "  " + boneAssignmentList[k].weight.ToFloat6String();
                                if (k < (boneAssignmentList.Count - 1))
                                {
                                    vertexString += "," + Environment.NewLine;
                                    weightString += "," + Environment.NewLine;
                                }
                                else
                                {
                                    vertexString += ";" + Environment.NewLine;
                                    weightString += ";" + Environment.NewLine;
                                }
                            }

                            Matrix matrix = RHToLHMatrix(bone.Matrix);
                            writer.Write(vertexString);
                            writer.Write(weightString);
                            writer.WriteLine(meshSpaces + "  " + GetStringMatrix(matrix) + ";;");
                            writer.WriteLine(meshSpaces + " }");
                            writer.WriteLine();
                        }
                    }

                    writer.WriteLine(meshSpaces + "}");
                    writer.WriteLine();
                }
            }
 public void SetPoints(List<Vector3> points, List<ColorEx> colors, List<VertexBoneAssignment> boneHandles)
 {
     // Preprocess the list of bone assignments so we get a list of
     // bone assignments for each vertex.
     List<List<VertexBoneAssignment>> boneAssignments = null;
     if (boneHandles != null) {
         Dictionary<int, List<VertexBoneAssignment>> dict = new Dictionary<int, List<VertexBoneAssignment>>();
         foreach (VertexBoneAssignment vba in boneHandles) {
             List<VertexBoneAssignment> vbaList;
             if (!dict.TryGetValue(vba.vertexIndex, out vbaList)) {
                 vbaList = new List<VertexBoneAssignment>();
                 dict[vba.vertexIndex] = vbaList;
             }
             vbaList.Add(vba);
         }
         // Construct the list of bone assignments for each vertex
         boneAssignments = new List<List<VertexBoneAssignment>>();
         for (int i = 0; i < points.Count; ++i) {
             List<VertexBoneAssignment> vbaList;
             if (!dict.TryGetValue(i, out vbaList))
                 vbaList = new List<VertexBoneAssignment>();
             if (vbaList.Count > 4) {
                 // only allowed to use 4 bone influences - trim the less important ones
                 vbaList.Sort(new VertexBoneAssignmentWeightComparer());
                 vbaList.RemoveRange(4, vbaList.Count - 4);
             } else {
                 while (vbaList.Count < 4) {
                     // Pad it out to 4 influences
                     VertexBoneAssignment vba = new VertexBoneAssignment();
                     vba.vertexIndex = i;
                     vba.boneIndex = 0;
                     vba.weight = 0;
                     vbaList.Add(vba);
                 }
             }
             boneAssignments.Add(vbaList);
         }
     }
     SetPointsImpl(points, colors, boneAssignments);
 }
 internal static global::System.Runtime.InteropServices.HandleRef getCPtr(VertexBoneAssignment obj)
 {
     return((obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr);
 }
        protected XmlElement WriteVertexBoneAssignment(VertexBoneAssignment vba)
        {
            XmlElement node = document.CreateElement("vertexboneassignment");
            XmlAttribute attr;

            attr = document.CreateAttribute("vertexindex");
            attr.Value = vba.vertexIndex.ToString();
            node.Attributes.Append(attr);

            attr = document.CreateAttribute("boneindex");
            attr.Value = vba.boneIndex.ToString();
            node.Attributes.Append(attr);

            attr = document.CreateAttribute("weight");
            attr.Value = vba.weight.ToString();
            node.Attributes.Append(attr);

            return node;
        }
        protected void ReadVertexBoneAssigment(XmlNode node, SubMesh subMesh)
        {
            VertexBoneAssignment assignment = new VertexBoneAssignment();

            // read the data from the file
            assignment.vertexIndex = int.Parse(node.Attributes["vertexindex"].Value);
            assignment.boneIndex = ushort.Parse(node.Attributes["boneindex"].Value); ;
            assignment.weight = float.Parse(node.Attributes["weight"].Value); ;

            // add the assignment to the mesh
            subMesh.AddBoneAssignment(assignment);
        }