internal BlendFile(BlenderFile file) { Version = file.VersionNumber; PopulatedStructure fileGlobal = file.GetStructuresOfType("FileGlobal")[0]; Filename = new string(fileGlobal["filename"].GetValueAsCharArray()).Split('\0')[0]; Revision = fileGlobal["revision"].GetValueAsInt(); ulong curSceneAddr = fileGlobal["curscene"].GetValueAsPointer(); PopulatedStructure[] scenes = file.GetStructuresOfType("Scene"); int i = 0; Scenes = new Scene[scenes.Length]; foreach (PopulatedStructure scene in scenes) { if (scene.ContainingBlock.OldMemoryAddress == curSceneAddr) { currentSceneIndex = i; } Scenes[i++] = new Scene(file, scene); } }
private void loadModelData(BlenderFile file) { models = new List <BlenderModel>(); transparentModels = new List <BlenderModel>(); currentLayer = 1; Structure curscene = file.GetStructuresOfType("FileGlobal")[0]["curscene"].Dereference()[0]; ulong next = curscene["base.first"].Value; while (next != 0) { Structure objBase = file.GetStructuresByAddress(next)[0]; Structure obj = objBase["object"].Dereference()[0]; IField data = obj["data"]; int SDNAIndex = file.GetBlockByAddress((data as Field <ulong>).Value).SDNAIndex; while (file.StructureDNA.StructureList[SDNAIndex].StructureTypeName != "Mesh") { ulong nextPointer = (objBase["next"] as Field <ulong>).Value; if (nextPointer == 0) { return; // we've run out of objects in the list, and haven't found any meshes } objBase = file.GetStructuresByAddress(nextPointer)[0]; obj = objBase["object"].Dereference()[0]; data = obj["data"]; SDNAIndex = file.GetBlockByAddress((data as Field <ulong>).Value).SDNAIndex; } Structure mesh = data.Dereference()[0]; BlenderModel model = new BlenderModel(mesh, obj, GraphicsDevice, file); if (model.TextureHasTransparency) { transparentModels.Add(model); } else { models.Add(model); } next = (objBase["next"] as Field <ulong>).Value; } }
private VertexPositionNormalTexture[] loadOldModel(BlenderFile file, PopulatedStructure mesh, List <Vector3> verts, List <Vector3> normals, out BasicMaterialContent bmc) { // I believe this function has a bug when used on a mesh that has unconnected chunks of vertices; // however the only file I currently have that exhibits this problem decompresses to 240MB when I use the HTML // renderer tool, so I can't feasibly poke through the data to see what's going wrong. List <VertexPositionNormalTexture> output = new List <VertexPositionNormalTexture>(); bmc = new BasicMaterialContent(); List <int[]> faces = new List <int[]>(); List <float[, ]> tFaces = new List <float[, ]>(); foreach (PopulatedStructure s in file.GetStructuresByAddress(mesh["mface"].GetValueAsPointer())) { faces.Add(new[] { s["v1"].GetValueAsInt(), s["v2"].GetValueAsInt(), s["v3"].GetValueAsInt(), s["v4"].GetValueAsInt() }); } foreach (PopulatedStructure s in file.GetStructuresByAddress(mesh["mtface"].GetValueAsPointer())) { tFaces.Add((float[, ])s["uv"].GetValueAsMultidimensionalArray()); } // assume all faces use same texture PopulatedStructure image = file.GetStructuresByAddress(file.GetStructuresByAddress(mesh["mtface"].GetValueAsPointer())[0]["tpage"].GetValueAsPointer())[0]; if (image["packedfile"].GetValueAsPointer() != 0) { byte[] rawImage = file.GetBlockByAddress(file.GetStructuresByAddress(image["packedfile"].GetValueAsPointer())[0]["data"].GetValueAsPointer()).Data; string filename = Name + "_" + new string(image["id.name"].GetValueAsCharArray()).Split('\0')[0].Substring(2); using (BinaryWriter s = new BinaryWriter(File.Open(filename, FileMode.Create))) s.Write(rawImage); bmc.Texture = new ExternalReference <TextureContent>(filename); } else { try { string texturePath = image["name"].ToString().Split('\0')[0].Replace("/", "\\").Replace("\\\\", "\\"); string filePath = file.GetStructuresOfType("FileGlobal")[0]["filename"].ToString(); filePath = filePath.Substring(0, filePath.LastIndexOf('\\')); File.Copy((filePath + texturePath).Replace("\'", ""), Name + "_" + new string(image["id.name"].GetValueAsCharArray()).Split('\0')[0].Substring(2)); } catch { //texture = defaultTex; } } int j = 0; foreach (int[] face in faces) { Vector3[] faceVerts = new Vector3[face.Length]; Vector3[] faceVertNormals = new Vector3[face.Length]; Vector2[] faceUVs = new Vector2[face.Length]; for (int i = 0; i < face.Length; i++) { faceVerts[i] = verts[face[i]]; faceVertNormals[i] = normals[face[i]]; faceUVs[i] = new Vector2(tFaces[j][i, 0], tFaces[j][i, 1]); } j++; // 2, 1, 0 for (int i = 2; i >= 0; i--) { output.Add(new VertexPositionNormalTexture(faceVerts[i], faceVertNormals[i], faceUVs[i])); } // 3, 2, 0 for (int i = 3; i >= 1; i--) { output.Add(new VertexPositionNormalTexture(faceVerts[i == 1 ? 0 : i], faceVertNormals[i == 1 ? 0 : i], faceUVs[i == 1 ? 0 : i])); } } return(output.ToArray()); }
private VertexPositionNormalTexture[] loadNewModel(BlenderFile file, Structure mesh, List<Vector3> verts, List<Vector3> normals, out Texture2D texture) { List<VertexPositionNormalTexture> output = new List<VertexPositionNormalTexture>(); List<Vector2> edges = new List<Vector2>(); // using x as index1 and y as index2 foreach(Structure s in mesh["medge"].Dereference()) edges.Add(new Vector2((s["v1"] as IField<int>).Value, (s["v2"] as IField<int>).Value)); // a "loop" is a vertex index and an edge index. Groups of these are used to define a "poly", which is a face. List<Vector2> loops = new List<Vector2>(); // using x as "v" and y as "e" foreach(Structure s in mesh["mloop"].Dereference()) loops.Add(new Vector2((s["v"] as IField<int>).Value, (s["e"] as IField<int>).Value)); List<Vector2> uvLoops = null; // using x as u and y as v Vector2[] backupUVs = new[] { new Vector2(0, 0), new Vector2(0, 1), new Vector2(1, 1), new Vector2(1, 0) }; // in case uvLoops is null if(mesh["mloopuv"].Value != 0) { uvLoops = new List<Vector2>(); foreach(Structure s in mesh["mloopuv"].Dereference()) { float[] uv = s["uv"].Value; uvLoops.Add(new Vector2(uv[0], uv[1])); } } List<Vector2> polys = new List<Vector2>(); // using x as "loopstart" and y as "totloop" (loop length) foreach(Structure s in mesh["mpoly"].Dereference()) polys.Add(new Vector2((s["loopstart"] as IField<int>).Value, (s["totloop"] as IField<int>).Value)); // assume all faces use same texture for now if(mesh["mtpoly"].Value != 0) { try { // todo: sometimes this line fails, probably due to "assume all faces use same texture" Structure image = mesh["mtpoly"].Dereference()[0]["tpage"].Dereference()[0]; if(image["packedfile"].Value != 0) { byte[] rawImage = file.GetBlockByAddress(image["packedfile"].Dereference()[0]["data"].Value).Data; using(Stream s = new MemoryStream(rawImage)) texture = Texture2D.FromStream(GraphicsDevice, s); } else { string texturePath = image["name"].ToString().Split('\0')[0].Replace("/", "\\").Replace("\\\\", "\\"); string filePath = file.GetStructuresOfType("FileGlobal")[0]["filename"].ToString(); filePath = filePath.Substring(0, filePath.LastIndexOf('\\')); using(Stream s = File.Open((filePath + texturePath).Replace("\'", ""), FileMode.Open, FileAccess.Read)) texture = Texture2D.FromStream(GraphicsDevice, s); } } catch { texture = defaultTex; } } else { texture = new Texture2D(GraphicsDevice, 1, 1); texture.SetData(new Color[] { Color.Gray }); } // loops of length 3 are triangles and can be directly added to the vertex list. loops of length 4 // are quads, and have to be split into two triangles. foreach(Vector2 poly in polys) { Vector2[] faceEdges = new Vector2[(int)poly.Y]; Vector2[] faceUVs = new Vector2[faceEdges.Length]; int j = 0; int loopOffset = (int)poly.X; for(int i = loopOffset; i < (int)poly.Y + loopOffset; i++) { faceEdges[j] = edges[(int)loops[i].Y]; faceUVs[j] = uvLoops == null ? backupUVs[i - loopOffset] : uvLoops[i]; j++; } Vector3[] faceVerts = new Vector3[faceEdges.Length]; Vector3[] faceVertNormals = new Vector3[faceEdges.Length]; for(int i = 0; i < faceEdges.Length; i++) { int index = (int)(loops[loopOffset + i].X == faceEdges[i].X ? faceEdges[i].Y : faceEdges[i].X); faceVerts[i] = verts[index]; faceVertNormals[i] = normals[index]; } if(faceVerts.Length == 3) // already a triangle { // push 0 to the end Vector2 temp = faceUVs[0]; faceUVs[0] = faceUVs[1]; faceUVs[1] = temp; temp = faceUVs[1]; faceUVs[1] = faceUVs[2]; faceUVs[2] = temp; for(int i = 2; i >= 0; i--) // 2, 1, 0 output.Add(new VertexPositionNormalTexture(faceVerts[i], faceVertNormals[i], faceUVs[i])); } else if(faceVerts.Length == 4) // quad, split into tris { // swap 3 with 1 and 2 with 3 Vector2 temp = faceUVs[1]; faceUVs[1] = faceUVs[3]; faceUVs[3] = temp; temp = faceUVs[2]; faceUVs[2] = faceUVs[3]; faceUVs[3] = temp; // 2, 1, 0 for(int i = 2; i >= 0; i--) output.Add(new VertexPositionNormalTexture(faceVerts[i], faceVertNormals[i], faceUVs[i])); // 3, 2, 0 for(int i = 3; i >= 1; i--) output.Add(new VertexPositionNormalTexture(faceVerts[i == 1 ? 0 : i], faceVertNormals[i == 1 ? 0 : i], faceUVs[i == 1 ? 0 : i])); } } return output.ToArray(); }
private VertexPositionNormalTexture[] loadOldModel(BlenderFile file, Structure mesh, List<Vector3> verts, List<Vector3> normals, out Texture2D texture) { // I believe this function has a bug when used on a mesh that has unconnected chunks of vertices; // however the only file I currently have that exhibits this problem decompresses to 240MB when I use the HTML // renderer tool, so I can't feasibly poke through the data to see what's going wrong. List<VertexPositionNormalTexture> output = new List<VertexPositionNormalTexture>(); List<int[]> faces = new List<int[]>(); List<float[][]> tFaces = new List<float[][]>(); foreach(Structure s in mesh["mface"].Dereference()) faces.Add(new int[] { s["v1"].Value, s["v2"].Value, s["v3"].Value, s["v4"].Value }); foreach(Structure s in mesh["mtface"].Dereference()) tFaces.Add((float[][])s["uv"].Value); // assume all faces use same texture Structure image = mesh["mtface"].Dereference()[0]["tpage"].Dereference()[0]; if(image["packedfile"].Value != 0) { byte[] rawImage = file.GetBlockByAddress(image["packedfile"].Dereference()[0]["data"].Value).Data; using(Stream s = new MemoryStream(rawImage)) texture = Texture2D.FromStream(GraphicsDevice, s); } else { try { string texturePath = image["name"].ToString().Split('\0')[0].Replace("/", "\\").Replace("\\\\", "\\"); string filePath = file.GetStructuresOfType("FileGlobal")[0]["filename"].ToString(); filePath = filePath.Substring(0, filePath.LastIndexOf('\\')); using(Stream s = File.Open((filePath + texturePath).Replace("\'", ""), FileMode.Open, FileAccess.Read)) texture = Texture2D.FromStream(GraphicsDevice, s); } catch { texture = defaultTex; } } int j = 0; foreach(int[] face in faces) { Vector3[] faceVerts = new Vector3[face.Length]; Vector3[] faceVertNormals = new Vector3[face.Length]; Vector2[] faceUVs = new Vector2[face.Length]; for(int i = 0; i < face.Length; i++) { faceVerts[i] = verts[face[i]]; faceVertNormals[i] = normals[face[i]]; faceUVs[i] = new Vector2(tFaces[j][i][0], tFaces[j][i][1]); } j++; // 2, 1, 0 for(int i = 2; i >= 0; i--) output.Add(new VertexPositionNormalTexture(faceVerts[i], faceVertNormals[i], faceUVs[i])); // 3, 2, 0 for(int i = 3; i >= 1; i--) output.Add(new VertexPositionNormalTexture(faceVerts[i == 1 ? 0 : i], faceVertNormals[i == 1 ? 0 : i], faceUVs[i == 1 ? 0 : i])); } return output.ToArray(); }