Пример #1
0
        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);
            }
        }
Пример #2
0
        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;
            }
        }
Пример #3
0
        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());
        }
Пример #4
0
        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();
        }
Пример #5
0
        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();
        }