Ejemplo n.º 1
0
        /// <summary>
        /// Inserts a new mesh and returns its index in MeshPointers.
        /// </summary>
        public static int InsertMesh(TR2Level level, TRMesh newMesh)
        {
            //get the final mesh we currently have
            TRMesh lastMesh = level.Meshes[level.Meshes.Length - 1];

            //new mesh pointer will be the current final mesh's pointer plus its length
            newMesh.Pointer = lastMesh.Pointer + (uint)lastMesh.Serialize().Length;

            List <TRMesh> meshes = level.Meshes.ToList();

            meshes.Add(newMesh);
            level.Meshes = meshes.ToArray();

            List <uint> pointers = level.MeshPointers.ToList();

            pointers.Add(newMesh.Pointer);
            level.MeshPointers = pointers.ToArray();
            level.NumMeshPointers++;

            //NumMeshData needs the additional mesh size added
            level.NumMeshData += (uint)newMesh.Serialize().Length / 2;

            //the pointer index will be the final index in the array
            return(level.MeshPointers.Length - 1);
        }
Ejemplo n.º 2
0
        public override void Import()
        {
            // Copy the MeshTreeNodes and Meshes into the level, making a note of the first
            // inserted index for each - this is used to update the Model to point to the
            // correct starting positions.
            for (int i = 0; i < Definition.MeshTrees.Length; i++)
            {
                TRMeshTreeNode tree          = Definition.MeshTrees[i];
                int            insertedIndex = TR2LevelUtilities.InsertMeshTreeNode(Level, tree);
                if (i == 0)
                {
                    Definition.Model.MeshTree = 4 * (uint)insertedIndex;
                }
            }

            for (int i = 0; i < Definition.Meshes.Length; i++)
            {
                TRMesh mesh          = Definition.Meshes[i];
                int    insertedIndex = TR2LevelUtilities.InsertMesh(Level, mesh);
                if (i == 0)
                {
                    Definition.Model.StartingMesh = (ushort)insertedIndex;
                }
            }
        }
Ejemplo n.º 3
0
 private void AdjustOutfit(TR2CombinedLevel level, TR2Entities lara)
 {
     if (level.Is(LevelNames.HOME) && lara != TR2Entities.LaraHome)
     {
         // This ensures that Lara's hips match the new outfit for the starting animation and shower cutscene,
         // otherwise the dressing gown hips are rendered, but the mesh is completely different for this, plus
         // its textures will have been removed.
         TRMesh laraMiscMesh = TR2LevelUtilities.GetModelFirstMesh(level.Data, TR2Entities.LaraMiscAnim_H);
         TRMesh laraHipsMesh = TR2LevelUtilities.GetModelFirstMesh(level.Data, TR2Entities.Lara);
         TR2LevelUtilities.DuplicateMesh(level.Data, laraMiscMesh, laraHipsMesh);
     }
 }
Ejemplo n.º 4
0
        /// <summary>
        /// Duplicates the data from one mesh to another and ensures that the contents
        /// of MeshPointers remains consistent with respect to the mesh lengths.
        /// </summary>
        public static void DuplicateMesh(TR2Level level, TRMesh originalMesh, TRMesh replacementMesh)
        {
            int oldLength = originalMesh.Serialize().Length;

            originalMesh.Centre                = replacementMesh.Centre;
            originalMesh.CollRadius            = replacementMesh.CollRadius;
            originalMesh.ColouredRectangles    = replacementMesh.ColouredRectangles;
            originalMesh.ColouredTriangles     = replacementMesh.ColouredTriangles;
            originalMesh.Lights                = replacementMesh.Lights;
            originalMesh.Normals               = replacementMesh.Normals;
            originalMesh.NumColouredRectangles = replacementMesh.NumColouredRectangles;
            originalMesh.NumColouredTriangles  = replacementMesh.NumColouredTriangles;
            originalMesh.NumNormals            = replacementMesh.NumNormals;
            originalMesh.NumTexturedRectangles = replacementMesh.NumTexturedRectangles;
            originalMesh.NumTexturedTriangles  = replacementMesh.NumTexturedTriangles;
            originalMesh.NumVertices           = replacementMesh.NumVertices;
            originalMesh.TexturedRectangles    = replacementMesh.TexturedRectangles;
            originalMesh.TexturedTriangles     = replacementMesh.TexturedTriangles;
            originalMesh.Vertices              = replacementMesh.Vertices;

            // The length will have changed so all pointers above the original one will need adjusting
            int         lengthDiff   = originalMesh.Serialize().Length - oldLength;
            List <uint> pointers     = level.MeshPointers.ToList();
            int         pointerIndex = pointers.IndexOf(originalMesh.Pointer);

            for (int i = pointerIndex + 1; i < pointers.Count; i++)
            {
                if (pointers[i] > 0)
                {
                    int newPointer = (int)pointers[i] + lengthDiff;
                    pointers[i] = (uint)newPointer;
                }
            }

            level.MeshPointers = pointers.ToArray();

            int numMeshData = (int)level.NumMeshData + lengthDiff / 2;

            level.NumMeshData = (uint)numMeshData;
        }
Ejemplo n.º 5
0
        private TRMesh[] ConstructMeshData(uint DataCount, uint NumPointers, ushort[] MeshData)
        {
            //Track where we are in mesh data
            int MeshDataOffset = 0;

            //Temp storage for forming an int from two ushorts
            ushort LowBytes;
            ushort HighBytes;

            //We know the amount of meshes via NumPointers and we know amount of mesh data via DataCount
            //The mesh data as uint16s/words are stored in MeshData

            //We need to pack that data into the objects
            TRMesh[] meshes = new TRMesh[NumPointers];

            for (int i = 0; i < NumPointers; i++)
            {
                TRMesh mesh = new TRMesh();

                //Centre
                TRVertex centre = new TRVertex();

                centre.X = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                centre.Y = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                centre.Z = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;

                mesh.Centre = centre;

                //Coll Radius
                LowBytes = MeshData[MeshDataOffset];
                MeshDataOffset++;
                HighBytes = MeshData[MeshDataOffset];
                MeshDataOffset++;

                mesh.CollRadius = LowBytes | HighBytes;

                //Vertices
                mesh.NumVetices = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                mesh.Vertices = new TRVertex[mesh.NumVetices];

                for (int j = 0; j < mesh.NumVetices; j++)
                {
                    TRVertex v = new TRVertex();

                    v.X = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                    MeshDataOffset++;
                    v.Y = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                    MeshDataOffset++;
                    v.Z = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                    MeshDataOffset++;

                    mesh.Vertices[j] = v;
                }

                //Lights or Normals
                mesh.NumNormals = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;

                if (mesh.NumNormals > 0)
                {
                    mesh.Normals = new TRVertex[mesh.NumNormals];

                    for (int j = 0; j < mesh.NumNormals; j++)
                    {
                        TRVertex v = new TRVertex();

                        v.X = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                        MeshDataOffset++;
                        v.Y = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                        MeshDataOffset++;
                        v.Z = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                        MeshDataOffset++;

                        mesh.Normals[j] = v;
                    }
                }
                else
                {
                    mesh.Lights = new short[Math.Abs(mesh.NumNormals)];

                    for (int j = 0; j < mesh.Lights.Count(); j++)
                    {
                        mesh.Lights[j] = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                        MeshDataOffset++;
                    }
                }

                //Textured Rectangles
                mesh.NumTexturedRectangles = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                mesh.TexturedRectangles = new TRFace4[mesh.NumTexturedRectangles];

                for (int j = 0; j < mesh.NumTexturedRectangles; j++)
                {
                    TRFace4 face = new TRFace4();

                    face.Vertices = new ushort[4];

                    face.Vertices[0] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[1] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[2] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[3] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Texture = MeshData[MeshDataOffset];
                    MeshDataOffset++;

                    mesh.TexturedRectangles[j] = face;
                }

                //Textured Triangles
                mesh.NumTexturedTriangles = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                mesh.TexturedTriangles = new TRFace3[mesh.NumTexturedTriangles];

                for (int j = 0; j < mesh.NumTexturedTriangles; j++)
                {
                    TRFace3 face = new TRFace3();

                    face.Vertices = new ushort[3];

                    face.Vertices[0] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[1] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[2] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Texture = MeshData[MeshDataOffset];
                    MeshDataOffset++;

                    mesh.TexturedTriangles[j] = face;
                }

                //Coloured Rectangles
                mesh.NumColouredRectangles = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                mesh.ColouredRectangles = new TRFace4[mesh.NumColouredRectangles];

                for (int j = 0; j < mesh.NumColouredRectangles; j++)
                {
                    TRFace4 face = new TRFace4();

                    face.Vertices = new ushort[4];

                    face.Vertices[0] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[1] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[2] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[3] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Texture = MeshData[MeshDataOffset];
                    MeshDataOffset++;

                    mesh.ColouredRectangles[j] = face;
                }

                //Coloured Triangles
                mesh.NumColouredTriangles = UnsafeConversions.UShortToShort(MeshData[MeshDataOffset]);
                MeshDataOffset++;
                mesh.ColouredTriangles = new TRFace3[mesh.NumColouredTriangles];

                for (int j = 0; j < mesh.NumColouredTriangles; j++)
                {
                    TRFace3 face = new TRFace3();

                    face.Vertices = new ushort[3];

                    face.Vertices[0] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[1] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Vertices[2] = MeshData[MeshDataOffset];
                    MeshDataOffset++;
                    face.Texture = MeshData[MeshDataOffset];
                    MeshDataOffset++;

                    mesh.ColouredTriangles[j] = face;
                }

                meshes[i] = mesh;
            }

            //The offset should match the total amount of data.
            Debug.Assert(MeshDataOffset == DataCount);

            return(meshes);
        }
Ejemplo n.º 6
0
        private TRMesh[] ConstructMeshData(uint[] meshPointers, ushort[] rawMeshData)
        {
            byte[] target = new byte[rawMeshData.Length * 2];
            Buffer.BlockCopy(rawMeshData, 0, target, 0, target.Length);

            // The mesh pointer list can contain duplicates so we must make
            // sure to iterate over distinct values only
            meshPointers = meshPointers.Distinct().ToArray();

            List <TRMesh> meshes = new List <TRMesh>();

            using (MemoryStream ms = new MemoryStream(target))
                using (BinaryReader br = new BinaryReader(ms))
                {
                    for (int i = 0; i < meshPointers.Length; i++)
                    {
                        TRMesh mesh = new TRMesh();
                        meshes.Add(mesh);

                        uint meshPointer = meshPointers[i];
                        br.BaseStream.Position = meshPointer;

                        //Pointer
                        mesh.Pointer = meshPointer;

                        //Centre
                        mesh.Centre = TR2FileReadUtilities.ReadVertex(br);

                        //CollRadius
                        mesh.CollRadius = br.ReadInt32();

                        //Vertices
                        mesh.NumVertices = br.ReadInt16();
                        mesh.Vertices    = new TRVertex[mesh.NumVertices];
                        for (int j = 0; j < mesh.NumVertices; j++)
                        {
                            mesh.Vertices[j] = TR2FileReadUtilities.ReadVertex(br);
                        }

                        //Lights or Normals
                        mesh.NumNormals = br.ReadInt16();
                        if (mesh.NumNormals > 0)
                        {
                            mesh.Normals = new TRVertex[mesh.NumNormals];
                            for (int j = 0; j < mesh.NumNormals; j++)
                            {
                                mesh.Normals[j] = TR2FileReadUtilities.ReadVertex(br);
                            }
                        }
                        else
                        {
                            mesh.Lights = new short[Math.Abs(mesh.NumNormals)];
                            for (int j = 0; j < mesh.Lights.Length; j++)
                            {
                                mesh.Lights[j] = br.ReadInt16();
                            }
                        }

                        //Textured Rectangles
                        mesh.NumTexturedRectangles = br.ReadInt16();
                        mesh.TexturedRectangles    = new TRFace4[mesh.NumTexturedRectangles];
                        for (int j = 0; j < mesh.NumTexturedRectangles; j++)
                        {
                            mesh.TexturedRectangles[j] = TR2FileReadUtilities.ReadTRFace4(br);
                        }

                        //Textured Triangles
                        mesh.NumTexturedTriangles = br.ReadInt16();
                        mesh.TexturedTriangles    = new TRFace3[mesh.NumTexturedTriangles];
                        for (int j = 0; j < mesh.NumTexturedTriangles; j++)
                        {
                            mesh.TexturedTriangles[j] = TR2FileReadUtilities.ReadTRFace3(br);
                        }

                        //Coloured Rectangles
                        mesh.NumColouredRectangles = br.ReadInt16();
                        mesh.ColouredRectangles    = new TRFace4[mesh.NumColouredRectangles];
                        for (int j = 0; j < mesh.NumColouredRectangles; j++)
                        {
                            mesh.ColouredRectangles[j] = TR2FileReadUtilities.ReadTRFace4(br);
                        }

                        //Coloured Triangles
                        mesh.NumColouredTriangles = br.ReadInt16();
                        mesh.ColouredTriangles    = new TRFace3[mesh.NumColouredTriangles];
                        for (int j = 0; j < mesh.NumColouredTriangles; j++)
                        {
                            mesh.ColouredTriangles[j] = TR2FileReadUtilities.ReadTRFace3(br);
                        }

                        // There may be alignment padding at the end of the mesh, but rather than
                        // storing it, when the mesh is serialized the alignment should be considered.
                        // It seems to be 4-byte alignment for mesh data. The basestream position is
                        // moved to the next pointer in the next iteration, so we don't need to process
                        // the additional data here.
                        // See https://www.tombraiderforums.com/archive/index.php/t-215247.html
                    }
                }

            return(meshes.ToArray());
        }