private int tmdPrimitivePacketHashCode(TMDPrimitivePacket p) { var hashCode = p.Flags.GetHashCode(); hashCode = (hashCode * 397) ^ p.Options.GetHashCode(); hashCode = (hashCode * 397) ^ p.Type.GetHashCode(); hashCode = (hashCode * 397) ^ p.ILen.GetHashCode(); hashCode = (hashCode * 397) ^ p.OLen.GetHashCode(); hashCode = (hashCode * 397) ^ p.PacketData.Vertices.Length.GetHashCode(); IColoredPrimitivePacket coloredPacket = p.PacketData as IColoredPrimitivePacket; if (coloredPacket != null) { foreach (var col in coloredPacket.Colors) { hashCode = (hashCode * 397) ^ col.GetHashCode(); } } ILitPrimitivePacket litPacket = p.PacketData as ILitPrimitivePacket; if (litPacket != null) { foreach (var norm in litPacket.Normals) { hashCode = (hashCode * 397) ^ norm.GetHashCode(); } } ITexturedPrimitivePacket texturedPacket = p.PacketData as ITexturedPrimitivePacket; if (texturedPacket != null) { hashCode = (hashCode * 397) ^ texturedPacket.Texture.TexturePageNumber.GetHashCode(); hashCode = (hashCode * 397) ^ texturedPacket.Texture.ColorMode.GetHashCode(); hashCode = (hashCode * 397) ^ texturedPacket.Texture.AlphaBlendRate.GetHashCode(); hashCode = (hashCode * 397) ^ texturedPacket.ColorLookup.XPosition.GetHashCode(); hashCode = (hashCode * 397) ^ texturedPacket.ColorLookup.YPosition.GetHashCode(); foreach (var uv in texturedPacket.UVs) { hashCode = (hashCode * 397) ^ uv.GetHashCode(); } } foreach (var vert in p.PacketData.Vertices) { hashCode = (hashCode * 397) ^ vert.GetHashCode(); } hashCode = (hashCode * 397) ^ p.SpriteSize.GetHashCode(); return(hashCode); }
public Mesh CreateTMDObjectMesh(TMDObject obj) { clearCachedLists(); foreach (var prim in obj.Primitives) { // currently only polygon primitives are supported if (prim.Type != TMDPrimitivePacket.Types.POLYGON) { continue; } // figure out which index list to use based on whether or not this primitive is alpha blended List <int> indicesList = (prim.Options & TMDPrimitivePacket.OptionsFlags.AlphaBlended) != 0 ? _alphaBlendIndices : _indices; // get interfaces for different packet types from LibLSD IPrimitivePacket primitivePacket = prim.PacketData; ITexturedPrimitivePacket texturedPrimitivePacket = prim.PacketData as ITexturedPrimitivePacket; IColoredPrimitivePacket coloredPrimitivePacket = prim.PacketData as IColoredPrimitivePacket; ILitPrimitivePacket litPrimitivePacket = prim.PacketData as ILitPrimitivePacket; for (int i = 0; i < primitivePacket.Vertices.Length; i++) { // get index into vertices array int vertIndex = primitivePacket.Vertices[i]; _packetIndices[i] = _verts.Count; // create variables for each of the vertex types Vec3 vertPos = obj.Vertices[vertIndex]; Vector3 vec3VertPos = new Vector3(vertPos.X, -vertPos.Y, vertPos.Z) / 2048f; Color32 vertCol = Color.white; Vector3 vertNorm = Vector3.zero; Vector2 vertUV = Vector2.one; // handle packet colour if (coloredPrimitivePacket != null) { Vec3 packetVertCol = coloredPrimitivePacket.Colors[coloredPrimitivePacket.Colors.Length > 1 ? i : 0]; vertCol = new Color(packetVertCol.X, packetVertCol.Y, packetVertCol.Z); if (vertCol.r > 0 && vertCol.g > 0 && vertCol.b > 0 && (prim.Options & TMDPrimitivePacket.OptionsFlags.Textured) == 0 && (prim.Options & TMDPrimitivePacket.OptionsFlags.AlphaBlended) != 0) { vertCol.a = 127; } } // handle packet normals if (litPrimitivePacket != null) { TMDNormal packetVertNorm = obj.Normals[litPrimitivePacket.Normals[litPrimitivePacket.Normals.Length > 1 ? i : 0]]; vertNorm = new Vector3(packetVertNorm.X, packetVertNorm.Y, packetVertNorm.Z); } // handle packet UVs if (texturedPrimitivePacket != null) { // calculate which texture page we're on int texPage = texturedPrimitivePacket.Texture.TexturePageNumber; int texPageXPos = ((texPage % 16) * 128) - 640; int texPageYPos = texPage < 16 ? 256 : 0; // derive UV coords from the texture page int uvIndex = i * 2; int vramXPos = texPageXPos + texturedPrimitivePacket.UVs[uvIndex]; int vramYPos = texPageYPos + (256 - texturedPrimitivePacket.UVs[uvIndex + 1]); float uCoord = vramXPos / (float)PsxVram.VRAM_WIDTH; float vCoord = vramYPos / (float)PsxVram.VRAM_HEIGHT; vertUV = new Vector2(uCoord, vCoord); // check for overlapping UVs and fix them slightly foreach (var uv in _uvs) { if (uv.Equals(vertUV)) { vertUV += new Vector2(0.0001f, 0.0001f); } } } // add all computed aspects of vertex to lists _verts.Add(vec3VertPos); _normals.Add(vertNorm); _colors.Add(vertCol); _uvs.Add(vertUV); } // we want to add extra indices if this primitive is a quad (to triangulate) bool isQuad = (prim.Options & TMDPrimitivePacket.OptionsFlags.Quad) != 0; _polyIndices.Add(_packetIndices[0]); _polyIndices.Add(_packetIndices[1]); _polyIndices.Add(_packetIndices[2]); if (isQuad) { _polyIndices.Add(_packetIndices[2]); _polyIndices.Add(_packetIndices[1]); _polyIndices.Add(_packetIndices[3]); } // if this primitive is double sided we want to add more vertices with opposite winding order if ((prim.Flags & TMDPrimitivePacket.PrimitiveFlags.DoubleSided) != 0) { _polyIndices.Add(_packetIndices[1]); _polyIndices.Add(_packetIndices[0]); _polyIndices.Add(_packetIndices[2]); if (isQuad) { _polyIndices.Add(_packetIndices[1]); _polyIndices.Add(_packetIndices[2]); _polyIndices.Add(_packetIndices[3]); } } // add the indices to the list indicesList.AddRange(_polyIndices); _polyIndices.Clear(); } Mesh result = new Mesh(); result.SetVertices(_verts); result.SetNormals(_normals); result.SetColors(_colors); result.SetUVs(0, _uvs); // regular mesh if (_indices.Count >= 3) { result.SetTriangles(_indices, 0, false, 0); } // alpha blended mesh if (_alphaBlendIndices.Count >= 3) { result.subMeshCount = 2; result.SetTriangles(_alphaBlendIndices, 1, false, 0); } return(result); }
/// <summary> /// Create a mesh from an object stored inside a TMD model file. /// </summary> /// <param name="obj">The TMD object to create a mesh from.</param> /// <returns>The Mesh created from the object.</returns> public static Mesh MeshFromTMDObject(TMDObject obj) { Profiler.BeginSample("MeshFromTMDObject"); // create the mesh, and lists of vertices, normals, colors, uvs, and indices Mesh result = new Mesh(); List <Vector3> verts = new List <Vector3>(); List <Vector3> normals = new List <Vector3>(); List <Color32> colors = new List <Color32>(); List <Vector2> uvs = new List <Vector2>(); List <int> indices = new List <int>(); List <int> alphaBlendIndices = new List <int>(); // alpha blended polygons are stored in a submesh // TMD objects are built from 'primitives' foreach (var prim in obj.Primitives) { // currently only polygon primitives are supported if (prim.Type != TMDPrimitivePacket.Types.POLYGON) { continue; } // check which index list to use based on whether this primitive is alpha blended or not List <int> indicesList = (prim.Options & TMDPrimitivePacket.OptionsFlags.AlphaBlended) != 0 ? alphaBlendIndices : indices; // get interfaces for different packet types from LibLSD IPrimitivePacket primitivePacket = prim.PacketData; ITexturedPrimitivePacket texturedPrimitivePacket = prim.PacketData as ITexturedPrimitivePacket; IColoredPrimitivePacket coloredPrimitivePacket = prim.PacketData as IColoredPrimitivePacket; ILitPrimitivePacket litPrimitivePacket = prim.PacketData as ILitPrimitivePacket; // for each vertex in the primitive List <int> polyIndices = new List <int>(); int[] packetIndices = new int[primitivePacket.Vertices.Length]; for (int i = 0; i < primitivePacket.Vertices.Length; i++) { // get its index into the vertices array int vertIndex = primitivePacket.Vertices[i]; packetIndices[i] = verts.Count; // create variables for each of the vertex types Vec3 vertPos = obj.Vertices[vertIndex]; Vector3 vec3VertPos = new Vector3(vertPos.X, -vertPos.Y, vertPos.Z) / 2048f; Color32 vertCol = Color.white; Vector3 vertNorm = Vector3.zero; Vector2 vertUV = Vector2.one; // handle packet colour if (coloredPrimitivePacket != null) { Vec3 packetVertCol = coloredPrimitivePacket.Colors[coloredPrimitivePacket.Colors.Length > 1 ? i : 0]; vertCol = new Color(packetVertCol.X, packetVertCol.Y, packetVertCol.Z); if (vertCol.r > 0 && vertCol.g > 0 && vertCol.b > 0 && (prim.Options & TMDPrimitivePacket.OptionsFlags.Textured) == 0 && (prim.Options & TMDPrimitivePacket.OptionsFlags.AlphaBlended) != 0) { vertCol.a = 127; } } // handle packet normals if (litPrimitivePacket != null) { TMDNormal packetVertNorm = obj.Normals[litPrimitivePacket.Normals[litPrimitivePacket.Normals.Length > 1 ? i : 0]]; vertNorm = new Vector3(packetVertNorm.X, packetVertNorm.Y, packetVertNorm.Z); } // handle packet UVs if (texturedPrimitivePacket != null) { // calculate which texture page we're on int texPage = texturedPrimitivePacket.Texture.TexturePageNumber; int texPageXPos = ((texPage % 16) * 128) - 640; int texPageYPos = texPage < 16 ? 256 : 0; // derive UV coords from the texture page int uvIndex = i * 2; int vramXPos = texPageXPos + texturedPrimitivePacket.UVs[uvIndex]; int vramYPos = texPageYPos + (256 - texturedPrimitivePacket.UVs[uvIndex + 1]); float uCoord = vramXPos / (float)PsxVram.VRAM_WIDTH; float vCoord = vramYPos / (float)PsxVram.VRAM_HEIGHT; vertUV = new Vector2(uCoord, vCoord); // check for overlapping UVs and fix them slightly foreach (var uv in uvs) { if (uv.Equals(vertUV)) { vertUV += new Vector2(0.0001f, 0.0001f); } } } // add all computed aspects of vertex to lists verts.Add(vec3VertPos); normals.Add(vertNorm); colors.Add(vertCol); uvs.Add(vertUV); } // we want to add extra indices if this primitive is a quad (to triangulate) bool isQuad = (prim.Options & TMDPrimitivePacket.OptionsFlags.Quad) != 0; polyIndices.Add(packetIndices[0]); polyIndices.Add(packetIndices[1]); polyIndices.Add(packetIndices[2]); if (isQuad) { polyIndices.Add(packetIndices[2]); polyIndices.Add(packetIndices[1]); polyIndices.Add(packetIndices[3]); } // if this primitive is double sided we want to add more vertices with opposite winding order if ((prim.Flags & TMDPrimitivePacket.PrimitiveFlags.DoubleSided) != 0) { polyIndices.Add(packetIndices[1]); polyIndices.Add(packetIndices[0]); polyIndices.Add(packetIndices[2]); if (isQuad) { polyIndices.Add(packetIndices[1]); polyIndices.Add(packetIndices[2]); polyIndices.Add(packetIndices[3]); } } // add the indices to the list indicesList.AddRange(polyIndices); } // set the mesh arrays result.vertices = verts.ToArray(); result.normals = normals.ToArray(); result.colors32 = colors.ToArray(); result.uv = uvs.ToArray(); // regular mesh if (indices.Count >= 3) { result.SetTriangles(indices, 0, false, 0); } // alpha blended mesh if (alphaBlendIndices.Count >= 3) { result.subMeshCount = 2; result.SetTriangles(alphaBlendIndices, 1, false, 0); } Profiler.EndSample(); return(result); }