private void ReadTextureFile(PenumbraFileResource resource, MemoryStream ms) { var blocks = Reader.ReadStructures <LodBlock>(( int )resource.FileInfo !.BlockCount); // if there is a mipmap header, the comp_offset // will not be 0 var mipMapSize = blocks[0].CompressedOffset; if (mipMapSize != 0) { var originalPos = BaseStream.Position; BaseStream.Position = resource.FileInfo.Offset + resource.FileInfo.HeaderSize; ms.Write(Reader.ReadBytes(( int )mipMapSize)); BaseStream.Position = originalPos; } // i is for texture blocks, j is 'data blocks'... for (byte i = 0; i < blocks.Count; i++) { // start from comp_offset var runningBlockTotal = blocks[i].CompressedOffset + resource.FileInfo.Offset + resource.FileInfo.HeaderSize; ReadFileBlock(runningBlockTotal, ms, true); for (var j = 1; j < blocks[i].BlockCount; j++) { runningBlockTotal += ( uint )Reader.ReadInt16(); ReadFileBlock(runningBlockTotal, ms, true); } // unknown Reader.ReadInt16(); } }
private void ReadStandardFile(PenumbraFileResource resource, MemoryStream ms) { var blocks = Reader.ReadStructures <DatStdFileBlockInfos>(( int )resource.FileInfo !.BlockCount); foreach (var block in blocks) { ReadFileBlock(resource.FileInfo.Offset + resource.FileInfo.HeaderSize + block.Offset, ms); } // reset position ready for reading ms.Position = 0; }
private unsafe void ReadModelFile(PenumbraFileResource resource, MemoryStream ms) { var mdlBlock = resource.FileInfo !.ModelBlock; var baseOffset = resource.FileInfo.Offset + resource.FileInfo.HeaderSize; // 1/1/3/3/3 stack/runtime/vertex/egeo/index // TODO: consider testing if this is more reliable than the Explorer method // of adding mdlBlock.IndexBufferDataBlockIndex[2] + mdlBlock.IndexBufferDataBlockNum[2] // i don't want to move this to that method right now, because i know sometimes the index is 0 // but it seems to work fine in explorer... int totalBlocks = mdlBlock.StackBlockNum; totalBlocks += mdlBlock.RuntimeBlockNum; for (var i = 0; i < 3; i++) { totalBlocks += mdlBlock.VertexBufferBlockNum[i]; } for (var i = 0; i < 3; i++) { totalBlocks += mdlBlock.EdgeGeometryVertexBufferBlockNum[i]; } for (var i = 0; i < 3; i++) { totalBlocks += mdlBlock.IndexBufferBlockNum[i]; } var compressedBlockSizes = Reader.ReadStructures <ushort>(totalBlocks); var currentBlock = 0; var vertexDataOffsets = new int[3]; var indexDataOffsets = new int[3]; var vertexBufferSizes = new int[3]; var indexBufferSizes = new int[3]; ms.Seek(0x44, SeekOrigin.Begin); Reader.Seek(baseOffset + mdlBlock.StackOffset); var stackStart = ms.Position; for (var i = 0; i < mdlBlock.StackBlockNum; i++) { var lastPos = Reader.BaseStream.Position; ReadFileBlock(ms); Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } var stackEnd = ms.Position; var stackSize = ( int )(stackEnd - stackStart); Reader.Seek(baseOffset + mdlBlock.RuntimeOffset); var runtimeStart = ms.Position; for (var i = 0; i < mdlBlock.RuntimeBlockNum; i++) { var lastPos = Reader.BaseStream.Position; ReadFileBlock(ms); Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } var runtimeEnd = ms.Position; var runtimeSize = ( int )(runtimeEnd - runtimeStart); for (var i = 0; i < 3; i++) { if (mdlBlock.VertexBufferBlockNum[i] != 0) { var currentVertexOffset = ( int )ms.Position; if (i == 0 || currentVertexOffset != vertexDataOffsets[i - 1]) { vertexDataOffsets[i] = currentVertexOffset; } else { vertexDataOffsets[i] = 0; } Reader.Seek(baseOffset + mdlBlock.VertexBufferOffset[i]); for (var j = 0; j < mdlBlock.VertexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; vertexBufferSizes[i] += ( int )ReadFileBlock(ms); Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } } if (mdlBlock.EdgeGeometryVertexBufferBlockNum[i] != 0) { for (var j = 0; j < mdlBlock.EdgeGeometryVertexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; ReadFileBlock(ms); Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } } if (mdlBlock.IndexBufferBlockNum[i] != 0) { var currentIndexOffset = ( int )ms.Position; if (i == 0 || currentIndexOffset != indexDataOffsets[i - 1]) { indexDataOffsets[i] = currentIndexOffset; } else { indexDataOffsets[i] = 0; } // i guess this is only needed in the vertex area, for i = 0 // Reader.Seek( baseOffset + mdlBlock.IndexBufferOffset[ i ] ); for (var j = 0; j < mdlBlock.IndexBufferBlockNum[i]; j++) { var lastPos = Reader.BaseStream.Position; indexBufferSizes[i] += ( int )ReadFileBlock(ms); Reader.Seek(lastPos + compressedBlockSizes[currentBlock]); currentBlock++; } } } ms.Seek(0, SeekOrigin.Begin); ms.Write(BitConverter.GetBytes(mdlBlock.Version)); ms.Write(BitConverter.GetBytes(stackSize)); ms.Write(BitConverter.GetBytes(runtimeSize)); ms.Write(BitConverter.GetBytes(mdlBlock.VertexDeclarationNum)); ms.Write(BitConverter.GetBytes(mdlBlock.MaterialNum)); for (var i = 0; i < 3; i++) { ms.Write(BitConverter.GetBytes(vertexDataOffsets[i])); } for (var i = 0; i < 3; i++) { ms.Write(BitConverter.GetBytes(indexDataOffsets[i])); } for (var i = 0; i < 3; i++) { ms.Write(BitConverter.GetBytes(vertexBufferSizes[i])); } for (var i = 0; i < 3; i++) { ms.Write(BitConverter.GetBytes(indexBufferSizes[i])); } ms.Write(new[] { mdlBlock.NumLods }); ms.Write(BitConverter.GetBytes(mdlBlock.IndexBufferStreamingEnabled)); ms.Write(BitConverter.GetBytes(mdlBlock.EdgeGeometryEnabled)); ms.Write(new byte[] { 0 }); }