From afd710801fffc7dced8818aa47b67ce4ef889f4d Mon Sep 17 00:00:00 2001 From: Marisa Kirisame <OrdinaryMagician@users.noreply.github.com> Date: Thu, 5 Jul 2018 11:50:03 +0200 Subject: [PATCH] Update .3d support to match coelckers/gzdoom#506 (PR#221 by Marisa_Kirisame) --- Source/Core/GZBuilder/md3/ModelReader.cs | 311 +++++++++++++---------- 1 file changed, 171 insertions(+), 140 deletions(-) diff --git a/Source/Core/GZBuilder/md3/ModelReader.cs b/Source/Core/GZBuilder/md3/ModelReader.cs index 41a8f6851..fbb2cc9c6 100755 --- a/Source/Core/GZBuilder/md3/ModelReader.cs +++ b/Source/Core/GZBuilder/md3/ModelReader.cs @@ -29,14 +29,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 public List<Mesh> Meshes; public string Errors; - public MD3LoadResult() + public MD3LoadResult() { Skins = new List<string>(); Meshes = new List<Mesh>(); } } - private static readonly VertexElement[] vertexElements = new[] + private static readonly VertexElement[] vertexElements = new[] { new VertexElement(0, 0, DeclarationType.Float3, DeclarationMethod.Default, DeclarationUsage.Position, 0), new VertexElement(0, 12, DeclarationType.Color, DeclarationMethod.Default, DeclarationUsage.Color, 0), @@ -49,20 +49,20 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== Load - public static void Load(ModelData mde, List<DataReader> containers, Device device) + public static void Load(ModelData mde, List<DataReader> containers, Device device) { if(mde.IsVoxel) LoadKVX(mde, containers, device); else LoadModel(mde, containers, device); } - private static void LoadKVX(ModelData mde, List<DataReader> containers, Device device) + private static void LoadKVX(ModelData mde, List<DataReader> containers, Device device) { mde.Model = new GZModel(); string unused = string.Empty; foreach(string name in mde.ModelNames) { //find the model - foreach(DataReader dr in containers) + foreach(DataReader dr in containers) { Stream ms = dr.GetVoxelData(name, ref unused); if(ms == null) continue; @@ -80,32 +80,32 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 mde.SkinNames = null; mde.ModelNames = null; - if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) + if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) { mde.Model = null; } } - private static void LoadModel(ModelData mde, List<DataReader> containers, Device device) + private static void LoadModel(ModelData mde, List<DataReader> containers, Device device) { mde.Model = new GZModel(); BoundingBoxSizes bbs = new BoundingBoxSizes(); MD3LoadResult result = new MD3LoadResult(); //load models and textures - for(int i = 0; i < mde.ModelNames.Count; i++) + for(int i = 0; i < mde.ModelNames.Count; i++) { // Use model skins? - // INFO: Skin MODELDEF property overrides both embedded surface names and ones set using SurfaceSkin MODELDEF property + // INFO: Skin MODELDEF property overrides both embedded surface names and ones set using SurfaceSkin MODELDEF property Dictionary<int, string> skins = null; if(string.IsNullOrEmpty(mde.SkinNames[i])) { skins = (mde.SurfaceSkinNames[i].Count > 0 ? mde.SurfaceSkinNames[i] : new Dictionary<int, string>()); } - + // Load mesh MemoryStream ms = LoadFile(containers, mde.ModelNames[i], true); - if(ms == null) + if(ms == null) { General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": unable to find file."); continue; @@ -138,11 +138,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 continue; //got errors? - if (!String.IsNullOrEmpty(result.Errors)) + if (!String.IsNullOrEmpty(result.Errors)) { General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + result.Errors); - } - else + } + else { //add loaded data to ModeldefEntry mde.Model.Meshes.AddRange(result.Meshes); @@ -155,12 +155,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 List<string> errors = new List<string>(); // Texture not defined in MODELDEF? - if(skins != null) + if(skins != null) { - //try to use model's own skins - for(int m = 0; m < result.Meshes.Count; m++) + //try to use model's own skins + for(int m = 0; m < result.Meshes.Count; m++) { - if(string.IsNullOrEmpty(result.Skins[m])) + if(string.IsNullOrEmpty(result.Skins[m])) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); errors.Add("texture not found in MODELDEF or model skin."); @@ -170,7 +170,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 string path = result.Skins[m].Replace(Path.AltDirectorySeparatorChar, Path.DirectorySeparatorChar); ext = Path.GetExtension(path); - if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1) + if(Array.IndexOf(ModelData.SUPPORTED_TEXTURE_EXTENSIONS, ext) == -1) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); errors.Add("image format \"" + ext + "\" is not supported!"); @@ -183,12 +183,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 Texture t = LoadTexture(containers, path, device); - if(t == null) + if(t == null) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); errors.Add("unable to load skin \"" + result.Skins[m] + "\""); continue; - } + } mde.Model.Textures.Add(t); } @@ -197,19 +197,19 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 else { Texture t = LoadTexture(containers, mde.SkinNames[i], device); - if(t == null) + if(t == null) { mde.Model.Textures.Add(General.Map.Data.UnknownTexture3D.Texture); errors.Add("unable to load texture \"" + mde.SkinNames[i] + "\""); - } - else + } + else { mde.Model.Textures.Add(t); } } //report errors - if(errors.Count > 0) + if(errors.Count > 0) { foreach(string e in errors) General.ErrorLogger.Add(ErrorType.Error, "Error while loading \"" + mde.ModelNames[i] + "\": " + e); @@ -221,7 +221,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 mde.SkinNames = null; mde.ModelNames = null; - if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) + if(mde.Model.Meshes == null || mde.Model.Meshes.Count == 0) { mde.Model = null; return; @@ -234,7 +234,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 bbs.MinY = (int)(bbs.MinY * mde.Scale.Y); //calculate model radius - mde.Model.Radius = Math.Max(Math.Max(Math.Abs(bbs.MinY), Math.Abs(bbs.MaxY)), Math.Max(Math.Abs(bbs.MinX), Math.Abs(bbs.MaxX))); + mde.Model.Radius = Math.Max(Math.Max(Math.Abs(bbs.MinY), Math.Abs(bbs.MaxY)), Math.Max(Math.Abs(bbs.MinX), Math.Abs(bbs.MaxX))); } #endregion @@ -253,11 +253,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 { switch (c) { - case 2: + case 0: return PadInt16((n & 0x7ff) << 5) / 128f; case 1: return PadInt16((((int)n >> 11) & 0x7ff) << 5) / 128f; - case 0: + case 2: return PadInt16((((int)n >> 22) & 0x3ff) << 6) / 128f; default: return 0f; @@ -269,7 +269,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 public int[] V; public float[] S; public float[] T; - public int TexNum; + public int TexNum, Type; + public Vector3D Normal; } internal static MD3LoadResult Read3DModel(ref BoundingBoxSizes bbs, Dictionary<int, string> skins, Stream s, Device device, int frame, string filename, List<DataReader> containers) @@ -307,10 +308,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 // read d3d header uint d3d_numpolys = br_d.ReadUInt16(); uint d3d_numverts = br_d.ReadUInt16(); - stream_d.Position += 16; // bogusrot, bogusframe, bogusnorm[3] - uint d3d_fixscale = br_d.ReadUInt32(); - stream_d.Position += 12; // unused[3] - stream_d.Position += 12; // padding[12] + stream_d.Position += 44; // bogusrot, bogusframe, bogusnorm[3], fixscale, unused[3], padding[12] long start_d = stream_d.Position; @@ -327,19 +325,33 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 return result; } + // check for deus ex format + bool isdeusex = false; + if ( (a3d_framesize/d3d_numverts) == 8 ) isdeusex = true; + // read vertices WorldVertex[] vertices = new WorldVertex[d3d_numverts]; for (uint i = 0; i < d3d_numverts; i++) { WorldVertex Vert = new WorldVertex(); - stream_a.Position = start_a + (i + frame * d3d_numverts) * 4; - int v_uint = br_a.ReadInt32(); - //Vert.y = -UnpackUVertex(v_uint, 0); - //Vert.z = UnpackUVertex(v_uint, 1); - //Vert.x = UnpackUVertex(v_uint, 2); - Vert.y = -UnpackUVertex(v_uint, 2); - Vert.z = UnpackUVertex(v_uint, 0); - Vert.x = -UnpackUVertex(v_uint, 1); + if ( isdeusex ) + { + stream_a.Position = start_a + (i + frame * d3d_numverts) * 8; + int vx = br_a.ReadInt16(); + int vy = br_a.ReadInt16(); + int vz = br_a.ReadInt16(); + Vert.y = -vx; + Vert.z = vz; + Vert.x = -vy; + } + else + { + stream_a.Position = start_a + (i + frame * d3d_numverts) * 4; + int v_uint = br_a.ReadInt32(); + Vert.y = -UnpackUVertex(v_uint, 0); + Vert.z = UnpackUVertex(v_uint, 2); + Vert.x = -UnpackUVertex(v_uint, 1); + } vertices[i] = Vert; } @@ -348,14 +360,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int[] polyindexlist = new int[d3d_numpolys*3]; for (uint i = 0; i < d3d_numpolys; i++) { - // + // stream_d.Position = start_d + 16 * i; polys[i].V = new int[3]; polys[i].S = new float[3]; polys[i].T = new float[3]; for (int j = 0; j < 3; j++) polyindexlist[i*3+j] = polys[i].V[j] = br_d.ReadInt16(); - stream_d.Position += 2; + polys[i].Type = br_d.ReadByte(); + stream_d.Position += 1; // color for (int j = 0; j < 3; j++) { byte u = br_d.ReadByte(); @@ -366,6 +379,24 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 polys[i].TexNum = br_d.ReadByte(); } + // calculate poly normals + for (uint i = 0; i < d3d_numpolys; i++) + { + Vector3D[] dir = new Vector3D[2]; + Vector3D norm; + dir[0].x = vertices[polys[i].V[1]].x-vertices[polys[i].V[0]].x; + dir[0].y = vertices[polys[i].V[1]].y-vertices[polys[i].V[0]].y; + dir[0].z = vertices[polys[i].V[1]].z-vertices[polys[i].V[0]].z; + dir[1].x = vertices[polys[i].V[2]].x-vertices[polys[i].V[0]].x; + dir[1].y = vertices[polys[i].V[2]].y-vertices[polys[i].V[0]].y; + dir[1].z = vertices[polys[i].V[2]].z-vertices[polys[i].V[0]].z; + norm.x = dir[0].y * dir[1].z - dir[0].z * dir[1].y; + norm.y = dir[0].z * dir[1].x - dir[0].x * dir[1].z; + norm.z = dir[0].x * dir[1].y - dir[0].y * dir[1].x; + polys[i].Normal = norm.GetNormal(); + } + + // calculate vertex normals for (uint i = 0; i < d3d_numverts; i++) { Vector3D nsum = new Vector3D(0, 0, 0); @@ -373,25 +404,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 for (uint j = 0; j < d3d_numpolys; j++) { if ((polys[j].V[0] != i) && (polys[j].V[1] != i) && (polys[j].V[2] != i)) continue; - Vector3D[] vert = new Vector3D[3]; - Vector3D[] dir = new Vector3D[2]; - Vector3D norm; - // - for (int k = 0; k < 3; k++) - vert[k] = new Vector3D(vertices[polys[j].V[k]].x, vertices[polys[j].V[k]].y, vertices[polys[j].V[k]].z); - dir[0].x = vert[1].x - vert[0].x; - dir[0].y = vert[1].y - vert[0].y; - dir[0].z = vert[1].z - vert[0].z; - dir[1].x = vert[2].x - vert[0].x; - dir[1].y = vert[2].y - vert[0].y; - dir[1].z = vert[2].z - vert[0].z; - norm.x = dir[0].y * dir[1].z - dir[0].z * dir[1].y; - norm.y = dir[0].z * dir[1].x - dir[0].x * dir[1].z; - norm.z = dir[0].x * dir[1].y - dir[0].y * dir[1].x; - norm = norm.GetNormal(); - nsum.x += norm.x; - nsum.y += norm.y; - nsum.z += norm.z; + nsum.x += polys[j].Normal.x; + nsum.y += polys[j].Normal.y; + nsum.z += polys[j].Normal.z; total++; } vertices[i].nx = -nsum.x / total; @@ -423,11 +438,19 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 for (int i = 0; i < polys.Length; i++) { + if ( polys[i].Type&0x08 ) + continue; for (int j = 0; j < 3; j++) { WorldVertex vx = vertices[polys[i].V[j]]; vx.u = polys[i].S[j]; vx.v = polys[i].T[j]; + if ( polys[i].Type&0x20 ) + { + vx.nx = polys[i].Normal.x; + vx.ny = polys[i].Normal.y; + vx.nz = polys[i].Normal.z; + } out_polys.Add(out_verts.Count); out_verts.Add(vx); } @@ -445,6 +468,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 for (int i = 0; i < polys.Length; i++) { + if ( polys[i].Type&0x08 ) + continue; if (textureGroupRemap[polys[i].TexNum] != k) continue; @@ -454,6 +479,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 WorldVertex vx = vertices[polys[i].V[j]]; vx.u = polys[i].S[j]; vx.v = polys[i].T[j]; + if ( polys[i].Type&0x20 ) + { + vx.nx = polys[i].Normal.x; + vx.ny = polys[i].Normal.y; + vx.nz = polys[i].Normal.z; + } out_polys.Add(out_verts.Count); out_verts.Add(vx); } @@ -471,12 +502,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== MD3 - internal static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, Dictionary<int, string> skins, Stream s, Device device, int frame) + internal static MD3LoadResult ReadMD3Model(ref BoundingBoxSizes bbs, Dictionary<int, string> skins, Stream s, Device device, int frame) { long start = s.Position; MD3LoadResult result = new MD3LoadResult(); - using(var br = new BinaryReader(s, Encoding.ASCII)) + using(var br = new BinaryReader(s, Encoding.ASCII)) { string magic = ReadString(br, 4); if(magic != "IDP3") @@ -507,12 +538,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 Dictionary<string, List<int>> vertexOffsets = new Dictionary<string, List<int>>(StringComparer.Ordinal); bool useskins = false; - for(int c = 0; c < numSurfaces; c++) + for(int c = 0; c < numSurfaces; c++) { string skin = ""; string error = ReadSurface(ref bbs, ref skin, br, polyIndecesList, vertList, frame); - if(!string.IsNullOrEmpty(error)) + if(!string.IsNullOrEmpty(error)) { result.Errors = error; return result; @@ -533,14 +564,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(!string.IsNullOrEmpty(skin)) { useskins = true; - - if(polyIndecesListsPerTexture.ContainsKey(skin)) + + if(polyIndecesListsPerTexture.ContainsKey(skin)) { polyIndecesListsPerTexture[skin].Add(polyIndecesList); vertListsPerTexture[skin].AddRange(vertList.ToArray()); vertexOffsets[skin].Add(vertList.Count); - } - else + } + else { polyIndecesListsPerTexture.Add(skin, new List<List<int>> { polyIndecesList } ); vertListsPerTexture.Add(skin, vertList); @@ -553,27 +584,27 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } } - if(!useskins) + if(!useskins) { //create mesh CreateMesh(device, ref result, vertList, polyIndecesList); result.Skins.Add(""); - } - else + } + else { //create a mesh for each surface texture - foreach(KeyValuePair<string, List<List<int>>> group in polyIndecesListsPerTexture) + foreach(KeyValuePair<string, List<List<int>>> group in polyIndecesListsPerTexture) { polyIndecesList = new List<int>(); int offset = 0; - + //collect indices, fix vertex offsets - for(int i = 0; i < group.Value.Count; i++) + for(int i = 0; i < group.Value.Count; i++) { - if(i > 0) + if(i > 0) { //TODO: Damn I need to rewrite all of this stuff from scratch... - offset += vertexOffsets[group.Key][i - 1]; + offset += vertexOffsets[group.Key][i - 1]; for(int c = 0; c < group.Value[i].Count; c++) group.Value[i][c] += offset; } @@ -589,11 +620,11 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 return result; } - private static string ReadSurface(ref BoundingBoxSizes bbs, ref string skin, BinaryReader br, List<int> polyIndecesList, List<WorldVertex> vertList, int frame) + private static string ReadSurface(ref BoundingBoxSizes bbs, ref string skin, BinaryReader br, List<int> polyIndecesList, List<WorldVertex> vertList, int frame) { int vertexOffset = vertList.Count; long start = br.BaseStream.Position; - + string magic = ReadString(br, 4); if(magic != "IDP3") return "error while reading surface. Unknown header: expected \"IDP3\", but got \"" + magic + "\""; @@ -632,7 +663,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 if(start + ofsST != br.BaseStream.Position) br.BaseStream.Position = start + ofsST; - for(int i = 0; i < numVerts; i++) + for(int i = 0; i < numVerts; i++) { WorldVertex v = new WorldVertex(); v.c = -1; //white @@ -646,7 +677,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 long vertoffset = start + ofsNormal + numVerts * 8 * frame; // The length of Vertex struct is 8 bytes if(br.BaseStream.Position != vertoffset) br.BaseStream.Position = vertoffset; - for(int i = vertexOffset; i < vertexOffset + numVerts; i++) + for(int i = vertexOffset; i < vertexOffset + numVerts; i++) { WorldVertex v = vertList[i]; @@ -677,12 +708,12 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== MD2 - private static MD3LoadResult ReadMD2Model(ref BoundingBoxSizes bbs, Stream s, Device device, int frame, string framename) + private static MD3LoadResult ReadMD2Model(ref BoundingBoxSizes bbs, Stream s, Device device, int frame, string framename) { long start = s.Position; MD3LoadResult result = new MD3LoadResult(); - using(var br = new BinaryReader(s, Encoding.ASCII)) + using(var br = new BinaryReader(s, Encoding.ASCII)) { string magic = ReadString(br, 4); if(magic != "IDP2") //magic number: "IDP2" @@ -693,7 +724,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int modelVersion = br.ReadInt32(); if(modelVersion != 8) //MD2 version. Must be equal to 8 - { + { result.Errors = "expected MD3 version 15, but got " + modelVersion; return result; } @@ -728,7 +759,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 // Polygons s.Position = ofs_tris + start; - for(int i = 0; i < num_tris; i++) + for(int i = 0; i < num_tris; i++) { polyIndecesList.Add(br.ReadUInt16()); polyIndecesList.Add(br.ReadUInt16()); @@ -742,7 +773,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 // UV coords s.Position = ofs_uv + start; - for(int i = 0; i < num_uv; i++) + for(int i = 0; i < num_uv; i++) uvCoordsList.Add(new Vector2((float)br.ReadInt16() / texWidth, (float)br.ReadInt16() / texHeight)); // Frames @@ -789,7 +820,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 float angleOfsetSin = (float)Math.Sin(-Angle2D.PIHALF); //verts - for(int i = 0; i < num_verts; i++) + for(int i = 0; i < num_verts; i++) { WorldVertex v = new WorldVertex(); @@ -807,10 +838,10 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 s.Position += 1; //vertex normal } - for(int i = 0; i < polyIndecesList.Count; i++) + for(int i = 0; i < polyIndecesList.Count; i++) { WorldVertex v = vertList[polyIndecesList[i]]; - + //bounding box BoundingBoxTools.UpdateBoundingBoxSizes(ref bbs, new WorldVertex(v.y, v.x, v.z)); @@ -819,13 +850,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 float tv = uvCoordsList[uvIndecesList[i]].Y; //uv-coordinates already set? - if(v.c == -1 && (v.u != tu || v.v != tv)) - { + if(v.c == -1 && (v.u != tu || v.v != tv)) + { //add a new vertex vertList.Add(new WorldVertex(v.x, v.y, v.z, -1, tu, tv)); polyIndecesList[i] = vertList.Count - 1; - } - else + } + else { v.u = tu; v.v = tv; @@ -839,13 +870,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //mesh Mesh mesh = new Mesh(device, polyIndecesList.Count / 3, vertList.Count, MeshFlags.Use32Bit | MeshFlags.IndexBufferManaged | MeshFlags.VertexBufferManaged, vertexElements); - using(DataStream stream = mesh.LockVertexBuffer(LockFlags.None)) + using(DataStream stream = mesh.LockVertexBuffer(LockFlags.None)) { stream.WriteRange(vertList.ToArray()); } mesh.UnlockVertexBuffer(); - using(DataStream stream = mesh.LockIndexBuffer(LockFlags.None)) + using(DataStream stream = mesh.LockIndexBuffer(LockFlags.None)) { stream.WriteRange(polyIndecesList.ToArray()); } @@ -865,7 +896,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== KVX - private static void ReadKVX(ModelData mde, Stream stream, Device device) + private static void ReadKVX(ModelData mde, Stream stream, Device device) { PixelColor[] palette = new PixelColor[256]; List<WorldVertex> verts = new List<WorldVertex>(); @@ -875,7 +906,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int facescount = 0; Vector3D pivot; - using(BinaryReader reader = new BinaryReader(stream, Encoding.ASCII)) + using(BinaryReader reader = new BinaryReader(stream, Encoding.ASCII)) { reader.ReadInt32(); //numbytes, we don't use that xsize = reader.ReadInt32(); @@ -891,14 +922,14 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int[] xoffset = new int[xsize + 1]; //why is it xsize + 1, not xsize?.. short[,] xyoffset = new short[xsize, ysize + 1]; //why is it ysize + 1, not ysize?.. - for(int i = 0; i < xoffset.Length; i++) + for(int i = 0; i < xoffset.Length; i++) { xoffset[i] = reader.ReadInt32(); } - for(int x = 0; x < xsize; x++) + for(int x = 0; x < xsize; x++) { - for(int y = 0; y < ysize + 1; y++) + for(int y = 0; y < ysize + 1; y++) { xyoffset[x, y] = reader.ReadInt16(); } @@ -906,9 +937,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //read slabs List<int> offsets = new List<int>(xsize * ysize); - for(int x = 0; x < xsize; x++) + for(int x = 0; x < xsize; x++) { - for(int y = 0; y < ysize; y++) + for(int y = 0; y < ysize; y++) { offsets.Add(xoffset[x] + xyoffset[x, y] + 28); //for some reason offsets are counted from start of xoffset[]... } @@ -918,49 +949,49 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int slabsEnd = (int)(reader.BaseStream.Length - 768); //read palette - if(!mde.OverridePalette) + if(!mde.OverridePalette) { reader.BaseStream.Position = slabsEnd; - for(int i = 0; i < 256; i++) + for(int i = 0; i < 256; i++) { byte r = (byte)(reader.ReadByte() * 4); byte g = (byte)(reader.ReadByte() * 4); byte b = (byte)(reader.ReadByte() * 4); palette[i] = new PixelColor(255, r, g, b); } - } - else + } + else { - for(int i = 0; i < 256; i++ ) + for(int i = 0; i < 256; i++ ) { palette[i] = General.Map.Data.Palette[i]; } } - for(int x = 0; x < xsize; x++) + for(int x = 0; x < xsize; x++) { - for(int y = 0; y < ysize; y++) + for(int y = 0; y < ysize; y++) { reader.BaseStream.Position = offsets[counter]; int next = (counter < offsets.Count - 1 ? offsets[counter + 1] : slabsEnd); //read slab - while(reader.BaseStream.Position < next) + while(reader.BaseStream.Position < next) { int ztop = reader.ReadByte(); int zleng = reader.ReadByte(); if(ztop + zleng > zsize) break; int flags = reader.ReadByte(); - if(zleng > 0) + if(zleng > 0) { List<int> colorIndices = new List<int>(zleng); - for(int i = 0; i < zleng; i++) + for(int i = 0; i < zleng; i++) { colorIndices.Add(reader.ReadByte()); } - if((flags & 16) != 0) + if((flags & 16) != 0) { AddFace(verts, indices, verthashes, new Vector3D(x, y, ztop), new Vector3D(x + 1, y, ztop), new Vector3D(x, y + 1, ztop), new Vector3D(x + 1, y + 1, ztop), pivot, colorIndices[0]); facescount += 2; @@ -968,27 +999,27 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int z = ztop; int cstart = 0; - while(z < ztop + zleng) + while(z < ztop + zleng) { int c = 0; while(z + c < ztop + zleng && colorIndices[cstart + c] == colorIndices[cstart]) c++; - if((flags & 1) != 0) + if((flags & 1) != 0) { AddFace(verts, indices, verthashes, new Vector3D(x, y, z), new Vector3D(x, y + 1, z), new Vector3D(x, y, z + c), new Vector3D(x, y + 1, z + c), pivot, colorIndices[cstart]); facescount += 2; } - if((flags & 2) != 0) + if((flags & 2) != 0) { AddFace(verts, indices, verthashes, new Vector3D(x + 1, y + 1, z), new Vector3D(x + 1, y, z), new Vector3D(x + 1, y + 1, z + c), new Vector3D(x + 1, y, z + c), pivot, colorIndices[cstart]); facescount += 2; } - if((flags & 4) != 0) + if((flags & 4) != 0) { AddFace(verts, indices, verthashes, new Vector3D(x + 1, y, z), new Vector3D(x, y, z), new Vector3D(x + 1, y, z + c), new Vector3D(x, y, z + c), pivot, colorIndices[cstart]); facescount += 2; } - if((flags & 8) != 0) + if((flags & 8) != 0) { AddFace(verts, indices, verthashes, new Vector3D(x, y + 1, z), new Vector3D(x + 1, y + 1, z), new Vector3D(x, y + 1, z + c), new Vector3D(x + 1, y + 1, z + c), pivot, colorIndices[cstart]); facescount += 2; @@ -999,7 +1030,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 cstart += c; } - if((flags & 32) != 0) + if((flags & 32) != 0) { z = ztop + zleng - 1; AddFace(verts, indices, verthashes, new Vector3D(x + 1, y, z + 1), new Vector3D(x, y, z + 1), new Vector3D(x + 1, y + 1, z + 1), new Vector3D(x, y + 1, z + 1), pivot, colorIndices[zleng - 1]); @@ -1018,7 +1049,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 int maxX = (int)((xsize / 2f + pivot.x) * mde.Scale.X); int minY = (int)((ysize / 2f - pivot.y) * mde.Scale.Y); int maxY = (int)((ysize / 2f + pivot.y) * mde.Scale.Y); - + // Calculate model radius mde.Model.Radius = Math.Max(Math.Max(Math.Abs(minY), Math.Abs(maxY)), Math.Max(Math.Abs(minX), Math.Abs(maxX))); @@ -1036,7 +1067,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 // Create mesh MeshFlags meshflags = MeshFlags.Managed; if(indices.Count > ushort.MaxValue - 1) meshflags |= MeshFlags.Use32Bit; - + Mesh mesh = new Mesh(device, facescount, verts.Count, meshflags, vertexElements); DataStream mstream = mesh.VertexBuffer.Lock(0, 0, LockFlags.None); @@ -1059,13 +1090,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } // Shameless GZDoom rip-off - private static void AddFace(List<WorldVertex> verts, List<int> indices, Dictionary<long, int> hashes, Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4, Vector3D pivot, int colorIndex) + private static void AddFace(List<WorldVertex> verts, List<int> indices, Dictionary<long, int> hashes, Vector3D v1, Vector3D v2, Vector3D v3, Vector3D v4, Vector3D pivot, int colorIndex) { float pu0 = (colorIndex % 16) / 16f; float pu1 = pu0 + 0.001f; float pv0 = (colorIndex / 16) / 16f; float pv1 = pv0 + 0.001f; - + WorldVertex wv1 = new WorldVertex { x = v1.x - pivot.x, @@ -1142,18 +1173,18 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 } } - private unsafe static Bitmap CreateVoxelTexture(PixelColor[] palette) + private unsafe static Bitmap CreateVoxelTexture(PixelColor[] palette) { Bitmap bmp = new Bitmap(16, 16); BitmapData bmpdata = bmp.LockBits(new Rectangle(0, 0, 16, 16), ImageLockMode.WriteOnly, PixelFormat.Format32bppArgb); - if(bmpdata != null) + if(bmpdata != null) { PixelColor* pixels = (PixelColor*)(bmpdata.Scan0.ToPointer()); const int numpixels = 256; int i = 255; - for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--, i--) + for(PixelColor* cp = pixels + numpixels - 1; cp >= pixels; cp--, i--) { cp->r = palette[i].r; cp->g = palette[i].g; @@ -1165,7 +1196,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //scale bitmap, so colors stay (almost) the same when bilinear filtering is enabled Bitmap scaled = new Bitmap(64, 64); - using(Graphics gs = Graphics.FromImage(scaled)) + using(Graphics gs = Graphics.FromImage(scaled)) { gs.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor; gs.DrawImage(bmp, new Rectangle(0, 0, 64, 64), new Rectangle(0, 0, 16, 16), GraphicsUnit.Pixel); @@ -1179,9 +1210,9 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #region ================== Utility - private static MemoryStream LoadFile(List<DataReader> containers, string path, bool isModel) + private static MemoryStream LoadFile(List<DataReader> containers, string path, bool isModel) { - foreach(DataReader dr in containers) + foreach(DataReader dr in containers) { if(isModel && dr is WADReader) continue; //models cannot be stored in WADs @@ -1191,7 +1222,7 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 return null; } - private static Texture LoadTexture(List<DataReader> containers, string path, Device device) + private static Texture LoadTexture(List<DataReader> containers, string path, Device device) { if(string.IsNullOrEmpty(path)) return null; @@ -1202,13 +1233,13 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 //create texture if(Path.GetExtension(path) == ".pcx") //pcx format requires special handling... - { + { FileImageReader fir = new FileImageReader(); Bitmap bitmap = fir.ReadAsBitmap(ms); ms.Close(); - if(bitmap != null) + if(bitmap != null) { BitmapData bmlock = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.ReadOnly, bitmap.PixelFormat); texture = new Texture(device, bitmap.Width, bitmap.Height, 1, Usage.None, Format.A8R8G8B8, Pool.Managed); @@ -1219,8 +1250,8 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 bitmap.UnlockBits(bmlock); texture.UnlockRectangle(0); } - } - else + } + else { texture = Texture.FromStream(device, ms); @@ -1253,15 +1284,15 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 result.Meshes.Add(mesh); } - private static string ReadString(BinaryReader br, int len) + private static string ReadString(BinaryReader br, int len) { string result = string.Empty; int i; - for(i = 0; i < len; ++i) + for(i = 0; i < len; ++i) { var c = br.ReadChar(); - if(c == '\0') + if(c == '\0') { ++i; break; @@ -1275,4 +1306,4 @@ namespace CodeImp.DoomBuilder.GZBuilder.MD3 #endregion } -} \ No newline at end of file +} -- GitLab