static void ProcessCNT(CNT cnt, Model model, int ParentBoneIndex = 0) { int boneIndex; SceneManager.Current.UpdateProgress(string.Format("Processing {0}", cnt.Name)); if (cnt.Section == CNT.NodeType.MODL || cnt.Section == CNT.NodeType.SKIN) { var m = SceneManager.Current.Content.Load<Model, MDLImporter>(cnt.Model, rootPath); boneIndex = model.AddMesh(m.Meshes[0], ParentBoneIndex); } else { boneIndex = model.AddMesh(null, ParentBoneIndex); switch (cnt.Section) { case CNT.NodeType.LITg: model.Bones[boneIndex].Type = BoneType.Light; if (cnt.EmbeddedLight) { model.Bones[boneIndex].Attachment = cnt.Light; } else { model.Bones[boneIndex].Attachment = SceneManager.Current.Content.Load<Model, LIGHTImporter>(cnt.LightName, rootPath).Bones[0].Attachment; model.Bones[boneIndex].AttachmentFile = cnt.LightName; } break; case CNT.NodeType.VFXI: model.Bones[boneIndex].Type = BoneType.VFX; model.Bones[boneIndex].AttachmentFile = cnt.VFXFile; break; } } model.SetName(cnt.Name, boneIndex); model.SetTransform( new Matrix4 ( cnt.Transform.M11, cnt.Transform.M12, cnt.Transform.M13, 0, cnt.Transform.M21, cnt.Transform.M22, cnt.Transform.M23, 0, cnt.Transform.M31, cnt.Transform.M32, cnt.Transform.M33, 0, cnt.Transform.M41, cnt.Transform.M42, cnt.Transform.M43, 1 ), boneIndex); foreach (CNT subcnt in cnt.Children) { ProcessCNT(subcnt, model, boneIndex); } }
public override Asset Import(string path) { FBX fbx = FBX.Load(path); Model model = new Model(); Dictionary<long, object> components = new Dictionary<long, object>(); Dictionary<long, Matrix4> transforms = new Dictionary<long, Matrix4>(); Dictionary<long, string> triangulationErrors = new Dictionary<long, string>(); string name = Path.GetFileNameWithoutExtension(path); if (fbx == null) { SceneManager.Current.RaiseError(string.Format("File \"{0}\" could not be opened. Please ensure this is a binary FBX file.", name)); return null; } var objects = fbx.Elements.Find(e => e.ID == "Objects"); RotationOrder order; var worldMatrix = createTransformFor(fbx.Elements.Find(e => e.ID == "GlobalSettings").Children[1], out order); foreach (var material in objects.Children.Where(e => e.ID == "Material")) { string matName = material.Properties[1].Value.ToString(); matName = matName.Substring(0, matName.IndexOf("::")); var m = new Material { Name = matName }; components.Add((long)material.Properties[0].Value, m); Console.WriteLine("Added material \"{0}\" ({1})", matName, material.Properties[0].Value); } var textures = objects.Children.Where(e => e.ID == "Texture"); foreach (var texture in textures) { Texture t = null; string fullFile = texture.Children.Find(e => e.ID == "FileName").Properties[0].Value.ToString(); if (fullFile.IndexOf('.') == -1) { continue; } string file = Path.GetFileName(fullFile); switch (Path.GetExtension(file)) { case ".bmp": t = SceneManager.Current.Content.Load<Texture, BMPImporter>(Path.GetFileNameWithoutExtension(file)); break; case ".png": t = SceneManager.Current.Content.Load<Texture, PNGImporter>(Path.GetFileNameWithoutExtension(file)); break; case ".tif": t = SceneManager.Current.Content.Load<Texture, TIFImporter>(Path.GetFileNameWithoutExtension(file)); break; case ".tga": t = SceneManager.Current.Content.Load<Texture, TGAImporter>(Path.GetFileNameWithoutExtension(file)); break; default: t = new Texture(); break; } if (!components.ContainsKey((long)texture.Properties[0].Value)) { components.Add((long)texture.Properties[0].Value, t); Console.WriteLine("Added texture \"{0}\" ({1})", file, texture.Properties[0].Value); } } foreach (var element in objects.Children.Where(e => e.ID == "Model")) { string modelName = element.Properties[1].Value.ToString(); modelName = modelName.Substring(0, modelName.IndexOf("::")); components.Add((long)element.Properties[0].Value, new ModelMesh { Name = modelName, Tag = (long)element.Properties[0].Value }); Console.WriteLine("Added model \"{0}\" ({1})", modelName, element.Properties[0].Value); var properties = element.Children.Find(c => c.ID == "Properties70"); var m = Matrix4.Identity; bool bRotationActive = false; var lclTranslation = OpenTK.Vector3.Zero; var lclRotation = Quaternion.Identity; var preRotation = Quaternion.Identity; var postRotation = Quaternion.Identity; var rotationPivot = OpenTK.Vector3.Zero; var rotationOffset = OpenTK.Vector3.Zero; var lclScaling = OpenTK.Vector3.One; var scalingPivot = OpenTK.Vector3.Zero; var scalingOffset = OpenTK.Vector3.Zero; var geoPosition = OpenTK.Vector3.Zero; var geoRotation = Quaternion.Identity; var geoScale = OpenTK.Vector3.One; FBXElem property; property = properties.Children.GetProperty("RotationActive"); if (property != null) { bRotationActive = ((int)property.Properties[4].Value == 1); } property = properties.Children.GetProperty("ScalingPivot"); if (property != null) { scalingPivot = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("Lcl Scaling"); if (property != null) { lclScaling = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("ScalingOffset"); if (property != null) { scalingOffset = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("RotationPivot"); if (property != null) { rotationPivot = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("PostRotation"); if (property != null) { postRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("Lcl Rotation"); if (property != null) { lclRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("PreRotation"); if (property != null) { preRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("RotationOffset"); if (property != null) { rotationOffset = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("Lcl Translation"); if (property != null) { lclTranslation = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("GeometricTranslation"); if (property != null) { geoPosition = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } property = properties.Children.GetProperty("GeometricRotation"); if (property != null) { geoRotation = MakeQuaternion( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value), order ); } property = properties.Children.GetProperty("GeometricScaling"); if (property != null) { geoScale = new OpenTK.Vector3( Convert.ToSingle(property.Properties[4].Value), Convert.ToSingle(property.Properties[5].Value), Convert.ToSingle(property.Properties[6].Value) ); } m = Matrix4.CreateTranslation(scalingPivot).Inverted() * Matrix4.CreateScale(lclScaling) * Matrix4.CreateTranslation(scalingPivot) * Matrix4.CreateTranslation(scalingOffset) * Matrix4.CreateTranslation(rotationPivot).Inverted() * Matrix4.CreateFromQuaternion(postRotation) * Matrix4.CreateFromQuaternion(lclRotation) * Matrix4.CreateFromQuaternion(preRotation) * Matrix4.CreateTranslation(rotationPivot) * Matrix4.CreateTranslation(rotationOffset) * Matrix4.CreateTranslation(lclTranslation); if (m != Matrix4.Identity) { transforms.Add((long)element.Properties[0].Value, m); } } foreach (var element in objects.Children.Where(e => e.ID == "Geometry")) { bool bUVs = true; bool bNorms = true; bool bColours = true; bool bUseIndexNorm = false; bool bNeedsTriangulating = false; string geometryName = element.Properties[1].Value.ToString(); geometryName = geometryName.Substring(0, geometryName.IndexOf("::")); var verts = new List<OpenTK.Vector3>(); var norms = new List<OpenTK.Vector3>(); var uvs = new List<OpenTK.Vector2>(); var colours = new List<OpenTK.Graphics.Color4>(); var vertParts = (double[])element.Children.Find(e => e.ID == "Vertices").Properties[0].Value; for (int i = 0; i < vertParts.Length; i += 3) { verts.Add(new OpenTK.Vector3((float)vertParts[i + 0], (float)vertParts[i + 1], (float)vertParts[i + 2])); } SceneManager.Current.UpdateProgress(string.Format("Processed {0}->Vertices", element.Properties[1].Value)); var normElem = element.Children.Find(e => e.ID == "LayerElementNormal"); if (normElem != null) { var normParts = (double[])normElem.Children.Find(e => e.ID == "Normals").Properties[0].Value; for (int i = 0; i < normParts.Length; i += 3) { norms.Add(new OpenTK.Vector3((float)normParts[i + 0], (float)normParts[i + 1], (float)normParts[i + 2])); } bUseIndexNorm = (normElem.Children.Find(e => e.ID == "MappingInformationType").Properties[0].Value.ToString() == "ByVertice"); SceneManager.Current.UpdateProgress(string.Format("Processed {0}->Normals", element.Properties[1].Value)); } else { bNorms = false; } var colourElem = element.Children.Find(e => e.ID == "LayerElementColor"); if (colourElem != null) { var colourParts = (double[])colourElem.Children.Find(e => e.ID == "Colors").Properties[0].Value; var colourReferenceType = colourElem.Children.Find(e => e.ID == "ReferenceInformationType"); switch (colourReferenceType.Properties[0].Value.ToString()) { case "IndexToDirect": var colourIndicies = (int[])colourElem.Children.Find(e => e.ID == "ColorIndex").Properties[0].Value; for (int i = 0; i < colourIndicies.Length; i++) { int offset = colourIndicies[i] * 4; colours.Add(new OpenTK.Graphics.Color4((float)colourParts[offset + 0], (float)colourParts[offset + 1], (float)colourParts[offset + 2], (float)colourParts[offset + 3])); } break; case "Direct": bColours = false; break; default: throw new NotImplementedException("Unsupported Colour Reference Type: " + colourReferenceType.Properties[0].Value.ToString()); } SceneManager.Current.UpdateProgress(string.Format("Processed {0}->Colours", element.Properties[1].Value)); } else { bColours = false; } var uvElem = element.Children.Find(e => e.ID == "LayerElementUV"); if (uvElem != null) { var uvParts = (double[])uvElem.Children.Find(e => e.ID == "UV").Properties[0].Value; var uvReferenceType = uvElem.Children.Find(e => e.ID == "ReferenceInformationType"); if (uvReferenceType.Properties[0].Value.ToString() == "IndexToDirect") { var luvs = new List<OpenTK.Vector2>(); for (int i = 0; i < uvParts.Length; i += 2) { luvs.Add(new OpenTK.Vector2((float)uvParts[i + 0], 1 - (float)uvParts[i + 1])); } var uvindicies = (int[])uvElem.Children.Find(e => e.ID == "UVIndex").Properties[0].Value; for (int i = 0; i < uvindicies.Length; i++) { if (uvindicies[i] == -1) { uvs.Add(OpenTK.Vector2.Zero); } else { uvs.Add(luvs[uvindicies[i]]); } } } else { for (int i = 0; i < uvParts.Length; i += 2) { uvs.Add(new OpenTK.Vector2((float)uvParts[i + 0], (float)uvParts[i + 1])); } } SceneManager.Current.UpdateProgress(string.Format("Processed {0}->UVs", element.Properties[1].Value)); } else { bUVs = false; } var indicies = (int[])element.Children.Find(e => e.ID == "PolygonVertexIndex").Properties[0].Value; var faces = new List<FBXFace>(); var face = new FBXFace(); var j = 0; for (int i = 0; i < indicies.Length; i++) { bool bFace = false; int index = indicies[i]; if (index < 0) { bFace = true; index = (index * -1) - 1; } j++; face.AddVertex(verts[index], (bNorms ? norms[(bUseIndexNorm ? index : i)] : OpenTK.Vector3.Zero), (bUVs ? uvs[i] : OpenTK.Vector2.Zero), (bColours ? colours[i] : OpenTK.Graphics.Color4.White)); if (bFace) { if (j > 3) { triangulationErrors.Add((long)element.Properties[0].Value, geometryName); bNeedsTriangulating = true; break; } faces.Add(face); face = new FBXFace(); j = 0; } } var parts = new List<ModelMeshPart>(); if (!bNeedsTriangulating) { SceneManager.Current.UpdateProgress(string.Format("Processed {0}->Faces", element.Properties[1].Value)); var elemMaterial = element.Children.Find(e => e.ID == "LayerElementMaterial"); if (elemMaterial != null) { var faceMaterials = (int[])elemMaterial.Children.Find(e => e.ID == "Materials").Properties[0].Value; for (int i = 0; i < faceMaterials.Length; i++) { faces[i].MaterialID = faceMaterials[i]; } SceneManager.Current.UpdateProgress(string.Format("Processed {0}->Materials", element.Properties[1].Value)); } var materialGroups = faces.GroupBy(f => f.MaterialID); int processedFaceCount = 0, processedGroupCount = 0; foreach (var materialGroup in materialGroups) { var smoothingGroups = materialGroup.GroupBy(f => f.SmoothingGroup); foreach (var smoothingGroup in smoothingGroups) { var meshpart = new ModelMeshPart { PrimitiveType = OpenTK.Graphics.OpenGL.PrimitiveType.Triangles }; processedFaceCount = 0; foreach (var groupface in smoothingGroup) { foreach (var vert in groupface.Vertices) { meshpart.AddVertex(vert.Position, vert.Normal, vert.UV, vert.Colour); } processedFaceCount++; if (processedFaceCount % 250 == 0) { SceneManager.Current.UpdateProgress(string.Format("Processed {0}->MeshPart[{1}]->Face[{2}]", element.Properties[1].Value, processedGroupCount, processedFaceCount)); } } meshpart.Key = materialGroup.Key; parts.Add(meshpart); SceneManager.Current.UpdateProgress(string.Format("Processed {0}->MeshPart", element.Properties[1].Value)); processedGroupCount++; } } } components.Add((long)element.Properties[0].Value, parts); SceneManager.Current.UpdateProgress(string.Format("Processed {0}", element.Properties[1].Value)); } string[] connectionOrder = new string[] { "System.Collections.Generic.List`1[Flummery.ModelMeshPart]", "Flummery.Texture", "Flummery.Material", "Flummery.ModelMesh" }; var connections = fbx.Elements.Find(e => e.ID == "Connections"); HashSet<long> loaded = new HashSet<long>(); foreach (var connectionType in connectionOrder) { var connectionsOfType = connections.Children.Where(c => components.ContainsKey((long)c.Properties[1].Value) && components[(long)c.Properties[1].Value].GetType().ToString() == connectionType); foreach (var connection in connectionsOfType) { long keyA = (long)connection.Properties[1].Value; long keyB = (long)connection.Properties[2].Value; Console.WriteLine("{0} is connected to {1} :: {2}", keyA, keyB, connectionType); switch (connectionType) { case "Flummery.ModelMesh": int boneID; if (keyB == 0) { boneID = model.AddMesh((ModelMesh)components[keyA]); model.SetName(((ModelMesh)components[keyA]).Name, boneID); if (transforms.ContainsKey(keyA)) { model.SetTransform(transforms[keyA], boneID); } } else { var parent = model.FindMesh(keyB); if (parent != null) { boneID = model.AddMesh((ModelMesh)components[keyA], parent.Parent.Index); model.SetName(((ModelMesh)components[keyA]).Name, boneID); if (transforms.ContainsKey(keyA)) { model.SetTransform(transforms[keyA], boneID); } } else { if (!components.ContainsKey(keyB)) { Console.WriteLine("Components doesn't contain {0}", keyB); } else { Console.WriteLine("Couldn't find {0}", ((ModelMesh)components[keyB]).Name); } } } break; case "Flummery.Texture": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.Material") { if (loaded.Add(keyB)) { ((Material)components[keyB]).Texture = (Texture)components[keyA]; SceneManager.Current.Add((Material)components[keyB]); } } else { Console.WriteLine("{0} is of unknown type {1}", keyA, components[keyA].GetType().ToString()); Console.WriteLine("{0} is of unknown type {1}", keyB, components[keyB].GetType().ToString()); } break; case "System.Collections.Generic.List`1[Flummery.ModelMeshPart]": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.ModelMesh") { if (triangulationErrors.ContainsKey(keyA)) { triangulationErrors[keyA] += " (geometry of " + ((ModelMesh)components[keyB]).Name + ")"; } foreach (var part in (List<ModelMeshPart>)components[keyA]) { ((ModelMesh)components[keyB]).AddModelMeshPart(part); } } break; case "Flummery.Material": if (components.ContainsKey(keyB) && components[keyB].GetType().ToString() == "Flummery.ModelMesh") { var materialLookup = connections.Children.Where(c => (long)c.Properties[2].Value == keyB).ToList(); for (int i = materialLookup.Count - 1; i > -1; i--) { if (!connectionsOfType.Any(c => (long)c.Properties[1].Value == (long)materialLookup[i].Properties[1].Value)) { materialLookup.RemoveAt(i); } } foreach (var part in ((ModelMesh)components[keyB]).MeshParts) { if ((long)materialLookup[(int)part.Key].Properties[1].Value == keyA) { part.Material = (Material)components[keyA]; //SceneManager.Current.Add(part.Material); } } } break; default: Console.WriteLine("{0} is of unknown type {1}", keyA, components[keyA].GetType().ToString()); if (components.ContainsKey(keyB)) { Console.WriteLine("{0} is of unknown type {1}", keyB, components[keyB].GetType().ToString()); } Console.WriteLine("==="); break; } } } if (triangulationErrors.Count > 0) { SceneManager.Current.UpdateProgress(string.Format("Failed to load {0}", name)); string error = string.Format("File \"{0}\" has part{1} that need been triangulating! Please triangulate the following:", name, (triangulationErrors.Count > 1 ? "s" : "")); foreach (var kvp in triangulationErrors) { error += "\r\n" + kvp.Value; } SceneManager.Current.RaiseError(error); return null; } else { SceneManager.Current.UpdateProgress(string.Format("Loaded {0}", name)); model.Santise(); if (worldMatrix != Matrix4.Identity) { ModelManipulator.Freeze(model, worldMatrix); } ModelManipulator.FlipAxis(model.Root.Mesh, Axis.X, true); return model; } }
public override Asset Import(string path) { ACT act = ACT.Load(path); Model model = new Model(); int boneIndex = 0; string fileName = path.Substring(path.LastIndexOf("\\") + 1); path = path.Replace(fileName, ""); Model dat = SceneManager.Current.Content.Load<Model, DATImporter>(fileName.Replace(".act", ".dat", StringComparison.OrdinalIgnoreCase), path); Material material = null; foreach (var section in act.Sections) { switch (section.Section) { case Section.Name: boneIndex = model.AddMesh(null, boneIndex); model.SetName(section.Identifier, boneIndex); material = null; break; case Section.Material: material = (Material)SceneManager.Current.Materials.Entries.Find(m => m.Name == section.Material); if (material == null) { material = new Material() { Name = section.Material }; SceneManager.Current.Add(material); } break; case Section.Model: model.SetMesh(new ModelMesh(dat.FindMesh((section.Model.Contains(".") ? section.Model.Substring(0, section.Model.IndexOf(".")) : section.Model))), boneIndex); if (material != null) { foreach (var modelmesh in model.Meshes) { foreach (var meshpart in modelmesh.MeshParts) { if (meshpart.Material == null) { meshpart.Material = material; } } } } break; case Section.Matrix: model.SetTransform( new Matrix4( section.Transform.M11, section.Transform.M12, section.Transform.M13, 0, section.Transform.M21, section.Transform.M22, section.Transform.M23, 0, section.Transform.M31, section.Transform.M32, section.Transform.M33, 0, section.Transform.M41, section.Transform.M42, section.Transform.M43, 1 ), boneIndex ); break; case Section.SubLevelBegin: break; case Section.SubLevelEnd: boneIndex = model.Bones[boneIndex].Parent.Index; break; } } SceneManager.Current.UpdateProgress(string.Format("Loaded {0}", fileName)); return model; }
static void ProcessNode(TDRNode node, Model model, Model mshses, HIE hie, int ParentBoneIndex = 0) { int boneIndex = ParentBoneIndex; if (exit) { return; } switch (node.Type) { case TDRNode.NodeType.Matrix: boneIndex = model.AddMesh(null, boneIndex); model.SetName(node.Name, boneIndex); model.SetTransform( new Matrix4 ( node.Transform.M11, node.Transform.M12, node.Transform.M13, 0, node.Transform.M21, node.Transform.M22, node.Transform.M23, 0, node.Transform.M31, node.Transform.M32, node.Transform.M33, 0, node.Transform.M41, node.Transform.M42, node.Transform.M43, 1 ), boneIndex); break; case TDRNode.NodeType.Mesh: int index = node.Index; mshses.Meshes[index].MeshParts[0].Material = material; if (model.Bones[ParentBoneIndex].Mesh == null) { model.SetMesh(mshses.Meshes[index], boneIndex); //exit = true; //Console.WriteLine("Adding mesh #{0} \"{1}\" to bone #{2} \"{3}\"", index, mshses.Meshes[index].Name, boneIndex, model.Bones[boneIndex].Name); } else { boneIndex = model.AddMesh(mshses.Meshes[index], ParentBoneIndex); model.SetName(mshses.Meshes[index].Name, boneIndex); //model.SetName(mshses.Meshes[index].Name, model.AddMesh(mshses.Meshes[index], ParentBoneIndex)); //Console.WriteLine("Adding mesh #{0} \"{1}\" to brand new bone", index, mshses.Meshes[index].Name); } break; case TDRNode.NodeType.Texture: if (node.Index > -1) { material = SceneManager.Current.Content.Load<Material, TXImporter>(hie.Textures[node.Index]); } else { material = null; } break; } foreach (var child in node.Children) { ProcessNode(child, model, mshses, hie, boneIndex); } }