private void packPNK(FileStream data, BinaryReader input, loadedBCH bch) { uint veryBase = (uint)data.Position; input.ReadUInt32(); uint[] sectionsCnt = new uint[5]; for (int i = 0; i < 5; i++) { sectionsCnt[i] = input.ReadUInt32(); //Count for each section on the file (total 5) } uint baseAddr = (uint)data.Position; for (int sect = 0; sect < 5; sect++) { uint count = sectionsCnt[sect]; for (int i = 0; i < count; i++) { data.Seek(baseAddr + i * 4, SeekOrigin.Begin); data.Seek(input.ReadUInt32() + veryBase, SeekOrigin.Begin); byte nameStrLen = input.ReadByte(); string name = IOUtils.readStringWithLength(input, nameStrLen); uint descAddress = input.ReadUInt32() + veryBase; data.Seek(descAddress, SeekOrigin.Begin); if (sect == 1) { bch.mips[0].textures.Add(loadPKM(data, input)); } } baseAddr += count * 4; } }
private bool open(string fileName) { using (FileStream data = new FileStream(fileName, FileMode.Open)) { BinaryReader input = new BinaryReader(data); string magic = IOUtils.readString(input, 0); if (magic != "BCH") return false; currentFile = fileName; data.Seek(4, SeekOrigin.Current); byte backwardCompatibility = input.ReadByte(); byte forwardCompatibility = input.ReadByte(); ushort version = input.ReadUInt16(); uint mainHeaderOffset = input.ReadUInt32(); uint stringTableOffset = input.ReadUInt32(); uint gpuCommandsOffset = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataExtendedOffset = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableOffset = input.ReadUInt32(); uint mainHeaderLength = input.ReadUInt32(); uint stringTableLength = input.ReadUInt32(); uint gpuCommandsLength = input.ReadUInt32(); uint dataLength = input.ReadUInt32(); uint dataExtendedLength = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableLength = input.ReadUInt32(); data.Seek(mainHeaderOffset, SeekOrigin.Begin); uint modelsPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint modelsPointerTableEntries = input.ReadUInt32(); data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin); uint texturesPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint texturesPointerTableEntries = input.ReadUInt32(); bch = new loadedBCH(); //Textures for (int index = 0; index < texturesPointerTableEntries; index++) { data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; tex.gpuCommandsWordCount = input.ReadUInt32(); data.Seek(0x14, SeekOrigin.Current); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset + stringTableOffset); data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin); PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount); tex.offset = textureCommands.getTexUnit0Address() + dataOffset; RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format(); Size textureSize = textureCommands.getTexUnit0Size(); switch (fmt) { case RenderBase.OTextureFormat.rgba8: tex.length = (textureSize.Width * textureSize.Height) * 4; break; case RenderBase.OTextureFormat.rgb8: tex.length = (textureSize.Width * textureSize.Height) * 3; break; case RenderBase.OTextureFormat.rgba5551: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgb565: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgba4: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.la8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.hilo8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.l8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.a8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.la4: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.l4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.a4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1a4: tex.length = textureSize.Width * textureSize.Height; break; default: throw new Exception("OBCHTextureReplacer: Invalid texture format on BCH!"); } while ((tex.length & 0x7f) > 0) tex.length++; data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[textureSize.Width * textureSize.Height * 4]; input.Read(buffer, 0, buffer.Length); Bitmap texture = TextureCodec.decode( buffer, textureSize.Width, textureSize.Height, fmt); tex.texture = new RenderBase.OTexture(texture, textureName); bch.textures.Add(tex); } //Materials for (int mdlIndex = 0; mdlIndex < modelsPointerTableEntries; mdlIndex++) { data.Seek(modelsPointerTableOffset + (mdlIndex * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); data.Seek(0x34, SeekOrigin.Current); uint materialsTableOffset = input.ReadUInt32() + mainHeaderOffset; uint materialsTableEntries = input.ReadUInt32(); for (int index = 0; index < materialsTableEntries; index++) { if (backwardCompatibility < 0x21) data.Seek(materialsTableOffset + (index * 0x58), SeekOrigin.Begin); else data.Seek(materialsTableOffset + (index * 0x2c), SeekOrigin.Begin); loadedMaterial mat; data.Seek(0x10, SeekOrigin.Current); mat.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; mat.gpuCommandsWordCount = input.ReadUInt32(); if (backwardCompatibility < 0x21) data.Seek(0x30, SeekOrigin.Current); else data.Seek(4, SeekOrigin.Current); uint texture0Offset = input.ReadUInt32() + stringTableOffset; uint texture1Offset = input.ReadUInt32() + stringTableOffset; uint texture2Offset = input.ReadUInt32() + stringTableOffset; mat.texture0 = IOUtils.readString(input, texture0Offset); mat.texture1 = IOUtils.readString(input, texture1Offset); mat.texture2 = IOUtils.readString(input, texture2Offset); bch.materials.Add(mat); } } bch.mainHeaderOffset = mainHeaderOffset; bch.gpuCommandsOffset = gpuCommandsOffset; bch.dataOffset = dataOffset; bch.relocationTableOffset = relocationTableOffset; bch.relocationTableLength = relocationTableLength; } updateTexturesList(); return true; }
private bool open(string fileName) { using (FileStream data = new FileStream(fileName, FileMode.Open)) { BinaryReader input = new BinaryReader(data); if (peek(input) == 0x00010000) { currentFile = fileName; bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); packPNK(data, input, bch); } if (peek(input) == 0x15041213) { currentFile = fileName; bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); bch.mips[0].textures.Add(loadPKM(data, input)); } string magic2b = getMagic(input, 2); if (magic2b == "PC" || magic2b == "CM") { bch = new loadedBCH(); bch.isBCH = false; currentFile = fileName; data.Seek(2, SeekOrigin.Current); ushort numEntrys = input.ReadUInt16(); for (int i = 0; i < (int)numEntrys; i++) { data.Seek(4 + (i * 4), SeekOrigin.Begin); uint offset = input.ReadUInt32(); uint end = input.ReadUInt32(); uint lenth = end - offset; long rtn = data.Position; data.Seek(offset, SeekOrigin.Begin); if (magic2b == "CM" & i == 0) { packPNK(data, input, bch); } if (lenth > 4) { if (magic2b == "PC") { if (peek(input) == 0x15041213) { bch.mips[0].textures.Add(loadPKM(data, input)); } } } } } string magic = IOUtils.readString(input, 0); if (magic == "BCH") { currentFile = fileName; data.Seek(4, SeekOrigin.Current); byte backwardCompatibility = input.ReadByte(); byte forwardCompatibility = input.ReadByte(); ushort version = input.ReadUInt16(); uint mainHeaderOffset = input.ReadUInt32(); uint stringTableOffset = input.ReadUInt32(); uint gpuCommandsOffset = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataExtendedOffset = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableOffset = input.ReadUInt32(); uint mainHeaderLength = input.ReadUInt32(); uint stringTableLength = input.ReadUInt32(); uint gpuCommandsLength = input.ReadUInt32(); uint dataLength = input.ReadUInt32(); uint dataExtendedLength = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableLength = input.ReadUInt32(); data.Seek(mainHeaderOffset, SeekOrigin.Begin); uint modelsPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint modelsPointerTableEntries = input.ReadUInt32(); data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin); uint texturesPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint texturesPointerTableEntries = input.ReadUInt32(); bch = new loadedBCH(); bch.isBCH = true; for (int i = 0; i < 6; i++) { bch.mips.Add(new MIPlayer()); } MipSelect.Enabled = true; //Textures for (int index = 0; index < texturesPointerTableEntries; index++) { data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; tex.gpuCommandsWordCount = input.ReadUInt32(); data.Seek(0x14, SeekOrigin.Current); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset + stringTableOffset); data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin); PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount); tex.offset = textureCommands.getTexUnit0Address() + dataOffset; RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format(); Size textureSize = textureCommands.getTexUnit0Size(); tex.type = fmt; int OGW = textureSize.Width; int OGH = textureSize.Height; for (int i = 0; i < 6; i++) { textureSize.Width = OGW / Convert.ToInt32(Math.Pow(2, i)); textureSize.Height = OGH / Convert.ToInt32(Math.Pow(2, i)); tex.length = returnSize(fmt, textureSize.Width, textureSize.Height); if (textureSize.Height >= 8 & textureSize.Width >= 8) { data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[tex.length]; //data.Seek(tex.length + returnSize(fmt, textureSize.Width / 2, textureSize.Height / 2), SeekOrigin.Current); tex.offset = (uint)data.Position; input.Read(buffer, 0, tex.length); Bitmap texture = TextureCodec.decode( buffer, textureSize.Width, textureSize.Height, fmt); tex.texture = new RenderBase.OTexture(texture, textureName); bch.mips[i].textures.Add(tex); tex.offset = (uint)data.Position; } } } bch.mainHeaderOffset = mainHeaderOffset; bch.gpuCommandsOffset = gpuCommandsOffset; bch.dataOffset = dataOffset; bch.relocationTableOffset = relocationTableOffset; bch.relocationTableLength = relocationTableLength; } else if (magic == "CTPK\u0001") { currentFile = fileName; data.Seek(4, SeekOrigin.Current); ushort ver = input.ReadUInt16(); ushort numTexture = input.ReadUInt16(); uint TextureSectionOffset = input.ReadUInt32(); uint TextureSectionSize = input.ReadUInt32(); uint HashSectionOffset = input.ReadUInt32(); uint TextureInfoSection = input.ReadUInt32(); bch = new loadedBCH(); bch.isBCH = false; bch.mips.Add(new MIPlayer()); for (int i = 0; i < numTexture; i++) { data.Seek(0x20 * (i + 1), SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = (uint)(0x20 * (i + 1)); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset); tex.length = input.ReadInt32(); tex.offset = input.ReadUInt32() + TextureSectionOffset; tex.type = (RenderBase.OTextureFormat)input.ReadUInt32(); ushort Width = input.ReadUInt16(); ushort Height = input.ReadUInt16(); data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[tex.length]; input.Read(buffer, 0, buffer.Length); Bitmap texture = TextureCodec.decode( buffer, Width, Height, tex.type); tex.texture = new RenderBase.OTexture(texture, textureName); tex.gpuCommandsWordCount = 0; bch.mips[0].textures.Add(tex); } } } updateTexturesList(); return(true); }
private bool open(string fileName) { using (FileStream data = new FileStream(fileName, FileMode.Open)) { BinaryReader input = new BinaryReader(data); string magic = IOUtils.readString(input, 0); if (magic != "BCH") { return(false); } currentFile = fileName; data.Seek(4, SeekOrigin.Current); byte backwardCompatibility = input.ReadByte(); byte forwardCompatibility = input.ReadByte(); ushort version = input.ReadUInt16(); uint mainHeaderOffset = input.ReadUInt32(); uint stringTableOffset = input.ReadUInt32(); uint gpuCommandsOffset = input.ReadUInt32(); uint dataOffset = input.ReadUInt32(); uint dataExtendedOffset = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableOffset = input.ReadUInt32(); uint mainHeaderLength = input.ReadUInt32(); uint stringTableLength = input.ReadUInt32(); uint gpuCommandsLength = input.ReadUInt32(); uint dataLength = input.ReadUInt32(); uint dataExtendedLength = backwardCompatibility > 0x20 ? input.ReadUInt32() : 0; uint relocationTableLength = input.ReadUInt32(); data.Seek(mainHeaderOffset, SeekOrigin.Begin); uint modelsPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint modelsPointerTableEntries = input.ReadUInt32(); data.Seek(mainHeaderOffset + 0x24, SeekOrigin.Begin); uint texturesPointerTableOffset = input.ReadUInt32() + mainHeaderOffset; uint texturesPointerTableEntries = input.ReadUInt32(); bch = new loadedBCH(); //Textures for (int index = 0; index < texturesPointerTableEntries; index++) { data.Seek(texturesPointerTableOffset + (index * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); loadedTexture tex; tex.modified = false; tex.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; tex.gpuCommandsWordCount = input.ReadUInt32(); data.Seek(0x14, SeekOrigin.Current); uint textureNameOffset = input.ReadUInt32(); string textureName = IOUtils.readString(input, textureNameOffset + stringTableOffset); data.Seek(tex.gpuCommandsOffset, SeekOrigin.Begin); PICACommandReader textureCommands = new PICACommandReader(data, tex.gpuCommandsWordCount); tex.offset = textureCommands.getTexUnit0Address() + dataOffset; RenderBase.OTextureFormat fmt = textureCommands.getTexUnit0Format(); Size textureSize = textureCommands.getTexUnit0Size(); switch (fmt) { case RenderBase.OTextureFormat.rgba8: tex.length = (textureSize.Width * textureSize.Height) * 4; break; case RenderBase.OTextureFormat.rgb8: tex.length = (textureSize.Width * textureSize.Height) * 3; break; case RenderBase.OTextureFormat.rgba5551: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgb565: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.rgba4: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.la8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.hilo8: tex.length = (textureSize.Width * textureSize.Height) * 2; break; case RenderBase.OTextureFormat.l8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.a8: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.la4: tex.length = textureSize.Width * textureSize.Height; break; case RenderBase.OTextureFormat.l4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.a4: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1: tex.length = (textureSize.Width * textureSize.Height) >> 1; break; case RenderBase.OTextureFormat.etc1a4: tex.length = textureSize.Width * textureSize.Height; break; default: throw new Exception("OBCHTextureReplacer: Invalid texture format on BCH!"); } while ((tex.length & 0x7f) > 0) { tex.length++; } data.Seek(tex.offset, SeekOrigin.Begin); byte[] buffer = new byte[textureSize.Width * textureSize.Height * 4]; input.Read(buffer, 0, buffer.Length); Bitmap texture = TextureCodec.decode( buffer, textureSize.Width, textureSize.Height, fmt); tex.texture = new RenderBase.OTexture(texture, textureName); bch.textures.Add(tex); } //Materials for (int mdlIndex = 0; mdlIndex < modelsPointerTableEntries; mdlIndex++) { data.Seek(modelsPointerTableOffset + (mdlIndex * 4), SeekOrigin.Begin); data.Seek(input.ReadUInt32() + mainHeaderOffset, SeekOrigin.Begin); data.Seek(0x34, SeekOrigin.Current); uint materialsTableOffset = input.ReadUInt32() + mainHeaderOffset; uint materialsTableEntries = input.ReadUInt32(); for (int index = 0; index < materialsTableEntries; index++) { if (backwardCompatibility < 0x21) { data.Seek(materialsTableOffset + (index * 0x58), SeekOrigin.Begin); } else { data.Seek(materialsTableOffset + (index * 0x2c), SeekOrigin.Begin); } loadedMaterial mat; data.Seek(0x10, SeekOrigin.Current); mat.gpuCommandsOffset = input.ReadUInt32() + gpuCommandsOffset; mat.gpuCommandsWordCount = input.ReadUInt32(); if (backwardCompatibility < 0x21) { data.Seek(0x30, SeekOrigin.Current); } else { data.Seek(4, SeekOrigin.Current); } uint texture0Offset = input.ReadUInt32() + stringTableOffset; uint texture1Offset = input.ReadUInt32() + stringTableOffset; uint texture2Offset = input.ReadUInt32() + stringTableOffset; mat.texture0 = IOUtils.readString(input, texture0Offset); mat.texture1 = IOUtils.readString(input, texture1Offset); mat.texture2 = IOUtils.readString(input, texture2Offset); bch.materials.Add(mat); } } bch.mainHeaderOffset = mainHeaderOffset; bch.gpuCommandsOffset = gpuCommandsOffset; bch.dataOffset = dataOffset; bch.relocationTableOffset = relocationTableOffset; bch.relocationTableLength = relocationTableLength; } updateTexturesList(); return(true); }