Example #1
0
        /// <summary>
        /// Create a new TMD by reading from a binary stream.
        /// </summary>
        /// <param name="b">The binary stream.</param>
        public TMD(BinaryReader b)
        {
            Header           = new TMDHeader(b);
            NumberOfVertices = 0;
            ObjectTable      = new TMDObject[Header.NumObjects];
            uint objTableTop = (uint)b.BaseStream.Position;

            for (int i = 0; i < Header.NumObjects; i++)
            {
                ObjectTable[i]    = new TMDObject(b, Header.FixP, objTableTop);
                NumberOfVertices += ObjectTable[i].NumVertices;
            }
        }
        private FastMesh createTileMesh(LBDTile tile, TMD tilesTmd, Dictionary <TMDObject, FastMesh> tileCache)
        {
            TMDObject tileObj = tilesTmd.ObjectTable[tile.TileType];

            if (tileCache.ContainsKey(tileObj))
            {
                return(tileCache[tileObj]);
            }

            Mesh     m  = LibLSDUnity.MeshFromTMDObject(tileObj);
            FastMesh fm = new FastMesh(m, new[] { LBDDiffuse, LBDAlpha });

            tileCache[tileObj] = fm;
            return(fm);
        }
Example #3
0
        private static IRenderable createSingleLBDTileMesh(LBDTile tile,
                                                           int x,
                                                           int y,
                                                           TMD tilesTmd,
                                                           Shader shader,
                                                           ITexture2D vram,
                                                           bool headless)
        {
            TMDObject   tileObj  = tilesTmd.ObjectTable[tile.TileType];
            IRenderable tileMesh = MeshFromTMDObject(tileObj, shader, headless);

            switch (tile.TileDirection)
            {
            case LBDTile.TileDirections.Deg90:
            {
                tileMesh.Transform.Rotation =
                    Quaternion.FromAxisAngle(Vector3.UnitY, MathHelper.DegreesToRadians(90));
                break;
            }

            case LBDTile.TileDirections.Deg180:
            {
                tileMesh.Transform.Rotation =
                    Quaternion.FromAxisAngle(Vector3.UnitY, MathHelper.DegreesToRadians(180));
                break;
            }

            case LBDTile.TileDirections.Deg270:
            {
                tileMesh.Transform.Rotation =
                    Quaternion.FromAxisAngle(Vector3.UnitY, MathHelper.DegreesToRadians(270));
                break;
            }
            }

            tileMesh.Transform.Position = new Vector3(x, tile.TileHeight, y);

            tileMesh.Textures.Add(vram);

            return(tileMesh);
        }
Example #4
0
        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);
        }
Example #5
0
        public static IRenderable MeshFromTMDObject(TMDObject obj, Shader shader, bool headless)
        {
            Vec3[]        verts    = new Vec3[obj.NumVertices];
            List <Vertex> vertList = new List <Vertex>();
            List <int>    indices  = new List <int>();

            for (int i = 0; i < obj.NumVertices; i++)
            {
                verts[i] = obj.Vertices[i] / 2048f;
            }

            foreach (var prim in obj.Primitives)
            {
                if (prim.Type != TMDPrimitivePacket.Types.POLYGON)
                {
                    continue;
                }

                ITMDPrimitivePacket         primitivePacket    = prim.PacketData;
                ITMDTexturedPrimitivePacket texPrimitivePacket = prim.PacketData as ITMDTexturedPrimitivePacket;
                ITMDColoredPrimitivePacket  colPrimitivePacket = prim.PacketData as ITMDColoredPrimitivePacket;
                ITMDLitPrimitivePacket      litPrimitivePacket = prim.PacketData as ITMDLitPrimitivePacket;

                List <int> polyIndices   = new List <int>();
                int[]      packetIndices = new int[primitivePacket.Vertices.Length];
                for (int i = 0; i < primitivePacket.Vertices.Length; i++)
                {
                    int vertIndex = primitivePacket.Vertices[i];
                    packetIndices[i] = vertList.Count;

                    Vector3 vertPos  = new Vector3(verts[vertIndex].X, verts[vertIndex].Y, verts[vertIndex].Z);
                    Vector4 vertCol  = Vector4.One;
                    Vector3 vertNorm = Vector3.Zero;
                    Vector2 vertUV   = Vector2.One;

                    // handle packet colour
                    if (colPrimitivePacket != null)
                    {
                        Vec3 packetVertCol = colPrimitivePacket.Colors[colPrimitivePacket.Colors.Length > 1 ? i : 0];
                        vertCol = new Vector4(packetVertCol.X, packetVertCol.Y, packetVertCol.Z, 1f);
                    }

                    // 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 (texPrimitivePacket != null)
                    {
                        int texPage = texPrimitivePacket.Texture.TexturePageNumber;

                        // the PSX VRAM is split into 32 texture pages, 16 on top and 16 on bottom
                        // a texture page is 128x256 pixels large
                        // pages 0-4 and 16-20 are used as a double buffer, with a width of 640 (5*128)

                        // the X position of the texture page is it's row index multiplied by the width
                        // we're also subtracting the width of the double buffer as we don't want to include
                        // it - we're using modern graphics so this will be on the video card!
                        int texPageXPos = ((texPage % TEX_PAGE_PER_ROW) * TEX_PAGE_WIDTH) - DOUBLE_BUFFER_WIDTH;

                        // more simply, the Y position of the texture page is 0 or the height of a texture page, based
                        // on if the texture page number is on the 2nd row of pages or not
                        int texPageYPos = texPage <= TEX_PAGE_PER_ROW ? TEX_PAGE_HEIGHT : 0;

                        int uvIndex = i * 2; // 2 UVs per vertex

                        // the UV information we get from the TMD model is UVs into a specific texture page, using
                        // only that texture page's coordinate system
                        // here, we're adding the texture page position offsets (into VRAM) to the TMD UVs, transforming
                        // them into the VRAM coordinate space
                        int vramXPos = texPageXPos + texPrimitivePacket.UVs[uvIndex];

                        // we're subtracting from the texture page height for the Y position as OpenGL uses flipped
                        // Y coordinates for textures compared with the PSX
                        int vramYPos = texPageYPos + (TEX_PAGE_HEIGHT - texPrimitivePacket.UVs[uvIndex + 1]);

                        // finally, we're normalizing the UVs from pixels
                        float uCoord = vramXPos / (float)VRAM_WIDTH;
                        float vCoord = vramYPos / (float)VRAM_HEIGHT;

                        vertUV = new Vector2(uCoord, vCoord);
                    }

                    vertList.Add(new Vertex(vertPos, vertNorm, vertUV, vertCol));
                }

                bool isQuad = (prim.Options & TMDPrimitivePacket.OptionsFlags.Quad) != 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]);
                }

                // if primitive is double sided poly we need to add other side with reverse winding
                if ((prim.Flags & TMDPrimitivePacket.PrimitiveFlags.DoubleSided) != 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]);
                    }
                }

                indices.AddRange(polyIndices);
            }

            return(headless
                ? (IRenderable) new HeadlessMesh(vertList.ToArray(), indices.ToArray())
                : (IRenderable) new Mesh(vertList.ToArray(), indices.ToArray(), shader));
        }
        // create a single LBD tile GameObject (not including extra tiles)
        private GameObject createSingleLBDTile(LBDTile tile, int x, int y, TMD tilesTmd,
                                               List <CombineInstance> meshesCreated, Dictionary <TMDObject, Mesh> cache)
        {
            // rotate the tile based on its direction
            Quaternion tileRot = Quaternion.identity;

            switch (tile.TileDirection)
            {
            case LBDTile.TileDirections.Deg90:
            {
                tileRot = Quaternion.AngleAxis(90, Vector3.up);
                break;
            }

            case LBDTile.TileDirections.Deg180:
            {
                tileRot = Quaternion.AngleAxis(180, Vector3.up);
                break;
            }

            case LBDTile.TileDirections.Deg270:
            {
                tileRot = Quaternion.AngleAxis(270, Vector3.up);
                break;
            }
            }

            // create the GameObject and add/setup necessary components
            GameObject   lbdTile = LBDTilePool.Summon(new Vector3(x, -tile.TileHeight, y), tileRot);
            MeshFilter   mf      = lbdTile.GetComponent <MeshFilter>();
            MeshRenderer mr      = lbdTile.GetComponent <MeshRenderer>();
            TMDObject    tileObj = tilesTmd.ObjectTable[tile.TileType];
            Mesh         tileMesh;

            if (cache.ContainsKey(tileObj))
            {
                tileMesh = cache[tileObj];
            }
            else
            {
                tileMesh       = LibLSDUnity.MeshFromTMDObject(tileObj);
                cache[tileObj] = tileMesh;
            }
            mf.sharedMesh = tileMesh;

            // the renderer needs to use virtual PSX Vram as its materials
            mr.sharedMaterials = new[] { LBDDiffuse, LBDAlpha };

            // set the tile's height
            lbdTile.transform.position = new Vector3(x, -tile.TileHeight, y);

            // make a CombineInstance for combining all tiles into one mesh later on
            var             localToWorldMatrix = lbdTile.transform.localToWorldMatrix;
            CombineInstance combine            = new CombineInstance()
            {
                mesh         = tileMesh,
                transform    = localToWorldMatrix,
                subMeshIndex = 0
            };

            meshesCreated.Add(combine);

            // if tile has transparent part, do the same for the transparent mesh
            if (tileMesh.subMeshCount > 1)
            {
                CombineInstance combineTrans = new CombineInstance()
                {
                    mesh         = tileMesh,
                    transform    = localToWorldMatrix,
                    subMeshIndex = 1
                };
                meshesCreated.Add(combineTrans);
            }

            return(lbdTile);
        }
Example #7
0
        public static IRenderable MeshFromTMDObject(TMDObject obj, Shader shader)
        {
            Vec3[]        verts    = new Vec3[obj.NumVertices];
            List <Vertex> vertList = new List <Vertex>();
            List <int>    indices  = new List <int>();

            for (int i = 0; i < obj.NumVertices; i++)
            {
                verts[i] = obj.Vertices[i] / 2048f;
            }

            foreach (var prim in obj.Primitives)
            {
                if (prim.Type != TMDPrimitivePacket.Types.POLYGON)
                {
                    continue;
                }

                ITMDPrimitivePacket         primitivePacket    = prim.PacketData;
                ITMDTexturedPrimitivePacket texPrimitivePacket = prim.PacketData as ITMDTexturedPrimitivePacket;
                ITMDColoredPrimitivePacket  colPrimitivePacket = prim.PacketData as ITMDColoredPrimitivePacket;
                ITMDLitPrimitivePacket      litPrimitivePacket = prim.PacketData as ITMDLitPrimitivePacket;

                List <int> polyIndices   = new List <int>();
                int[]      packetIndices = new int[primitivePacket.Vertices.Length];
                for (int i = 0; i < primitivePacket.Vertices.Length; i++)
                {
                    int vertIndex = primitivePacket.Vertices[i];
                    packetIndices[i] = vertList.Count;

                    Vector3 vertPos  = new Vector3(verts[vertIndex].X, verts[vertIndex].Y, verts[vertIndex].Z);
                    Vector4 vertCol  = Vector4.One;
                    Vector3 vertNorm = Vector3.Zero;
                    Vector2 vertUV   = Vector2.One;

                    // handle packet colour
                    if (colPrimitivePacket != null)
                    {
                        Vec3 packetVertCol = colPrimitivePacket.Colors[colPrimitivePacket.Colors.Length > 1 ? i : 0];
                        vertCol = new Vector4(packetVertCol.X, packetVertCol.Y, packetVertCol.Z, 1f);
                    }

                    // 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 (texPrimitivePacket != null)
                    {
                        int texPage = texPrimitivePacket.Texture.TexturePageNumber;

                        int texPageXPos = ((texPage % 16) * 128) - 640;
                        int texPageYPos = texPage < 16 ? 256 : 0;

                        int uvIndex  = i * 2;
                        int vramXPos = texPageXPos + texPrimitivePacket.UVs[uvIndex];
                        int vramYPos = texPageYPos + (256 - texPrimitivePacket.UVs[uvIndex + 1]);

                        float uCoord = vramXPos / (float)VRAMController.VRAM_WIDTH;
                        float vCoord = vramYPos / (float)VRAMController.VRAM_HEIGHT;

                        vertUV = new Vector2(uCoord, vCoord);
                    }

                    vertList.Add(new Vertex(vertPos, vertNorm, vertUV, vertCol));
                }

                bool isQuad = (prim.Options & TMDPrimitivePacket.OptionsFlags.Quad) != 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]);
                }

                // if primitive is double sided poly we need to add other side with reverse winding
                if ((prim.Flags & TMDPrimitivePacket.PrimitiveFlags.DoubleSided) != 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]);
                    }
                }

                indices.AddRange(polyIndices);
            }

            Mesh toReturn = new Mesh(vertList.ToArray(), indices.ToArray(), shader);

            return(toReturn);
        }
Example #8
0
        /// <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);
        }
Example #9
0
        // create a single LBD tile GameObject (not including extra tiles)
        private static GameObject createSingleLBDTile(LBDTile tile, int x, int y, TMD tilesTmd,
                                                      List <CombineInstance> meshesCreated)
        {
            // create the GameObject and add/setup necessary components
            GameObject   lbdTile = new GameObject($"Tile {tile.TileType}");
            MeshFilter   mf      = lbdTile.AddComponent <MeshFilter>();
            MeshRenderer mr      = lbdTile.AddComponent <MeshRenderer>();

            lbdTile.AddComponent <CullMeshOnDistance>();
            lbdTile.AddComponent <MeshFog>();
            TMDObject tileObj  = tilesTmd.ObjectTable[tile.TileType];
            Mesh      tileMesh = MeshFromTMDObject(tileObj);

            mf.mesh = tileMesh;

            // the renderer needs to use virtual PSX Vram as its materials
            mr.sharedMaterials = new[] { PsxVram.VramMaterial, PsxVram.VramAlphaBlendMaterial };

            // rotate the tile based on its direction
            switch (tile.TileDirection)
            {
            case LBDTile.TileDirections.Deg90:
            {
                lbdTile.transform.Rotate(Vector3.up, 90);
                break;
            }

            case LBDTile.TileDirections.Deg180:
            {
                lbdTile.transform.Rotate(Vector3.up, 180);
                break;
            }

            case LBDTile.TileDirections.Deg270:
            {
                lbdTile.transform.Rotate(Vector3.up, 270);
                break;
            }
            }

            // set the tile's height
            lbdTile.transform.position = new Vector3(x, -tile.TileHeight, y);

            // make a CombineInstance for combining all tiles into one mesh later on
            var             localToWorldMatrix = lbdTile.transform.localToWorldMatrix;
            CombineInstance combine            = new CombineInstance()
            {
                mesh         = tileMesh,
                transform    = localToWorldMatrix,
                subMeshIndex = 0
            };

            meshesCreated.Add(combine);

            // if tile has transparent part, do the same for the transparent mesh
            if (tileMesh.subMeshCount > 1)
            {
                CombineInstance combineTrans = new CombineInstance()
                {
                    mesh         = tileMesh,
                    transform    = localToWorldMatrix,
                    subMeshIndex = 1
                };
                meshesCreated.Add(combineTrans);
            }

            return(lbdTile);
        }