/* Creates a list of bones based on object names found in OBJ file and assigns them * default values. These will be replaced if a bone definition file is found. * By default there is one root parent bone and every other bone is a child bone with one child (until the end) */ protected bool LoadDefaultBones(string modelFileName) { Stream fs = File.OpenRead(m_ModelFileName); StreamReader sr = new StreamReader(fs); bool foundObjects = false; ModelBase.BoneDef bone = null; string curline; while ((curline = sr.ReadLine()) != null) { curline = curline.Trim(); // skip empty lines and comments if (curline.Length < 1) { continue; } if (curline[0] == '#') { continue; } string[] parts = curline.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 1) { continue; } switch (parts[0]) { case "o": // object (bone) { bone = new ModelBase.BoneDef(parts[1]); if (m_Model.m_BoneTree.Count == 0) { m_Model.m_BoneTree.AddRootBone(bone); } else { m_Model.m_BoneTree.GetAsList()[m_Model.m_BoneTree.Count - 1].AddChild(bone); } foundObjects = true; } break; } } sr.Close(); return(foundObjects); }
public override ModelBase LoadModel(float scale) { ModelBase.BoneDef rootBone = new ModelBase.BoneDef("CollisionMap"); m_Model.m_BoneTree.AddRootBone(rootBone); rootBone.CalculateBranchTransformations(); m_Model.m_BoneTransformsMap.Add(rootBone.m_ID, m_Model.m_BoneTransformsMap.Count); ModelBase.GeometryDef geometry = new ModelBase.GeometryDef("geometry-0"); rootBone.m_Geometries.Add(geometry.m_ID, geometry); List <int> uniqueCollisionTypes = new List <int>(); foreach (KCL.ColFace plane in m_KCL.m_Planes) { if (!uniqueCollisionTypes.Contains(plane.type)) { uniqueCollisionTypes.Add(plane.type); } } uniqueCollisionTypes.Sort(); CollisionMapColours collisionMapColours = new CollisionMapColours(); foreach (int type in uniqueCollisionTypes) { ModelBase.MaterialDef material = new ModelBase.MaterialDef("material-" + type); material.m_Diffuse = collisionMapColours[type]; m_Model.m_Materials.Add(material.m_ID, material); rootBone.m_MaterialsInBranch.Add(material.m_ID); ModelBase.PolyListDef tmp = new ModelBase.PolyListDef("polylist-" + type, material.m_ID); tmp.m_FaceLists.Add(new ModelBase.FaceListDef(ModelBase.PolyListType.Triangles)); rootBone.m_Geometries[geometry.m_ID].m_PolyLists.Add("polylist-" + type, tmp); } foreach (KCL.ColFace plane in m_KCL.m_Planes) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0].m_Position = plane.point1; face.m_Vertices[1].m_Position = plane.point2; face.m_Vertices[2].m_Position = plane.point3; for (int vert = 0; vert < face.m_Vertices.Length; vert++) { face.m_Vertices[vert].m_TextureCoordinate = null; face.m_Vertices[vert].m_Normal = null; face.m_Vertices[vert].m_VertexColour = Color.White; face.m_Vertices[vert].m_VertexBoneIndex = 0; } geometry.m_PolyLists["polylist-" + plane.type].m_FaceLists[0].m_Faces.Add(face); } return(m_Model); }
public override ModelBase LoadModel(OpenTK.Vector3 scale) { ModelBase.BoneDef rootBone = new ModelBase.BoneDef("CollisionMap"); m_Model.m_BoneTree.AddRootBone(rootBone); ModelBase.GeometryDef geometry = new ModelBase.GeometryDef("geometry-0"); rootBone.m_Geometries.Add(geometry.m_ID, geometry); List<int> uniqueCollisionTypes = new List<int>(); foreach (KCL.ColFace plane in m_KCL.m_Planes) { if (!uniqueCollisionTypes.Contains(plane.type)) uniqueCollisionTypes.Add(plane.type); } uniqueCollisionTypes.Sort(); List<Color> uniqueColours = GetColours(uniqueCollisionTypes[uniqueCollisionTypes.Count - 1] + 1); foreach (int type in uniqueCollisionTypes) { ModelBase.MaterialDef material = new ModelBase.MaterialDef("material-" + type, m_Model.m_Materials.Count); material.m_Diffuse = uniqueColours[type]; m_Model.m_Materials.Add(material.m_ID, material); rootBone.m_MaterialsInBranch.Add(material.m_ID); ModelBase.PolyListDef tmp = new ModelBase.PolyListDef("polylist-" + type, material.m_ID); tmp.m_FaceLists.Add(new ModelBase.FaceListDef()); rootBone.m_Geometries[geometry.m_ID].m_PolyLists.Add("polylist-" + type, tmp); } foreach (KCL.ColFace plane in m_KCL.m_Planes) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0].m_Position = plane.point1; face.m_Vertices[1].m_Position = plane.point2; face.m_Vertices[2].m_Position = plane.point3; for (int vert = 0; vert < face.m_Vertices.Length; vert++) { face.m_Vertices[vert].m_TextureCoordinate = Vector2.Zero; face.m_Vertices[vert].m_Normal = null; face.m_Vertices[vert].m_VertexColour = Color.White; face.m_Vertices[vert].m_VertexBoneID = 0; } geometry.m_PolyLists["polylist-" + plane.type].m_FaceLists[0].m_Faces.Add(face); } return m_Model; }
private void ReadNode(node joint, node parent, bool inSkeleton) { string id = (joint.id != null ? joint.id : (joint.name != null ? joint.name : m_Model.m_BoneTree.Count.ToString())); Vector3 nodeScale = Vector3.One; Vector3 nodeRotation = Vector3.Zero; Vector3 nodeTranslation = Vector3.Zero; ReadNodeTransformations(joint, ref nodeScale, ref nodeRotation, ref nodeTranslation); if (joint.instance_geometry != null && joint.instance_geometry.Length > 0) { // Making an assumption that <instance_geometry> will never appear within a skeleton, not sure if it can? ModelBase.BoneDef rootBone = new ModelBase.BoneDef(id); rootBone.SetScale(nodeScale); rootBone.SetRotation(nodeRotation); rootBone.SetTranslation(nodeTranslation); m_Model.m_BoneTree.AddRootBone(rootBone); m_Model.m_BoneTransformsMap.Add(id, m_Model.m_BoneTree.GetBoneIndex(id)); foreach (instance_geometry instanceGeometry in joint.instance_geometry) { string geometryID = instanceGeometry.url.Replace("#", ""); Dictionary<string, string> bindMaterials = new Dictionary<string, string>(); if (instanceGeometry.bind_material != null) { foreach (instance_material instanceMaterial in instanceGeometry.bind_material.technique_common) { bindMaterials.Add(instanceMaterial.symbol, instanceMaterial.target.Replace("#", "")); } } ModelBase.GeometryDef geometry = ReadGeometry(geometryID, id, bindMaterials); rootBone.m_Geometries.Add(geometryID, geometry); } } else if (joint.instance_controller != null && joint.instance_controller.Length > 0) { // Making an assumption that <instance_controller> will never appear within a skeleton, not sure if it can? instance_controller instanceController = joint.instance_controller[0]; string controllerID = instanceController.url.Replace("#", ""); if (instanceController.skeleton != null && instanceController.skeleton.Length > 0) { /*string skeletonRoot = null; foreach (string skel in instanceController.skeleton) { string skeleton = skel.Replace("#", ""); if (skeletonRoot == null) skeletonRoot = skeleton; if (m_Model.m_BoneTree.GetBoneByID(skeleton) != null) continue; ReadSkeleton(skeletonRoot); } // WRONG */ string skeletonRoot = instanceController.skeleton[0].Replace("#", ""); ReadSkeleton(skeletonRoot); controller cntl = this.library_controllers.controller.Where(cntl0 => cntl0.id.Equals(controllerID)).ElementAt(0); if (cntl.Item as skin != null) { // Currently there is only support for skin controllers. Where a skin uses as its source another // controller eg. a morph, we'll just recursively go through until we find a skin with a geometry // as the source and return the geometry's ID. // I've seen a skin use a skin as a source where the first skin gave joint indices of -1 from 3DS Max and // OpenCOLLAD, in cases like this, we do as above and just take the geometry ID and attach the skin being // read to that. string skinSourceID = null; var queue = new Queue<controller>(); queue.Enqueue(cntl); while (queue.Count > 0) { controller cont = queue.Dequeue(); string srcID = (cont.Item as skin).source1.Replace("#", ""); if (this.library_geometries != null && this.library_geometries.geometry.Where(geom0 => geom0.id.Equals(srcID)).Count() < 1) { IEnumerable<controller> res = this.library_controllers.controller.Where(cont0 => cont0.id.Equals(srcID)); if (res.Count() > 0) { queue.Enqueue(res.ElementAt(0)); } } else { skinSourceID = srcID; } } m_Model.m_BoneTransformsMap.Clear(); int[] vertexBoneIDs = ReadSkinController(controllerID, skeletonRoot, skinSourceID); Dictionary<string, string> bindMaterials = new Dictionary<string, string>(); if (instanceController.bind_material != null) { foreach (instance_material instanceMaterial in instanceController.bind_material.technique_common) { bindMaterials.Add(instanceMaterial.symbol, instanceMaterial.target.Replace("#", "")); } } ModelBase.GeometryDef geomDef = ReadGeometry(skinSourceID, skeletonRoot, bindMaterials, vertexBoneIDs); m_Model.m_BoneTree.GetBoneByID(skeletonRoot).m_Geometries.Add(skinSourceID, geomDef); } } } else if (inSkeleton) { ModelBase.BoneDef boneDef = new ModelBase.BoneDef(joint.id); if (joint == parent) { m_Model.m_BoneTree.AddRootBone(boneDef); } else { ModelBase.BoneDef parentBone = m_Model.m_BoneTree.GetBoneByID(parent.id); parentBone.AddChild(boneDef); } boneDef.SetScale(nodeScale); boneDef.SetRotation(nodeRotation); boneDef.SetTranslation(nodeTranslation); if (joint.node1 == null || joint.node1.Length == 0) return; foreach (node child in joint.node1) { if (child.type.Equals(NodeType.NODE)) { Console.WriteLine("Warning: node: " + joint.id + " has a child of type \"NODE\" within a skeleton, failure likely"); } ReadNode(child, joint, true); } } }
protected void ReadNodes(XmlNode node_array, XmlNode polygon_array, XmlNode matrix_array) { if (node_array == null) { return; } int nodeArray_size = int.Parse(node_array.Attributes["size"].Value); if (nodeArray_size < 1) { return; } XmlNodeList nodes = node_array.SelectNodes("node"); foreach (XmlNode node in nodes) { m_OriginalNodeIndices.Add(int.Parse(node.Attributes["index"].Value), node.Attributes["name"].Value); } ReadMatrices(matrix_array, m_OriginalNodeIndices); var queue = new Queue <XmlNode>(); var geometryQueue = new Queue <XmlNode>(); queue.Enqueue(nodes[0]); while (queue.Count > 0) { XmlNode node = queue.Dequeue(); int index = int.Parse(node.Attributes["index"].Value); string name = node.Attributes["name"].Value; string kind = node.Attributes["kind"].Value; int parent = int.Parse(node.Attributes["parent"].Value); int child = int.Parse(node.Attributes["child"].Value); int brother_next = int.Parse(node.Attributes["brother_next"].Value); int brother_prev = int.Parse(node.Attributes["brother_prev"].Value); bool draw_mtx = node.Attributes["draw_mtx"].Value.Equals("on"); string scale_compensate = (node.Attributes["scale_compensate"] != null) ? node.Attributes["scale_compensate"].Value : null; string billboard = node.Attributes["billboard"].Value; // Either "on", "off" or "y_on" float[] scale = Array.ConvertAll( node.Attributes["scale"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); float[] rotate = Array.ConvertAll( node.Attributes["rotate"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); float[] translate = Array.ConvertAll( node.Attributes["translate"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); bool visibility = node.Attributes["visibility"].Value.Equals("on"); int display_size = int.Parse(node.Attributes["display_size"].Value); int vertex_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["vertex_size"].Value) : -1; int polygon_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["polygon_size"].Value) : -1; int triangle_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["triangle_size"].Value) : -1; int quad_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["quad_size"].Value) : -1; float[] volume_min = (kind.Equals("mesh")) ? Array.ConvertAll( node.Attributes["volume_min"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle) : null; float[] volume_max = (kind.Equals("mesh")) ? Array.ConvertAll( node.Attributes["volume_max"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle) : null; float volume_r = (kind.Equals("mesh")) ? float.Parse(node.Attributes["volume_r"].Value) : -1; ModelBase.BoneDef boneDef = new ModelBase.BoneDef(name); boneDef.SetScale(new Vector3(scale[0], scale[1], scale[2])); boneDef.SetRotation(new Vector3(rotate[0] * Helper.Deg2Rad, rotate[1] * Helper.Deg2Rad, rotate[2] * Helper.Deg2Rad)); boneDef.SetTranslation(new Vector3(translate[0], translate[1], translate[2])); boneDef.CalculateBranchTransformations(); if (display_size > 0) { geometryQueue.Enqueue(node); } if (parent == -1) { m_Model.m_BoneTree.AddRootBone(boneDef); } else { m_Model.m_BoneTree.GetBoneByID(m_OriginalNodeIndices[parent]).AddChild(boneDef); } /* Child node takes priority and siblings are stored consecutively by name in alphanumerical order * (a→z and 0→9). The model root node must be the first <node> in <node_array> (index 0). * "child" attribute gives first child, alphanumerically. */ if (child != -1) { queue.Enqueue(nodes[child]); } if (brother_next != -1) { queue.Enqueue(nodes[brother_next]); } } // In oder to correctly read the geometry we need to already have the list of bones read in so that bone ID's // can be assigned to vertices while (geometryQueue.Count > 0) { XmlNode node = geometryQueue.Dequeue(); XmlNodeList displays = node.SelectNodes("display"); ModelBase.BoneDef boneDef = m_Model.m_BoneTree.GetBoneByID(node.Attributes["name"].Value); ModelBase.GeometryDef geometryDef = new ModelBase.GeometryDef("geometry-0"); foreach (XmlNode display in displays) { int display_index = int.Parse(display.Attributes["index"].Value); int display_material = int.Parse(display.Attributes["material"].Value); int display_polygon = int.Parse(display.Attributes["polygon"].Value); int display_priority = int.Parse(display.Attributes["priority"].Value); ReadPolygon(display_polygon, polygon_array, m_Model.m_Materials.ElementAt(display_material).Key, geometryDef); boneDef.m_MaterialsInBranch.Add(m_Model.m_Materials.ElementAt(display_material).Key); } boneDef.m_Geometries.Add(geometryDef.m_ID, geometryDef); } m_Model.ApplyTransformations(); }
public override ModelBase LoadModel(OpenTK.Vector3 scale) { foreach (BMD.ModelChunk mdchunk in m_BMD.m_ModelChunks) { ModelBase.BoneDef bone = new ModelBase.BoneDef(mdchunk.m_Name); bone.SetScale(mdchunk.m_20_12Scale); bone.SetRotation(mdchunk.m_4_12Rotation); bone.SetTranslation(mdchunk.m_20_12Translation); if (mdchunk.m_ParentOffset == 0) { m_Model.m_BoneTree.AddRootBone(bone); } else { List <ModelBase.BoneDef> listOfBones = m_Model.m_BoneTree.GetAsList(); listOfBones[listOfBones.Count + mdchunk.m_ParentOffset].AddChild(bone); } ModelBase.GeometryDef geomDef = null; if (mdchunk.m_MatGroups.Length > 0) { geomDef = new ModelBase.GeometryDef("geometry-0"); bone.m_Geometries.Add(geomDef.m_ID, geomDef); } foreach (BMD.MaterialGroup matgroup in mdchunk.m_MatGroups) { if (!geomDef.m_PolyLists.ContainsKey(matgroup.m_Name)) { ModelBase.PolyListDef pld = new ModelBase.PolyListDef("polylist-" + matgroup.m_Name, matgroup.m_Name); geomDef.m_PolyLists.Add(pld.m_MaterialName, pld); } ModelBase.PolyListDef polyListDef = geomDef.m_PolyLists[matgroup.m_Name]; ModelBase.MaterialDef material = new ModelBase.MaterialDef(matgroup.m_Name, m_Model.m_Materials.Count); material.m_Diffuse = matgroup.m_DiffuseColor; material.m_Ambient = matgroup.m_AmbientColor; material.m_Specular = matgroup.m_SpecularColor; material.m_Emission = matgroup.m_EmissionColor; bool hasTextures = (matgroup.m_Texture != null); if (hasTextures) { if (!m_Model.m_Textures.ContainsKey(matgroup.m_Texture.m_TexName)) { ModelBase.TextureDefBase texture = new ModelBase.TextureDefInMemoryBitmap( matgroup.m_Texture.m_TexName, ConvertBMDTextureToBitmap(matgroup.m_Texture)); m_Model.m_Textures.Add(texture.m_ID, texture); } material.m_TextureDefID = matgroup.m_Texture.m_TexName; } material.m_Alpha = matgroup.m_Alpha; if ((matgroup.m_PolyAttribs & 0xC0) == 0xC0) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.FrontAndBack; } else if ((matgroup.m_PolyAttribs & 0xC0) == 0x80) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Front; } else if ((matgroup.m_PolyAttribs & 0xC0) == 0x40) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Back; } if (!m_Model.m_Materials.ContainsKey(material.m_ID)) { m_Model.m_Materials.Add(material.m_ID, material); } bone.m_MaterialsInBranch.Add(matgroup.m_Name); ModelBase.BoneDef upToRoot = bone; while ((upToRoot = upToRoot.m_Parent) != null) { if (!upToRoot.m_MaterialsInBranch.Contains(matgroup.m_Name)) { upToRoot.m_MaterialsInBranch.Add(matgroup.m_Name); } } foreach (BMD.VertexList geometry in matgroup.m_Geometry) { uint polyType = geometry.m_PolyType; List <BMD.Vertex> vtxList = geometry.m_VertexList; switch (polyType) { case 0: //Separate Triangles { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Triangles); if (vtxList.Count <= 3) //Just 1 triangle { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[0].m_Position, vtxList[0].m_TexCoord, vtxList[0].m_Normal, vtxList[0].m_Color, (int)matgroup.m_BoneIDs[vtxList[0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[1].m_Position, vtxList[1].m_TexCoord, vtxList[1].m_Normal, vtxList[1].m_Color, (int)matgroup.m_BoneIDs[vtxList[1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[2].m_Position, vtxList[2].m_TexCoord, vtxList[2].m_Normal, vtxList[2].m_Color, (int)matgroup.m_BoneIDs[vtxList[2].m_MatrixID]); faceList.m_Faces.Add(face); } else if (vtxList.Count > 3 && (float)vtxList.Count % 3 == 0.0f) //Eg. 9 vertices in 3 triangles { int numFaces = vtxList.Count / 3; for (int a = 0, b = 0; a < numFaces; a++, b = b + 3) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); faceList.m_Faces.Add(face); } } polyListDef.m_FaceLists.Add(faceList); break; } case 1: //Separate Quadrilaterals { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Polygons); if (vtxList.Count <= 4) //Just 1 quadrilateral { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[0].m_Position, vtxList[0].m_TexCoord, vtxList[0].m_Normal, vtxList[0].m_Color, (int)matgroup.m_BoneIDs[vtxList[0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[1].m_Position, vtxList[1].m_TexCoord, vtxList[1].m_Normal, vtxList[1].m_Color, (int)matgroup.m_BoneIDs[vtxList[1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[2].m_Position, vtxList[2].m_TexCoord, vtxList[2].m_Normal, vtxList[2].m_Color, (int)matgroup.m_BoneIDs[vtxList[2].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[3].m_Position, vtxList[3].m_TexCoord, vtxList[3].m_Normal, vtxList[3].m_Color, (int)matgroup.m_BoneIDs[vtxList[3].m_MatrixID]); faceList.m_Faces.Add(face); } else if (vtxList.Count > 4 && (float)vtxList.Count % 4 == 0.0f) //Eg. 8 vertices in 2 quadrilaterals { int numFaces = vtxList.Count / 4; for (int a = 0, b = 0; a < numFaces; a++, b = b + 4) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[b + 3].m_Position, vtxList[b + 3].m_TexCoord, vtxList[b + 3].m_Normal, vtxList[b + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 3].m_MatrixID]); faceList.m_Faces.Add(face); } } polyListDef.m_FaceLists.Add(faceList); break; } case 2: //Triangle Strips { //3+(N-1) vertices per N triangles //(N-3)+1 Triangles per N Vertices int numFaces = vtxList.Count - 2; if (vtxList.Count < 3) //Should never be { break; } ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip); //Convert all faces with more than 3 vertices to ones with only 3 for (int n = 0; n < numFaces; n++) { if (n % 2 == 0) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 1].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); faceList.m_Faces.Add(face); } else { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); faceList.m_Faces.Add(face); } //Because of how normals are defined in triangle strips, every 2nd triangle is clockwise, whereas all others are anti-clockwise } polyListDef.m_FaceLists.Add(faceList); break; } case 3: //Quadrilateral Strips { //4+(N-1)*2 vertices per N quads //((N-4)/2) + 1 Quads. per N Vertices int numFaces = ((vtxList.Count - 4) / 2) + 1; if (vtxList.Count < 4) //Should never be { break; } ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(); for (int n = 0, p = 0; n < numFaces; n++, p = p + 2) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[p + 0].m_Position, vtxList[p + 0].m_TexCoord, vtxList[p + 0].m_Normal, vtxList[p + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[p + 1].m_Position, vtxList[p + 1].m_TexCoord, vtxList[p + 1].m_Normal, vtxList[p + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[p + 3].m_Position, vtxList[p + 3].m_TexCoord, vtxList[p + 3].m_Normal, vtxList[p + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 3].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[p + 2].m_Position, vtxList[p + 2].m_TexCoord, vtxList[p + 2].m_Normal, vtxList[p + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 2].m_MatrixID]); faceList.m_Faces.Add(face); } polyListDef.m_FaceLists.Add(faceList); break; } default: MessageBox.Show("Unknown polygon type."); break; }//End polyType switch } } bone.CalculateBranchTransformations(); } m_Model.ApplyTransformations(); return(m_Model); }
public override void WriteModel(bool save = true) { StreamWriter objWriter = new StreamWriter(m_ModelFileName); StreamWriter mtlWriter = new StreamWriter(m_ModelFileName.Substring(0, m_ModelFileName.Length - 4) + ".mtl"); string dir = Path.GetDirectoryName(m_ModelFileName); string baseFileName = Path.GetFileNameWithoutExtension(m_ModelFileName); objWriter.Write("#" + Program.AppTitle + " " + Program.AppVersion + " " + Program.AppDate + "\n\n"); objWriter.Write("mtllib " + baseFileName + ".mtl" + "\n\n"); // Specify name of material library objWriter.Write("bonelib " + baseFileName + ".bones" + "\n\n"); // Specify name of bones list // OBJ does not support skinning, bones or vertex-specific object assignment so instead we use the bone ID // specified in the first vertex of each face to assign that whole face to an object int boneIndex = 0; List <ModelBase.BoneDef> flatBoneList = m_Model.m_BoneTree.GetAsList(); foreach (ModelBase.BoneDef bone in m_Model.m_BoneTree) { foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values) { foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values) { int fl = 0; while (fl < polyList.m_FaceLists.Count) { ModelBase.FaceListDef faceList = polyList.m_FaceLists[fl]; int f = 0; int count = faceList.m_Faces.Count; while (f < faceList.m_Faces.Count) { ModelBase.FaceDef face = faceList.m_Faces[f]; int objSplitBoneID = face.m_Vertices[0].m_VertexBoneIndex; if (objSplitBoneID != boneIndex) { ModelBase.BoneDef newBone = flatBoneList[objSplitBoneID]; // For models using "areas" (multiple-parent bones) the vertices all seem to be // assigned to the first parent bone. We don't want to move faces about in such // cases so only move faces between bones within the same branch. if (bone.GetBranch().Contains(newBone)) { if (!newBone.m_Geometries.ContainsKey(geometry.m_ID)) { newBone.m_Geometries.Add(geometry.m_ID, new ModelBase.GeometryDef(geometry.m_ID)); } if (!newBone.m_Geometries[geometry.m_ID].m_PolyLists.ContainsKey(polyList.m_MaterialName)) { ModelBase.PolyListDef tmp = new ModelBase.PolyListDef(polyList.m_ID, polyList.m_MaterialName); tmp.m_FaceLists.Add(new ModelBase.FaceListDef()); newBone.m_Geometries[geometry.m_ID].m_PolyLists.Add(polyList.m_MaterialName, tmp); } if (!newBone.m_MaterialsInBranch.Contains(polyList.m_MaterialName)) { newBone.m_MaterialsInBranch.Add(polyList.m_MaterialName); } newBone.m_Geometries[geometry.m_ID].m_PolyLists[polyList.m_MaterialName].m_FaceLists[0].m_Faces.Add(face); faceList.m_Faces.RemoveAt(f); } } f++; } fl++; } } } boneIndex++; } // Write mtllib foreach (ModelBase.MaterialDef material in m_Model.m_Materials.Values) { //For every texture, string textureName = (material.m_TextureDefID != null) ? m_Model.m_Textures[material.m_TextureDefID].m_ID : null; //Create new material mtlWriter.Write("newmtl " /*+ ((i * 2) + j)*/ + material.m_ID + "\n"); //Specify ambient colour - RGB 0-1 mtlWriter.Write("Ka " + Helper.ToString(material.m_Ambient.R / 255.0f) + " " + Helper.ToString(material.m_Ambient.G / 255.0f) + " " + Helper.ToString(material.m_Ambient.B / 255.0f) + "\n"); //Specify diffuse colour - RGB 0-1 mtlWriter.Write("Kd " + Helper.ToString(material.m_Diffuse.R / 255.0f) + " " + Helper.ToString(material.m_Diffuse.G / 255.0f) + " " + Helper.ToString(material.m_Diffuse.B / 255.0f) + "\n"); //Specify specular colour - RGB 0-1 mtlWriter.Write("Ks " + Helper.ToString(material.m_Specular.R / 255.0f) + " " + Helper.ToString(material.m_Specular.G / 255.0f) + " " + Helper.ToString(material.m_Specular.B / 255.0f) + "\n"); //Specify specular colour co-efficient - RGB 0-1 //mtllib += "Ns " + material.m_SpeEmiColors + "\n"; //Specify transparency - RGB Alpha channel 0-1 mtlWriter.Write("d " + Helper.ToString(material.m_Alpha / 31f) + "\n"); //Specify texture type 0 - 10 //uint textype = (currentTexture.m_Params >> 26) & 0x7; mtlWriter.Write("illum 2\n"); if (textureName != null && !textureName.Equals("")) { //Specify name of texture image mtlWriter.Write("map_Kd " + textureName + ".png" + "\n\n"); ExportTextureToPNG(dir, m_Model.m_Textures[material.m_TextureDefID]); } else { mtlWriter.Write("\n\n"); } } WriteBonesFileOBJ(m_ModelFileName.Substring(0, m_ModelFileName.Length - 4) + ".bones", m_Model.m_BoneTree); // Write each bone to file as a separate mesh/object using o command List <Vector3> verts = new List <Vector3>(); List <Vector2> textureCoords = new List <Vector2>(); List <Color> vertexColours = new List <Color>(); foreach (ModelBase.BoneDef bone in m_Model.m_BoneTree) { objWriter.Write("o " + bone.m_ID + "\n"); // Get a list of all verices and texture co-ordinates for the current bone List <Vector3> vertsCurBone = new List <Vector3>(); List <Vector2> textureCoordsCurBone = new List <Vector2>(); List <Color> vertexColoursCurBone = new List <Color>(); foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values) { foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values) { foreach (ModelBase.FaceListDef faceList in polyList.m_FaceLists) { foreach (ModelBase.FaceDef face in faceList.m_Faces) { foreach (ModelBase.VertexDef vert in face.m_Vertices) { if (!vertsCurBone.Contains(vert.m_Position)) { vertsCurBone.Add(vert.m_Position); verts.Add(vert.m_Position); } if (vert.m_TextureCoordinate != null && !textureCoordsCurBone.Contains((Vector2)vert.m_TextureCoordinate)) { textureCoordsCurBone.Add((Vector2)vert.m_TextureCoordinate); textureCoords.Add((Vector2)vert.m_TextureCoordinate); } if (vert.m_VertexColour != null && !vertexColoursCurBone.Contains((Color)vert.m_VertexColour)) { vertexColoursCurBone.Add((Color)vert.m_VertexColour); vertexColours.Add((Color)vert.m_VertexColour); } } } } } } // Print a list of all vertices, texture co-ordinates and vertex colours foreach (Vector3 vert in vertsCurBone) { objWriter.Write("v " + Helper.ToString(vert.X) + " " + Helper.ToString(vert.Y) + " " + Helper.ToString(vert.Z) + "\n"); } foreach (Vector2 textureCoord in textureCoordsCurBone) { objWriter.Write("vt " + Helper.ToString(textureCoord.X) + " " + Helper.ToString(textureCoord.Y) + "\n"); } foreach (Color vColour in vertexColoursCurBone) { objWriter.Write("vc " + Helper.ToString(vColour.R / 255.0f) + " " + Helper.ToString(vColour.G / 255.0f) + " " + Helper.ToString(vColour.B / 255.0f) + "\n"); } // For each material used in the current bone, print all faces foreach (ModelBase.GeometryDef geometry in bone.m_Geometries.Values) { foreach (ModelBase.PolyListDef polyList in geometry.m_PolyLists.Values) { objWriter.Write("usemtl " + polyList.m_MaterialName + "\n"); foreach (ModelBase.FaceListDef faceList in polyList.m_FaceLists) { foreach (ModelBase.FaceDef face in faceList.m_Faces) { // Each face is a triangle or a quad, as they have already been extracted individually from // the vertex lists // Note: Indices start at 1 in OBJ int numVerticesInFace = face.m_NumVertices; objWriter.Write("f "); foreach (ModelBase.VertexDef vert in face.m_Vertices) { objWriter.Write((verts.LastIndexOf(vert.m_Position) + 1) + "/" + ((vert.m_TextureCoordinate != null) ? (textureCoords.LastIndexOf((Vector2)vert.m_TextureCoordinate) + 1).ToString() : "") + "//" + ((vert.m_VertexColour != null) ? (vertexColours.LastIndexOf((Color)vert.m_VertexColour) + 1).ToString() : "") + " "); } objWriter.Write("\n"); } } } } } objWriter.Close(); mtlWriter.Close(); }
protected void LoadBoneDefinitionsForOBJ(string filename) { Stream fs; try { fs = File.OpenRead(filename); } catch { MessageBox.Show("Specified Bone definitions not found:\n\n" + filename + "\n\nUsing default values."); return; } StreamReader sr = new StreamReader(fs); m_Model.m_BoneTree.Clear(); ModelBase.BoneDef bone = null; string curline; while ((curline = sr.ReadLine()) != null) { curline = curline.Trim(); // skip empty lines and comments if (curline.Length < 1) { continue; } if (curline[0] == '#') { continue; } string[] parts = curline.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 1) { continue; } switch (parts[0]) { case "newbone": // new bone definition { if (parts.Length < 2) { continue; } bone = new ModelBase.BoneDef(parts[1]); } break; case "parent_offset": // Offset in bones to parent bone (signed 16-bit. 0=no parent, -1=parent is the previous bone, ...) { if (parts.Length < 2) { continue; } short parent_offset = short.Parse(parts[1]); if ((parent_offset < 0 && m_Model.m_BoneTree.Count == 0) || parent_offset > 0) { throw new SystemException("Child bones cannot be defined before their parent in: " + filename); } if (parent_offset == 0) { m_Model.m_BoneTree.AddRootBone(bone); } else if (parent_offset < 0) { List <ModelBase.BoneDef> listOfBones = m_Model.m_BoneTree.GetAsList(); listOfBones[listOfBones.Count + parent_offset].AddChild(bone); } } break; case "has_children": // 1 if the bone has children, 0 otherwise { if (parts.Length < 2) { continue; } bool has_children = (short.Parse(parts[1]) == 1); // No longer needed } break; case "sibling_offset": // Offset in bones to the next sibling bone (0=bone is last child of its parent) { if (parts.Length < 2) { continue; } short sibling_offset = short.Parse(parts[1]); // No longer needed } break; case "scale": // Scale transformation { if (parts.Length < 4) { continue; } uint[] scale = new uint[] { uint.Parse(parts[1], System.Globalization.NumberStyles.HexNumber), uint.Parse(parts[2], System.Globalization.NumberStyles.HexNumber), uint.Parse(parts[3], System.Globalization.NumberStyles.HexNumber) }; bone.SetScale(scale); } break; case "rotation": // Rotation transformation { if (parts.Length < 4) { continue; } ushort[] rotation = new ushort[] { ushort.Parse(parts[1], System.Globalization.NumberStyles.HexNumber), ushort.Parse(parts[2], System.Globalization.NumberStyles.HexNumber), ushort.Parse(parts[3], System.Globalization.NumberStyles.HexNumber) }; bone.SetRotation(rotation); } break; case "translation": // Scale transformation { if (parts.Length < 4) { continue; } uint[] translation = new uint[] { uint.Parse(parts[1], System.Globalization.NumberStyles.HexNumber), uint.Parse(parts[2], System.Globalization.NumberStyles.HexNumber), uint.Parse(parts[3], System.Globalization.NumberStyles.HexNumber) }; bone.SetTranslation(translation); } break; case "billboard": // Always rendered facing camera { if (parts.Length < 2) { continue; } bool billboard = (short.Parse(parts[1]) == 1); bone.m_Billboard = billboard; } break; } } // Calculate transformations and inverse transformations foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree.GetRootBones()) { boneDef.CalculateBranchTransformations(); } sr.Close(); }
public override ModelBase LoadModel(float scale) { if (m_ModelFileName == null || "".Equals(m_ModelFileName)) { throw new SystemException("You must specify the filename of the model to load via the constructor before " + "calling LoadModel()"); } Stream fs = File.OpenRead(m_ModelFileName); StreamReader sr = new StreamReader(fs); string curmaterial = null; bool foundObjects = LoadDefaultBones(m_ModelFileName); string currentBone = null; int currentBoneIndex = -1; if (!foundObjects) { currentBone = "default_bone_name"; ModelBase.BoneDef defaultBone = new ModelBase.BoneDef(currentBone); defaultBone.m_Geometries.Add("geometry-0", new ModelBase.GeometryDef("geometry-0")); m_Model.m_BoneTree.AddRootBone(defaultBone); currentBoneIndex = m_Model.m_BoneTree.GetBoneIndex(defaultBone); } string curline; while ((curline = sr.ReadLine()) != null) { curline = curline.Trim(); // skip empty lines and comments if (curline.Length < 1) { continue; } if (curline[0] == '#') { continue; } string[] parts = curline.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); if (parts.Length < 1) { continue; } switch (parts[0]) { case "mtllib": // material lib file { string filename = curline.Substring(parts[0].Length + 1).Trim(); LoadMaterials(m_ModelPath + Path.DirectorySeparatorChar + filename); } break; case "bonelib": // bone definitions file { string filename = curline.Substring(parts[0].Length + 1).Trim(); LoadBoneDefinitionsForOBJ(m_ModelPath + Path.DirectorySeparatorChar + filename); } break; case "o": // object (bone) if (parts.Length < 2) { continue; } currentBone = parts[1]; m_Model.m_BoneTree.GetBoneByID(currentBone).m_Geometries.Add(currentBone, new ModelBase.GeometryDef(currentBone)); currentBoneIndex = m_Model.m_BoneTree.GetBoneIndex(currentBone); break; case "usemtl": // material name if (parts.Length < 2) { continue; } curmaterial = parts[1]; if (!m_Model.m_Materials.ContainsKey(curmaterial)) { curmaterial = "default_white"; AddWhiteMat(currentBone); } break; case "v": // vertex { if (parts.Length < 4) { continue; } float x = Helper.ParseFloat(parts[1]); float y = Helper.ParseFloat(parts[2]); float z = Helper.ParseFloat(parts[3]); float w = 1f; //(parts.Length < 5) ? 1f : Helper.ParseFloat(parts[4]); m_Vertices.Add(new Vector4(x, y, z, w)); m_VertexBoneIDs.Add(currentBoneIndex); } break; case "vt": // texcoord { if (parts.Length < 2) { continue; } float s = Helper.ParseFloat(parts[1]); float t = (parts.Length < 3) ? 0f : Helper.ParseFloat(parts[2]); m_TexCoords.Add(new Vector2(s, t)); } break; case "vn": // normal { if (parts.Length < 4) { continue; } float x = Helper.ParseFloat(parts[1]); float y = Helper.ParseFloat(parts[2]); float z = Helper.ParseFloat(parts[3]); Vector3 vec = new Vector3(x, y, z).Normalized(); m_Normals.Add(vec); } break; case "vc": // vertex colour (non-standard "Extended OBJ" Blender plugin only) { if (parts.Length < 4) { continue; } float r = Helper.ParseFloat(parts[1]); float g = Helper.ParseFloat(parts[2]); float b = Helper.ParseFloat(parts[3]); Color vcolour = Color.FromArgb((int)(r * 255.0f), (int)(g * 255.0f), (int)(b * 255.0f)); m_Colours.Add(vcolour); } break; case "f": // face { if (parts.Length < 4) { continue; } int nvtx = parts.Length - 1; if (curmaterial != null) { // If a new object is defined but a material to use not set, we need to use the previous one and add // it to the current bone and its parent if (!m_Model.m_BoneTree.GetBoneByID(currentBone).GetRoot().m_MaterialsInBranch.Contains(curmaterial)) { m_Model.m_BoneTree.GetBoneByID(currentBone).GetRoot().m_MaterialsInBranch.Add(curmaterial); } if (!m_Model.m_BoneTree.GetBoneByID(currentBone).m_MaterialsInBranch.Contains(curmaterial)) { m_Model.m_BoneTree.GetBoneByID(currentBone).m_MaterialsInBranch.Add(curmaterial); } } else { // No "usemtl" command before declaring face curmaterial = "default_white"; AddWhiteMat(currentBone); } ModelBase.BoneDef bone = m_Model.m_BoneTree.GetBoneByID(currentBone); ModelBase.GeometryDef geomDef = bone.m_Geometries.Values.ElementAt(0); string polyListKey = "polylist-" + curmaterial; ModelBase.PolyListDef polyList; if (!geomDef.m_PolyLists.TryGetValue(polyListKey, out polyList)) { polyList = new ModelBase.PolyListDef(polyListKey, curmaterial); polyList.m_FaceLists.Add(new ModelBase.FaceListDef()); geomDef.m_PolyLists.Add(polyList.m_ID, polyList); } ModelBase.FaceDef face = new ModelBase.FaceDef(nvtx); for (int i = 0; i < nvtx; i++) { string vtx = parts[i + 1]; string[] idxs = vtx.Split(new char[] { '/' }); ModelBase.VertexDef vert = ModelBase.EMPTY_VERTEX; vert.m_Position = new Vector3(m_Vertices[int.Parse(idxs[0]) - 1].Xyz); if (m_Model.m_Materials[curmaterial].m_TextureDefID != null && idxs.Length >= 2 && idxs[1].Length > 0) { vert.m_TextureCoordinate = m_TexCoords[int.Parse(idxs[1]) - 1]; } else { vert.m_TextureCoordinate = null; } if (m_Model.m_Materials[curmaterial].m_Lights.Contains(true) && idxs.Length >= 3 && idxs[2].Trim().Length > 0) { vert.m_Normal = new Vector3(m_Normals[int.Parse(idxs[2]) - 1]); } else { vert.m_Normal = null; } // Vertex colours (non-standard "Extended OBJ" Blender plugin only) if (idxs.Length >= 4 && !idxs[3].Equals("")) { Color tmp = m_Colours[int.Parse(idxs[3]) - 1]; vert.m_VertexColour = Color.FromArgb(tmp.A, tmp.R, tmp.G, tmp.B); } else { vert.m_VertexColour = Color.White; } vert.m_VertexBoneIndex = currentBoneIndex; face.m_Vertices[i] = vert; } polyList.m_FaceLists[0].m_Faces.Add(face); } break; } } int count = 0; foreach (ModelBase.BoneDef boneDef in m_Model.m_BoneTree) { m_Model.m_BoneTransformsMap.Add(boneDef.m_ID, count); count++; } sr.Close(); m_Model.ScaleModel(scale); return(m_Model); }
public override ModelBase LoadModel(float scale) { foreach (BMD.ModelChunk mdchunk in m_BMD.m_ModelChunks) { ModelBase.BoneDef bone = new ModelBase.BoneDef(mdchunk.m_Name); bone.SetScale(mdchunk.m_20_12Scale); bone.SetRotation(mdchunk.m_4_12Rotation); bone.SetTranslation(mdchunk.m_20_12Translation); bone.m_Billboard = mdchunk.m_Billboard; if (mdchunk.m_ParentOffset == 0) { m_Model.m_BoneTree.AddRootBone(bone); } else { List <ModelBase.BoneDef> listOfBones = m_Model.m_BoneTree.GetAsList(); listOfBones[listOfBones.Count + mdchunk.m_ParentOffset].AddChild(bone); } m_Model.m_BoneTransformsMap.Add(bone.m_ID, m_Model.m_BoneTransformsMap.Count); ModelBase.GeometryDef geomDef = null; if (mdchunk.m_MatGroups.Length > 0) { geomDef = new ModelBase.GeometryDef("geometry-0"); bone.m_Geometries.Add(geomDef.m_ID, geomDef); } foreach (BMD.MaterialGroup matgroup in mdchunk.m_MatGroups) { string polyListKey = "polylist-" + matgroup.m_Name; ModelBase.PolyListDef polyListDef; if (!geomDef.m_PolyLists.TryGetValue(polyListKey, out polyListDef)) { polyListDef = new ModelBase.PolyListDef(polyListKey, matgroup.m_Name); geomDef.m_PolyLists.Add(polyListDef.m_ID, polyListDef); } ModelBase.MaterialDef material = new ModelBase.MaterialDef(matgroup.m_Name); material.m_Diffuse = matgroup.m_DiffuseColor; material.m_Ambient = matgroup.m_AmbientColor; material.m_Specular = matgroup.m_SpecularColor; material.m_Emission = matgroup.m_EmissionColor; bool hasTextures = (matgroup.m_Texture != null); if (hasTextures) { if (!m_Model.m_Textures.ContainsKey(matgroup.m_Texture.m_TextureName)) { ModelBase.TextureDefBase texture = new ModelBase.TextureDefNitro(matgroup.m_Texture); m_Model.m_Textures.Add(texture.m_ID, texture); } material.m_TextureDefID = matgroup.m_Texture.m_TextureName; } material.m_Alpha = matgroup.m_Alpha; if ((matgroup.m_PolyAttribs & 0xC0) == 0xC0) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.FrontAndBack; } else if ((matgroup.m_PolyAttribs & 0xC0) == 0x80) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Front; } else if ((matgroup.m_PolyAttribs & 0xC0) == 0x40) { material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Back; } material.m_TexGenMode = (ModelBase.TexGenMode)(matgroup.m_TexParams >> 30); material.m_TextureScale = matgroup.m_TexCoordScale; material.m_TextureRotation = matgroup.m_TexCoordRot; material.m_TextureTranslation = matgroup.m_TexCoordTrans; byte sRepeat = (byte)((matgroup.m_TexParams & 0x10000) >> 0x10); byte tRepeat = (byte)((matgroup.m_TexParams & 0x20000) >> 0x11); byte sFlip = (byte)((matgroup.m_TexParams & 0x40000) >> 0x12); byte tFlip = (byte)((matgroup.m_TexParams & 0x80000) >> 0x13); material.m_TexTiling[0] = (sRepeat == 1) ? ModelBase.MaterialDef.TexTiling.Repeat : ModelBase.MaterialDef.TexTiling.Clamp; material.m_TexTiling[0] = (sFlip == 1) ? ModelBase.MaterialDef.TexTiling.Flip : material.m_TexTiling[0]; material.m_TexTiling[1] = (tRepeat == 1) ? ModelBase.MaterialDef.TexTiling.Repeat : ModelBase.MaterialDef.TexTiling.Clamp; material.m_TexTiling[1] = (tFlip == 1) ? ModelBase.MaterialDef.TexTiling.Flip : material.m_TexTiling[1]; material.m_FogFlag = (matgroup.m_PolyAttribs & 0x8000) > 0; byte lights = (byte)(matgroup.m_PolyAttribs & 0x0F); for (int i = 0; i < 4; i++) { byte value = (byte)(lights >> i); material.m_Lights[i] = (value == 1); } Console.WriteLine("Materials Start"); if (!m_Model.m_Materials.ContainsKey(material.m_ID)) { m_Model.m_Materials.Add(material.m_ID, material); } Console.WriteLine("Materials End"); if (!bone.m_MaterialsInBranch.Contains(matgroup.m_Name)) { bone.m_MaterialsInBranch.Add(matgroup.m_Name); } ModelBase.BoneDef upToRoot = bone; while ((upToRoot = upToRoot.m_Parent) != null) { if (!upToRoot.m_MaterialsInBranch.Contains(matgroup.m_Name)) { upToRoot.m_MaterialsInBranch.Add(matgroup.m_Name); } } foreach (BMD.VertexList geometry in matgroup.m_Geometry) { uint polyType = geometry.m_PolyType; List <BMD.Vertex> vtxList = geometry.m_VertexList; switch (polyType) { case 0: //Separate Triangles { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Triangles); int numFaces = vtxList.Count / 3; for (int a = 0, b = 0; a < numFaces; a++, b = b + 3) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); faceList.m_Faces.Add(face); } polyListDef.m_FaceLists.Add(faceList); break; } case 1: //Separate Quadrilaterals { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Polygons); int numFaces = vtxList.Count / 4; for (int a = 0, b = 0; a < numFaces; a++, b = b + 4) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[b + 3].m_Position, vtxList[b + 3].m_TexCoord, vtxList[b + 3].m_Normal, vtxList[b + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 3].m_MatrixID]); faceList.m_Faces.Add(face); } polyListDef.m_FaceLists.Add(faceList); break; } case 2: //Triangle Strips { //3+(N-1) vertices per N triangles //(N-3)+1 Triangles per N Vertices int numFaces = vtxList.Count - 2; if (vtxList.Count < 3) //Should never be { break; } ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip); //Convert all faces with more than 3 vertices to ones with only 3 for (int n = 0; n < numFaces; n++) { if (n % 2 == 0) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 1].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); faceList.m_Faces.Add(face); } else { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 1].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); faceList.m_Faces.Add(face); } //Because of how normals are defined in triangle strips, every 2nd triangle is clockwise, whereas all others are anti-clockwise } polyListDef.m_FaceLists.Add(faceList); break; } case 3: //Quadrilateral Strips { //4+(N-1)*2 vertices per N quads //((N-4)/2) + 1 Quads. per N Vertices int numFaces = ((vtxList.Count - 4) / 2) + 1; if (vtxList.Count < 4) //Should never be { break; } ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Polygons); for (int n = 0, p = 0; n < numFaces; n++, p = p + 2) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[p + 0].m_Position, vtxList[p + 0].m_TexCoord, vtxList[p + 0].m_Normal, vtxList[p + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[p + 1].m_Position, vtxList[p + 1].m_TexCoord, vtxList[p + 1].m_Normal, vtxList[p + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[p + 3].m_Position, vtxList[p + 3].m_TexCoord, vtxList[p + 3].m_Normal, vtxList[p + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 3].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[p + 2].m_Position, vtxList[p + 2].m_TexCoord, vtxList[p + 2].m_Normal, vtxList[p + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 2].m_MatrixID]); faceList.m_Faces.Add(face); } polyListDef.m_FaceLists.Add(faceList); break; } default: MessageBox.Show("Unknown polygon type."); break; }//End polyType switch } } bone.CalculateBranchTransformations(); } m_Model.ApplyTransformations(); return(m_Model); }
protected ModelBase.AnimationComponentDataDef ReadAnimationComponent(XmlNode descriptor, ModelBase.AnimationComponentType componentType, int boneIndex) { int frame_step = int.Parse(descriptor.Attributes["frame_step"].Value); int data_size = int.Parse(descriptor.Attributes["data_size"].Value); int data_head = int.Parse(descriptor.Attributes["data_head"].Value); bool isConstant = (data_size == 1); bool useIdentity = (isConstant && data_head == 0); float[] values = new float[data_size]; if (!useIdentity) { switch (componentType) { case ModelBase.AnimationComponentType.ScaleX: Array.Copy(this.node_scale_data, data_head, values, 0, data_size); break; case ModelBase.AnimationComponentType.ScaleY: goto case ModelBase.AnimationComponentType.ScaleX; case ModelBase.AnimationComponentType.ScaleZ: goto case ModelBase.AnimationComponentType.ScaleX; case ModelBase.AnimationComponentType.RotateX: Array.Copy(this.node_rotate_data, data_head, values, 0, data_size); break; case ModelBase.AnimationComponentType.RotateY: goto case ModelBase.AnimationComponentType.RotateX; case ModelBase.AnimationComponentType.RotateZ: goto case ModelBase.AnimationComponentType.RotateX; case ModelBase.AnimationComponentType.TranslateX: Array.Copy(this.node_translate_data, data_head, values, 0, data_size); break; case ModelBase.AnimationComponentType.TranslateY: goto case ModelBase.AnimationComponentType.TranslateX; case ModelBase.AnimationComponentType.TranslateZ: goto case ModelBase.AnimationComponentType.TranslateX; } } else { ModelBase.BoneDef boneDef = m_Model.m_BoneTree.GetBoneByIndex(boneIndex); switch (componentType) { case ModelBase.AnimationComponentType.ScaleX: values[0] = boneDef.m_Scale.X; break; case ModelBase.AnimationComponentType.ScaleY: values[0] = boneDef.m_Scale.Y; break; case ModelBase.AnimationComponentType.ScaleZ: values[0] = boneDef.m_Scale.Z; break; case ModelBase.AnimationComponentType.RotateX: values[0] = boneDef.m_Rotation.X; break; case ModelBase.AnimationComponentType.RotateY: values[0] = boneDef.m_Rotation.Y; break; case ModelBase.AnimationComponentType.RotateZ: values[0] = boneDef.m_Rotation.Z; break; case ModelBase.AnimationComponentType.TranslateX: values[0] = boneDef.m_Translation.X; break; case ModelBase.AnimationComponentType.TranslateY: values[0] = boneDef.m_Translation.Y; break; case ModelBase.AnimationComponentType.TranslateZ: values[0] = boneDef.m_Translation.Z; break; } } return(new ModelBase.AnimationComponentDataDef(values, this.node_anm_info.frame_size, isConstant, frame_step, useIdentity, componentType)); }
protected void ReadNodes(XmlNode node_array, XmlNode polygon_array, XmlNode matrix_array) { if (node_array == null) return; int nodeArray_size = int.Parse(node_array.Attributes["size"].Value); if (nodeArray_size < 1) return; XmlNodeList nodes = node_array.SelectNodes("node"); foreach (XmlNode node in nodes) m_OriginalNodeIndices.Add(int.Parse(node.Attributes["index"].Value), node.Attributes["name"].Value); ReadMatrices(matrix_array, m_OriginalNodeIndices); var queue = new Queue<XmlNode>(); var geometryQueue = new Queue<XmlNode>(); queue.Enqueue(nodes[0]); while (queue.Count > 0) { XmlNode node = queue.Dequeue(); int index = int.Parse(node.Attributes["index"].Value); string name = node.Attributes["name"].Value; string kind = node.Attributes["kind"].Value; int parent = int.Parse(node.Attributes["parent"].Value); int child = int.Parse(node.Attributes["child"].Value); int brother_next = int.Parse(node.Attributes["brother_next"].Value); int brother_prev = int.Parse(node.Attributes["brother_prev"].Value); bool draw_mtx = node.Attributes["draw_mtx"].Value.Equals("on"); string scale_compensate = (node.Attributes["scale_compensate"] != null) ? node.Attributes["scale_compensate"].Value : null; string billboard = node.Attributes["billboard"].Value; // Either "on", "off" or "y_on" float[] scale = Array.ConvertAll( node.Attributes["scale"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); float[] rotate = Array.ConvertAll( node.Attributes["rotate"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); float[] translate = Array.ConvertAll( node.Attributes["translate"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle); bool visibility = node.Attributes["visibility"].Value.Equals("on"); int display_size = int.Parse(node.Attributes["display_size"].Value); int vertex_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["vertex_size"].Value) : -1; int polygon_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["polygon_size"].Value) : -1; int triangle_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["triangle_size"].Value) : -1; int quad_size = (kind.Equals("mesh")) ? int.Parse(node.Attributes["quad_size"].Value) : -1; float[] volume_min = (kind.Equals("mesh")) ? Array.ConvertAll( node.Attributes["volume_min"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle) : null; float[] volume_max = (kind.Equals("mesh")) ? Array.ConvertAll( node.Attributes["volume_max"].Value.Split(new string[] { " " }, StringSplitOptions.RemoveEmptyEntries), Convert.ToSingle) : null; float volume_r = (kind.Equals("mesh")) ? float.Parse(node.Attributes["volume_r"].Value) : -1; ModelBase.BoneDef boneDef = new ModelBase.BoneDef(name); boneDef.SetScale(new Vector3(scale[0], scale[1], scale[2])); boneDef.SetRotation(new Vector3(rotate[0] * Helper.Deg2Rad, rotate[1] * Helper.Deg2Rad, rotate[2] * Helper.Deg2Rad)); boneDef.SetTranslation(new Vector3(translate[0], translate[1], translate[2])); boneDef.CalculateBranchTransformations(); if (display_size > 0) { geometryQueue.Enqueue(node); } if (parent == -1) m_Model.m_BoneTree.AddRootBone(boneDef); else m_Model.m_BoneTree.GetBoneByID(m_OriginalNodeIndices[parent]).AddChild(boneDef); /* Child node takes priority and siblings are stored consecutively by name in alphanumerical order * (a→z and 0→9). The model root node must be the first <node> in <node_array> (index 0). * "child" attribute gives first child, alphanumerically. */ if (child != -1) queue.Enqueue(nodes[child]); if (brother_next != -1) queue.Enqueue(nodes[brother_next]); } // In oder to correctly read the geometry we need to already have the list of bones read in so that bone ID's // can be assigned to vertices while (geometryQueue.Count > 0) { XmlNode node = geometryQueue.Dequeue(); XmlNodeList displays = node.SelectNodes("display"); ModelBase.BoneDef boneDef = m_Model.m_BoneTree.GetBoneByID(node.Attributes["name"].Value); ModelBase.GeometryDef geometryDef = new ModelBase.GeometryDef("geometry-0"); foreach (XmlNode display in displays) { int display_index = int.Parse(display.Attributes["index"].Value); int display_material = int.Parse(display.Attributes["material"].Value); int display_polygon = int.Parse(display.Attributes["polygon"].Value); int display_priority = int.Parse(display.Attributes["priority"].Value); ReadPolygon(display_polygon, polygon_array, m_Model.m_Materials.ElementAt(display_material).Key, geometryDef); boneDef.m_MaterialsInBranch.Add(m_Model.m_Materials.ElementAt(display_material).Key); } boneDef.m_Geometries.Add(geometryDef.m_ID, geometryDef); } m_Model.ApplyTransformations(); }
public override ModelBase LoadModel(OpenTK.Vector3 scale) { foreach (BMD.ModelChunk mdchunk in m_BMD.m_ModelChunks) { ModelBase.BoneDef bone = new ModelBase.BoneDef(mdchunk.m_Name); bone.SetScale(mdchunk.m_20_12Scale); bone.SetRotation(mdchunk.m_4_12Rotation); bone.SetTranslation(mdchunk.m_20_12Translation); if (mdchunk.m_ParentOffset == 0) { m_Model.m_BoneTree.AddRootBone(bone); } else { List<ModelBase.BoneDef> listOfBones = m_Model.m_BoneTree.GetAsList(); listOfBones[listOfBones.Count + mdchunk.m_ParentOffset].AddChild(bone); } ModelBase.GeometryDef geomDef = null; if (mdchunk.m_MatGroups.Length > 0) { geomDef = new ModelBase.GeometryDef("geometry-0"); bone.m_Geometries.Add(geomDef.m_ID, geomDef); } foreach (BMD.MaterialGroup matgroup in mdchunk.m_MatGroups) { if (!geomDef.m_PolyLists.ContainsKey(matgroup.m_Name)) { ModelBase.PolyListDef pld = new ModelBase.PolyListDef("polylist-" + matgroup.m_Name, matgroup.m_Name); geomDef.m_PolyLists.Add(pld.m_MaterialName, pld); } ModelBase.PolyListDef polyListDef = geomDef.m_PolyLists[matgroup.m_Name]; ModelBase.MaterialDef material = new ModelBase.MaterialDef(matgroup.m_Name, m_Model.m_Materials.Count); material.m_Diffuse = matgroup.m_DiffuseColor; material.m_Ambient = matgroup.m_AmbientColor; material.m_Specular = matgroup.m_SpecularColor; material.m_Emission = matgroup.m_EmissionColor; bool hasTextures = (matgroup.m_Texture != null); if (hasTextures) { if (!m_Model.m_Textures.ContainsKey(matgroup.m_Texture.m_TexName)) { ModelBase.TextureDefBase texture = new ModelBase.TextureDefInMemoryBitmap( matgroup.m_Texture.m_TexName, ConvertBMDTextureToBitmap(matgroup.m_Texture)); m_Model.m_Textures.Add(texture.m_ID, texture); } material.m_TextureDefID = matgroup.m_Texture.m_TexName; } material.m_Alpha = matgroup.m_Alpha; if ((matgroup.m_PolyAttribs & 0xC0) == 0xC0) material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.FrontAndBack; else if ((matgroup.m_PolyAttribs & 0xC0) == 0x80) material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Front; else if ((matgroup.m_PolyAttribs & 0xC0) == 0x40) material.m_PolygonDrawingFace = ModelBase.MaterialDef.PolygonDrawingFace.Back; if (!m_Model.m_Materials.ContainsKey(material.m_ID)) m_Model.m_Materials.Add(material.m_ID, material); bone.m_MaterialsInBranch.Add(matgroup.m_Name); ModelBase.BoneDef upToRoot = bone; while ((upToRoot = upToRoot.m_Parent) != null) { if (!upToRoot.m_MaterialsInBranch.Contains(matgroup.m_Name)) upToRoot.m_MaterialsInBranch.Add(matgroup.m_Name); } foreach (BMD.VertexList geometry in matgroup.m_Geometry) { uint polyType = geometry.m_PolyType; List<BMD.Vertex> vtxList = geometry.m_VertexList; switch (polyType) { case 0://Separate Triangles { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Triangles); if (vtxList.Count <= 3)//Just 1 triangle { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[0].m_Position, vtxList[0].m_TexCoord, vtxList[0].m_Normal, vtxList[0].m_Color, (int)matgroup.m_BoneIDs[vtxList[0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[1].m_Position, vtxList[1].m_TexCoord, vtxList[1].m_Normal, vtxList[1].m_Color, (int)matgroup.m_BoneIDs[vtxList[1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[2].m_Position, vtxList[2].m_TexCoord, vtxList[2].m_Normal, vtxList[2].m_Color, (int)matgroup.m_BoneIDs[vtxList[2].m_MatrixID]); faceList.m_Faces.Add(face); } else if (vtxList.Count > 3 && (float)vtxList.Count % 3 == 0.0f)//Eg. 9 vertices in 3 triangles { int numFaces = vtxList.Count / 3; for (int a = 0, b = 0; a < numFaces; a++, b = b + 3) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); faceList.m_Faces.Add(face); } } polyListDef.m_FaceLists.Add(faceList); break; } case 1://Separate Quadrilaterals { ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.Polygons); if (vtxList.Count <= 4)//Just 1 quadrilateral { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[0].m_Position, vtxList[0].m_TexCoord, vtxList[0].m_Normal, vtxList[0].m_Color, (int)matgroup.m_BoneIDs[vtxList[0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[1].m_Position, vtxList[1].m_TexCoord, vtxList[1].m_Normal, vtxList[1].m_Color, (int)matgroup.m_BoneIDs[vtxList[1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[2].m_Position, vtxList[2].m_TexCoord, vtxList[2].m_Normal, vtxList[2].m_Color, (int)matgroup.m_BoneIDs[vtxList[2].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[3].m_Position, vtxList[3].m_TexCoord, vtxList[3].m_Normal, vtxList[3].m_Color, (int)matgroup.m_BoneIDs[vtxList[3].m_MatrixID]); faceList.m_Faces.Add(face); } else if (vtxList.Count > 4 && (float)vtxList.Count % 4 == 0.0f)//Eg. 8 vertices in 2 quadrilaterals { int numFaces = vtxList.Count / 4; for (int a = 0, b = 0; a < numFaces; a++, b = b + 4) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[b + 0].m_Position, vtxList[b + 0].m_TexCoord, vtxList[b + 0].m_Normal, vtxList[b + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[b + 1].m_Position, vtxList[b + 1].m_TexCoord, vtxList[b + 1].m_Normal, vtxList[b + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[b + 2].m_Position, vtxList[b + 2].m_TexCoord, vtxList[b + 2].m_Normal, vtxList[b + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 2].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[b + 3].m_Position, vtxList[b + 3].m_TexCoord, vtxList[b + 3].m_Normal, vtxList[b + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[b + 3].m_MatrixID]); faceList.m_Faces.Add(face); } } polyListDef.m_FaceLists.Add(faceList); break; } case 2://Triangle Strips { //3+(N-1) vertices per N triangles //(N-3)+1 Triangles per N Vertices int numFaces = vtxList.Count - 2; if (vtxList.Count < 3)//Should never be break; ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(ModelBase.PolyListType.TriangleStrip); //Convert all faces with more than 3 vertices to ones with only 3 for (int n = 0; n < numFaces; n++) { if (n % 2 == 0) { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 1].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); faceList.m_Faces.Add(face); } else { ModelBase.FaceDef face = new ModelBase.FaceDef(3); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[n + 2].m_Position, vtxList[n + 2].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 2].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[n + 1].m_Position, vtxList[n + 1].m_TexCoord, vtxList[n + 2].m_Normal, vtxList[n + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[n + 0].m_Position, vtxList[n + 0].m_TexCoord, vtxList[n + 0].m_Normal, vtxList[n + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[n + 0].m_MatrixID]); faceList.m_Faces.Add(face); } //Because of how normals are defined in triangle strips, every 2nd triangle is clockwise, whereas all others are anti-clockwise } polyListDef.m_FaceLists.Add(faceList); break; } case 3://Quadrilateral Strips { //4+(N-1)*2 vertices per N quads //((N-4)/2) + 1 Quads. per N Vertices int numFaces = ((vtxList.Count - 4) / 2) + 1; if (vtxList.Count < 4)//Should never be break; ModelBase.FaceListDef faceList = new ModelBase.FaceListDef(); for (int n = 0, p = 0; n < numFaces; n++, p = p + 2) { ModelBase.FaceDef face = new ModelBase.FaceDef(4); face.m_Vertices[0] = new ModelBase.VertexDef(vtxList[p + 0].m_Position, vtxList[p + 0].m_TexCoord, vtxList[p + 0].m_Normal, vtxList[p + 0].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 0].m_MatrixID]); face.m_Vertices[1] = new ModelBase.VertexDef(vtxList[p + 1].m_Position, vtxList[p + 1].m_TexCoord, vtxList[p + 1].m_Normal, vtxList[p + 1].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 1].m_MatrixID]); face.m_Vertices[2] = new ModelBase.VertexDef(vtxList[p + 3].m_Position, vtxList[p + 3].m_TexCoord, vtxList[p + 3].m_Normal, vtxList[p + 3].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 3].m_MatrixID]); face.m_Vertices[3] = new ModelBase.VertexDef(vtxList[p + 2].m_Position, vtxList[p + 2].m_TexCoord, vtxList[p + 2].m_Normal, vtxList[p + 2].m_Color, (int)matgroup.m_BoneIDs[vtxList[p + 2].m_MatrixID]); faceList.m_Faces.Add(face); } polyListDef.m_FaceLists.Add(faceList); break; } default: MessageBox.Show("Unknown polygon type."); break; }//End polyType switch } } bone.CalculateBranchTransformations(); } m_Model.ApplyTransformations(); return m_Model; }