public bool Equals(WadMesh other) => Hash == other.Hash;
private static WadMesh LoadMesh(ChunkReader chunkIO, long chunkSize, Dictionary <long, WadTexture> textures) { var mesh = new WadMesh(); long obsoleteIndex = 0; chunkIO.ReadChunks((id2, chunkSize2) => { if (id2 == Wad2Chunks.MeshIndex) { obsoleteIndex = chunkIO.ReadChunkLong(chunkSize2); } else if (id2 == Wad2Chunks.MeshName) { mesh.Name = chunkIO.ReadChunkString(chunkSize2); } else if (id2 == Wad2Chunks.MeshSphere) { // Read bounding sphere float radius = 0; Vector3 center = Vector3.Zero; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshSphereCenter) { center = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.MeshSphereRadius) { radius = chunkIO.ReadChunkFloat(chunkSize3); } else { return(false); } return(true); }); mesh.BoundingSphere = new BoundingSphere(center, radius); } else if (id2 == Wad2Chunks.MeshBoundingBox) { // Read bounding box Vector3 min = Vector3.Zero; Vector3 max = Vector3.Zero; chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshBoundingBoxMin) { min = chunkIO.ReadChunkVector3(chunkSize3); } else if (id3 == Wad2Chunks.MeshBoundingBoxMax) { max = chunkIO.ReadChunkVector3(chunkSize3); } else { return(false); } return(true); }); mesh.BoundingBox = new BoundingBox(min, max); } else if (id2 == Wad2Chunks.MeshVertexPositions) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexPosition) { mesh.VerticesPositions.Add(chunkIO.ReadChunkVector3(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshVertexNormals) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexNormal) { mesh.VerticesNormals.Add(chunkIO.ReadChunkVector3(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshVertexShades) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshVertexShade) { mesh.VerticesShades.Add(chunkIO.ReadChunkShort(chunkSize3)); } else { return(false); } return(true); }); } else if (id2 == Wad2Chunks.MeshPolygons) { chunkIO.ReadChunks((id3, chunkSize3) => { if (id3 == Wad2Chunks.MeshQuad || id3 == Wad2Chunks.MeshTriangle) { var polygon = new WadPolygon(); polygon.Shape = id3 == Wad2Chunks.MeshQuad ? WadPolygonShape.Quad : WadPolygonShape.Triangle; polygon.Index0 = LEB128.ReadInt(chunkIO.Raw); polygon.Index1 = LEB128.ReadInt(chunkIO.Raw); polygon.Index2 = LEB128.ReadInt(chunkIO.Raw); if (id3 == Wad2Chunks.MeshQuad) { polygon.Index3 = LEB128.ReadInt(chunkIO.Raw); } polygon.ShineStrength = LEB128.ReadByte(chunkIO.Raw); TextureArea textureArea = new TextureArea(); textureArea.Texture = textures[LEB128.ReadInt(chunkIO.Raw)]; textureArea.TexCoord0 = chunkIO.Raw.ReadVector2(); textureArea.TexCoord1 = chunkIO.Raw.ReadVector2(); textureArea.TexCoord2 = chunkIO.Raw.ReadVector2(); if (id3 == Wad2Chunks.MeshQuad) { textureArea.TexCoord3 = chunkIO.Raw.ReadVector2(); } else { textureArea.TexCoord3 = textureArea.TexCoord2; } textureArea.BlendMode = (BlendMode)LEB128.ReadLong(chunkIO.Raw); textureArea.DoubleSided = chunkIO.Raw.ReadBoolean(); polygon.Texture = textureArea; chunkIO.ReadChunks((id4, chunkSize4) => { return(false); }); mesh.Polys.Add(polygon); } else { return(false); } return(true); }); } else { return(false); } return(true); }); return(mesh); }
public static List <WadMesh> ImportFromExternalModel(string fileName, IOGeometrySettings settings, bool mergeIntoOne) { IOModel tmpModel = null; var meshList = new List <WadMesh>(); bool calculateNormals = false; // Import the model try { var importer = BaseGeometryImporter.CreateForFile(fileName, settings, absoluteTexturePath => { return(new WadTexture(ImageC.FromFile(absoluteTexturePath))); }); tmpModel = importer.ImportFromFile(fileName); calculateNormals = importer is MetasequoiaImporter; } catch (Exception ex) { logger.Error(ex, "Geometry import failed!"); return(null); } // Create a new mesh (all meshes from model will be joined) WadMesh mesh = null; var lastBaseVertex = 0; for (int i = 0; i < tmpModel.Meshes.Count; i++) { var tmpMesh = tmpModel.Meshes[i]; if (mesh == null || !mergeIntoOne) { mesh = new WadMesh(); mesh.Name = string.IsNullOrEmpty(tmpMesh.Name) ? "ImportedMesh" + i : tmpMesh.Name; if (mergeIntoOne) { lastBaseVertex = 0; // Reset if we're doing multi-mesh import } } mesh.VerticesPositions.AddRange(tmpMesh.Positions); // Copy normals as well, if they are consistent if (tmpMesh.Normals.Count == tmpMesh.Positions.Count) { mesh.VerticesNormals.AddRange(tmpMesh.Normals); } // FIXME: Why do we keep white intensity shades for wad2 meshes internally, and not vertex colors? if (tmpMesh.Colors.Count == tmpMesh.Positions.Count) { mesh.VerticesShades.AddRange(tmpMesh.Colors.Select(v => (short)(8191.0f - (v.To3().GetLuma() * 8191.0f)))); } foreach (var tmpSubmesh in tmpMesh.Submeshes) { foreach (var tmpPoly in tmpSubmesh.Value.Polygons) { if (tmpPoly.Shape == IOPolygonShape.Quad) { var poly = new WadPolygon { Shape = WadPolygonShape.Quad }; poly.Index0 = tmpPoly.Indices[0] + lastBaseVertex; poly.Index1 = tmpPoly.Indices[1] + lastBaseVertex; poly.Index2 = tmpPoly.Indices[2] + lastBaseVertex; poly.Index3 = tmpPoly.Indices[3] + lastBaseVertex; var area = new TextureArea(); area.TexCoord0 = tmpMesh.UV[tmpPoly.Indices[0]]; area.TexCoord1 = tmpMesh.UV[tmpPoly.Indices[1]]; area.TexCoord2 = tmpMesh.UV[tmpPoly.Indices[2]]; area.TexCoord3 = tmpMesh.UV[tmpPoly.Indices[3]]; area.Texture = tmpSubmesh.Value.Material.Texture; area.DoubleSided = tmpSubmesh.Value.Material.DoubleSided; poly.Texture = area; poly.ShineStrength = (byte)Math.Round(tmpSubmesh.Value.Material.Shininess / 16.0f, MidpointRounding.ToEven); mesh.Polys.Add(poly); } else { var poly = new WadPolygon { Shape = WadPolygonShape.Triangle }; poly.Index0 = tmpPoly.Indices[0] + lastBaseVertex; poly.Index1 = tmpPoly.Indices[1] + lastBaseVertex; poly.Index2 = tmpPoly.Indices[2] + lastBaseVertex; var area = new TextureArea(); area.TexCoord0 = tmpMesh.UV[tmpPoly.Indices[0]]; area.TexCoord1 = tmpMesh.UV[tmpPoly.Indices[1]]; area.TexCoord2 = tmpMesh.UV[tmpPoly.Indices[2]]; area.TexCoord3 = area.TexCoord2; area.Texture = tmpSubmesh.Value.Material.Texture; area.DoubleSided = tmpSubmesh.Value.Material.DoubleSided; poly.Texture = area; poly.ShineStrength = (byte)Math.Round(tmpSubmesh.Value.Material.Shininess / 16.0f, MidpointRounding.ToEven); mesh.Polys.Add(poly); } } } if (!mergeIntoOne || i == tmpModel.Meshes.Count - 1) { mesh.BoundingBox = mesh.CalculateBoundingBox(); mesh.BoundingSphere = mesh.CalculateBoundingSphere(); if (mesh.VerticesNormals.Count == 0 || calculateNormals) { mesh.CalculateNormals(); // MQO files rarely have normals } if (mesh.VerticesPositions.Count != mesh.VerticesShades.Count) { mesh.VerticesShades.Clear(); // Reset vertex shades in case they got desynced from vertex count } lastBaseVertex = 0; meshList.Add(mesh); } else { lastBaseVertex = mesh.VerticesPositions.Count; } } return(meshList); }
public static void WriteMesh(ChunkWriter chunkIO, WadMesh mesh, List <WadTexture> textureTable) { chunkIO.WriteChunkWithChildren(Wad2Chunks.Mesh, () => { chunkIO.WriteChunkInt(Wad2Chunks.MeshIndex, 0); chunkIO.WriteChunkString(Wad2Chunks.MeshName, mesh.Name); // Write bounding sphere chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshSphere, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshSphereCenter, mesh.BoundingSphere.Center); chunkIO.WriteChunkFloat(Wad2Chunks.MeshSphereRadius, mesh.BoundingSphere.Radius); }); // Write bounding box chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshBoundingBox, () => { chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMin, mesh.BoundingBox.Minimum); chunkIO.WriteChunkVector3(Wad2Chunks.MeshBoundingBoxMax, mesh.BoundingBox.Maximum); }); // Write positions chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexPositions, () => { foreach (var pos in mesh.VerticesPositions) { chunkIO.WriteChunkVector3(Wad2Chunks.MeshVertexPosition, pos); } }); // Write normals chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexNormals, () => { foreach (var normal in mesh.VerticesNormals) { chunkIO.WriteChunkVector3(Wad2Chunks.MeshVertexNormal, normal); } }); // Write shades chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshVertexShades, () => { foreach (var shade in mesh.VerticesShades) { chunkIO.WriteChunkInt(Wad2Chunks.MeshVertexShade, shade); } }); // Write polygons chunkIO.WriteChunkWithChildren(Wad2Chunks.MeshPolygons, () => { foreach (var poly in mesh.Polys) { bool isQuad = poly.Shape == WadPolygonShape.Quad; chunkIO.WriteChunkWithChildren(isQuad ? Wad2Chunks.MeshQuad : Wad2Chunks.MeshTriangle, () => { LEB128.Write(chunkIO.Raw, poly.Index0); LEB128.Write(chunkIO.Raw, poly.Index1); LEB128.Write(chunkIO.Raw, poly.Index2); if (isQuad) { LEB128.Write(chunkIO.Raw, poly.Index3); } LEB128.Write(chunkIO.Raw, poly.ShineStrength); LEB128.Write(chunkIO.Raw, textureTable.IndexOf(poly.Texture.Texture as WadTexture)); chunkIO.Raw.Write(poly.Texture.TexCoord0); chunkIO.Raw.Write(poly.Texture.TexCoord1); chunkIO.Raw.Write(poly.Texture.TexCoord2); if (isQuad) { chunkIO.Raw.Write(poly.Texture.TexCoord3); } LEB128.Write(chunkIO.Raw, (long)poly.Texture.BlendMode); chunkIO.Raw.Write(poly.Texture.DoubleSided); }); } }); }); }