public byte[] ToByteArray() { using (var ms = new MemoryStream()) { var writer = new BinaryWriterEx(ms); writer.Write(BoundingSphere.Center.X); writer.Write(BoundingSphere.Center.Y); writer.Write(BoundingSphere.Center.Z); writer.Write(BoundingSphere.Radius); int numVertices = VerticesPositions.Count; writer.Write(numVertices); for (int i = 0; i < VerticesPositions.Count; i++) { writer.Write(VerticesPositions[i]); } if (VerticesNormals.Count > 0) { for (int i = 0; i < VerticesNormals.Count; i++) { writer.Write(VerticesNormals[i]); } } if (VerticesShades.Count > 0) { for (int i = 0; i < VerticesShades.Count; i++) { writer.Write(VerticesShades[i]); } } int numPolygons = Polys.Count; writer.Write(numPolygons); for (int i = 0; i < Polys.Count; i++) { WadPolygon poly = Polys[i]; writer.Write((ushort)Polys[i].Shape); writer.Write(Polys[i].Index0); writer.Write(Polys[i].Index1); writer.Write(Polys[i].Index2); if (Polys[i].Shape == WadPolygonShape.Quad) { writer.Write(Polys[i].Index3); } writer.Write(((WadTexture)Polys[i].Texture.Texture).Hash); writer.Write(Polys[i].Texture.DoubleSided); writer.Write((short)Polys[i].Texture.BlendMode); writer.Write(Polys[i].Texture.TexCoord0); writer.Write(Polys[i].Texture.TexCoord1); writer.Write(Polys[i].Texture.TexCoord2); if (Polys[i].Shape == WadPolygonShape.Quad) { writer.Write(Polys[i].Texture.TexCoord3); } writer.Write(Polys[i].ShineStrength); } return(ms.ToArray()); } }
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); }
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); }