def rogueParseOffsetTable(bs, tableAddr): bs.seek(snesLoRomPtrToFileOffset(tableAddr), NOESEEK_ABS) offsets = [] while not bs.checkEOF(): addr = bs.readUInt24() if addr >= 0xFF0000: break offsets.append(snesLoRomPtrToFileOffset(addr)) return offsets
def rogueReadTerminatedCompList(bs): offsets = [] while not bs.checkEOF(): addr = bs.readUInt24() if not addr: break offsets.append(snesLoRomPtrToFileOffset(addr)) return offsets
def __init__(self, bs): self.width = bs.readUShort() self.height = bs.readUShort() self.palOffset = snesLoRomPtrToFileOffset(bs.readUInt24()) self.c0 = rogueReadTerminatedCompList(bs) self.c1 = rogueReadTerminatedCompList(bs) self.c2 = rogueReadTerminatedCompList(bs) self.c3 = rogueReadTerminatedCompList(bs) self.c4 = rogueReadTerminatedCompList(bs) self.c5 = rogueReadTerminatedCompList(bs)
def rogueTestDump(binName, binData): for addr in TEST_DUMP_LIST: offset = snesLoRomPtrToFileOffset(addr) decompData = rapi.callExtensionMethod("ftrogue_decomp", binData[offset:], None, None) if decompData: name = os.path.splitext(binName)[0] + ".dump_%08x.bin" % addr print("Writing", name) with open(name, "wb") as f: f.write(decompData) return 0
def rogueBgDump(binName, binData): bs = NoeBitStream(binData) bgOffsets = rogueParseOffsetTable(bs, BG_TABLE_ADDRESS) print("Found", len(bgOffsets), "background offsets.") for bgIndex in range(0, len(bgOffsets)): bs.seek(bgOffsets[bgIndex], NOESEEK_ABS) bg = BgEntry(bs) bs.seek(bg.palOffset, NOESEEK_ABS) palData = bs.readBytes(512) lTable = bytearray(0x20000) charData = rogueDecompList(bg.c0, binData, None, lTable) dTable = rogueDecompList(bg.c2, binData) mapData = rogueDecompList(bg.c1, binData, None, None, lTable, dTable) mapLutData = rogueDecompList(bg.c3, binData, mapData, bytearray()) colData = rogueDecompList(bg.c4, binData) colIdxData = rogueDecompList(bg.c5, binData, None, bytearray()) if DUMP_RAW_BINARIES: rogueRawDump(charData, binName, "bg%03i.chardata.bin" % bgIndex) rogueRawDump(mapData, binName, "bg%03i.mapdata.bin" % bgIndex) rogueRawDump(mapLutData, binName, "bg%03i.maplutdata.bin" % bgIndex) rogueRawDump(colData, binName, "bg%03i.coldata.bin" % bgIndex) #the game converts the indices to word offsets into collision data on load, but we just leave it as-is rogueRawDump(colIdxData, binName, "bg%03i.colidxdata.bin" % bgIndex) drawFlags = 2 blockWidth = bg.width blockHeight = bg.height tileWidth = blockWidth * 4 tileHeight = blockHeight * 4 texWidth = tileWidth * 8 texHeight = tileHeight * 8 mapBs = NoeBitStream(mapData) mapLutBs = NoeBitStream(mapLutData) mapLutBs.seek(len(mapLutData) - 4) extraTileSize = mapLutBs.readInt() mapLutBs.seek( len(mapLutData) - extraTileSize - blockWidth * blockHeight * 2) extraTileBs = NoeBitStream(mapLutData[len(mapLutData) - extraTileSize:]) rgba = bytearray(texWidth * texHeight * 4) for blockY in range(0, blockHeight): tileY = blockY * 4 for blockX in range(0, blockWidth): tileX = blockX * 4 blockOffset = mapLutBs.readUShort() if blockOffset & 0x8000: extraTileBs.seek(blockOffset & 0x7FFF, NOESEEK_ABS) useBs = extraTileBs else: mapBs.seek(blockOffset, NOESEEK_ABS) useBs = mapBs for subTileY in range(0, 4): pixelY = (tileY + subTileY) * 8 for subTileX in range(0, 4): pixelX = (tileX + subTileX) * 8 tileData = useBs.readUShort() rapi.callExtensionMethod("snes_m1b0_drawtile_rgba", rgba, texWidth, texHeight, pixelX, pixelY, tileData, charData, palData, drawFlags) name = os.path.splitext(binName)[0] + ".bg%03i.png" % bgIndex print("Writing", name) noesis.saveImageRGBA( name, NoeTexture(name, texWidth, texHeight, rgba, noesis.NOESISTEX_RGBA32)) if DRAW_COLLISION: rgba = bytearray(texWidth * texHeight * 4) rapi.callExtensionMethod( "ftrogue_drawcol", rgba, binData, colData, colIdxData, blockWidth, blockHeight, snesLoRomPtrToFileOffset(COLLISION_LUT_ADDRESS), snesLoRomPtrToFileOffset(COLLISION_TILES_ADDRESS), 0) name = os.path.splitext(binName)[0] + ".bg%03i.col.png" % bgIndex print("Writing", name) noesis.saveImageRGBA( name, NoeTexture(name, texWidth, texHeight, rgba, noesis.NOESISTEX_RGBA32)) return 0