private tr_mesh CreateDummyWadMesh(WadMesh oldMesh, bool isStatic, int objectId, bool isWaterfall = false, bool isOptics = false, WadMeshLightingType lightType = WadMeshLightingType.PrecalculatedGrayShades) { int currentMeshSize = 0; var newMesh = new tr_mesh { Center = new tr_vertex { X = (short)oldMesh.BoundingSphere.Center.X, Y = (short)-oldMesh.BoundingSphere.Center.Y, Z = (short)oldMesh.BoundingSphere.Center.Z }, Radius = (short)oldMesh.BoundingSphere.Radius }; int numShades = 0; currentMeshSize += 10; newMesh.NumVertices = 0; currentMeshSize += 2; int numNormals = 0; newMesh.Vertices = new tr_vertex[0]; newMesh.NumNormals = 0; currentMeshSize += 2; short numQuads = 0; short numTriangles = 0; newMesh.NumTexturedQuads = numQuads; currentMeshSize += 2; newMesh.NumTexturedTriangles = numTriangles; currentMeshSize += 2; int lastQuad = 0; int lastTriangle = 0; newMesh.TexturedQuads = new tr_face4[numQuads]; newMesh.TexturedTriangles = new tr_face3[numTriangles]; if (_level.Settings.GameVersion <= TRVersion.Game.TR3) { currentMeshSize += 4; // Num colored quads and triangles } if (currentMeshSize % 4 != 0) { currentMeshSize += 2; } newMesh.MeshSize = currentMeshSize; newMesh.MeshPointer = _totalMeshSize; _meshPointers.Add((uint)_totalMeshSize); _totalMeshSize += currentMeshSize; _meshes.Add(newMesh); return(newMesh); }
private tr_mesh ConvertWadMesh(WadMesh oldMesh, bool isStatic, int objectId, int meshIndex, bool isWaterfall = false, bool isOptics = false, WadMeshLightingType lightType = WadMeshLightingType.PrecalculatedGrayShades) { int currentMeshSize = 0; var newMesh = new tr_mesh { Center = new tr_vertex { X = (short)oldMesh.BoundingSphere.Center.X, Y = (short)-oldMesh.BoundingSphere.Center.Y, Z = (short)oldMesh.BoundingSphere.Center.Z }, Radius = (short)oldMesh.BoundingSphere.Radius }; currentMeshSize += 10; newMesh.NumVertices = (short)oldMesh.VerticesPositions.Count; currentMeshSize += 2; newMesh.Vertices = new tr_vertex[oldMesh.VerticesPositions.Count]; for (int j = 0; j < oldMesh.VerticesPositions.Count; j++) { var vertex = oldMesh.VerticesPositions[j]; newMesh.Vertices[j] = new tr_vertex((short)vertex.X, (short)-vertex.Y, (short)vertex.Z); currentMeshSize += 6; } // FIX: the following code will check for valid normals and shades combinations. // As last chance, I recalculate the normals on the fly. bool useShades = false; if (isStatic) { if (lightType == WadMeshLightingType.Normals) { if (oldMesh.VerticesNormals.Count == 0) { _progressReporter.ReportWarn(string.Format("Static {0} is a mesh with invalid lighting data. Normals will be recalculated on the fly.", objectId)); oldMesh.CalculateNormals(); } useShades = false; } else { if (oldMesh.VerticesShades.Count == 0) { if (oldMesh.VerticesNormals.Count == 0) { _progressReporter.ReportWarn(string.Format("Static {0} is a mesh with invalid lighting data. Normals will be recalculated on the fly.", objectId)); oldMesh.CalculateNormals(); } useShades = false; } else { useShades = true; } } } else { if (oldMesh.VerticesNormals.Count == 0) { _progressReporter.ReportWarn(string.Format("Mesh {0} of Moveable {1} contains invalid lighting data. Normals will be recalculated on the fly.", meshIndex, objectId)); oldMesh.CalculateNormals(); } useShades = false; } newMesh.NumNormals = (short)(useShades ? -oldMesh.VerticesShades.Count : oldMesh.VerticesNormals.Count); currentMeshSize += 2; if (!useShades) { newMesh.Normals = new tr_vertex[oldMesh.VerticesNormals.Count]; for (int j = 0; j < oldMesh.VerticesNormals.Count; j++) { Vector3 normal = oldMesh.VerticesNormals[j]; normal = Vector3.Normalize(normal); normal *= 16300.0f; newMesh.Normals[j] = new tr_vertex((short)normal.X, (short)-normal.Y, (short)normal.Z); currentMeshSize += 6; } } else { newMesh.Lights = new short[oldMesh.VerticesShades.Count]; for (int j = 0; j < oldMesh.VerticesShades.Count; j++) { newMesh.Lights[j] = oldMesh.VerticesShades[j]; currentMeshSize += 2; } } short numQuads = 0; short numTriangles = 0; foreach (var poly in oldMesh.Polys) { if (poly.Shape == WadPolygonShape.Quad) { numQuads++; } else { numTriangles++; } } newMesh.NumTexturedQuads = numQuads; currentMeshSize += 2; newMesh.NumTexturedTriangles = numTriangles; currentMeshSize += 2; int lastQuad = 0; int lastTriangle = 0; newMesh.TexturedQuads = new tr_face4[numQuads]; newMesh.TexturedTriangles = new tr_face3[numTriangles]; for (int j = 0; j < oldMesh.Polys.Count; j++) { var poly = oldMesh.Polys[j]; ushort lightingEffect = poly.Texture.BlendMode == BlendMode.Additive ? (ushort)1 : (ushort)0; if (poly.ShineStrength > 0) { if (useShades && isStatic) { _progressReporter.ReportWarn("Stray shiny effect found on static " + objectId + ", face " + oldMesh.Polys.IndexOf(poly) + ". Ignoring data."); } else { lightingEffect |= 0x02; lightingEffect |= (ushort)(Math.Min((byte)63, poly.ShineStrength) << 2); } } // Very quirky way to identify 1st face of a waterfall in TR4-TR5 wads. bool topmostAndUnpadded = (j == 0) ? isWaterfall : false; // Check if we should merge object and room textures in same texture tiles. bool agressivePacking = _level.Settings.AgressiveTexturePacking; if (poly.Shape == WadPolygonShape.Quad) { FixWadTextureCoordinates(ref poly.Texture); var result = _textureInfoManager.AddTexture(poly.Texture, agressivePacking, false, topmostAndUnpadded); if (isOptics) { result.Rotation = 0; // Very ugly hack for TR4-5 binocular/target optics! } newMesh.TexturedQuads[lastQuad++] = result.CreateFace4(new ushort[] { (ushort)poly.Index0, (ushort)poly.Index1, (ushort)poly.Index2, (ushort)poly.Index3 }, poly.Texture.DoubleSided, lightingEffect); currentMeshSize += _level.Settings.GameVersion <= TRVersion.Game.TR3 ? 10 : 12; } else { FixWadTextureCoordinates(ref poly.Texture); var result = _textureInfoManager.AddTexture(poly.Texture, agressivePacking, true, topmostAndUnpadded); if (isOptics) { result.Rotation = 0; // Very ugly hack for TR4-5 binocular/target optics! } newMesh.TexturedTriangles[lastTriangle++] = result.CreateFace3(new ushort[] { (ushort)poly.Index0, (ushort)poly.Index1, (ushort)poly.Index2 }, poly.Texture.DoubleSided, lightingEffect); currentMeshSize += _level.Settings.GameVersion <= TRVersion.Game.TR3 ? 8 : 10; } } if (_level.Settings.GameVersion <= TRVersion.Game.TR3) { currentMeshSize += 4; // Num colored quads and triangles } if (currentMeshSize % 4 != 0) { currentMeshSize += 2; } newMesh.MeshSize = currentMeshSize; newMesh.MeshPointer = _totalMeshSize; _meshPointers.Add((uint)_totalMeshSize); _totalMeshSize += currentMeshSize; _meshes.Add(newMesh); return(newMesh); }