/// <summary> /// Reads a texture with the specified characteristics from a binary stream. /// </summary> internal void LoadTextureData(EndianBinaryReader input, GcGame game, GcTextureFormat format, int totalLevelSize, int width, int height, int levelCount) { if (!SupportedTextureFormats.Contains(format)) { throw new InvalidTplFileException("Unsupported texture format."); } int remainingSize = totalLevelSize; this.format = format; this.width = width; this.height = height; for (int level = 0; level < levelCount; level++) { byte[] levelData = new byte[CalculateSizeOfLevel(level)]; // Try to read as many bytes as we can into the level data buffer, // but we may not be able to due to bugs in F-Zero GX / SMB2. int sizeToRead = Math.Min(levelData.Length, remainingSize); input.Read(levelData, 0, sizeToRead); remainingSize -= sizeToRead; encodedLevelData.Add(levelData); } if (TplVersionDetails.VerifyCorrectSize(game) && SizeOfTextureData(game) != totalLevelSize) { throw new InvalidTplFileException("Texture size doesn't match expected size."); } }
/// 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); }