示例#1
0
文件: Gcmf.cs 项目: trashbyte/LibGC
        private int SizeOf2MeshData(GcGame game)
        {
            bool isVtx16Bit = (SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0 &&
                              !GcmfVersionDetails.Is16BitEffectiveModelIgnored(game);

            return(PaddingUtils.Align(Meshes.Sum(mesh => mesh.SizeOfIndexedData(isVtx16Bit)), 0x20));
        }
示例#2
0
 private int SizeOfHeaderEntries(GxGame game)
 {
     if (game == GxGame.SuperMonkeyBallDX)
     {
         return(PaddingUtils.Align((8 + (4 + 4 + 2 + 2 + 2 + 2) * Count), 0x20));
     }
     else
     {
         return(PaddingUtils.Align(4 + (4 + 4 + 2 + 2 + 2 + 2) * Count, 0x20));
     }
 }
示例#3
0
        private void GenerateNodes(ArcFileSystemEntry currentEntry, List <U8Node> nodes, List <ArcFileSystemEntry> entries,
                                   ref int currentNodeId, int parentNodeId, ref int currentStringTableOffset, ref int currentDataOffset)
        {
            // Add the node and the entry to the enumeration
            U8Node node = new U8Node();

            nodes.Add(node);
            entries.Add(currentEntry);

            int thisNodeId = currentNodeId;

            currentNodeId++;

            // Reserve space for the name in the string table
            node.NameOffset           = currentStringTableOffset;
            currentStringTableOffset += currentEntry.Name.Length + 1;

            if (currentEntry is ArcFileSystemDirectory)
            {
                ArcFileSystemDirectory currentDirectory = (ArcFileSystemDirectory)currentEntry;

                foreach (ArcFileSystemEntry subEntry in currentDirectory.Entries)
                {
                    GenerateNodes(subEntry, nodes, entries, ref currentNodeId, thisNodeId, ref currentStringTableOffset, ref currentDataOffset);
                }

                node.Type       = U8Node.TYPE_DIRECTORY;
                node.DataOffset = parentNodeId;
                node.Size       = currentNodeId;
            }
            else if (currentEntry is ArcFileSystemFile)
            {
                ArcFileSystemFile currentFile = (ArcFileSystemFile)currentEntry;

                node.Type       = U8Node.TYPE_FILE;
                node.DataOffset = currentDataOffset;
                node.Size       = currentFile.Data.Length;

                currentDataOffset = PaddingUtils.Align(currentDataOffset + currentFile.Data.Length, 0x20);
            }
        }
示例#4
0
        /// <summary>
        /// Calculates the size of a level of the texture.
        /// </summary>
        /// <param name="level">The level of the texture.</param>
        /// <param name="replicateCmprBug">true to replicate the F-Zero GX CMPR encoding bug.</param>
        /// <returns>The size of the encoded data in the specified level.</returns>
        private int CalculateSizeOfLevel(int level, bool replicateCmprBug = false)
        {
            // Here we allow also to specify the "next" level for easier implementation
            // of the methods that encode the new texture
            if (level < 0 || level > LevelCount)
            {
                throw new ArgumentOutOfRangeException("level");
            }

            int levelWidth = width >> level, levelHeight = height >> level;

            // Hack: CMPR sizes are not calculated correctly, replicate the bug
            if (replicateCmprBug && format == GxTextureFormat.CMPR)
            {
                int w     = PaddingUtils.Align(levelWidth, 4);  // Align to 4 (should really be 8)
                int h     = PaddingUtils.Align(levelHeight, 4); // Align to 4 (should really be 8)
                int sz    = (w * h * 4) / 8;                    // CMPR is 4 bits per pixel
                int szpad = PaddingUtils.Align(sz, 32);         // Align to 32 (this should normally not be needed)
                return(szpad);
            }

            return(GxTextureFormatCodec.GetCodec(format).CalcTextureSize(levelWidth, levelHeight));
        }
示例#5
0
        /// Gets the size of the texture when written to a binary stream.
        internal int SizeOfTextureData(GcGame game)
        {
            int size = 0;

            for (int level = 0; level < LevelCount; level++)
            {
                // Hack: CMPR sizes are not calculated correctly as explained in the doc., replicate the bug
                if (TplVersionDetails.HasCmprSizeBug(game) && format == GcTextureFormat.CMPR)
                {
                    int levelWidth = width >> level, levelHeight = height >> level;
                    int w     = PaddingUtils.Align(levelWidth, 4);  // Align to 4 (should really be 8)
                    int h     = PaddingUtils.Align(levelHeight, 4); // Align to 4 (should really be 8)
                    int sz    = (w * h * 4) / 8;                    // CMPR is 4 bits per pixel
                    int szpad = PaddingUtils.Align(sz, 32);         // Align to 32 (this should normally not be needed)
                    size += szpad;
                }
                else
                {
                    size += CalculateSizeOfLevel(level);
                }
            }
            return(size);
        }
示例#6
0
 private int SizeOfHeader()
 {
     return(PaddingUtils.Align(SizeOfHeaderEntries() + SizeOfHeaderNameTable(), 0x20));
 }
示例#7
0
 private int SizeOfHeaderEntries()
 {
     return(PaddingUtils.Align(4 + (4 + 4 + 2 + 2 + 2 + 2) * Count, 0x20));
 }
 internal int SizeOfNonIndexed(bool is16Bit)
 {
     return(PaddingUtils.Align(1 + Items.Sum(strip => strip.SizeOfNonIndexed(is16Bit)), 0x20));
 }
示例#9
0
文件: Gcmf.cs 项目: trashbyte/LibGC
 private int SizeOf2Type8Unknown2()
 {
     return(PaddingUtils.Align(2 * Type8Unknown2.Count, 0x20));
 }
示例#10
0
文件: Gcmf.cs 项目: trashbyte/LibGC
 private int SizeOfHeader()
 {
     return(PaddingUtils.Align(0x40 +
                               Materials.Sum(mat => mat.SizeOf()) +
                               TransformMatrices.Sum(tmtx => tmtx.SizeOf()), 0x20));
 }
示例#11
0
文件: Gcmf.cs 项目: trashbyte/LibGC
        internal void Load(EndianBinaryReader input, GcGame game)
        {
            int baseOffset = Convert.ToInt32(input.BaseStream.Position);

            // Load GCMF header
            if (input.ReadUInt32() != GcmfMagic)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x00] == GcmfMagic.");
            }
            SectionFlags         = input.ReadUInt32();
            BoundingSphereCenter = new Vector3(input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
            BoundingSphereRadius = input.ReadSingle();
            int numMaterials         = (int)input.ReadUInt16();
            int numLayer1Meshes      = (int)input.ReadUInt16();
            int numLayer2Meshes      = (int)input.ReadUInt16();
            int numTransformMatrices = (int)input.ReadByte();

            if (input.ReadByte() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x1F] == 0");
            }
            int headerSize = input.ReadInt32();

            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x24] == 0");
            }
            input.Read(TransformMatrixDefaultIdxs, 0, 8);
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x30] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x34] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x38] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x3C] == 0");
            }

            // Check that the combination of flags is correct
            if ((SectionFlags & (uint)~(GcmfSectionFlags._16Bit |
                                        GcmfSectionFlags.StitchingModel |
                                        GcmfSectionFlags.SkinModel |
                                        GcmfSectionFlags.EffectiveModel)) != 0)
            {
                throw new InvalidGmaFileException("Unknown GCMF section flags.");
            }

            if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0 && !GcmfVersionDetails.IsGcmfSkinModelSupported(game))
            {
                throw new InvalidGmaFileException("GCMF with skin model flag is not supported in this game.");
            }

            // Load materials
            for (int i = 0; i < numMaterials; i++)
            {
                GcmfMaterial mat = new GcmfMaterial();
                mat.Load(input, i);
                Materials.Add(mat);
            }

            // Load transform matrices
            if ((SectionFlags & (uint)GcmfSectionFlags.StitchingModel) != 0 ||
                (SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
            {
                for (int i = 0; i < numTransformMatrices; i++)
                {
                    GcmfTransformMatrix tmtx = new GcmfTransformMatrix();
                    tmtx.Load(input);
                    TransformMatrices.Add(tmtx);
                }
            }
            else
            {
                if (numTransformMatrices != 0)
                {
                    throw new InvalidGmaFileException("GcmfSection: No transform matrices expected, but transformMatrixCount != 0?");
                }
            }

            if (PaddingUtils.Align(Convert.ToInt32(input.BaseStream.Position), 0x20) != baseOffset + headerSize)
            {
                throw new InvalidGmaFileException("Gcmf [End Header Offset] mismatch.");
            }

            input.BaseStream.Position = baseOffset + headerSize;

            if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0 ||
                (SectionFlags & (uint)GcmfSectionFlags.EffectiveModel) != 0)
            {
                int sectionBaseOffset = Convert.ToInt32(input.BaseStream.Position);

                int numVertices             = input.ReadInt32();
                int offsetPartType8Unknown1 = input.ReadInt32();
                int offsetPartVertexPool    = input.ReadInt32();
                int offsetPartMeshData      = input.ReadInt32();
                int offsetPartType8Unknown2 = input.ReadInt32();
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x14]");
                }
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x18]");
                }
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x1C]");
                }

                // Load the mesh headers
                List <GcmfMesh.HeaderSectionInfo> meshHeaderSectionInfos = new List <GcmfMesh.HeaderSectionInfo>();
                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    GcmfMesh mesh = new GcmfMesh();
                    meshHeaderSectionInfos.Add(mesh.LoadHeader(input,
                                                               (i < numLayer1Meshes) ? GcmfMesh.MeshLayer.Layer1 : GcmfMesh.MeshLayer.Layer2));
                    Meshes.Add(mesh);
                }

                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartVertexPool)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartVertexPool doesn't match expected value.");
                }

                // Load the vertex pool, i.e. the vertices referenced from the indexed triangle strips
                // On SMB1, the 16 bit flag is ignored in effective models
                bool isVtx16Bit = (SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0 &&
                                  !GcmfVersionDetails.Is16BitEffectiveModelIgnored(game);

                for (int i = 0; i < numVertices; i++)
                {
                    GcmfVertex vtx = new GcmfVertex();
                    vtx.LoadIndexed(input, isVtx16Bit);
                    VertexPool.Add(vtx);
                }

                // Load type 8 unknown 1 / unknown 2
                if (GcmfVersionDetails.IsGcmfSkinModelSupported(game))
                {
                    if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartType8Unknown1)
                    {
                        throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown1 doesn't match expected value.");
                    }

                    if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
                    {
                        for (int i = 0; i < (offsetPartType8Unknown2 - offsetPartType8Unknown1) / 0x20; i++)
                        {
                            GcmfType8Unknown1 unk1 = new GcmfType8Unknown1();
                            unk1.Load(input);
                            Type8Unknown1.Add(unk1);
                        }
                    }

                    if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartType8Unknown2)
                    {
                        throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown2 doesn't match expected value.");
                    }

                    if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
                    {
                        for (int i = 0; i < numTransformMatrices; i++)
                        {
                            Type8Unknown2.Add(input.ReadUInt16());
                        }

                        if (PaddingUtils.Align(Convert.ToInt32(input.BaseStream.Position), 0x20) != sectionBaseOffset + offsetPartMeshData)
                        {
                            throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartMeshData doesn't match expected value.");
                        }

                        input.BaseStream.Position = sectionBaseOffset + offsetPartMeshData;
                    }
                }
                else
                {
                    // We already made sure that the section flags are not skin model if it's not supported,
                    // so if we're here, the flag is set to effective model.

                    // In this case, the offsets of those sections must be zero

                    // SMB doesn't have have any 0x08 section flags, so those offsets are zero
                    if (offsetPartType8Unknown1 != 0)
                    {
                        throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown1 is not zero on SMB.");
                    }

                    if (offsetPartType8Unknown2 != 0)
                    {
                        throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown2 is not zero on SMB.");
                    }
                }

                // Load the mesh data itself (the indexed triangle strips)
                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartMeshData)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartMeshData doesn't match expected value.");
                }

                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    Meshes[i].LoadIndexedData(input, isVtx16Bit, VertexPool, meshHeaderSectionInfos[i]);
                }

                // Make sure that all the vertices in the vertex pool got their
                // vertex flags set when we read the indexed triangle strips,
                // that is, that they were referenced at least once.
                // Otherwise, we would have semi-initialized vertices in the vertex pool!
                if (VertexPool.Any(vtx => !vtx.IsIndexedVertexInitialized()))
                {
                    throw new InvalidGmaFileException("Not all vertex flags of all vertices in the vertex pool got initialized!");
                }
            }
            else
            {
                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    GcmfMesh mesh = new GcmfMesh();
                    GcmfMesh.HeaderSectionInfo headerSectionInfo = mesh.LoadHeader(input,
                                                                                   (i < numLayer1Meshes) ? GcmfMesh.MeshLayer.Layer1 : GcmfMesh.MeshLayer.Layer2);
                    mesh.LoadNonIndexedData(input, headerSectionInfo, (SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0);
                    Meshes.Add(mesh);
                }
            }
        }
示例#12
0
 private int SizeOf2MeshData()
 {
     return(PaddingUtils.Align(Meshes.Sum(mesh => mesh.SizeOfIndexedData()), 0x20));
 }
示例#13
0
        internal void Load(EndianBinaryReader input, GxGame game)
        {
            int baseOffset = Convert.ToInt32(input.BaseStream.Position);

            // Load GCMF header
            if (input.ReadUInt32() != GcmfMagic)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x00] == GcmfMagic.");
            }
            SectionFlags         = input.ReadUInt32();
            BoundingSphereCenter = new Vector3(input.ReadSingle(), input.ReadSingle(), input.ReadSingle());
            BoundingSphereRadius = input.ReadSingle();
            int numMaterials         = (int)input.ReadUInt16();
            int numLayer1Meshes      = (int)input.ReadUInt16();
            int numLayer2Meshes      = (int)input.ReadUInt16();
            int transformMatrixCount = (int)input.ReadByte();

            if (input.ReadByte() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x1F] == 0");
            }
            int headerSize = input.ReadInt32();

            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x24] == 0");
            }
            input.Read(TransformMatrixDefaultIdxs, 0, 8);
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x30] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x34] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x38] == 0");
            }
            if (input.ReadUInt32() != 0)
            {
                throw new InvalidGmaFileException("Expected Gcmf[0x3C] == 0");
            }

            // Load materials
            for (int i = 0; i < numMaterials; i++)
            {
                GcmfMaterial mat = new GcmfMaterial();
                mat.Load(input, i);
                Materials.Add(mat);
            }

            if ((SectionFlags & (uint)~(GcmfSectionFlags._16Bit |
                                        GcmfSectionFlags.StitchingModel |
                                        GcmfSectionFlags.SkinModel |
                                        GcmfSectionFlags.EffectiveModel)) != 0)
            {
                throw new InvalidGmaFileException("Unknown GCMF section flags.");
            }

            if ((SectionFlags & (uint)GcmfSectionFlags.StitchingModel) != 0 ||
                (SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
            {
                for (int i = 0; i < transformMatrixCount; i++)
                {
                    GcmfTransformMatrix tmtx = new GcmfTransformMatrix();
                    tmtx.Load(input);
                    TransformMatrices.Add(tmtx);
                }
            }
            else
            {
                if (transformMatrixCount != 0)
                {
                    throw new InvalidGmaFileException("GcmfSection: No transform matrices expected, but transformMatrixCount != 0?");
                }
            }

            if (PaddingUtils.Align(Convert.ToInt32(input.BaseStream.Position), 0x20) != baseOffset + headerSize)
            {
                throw new InvalidGmaFileException("Gcmf [End Header Offset] mismatch.");
            }

            input.BaseStream.Position = baseOffset + headerSize;

            if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0 ||
                (SectionFlags & (uint)GcmfSectionFlags.EffectiveModel) != 0)
            {
                int sectionBaseOffset = Convert.ToInt32(input.BaseStream.Position);

                int numVertices             = input.ReadInt32();
                int offsetPartType8Unknown1 = input.ReadInt32();
                int offsetPartVertexPool    = input.ReadInt32();
                int offsetPartMeshData      = input.ReadInt32();
                int offsetPartType8Unknown2 = input.ReadInt32();
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x14]");
                }
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x18]");
                }
                if (input.ReadUInt32() != 0)
                {
                    throw new InvalidGmaFileException("Gcmf[PreSectionHdr-0x1C]");
                }

                // Load the mesh headers
                List <GcmfMesh.HeaderSectionInfo> meshHeaderSectionInfos = new List <GcmfMesh.HeaderSectionInfo>();
                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    GcmfMesh mesh = new GcmfMesh();
                    meshHeaderSectionInfos.Add(mesh.LoadHeader(input,
                                                               (i < numLayer1Meshes) ? GcmfMesh.MeshLayer.Layer1 : GcmfMesh.MeshLayer.Layer2));
                    Meshes.Add(mesh);
                }

                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartVertexPool)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartVertexPool doesn't match expected value.");
                }

                // Load the vertex pool, i.e. the vertices referenced from the indexed triangle strips
                for (int i = 0; i < numVertices; i++)
                {
                    GcmfVertex vtx = new GcmfVertex();
                    vtx.LoadIndexed(input);
                    VertexPool.Add(vtx);
                }

                // Just because it probably won't be there doesn't mean we shouldn't allow it
                // and some stages have the things that are not allowed

                /*if ((game == GxGame.SuperMonkeyBall || game == GxGame.SuperMonkeyBallDX) && (SectionFlags & (uint)GcmfSectionFlags.EffectiveModel) != 0)
                 * {
                 *  // SMB doesn't have have any 0x08 section flags, so it's unknown how this field may work in that case
                 *  if (offsetPartType8Unknown1 != 0)
                 *      throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown1 is not zero on SMB.");
                 * }
                 * else
                 * {*/
                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartType8Unknown1)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown1 doesn't match expected value.");
                }
                //}

                if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
                {
                    for (int i = 0; i < (offsetPartType8Unknown2 - offsetPartType8Unknown1) / 0x20; i++)
                    {
                        GcmfType8Unknown1 unk1 = new GcmfType8Unknown1();
                        unk1.Load(input);
                        Type8Unknown1.Add(unk1);
                    }
                }

                // Just because it probably won't be there doesn't mean we shouldn't allow it
                // and some stages have the things that are not allowed

                /*if ((game == GxGame.SuperMonkeyBall || game == GxGame.SuperMonkeyBallDX) && (SectionFlags & (uint)GcmfSectionFlags.EffectiveModel) != 0)
                 * {
                 *  // SMB doesn't have have any 0x08 section flags, so it's unknown how this field may work in that case
                 *  if (offsetPartType8Unknown2 != 0)
                 *      throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown2 is not zero on SMB.");
                 * }
                 * else
                 * {*/
                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartType8Unknown2)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartType8Unknown2 doesn't match expected value.");
                }
                //}

                if ((SectionFlags & (uint)GcmfSectionFlags.SkinModel) != 0)
                {
                    // TODO figure out a better way to calculate this
                    int numEntriesPart3 = Type8Unknown1.Max(u1 => u1.unk18) + 1;
                    for (int i = 0; i < numEntriesPart3; i++)
                    {
                        Type8Unknown2.Add(input.ReadUInt16());
                    }

                    if (PaddingUtils.Align(Convert.ToInt32(input.BaseStream.Position), 0x20) != sectionBaseOffset + offsetPartMeshData)
                    {
                        throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPart4 doesn't match expected value.");
                    }

                    input.BaseStream.Position = sectionBaseOffset + offsetPartMeshData;
                }

                if (Convert.ToInt32(input.BaseStream.Position) != sectionBaseOffset + offsetPartMeshData)
                {
                    throw new InvalidGmaFileException("Gcmf [PreSectionHdr] offsetPartMeshData doesn't match expected value.");
                }

                // Load the mesh data itself (the indexed triangle strips)
                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    Meshes[i].LoadIndexedData(input, VertexPool, meshHeaderSectionInfos[i]);
                }

                // Make sure that all the vertices in the vertex pool got their
                // vertex flags set when we read the indexed triangle strips,
                // that is, that they were referenced at least once.
                // Otherwise, we would have semi-initialized vertices in the vertex pool!
                if (VertexPool.Any(vtx => !vtx.IsIndexedVertexInitialized()))
                {
                    throw new InvalidGmaFileException("Not all vertex flags of all vertices in the vertex pool got initialized!");
                }
            }
            else
            {
                for (int i = 0; i < numLayer1Meshes + numLayer2Meshes; i++)
                {
                    GcmfMesh mesh = new GcmfMesh();
                    GcmfMesh.HeaderSectionInfo headerSectionInfo = mesh.LoadHeader(input,
                                                                                   (i < numLayer1Meshes) ? GcmfMesh.MeshLayer.Layer1 : GcmfMesh.MeshLayer.Layer2);
                    mesh.LoadNonIndexedData(input, headerSectionInfo, (SectionFlags & (uint)GcmfSectionFlags._16Bit) != 0);
                    Meshes.Add(mesh);
                }
            }
        }
示例#14
0
        /// <summary>
        /// Save the contents of this ARC container to an output stream.
        /// </summary>
        /// <param name="outputStream">The stream to which the ARC container will be written.</param>
        public void Save(Stream outputStream)
        {
            EndianBinaryWriter outputBinaryStream = new EndianBinaryWriter(EndianBitConverter.Big, outputStream);

            // Generate node structures. Assign identifiers, string table offsets, data offsets
            // Note that here the data offsets will be assigned relative to the data zone and not as absolute offsets
            // This will be fixed later, when we're able to calculate the file layout
            List <U8Node>             nodes   = new List <U8Node>();
            List <ArcFileSystemEntry> entries = new List <ArcFileSystemEntry>();
            int currentNodeId            = 0;
            int currentStringTableOffset = 0;
            int currentDataOffset        = 0;

            GenerateNodes(Root, nodes, entries, ref currentNodeId, 0, ref currentStringTableOffset, ref currentDataOffset);

            // Compute offsets of different parts of the file
            int headerSize      = 0x20;
            int nodesSize       = nodes.Count * 12;
            int stringTableSize = currentStringTableOffset;

            int rootNodeOffset          = 0x20;
            int stringTableOffset       = rootNodeOffset + nodesSize;
            int nodesAndStringTableSize = nodesSize + stringTableSize;
            int dataBeginOffset         = PaddingUtils.Align(headerSize + nodesSize + stringTableSize, 0x20);

            foreach (U8Node node in nodes) // Convert data offsets from relative to absolute
            {
                if (node.Type == U8Node.TYPE_FILE)
                {
                    node.DataOffset += dataBeginOffset;
                }
            }

            // Write header
            outputBinaryStream.Write(ArcMagic);
            outputBinaryStream.Write(rootNodeOffset);
            outputBinaryStream.Write(nodesAndStringTableSize);
            outputBinaryStream.Write(dataBeginOffset);
            for (int i = 0; i < 0x10; i++)
            {
                outputBinaryStream.Write((byte)0xCC);
            }

            // Write nodes
            foreach (U8Node node in nodes)
            {
                node.Write(outputBinaryStream);
            }

            // Write string table
            foreach (ArcFileSystemEntry entry in entries)
            {
                outputBinaryStream.WriteAsciiString(entry.Name);
            }

            // Write file data
            foreach (ArcFileSystemEntry entry in entries)
            {
                if (entry is ArcFileSystemFile)
                {
                    outputBinaryStream.Align(0x20);
                    outputBinaryStream.Write(((ArcFileSystemFile)entry).Data);
                }
            }
        }