def get_deswizzled_data(flim): if flim.format == 0x01: format_ = 61 elif flim.format == 0x02: format_ = 112 elif flim.format == 0x07: format_ = 49 elif flim.format == 0x08: format_ = 85 elif flim.format == 0x0a: format_ = 86 elif flim.format == 0x0b: format_ = 115 elif flim.format in [0x1a, 0x41a]: format_ = 28 elif flim.format == 0x19: format_ = 24 elif flim.format in [0x31, 0x431]: format_ = flim.format_ elif flim.format in [0x32, 0x432]: format_ = "BC2" elif flim.format in [0x33, 0x433]: format_ = "BC3" elif flim.format == 0x34: format_ = "BC4U" elif flim.format == 0x35: format_ = "BC5U" result = addrlib.deswizzle(flim.width, flim.height, 1, flim.format, 0, 1, flim.surfOut.tileMode, flim.swizzle, flim.pitch, flim.surfOut.bpp, 0, 0, flim.data) if flim.format in BCn_formats: size = ((flim.width + 3) >> 2) * ((flim.height + 3) >> 2) * ( addrlib.surfaceGetBitsPerPixel(flim.format) >> 3) else: size = flim.width * flim.height * ( addrlib.surfaceGetBitsPerPixel(flim.format) >> 3) result = result[:size] hdr = dds.generateHeader(1, flim.width, flim.height, format_, flim.compSel, size, flim.format in BCn_formats) return hdr, result
def get_deswizzled_data(flim): result = addrlib.deswizzle(flim.width, flim.height, 1, flim.format, 0, 1, flim.surfOut.tileMode, flim.swizzle, flim.pitch, flim.surfOut.bpp, 0, 0, flim.data) if flim.format in BCn_formats: size = ((flim.width + 3) >> 2) * ((flim.height + 3) >> 2) * ( addrlib.surfaceGetBitsPerPixel(flim.format) >> 3) else: size = flim.width * flim.height * ( addrlib.surfaceGetBitsPerPixel(flim.format) >> 3) return result[:size]
def writeGFD(f, tileMode, swizzle_, SRGB, n, pos, numImages): width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS(f, SRGB) if 0 in [width, dataSize] and data == []: print("") if n != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if format_ not in formats: print("") print("Unsupported DDS format!") print("") if n != (numImages - 1): print("") print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if numMips > 13: print("") print("Invalid number of mipmaps for " + f) print("") if n != (numImages - 1): print("") print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) numMips += 1 bpp = addrlib.surfaceGetBitsPerPixel(format_) >> 3 surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) alignment = surfOut.baseAlign imageSize = surfOut.surfSize pitch = surfOut.pitch if surfOut.depth != 1: print("") print("Unsupported depth!") print("") if n != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if tileMode in [1, 2, 3, 16]: s = swizzle_ << 8 else: s = 0xd0000 | swizzle_ << 8 if numMips > 1: print("") print("Processing " + str(numMips - 1) + " mipmap(s):") if format_ in BCn_formats: blkWidth, blkHeight = 4, 4 else: blkWidth, blkHeight = 1, 1 swizzled_data = [] mipSize = 0 mipOffsets = [] for mipLevel in range(numMips): offset, size = getCurrentMipOffset_Size(width, height, blkWidth, blkHeight, bpp, mipLevel) data_ = data[offset:offset + size] width_ = max(1, width >> mipLevel) height_ = max(1, height >> mipLevel) if mipLevel: print(str(mipLevel) + ": " + str(width_) + "x" + str(height_)) surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, mipLevel) if mipLevel == 1: mipOffsets.append(imageSize) else: mipOffsets.append(mipSize) data_ += b'\0' * (surfOut.surfSize - size) dataAlignBytes = b'\0' * (roundUp(mipSize, surfOut.baseAlign) - mipSize) if mipLevel: mipSize += surfOut.surfSize + len(dataAlignBytes) swizzled_data.append(bytearray(dataAlignBytes) + addrlib.swizzle( width_, height_, surfOut.height, format_, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, data_)) compSels = ["R", "G", "B", "A", "0", "1"] print("") print("// ----- GX2Surface Info ----- ") print(" dim = 1") print(" width = " + str(width)) print(" height = " + str(height)) print(" depth = 1") print(" numMips = " + str(numMips)) print(" format = " + formats[format_]) print(" aa = 0") print(" use = 1") print(" imageSize = " + str(imageSize)) print(" mipSize = " + str(mipSize)) print(" tileMode = " + str(tileMode)) print(" swizzle = " + str(s) + ", " + hex(s)) print(" alignment = " + str(alignment)) print(" pitch = " + str(pitch)) print("") print(" GX2 Component Selector:") print(" Red Channel: " + str(compSels[compSel[0]])) print(" Green Channel: " + str(compSels[compSel[1]])) print(" Blue Channel: " + str(compSels[compSel[2]])) print(" Alpha Channel: " + str(compSels[compSel[3]])) print("") print(" bits per pixel = " + str(bpp << 3)) print(" bytes per pixel = " + str(bpp)) print(" realSize = " + str(divRoundUp(width, blkWidth) * divRoundUp(height, blkHeight) * bpp)) if format_ == 1: if compSel not in [[0, 0, 0, 5], [0, 5, 5, 5]]: warn_color() compSel = [0, 5, 5, 5] elif format_ in [2, 7]: if compSel not in [[0, 0, 0, 1], [0, 5, 5, 1]]: warn_color() compSel = [0, 5, 5, 1] elif format_ == 8: if compSel not in [[0, 1, 2, 5], [2, 1, 0, 5]]: warn_color() if compSel[0] == 2 and compSel[2] == 0: swizzled_data = [dds.form_conv.swapRB_16bpp(data, 'rgb565') for data in swizzled_data] compSel = [0, 1, 2, 5] elif format_ in [0xa, 0xb]: if compSel not in [[0, 1, 2, 3], [2, 1, 0, 3]]: warn_color() if compSel[0] == 2 and compSel[2] == 0: if format_ == 0xb: swizzled_data = [dds.form_conv.swapRB_16bpp(data, 'rgba4') for data in swizzled_data] else: swizzled_data = [dds.form_conv.swapRB_16bpp(data, 'rgb5a1') for data in swizzled_data] compSel = [0, 1, 2, 3] elif format_ in [0x1a, 0x41a, 0x19]: if compSel not in [[0, 1, 2, 3], [2, 1, 0, 3], [0, 1, 2, 5], [2, 1, 0, 5]]: warn_color() if compSel[0] == 2 and compSel[2] == 0: if format_ == 0x19: swizzled_data = [dds.form_conv.swapRB_32bpp(data, 'bgr10a2') for data in swizzled_data] else: swizzled_data = [dds.form_conv.swapRB_32bpp(data, 'rgba8') for data in swizzled_data] compSel = [0, 1, 2, 3] block_head_struct = GFDBlockHeader() gx2surf_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xb, 0x9c, 0, 0) gx2surf_struct = GX2Surface() gx2surf = gx2surf_struct.pack(1, width, height, 1, numMips, format_, 0, 1, imageSize, 0, mipSize, 0, tileMode, s, alignment, pitch) image_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xc, imageSize, 0, 0) mip_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xd, mipSize, 0, 0) output = gx2surf_blk_head + gx2surf if numMips > 1: i = 0 for offset in mipOffsets: output += offset.to_bytes(4, 'big') i += 1 for z in range(14 - i): output += 0 .to_bytes(4, 'big') else: output += b'\0' * 56 output += numMips.to_bytes(4, 'big') output += b'\0' * 4 output += 1 .to_bytes(4, 'big') for value in compSel: output += value.to_bytes(1, 'big') if format_ in BCn_formats: output += makeRegsBytearray(width, height, numMips, format_, tileMode, pitch * 4, compSel) else: output += makeRegsBytearray(width, height, numMips, format_, tileMode, pitch, compSel) alignSize = getAlignBlockSize(pos + len(output) + 32, alignment) align_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, alignSize, 0, 0) output += align_blk_head output += b'\0' * alignSize output += image_blk_head output += swizzled_data[0] if numMips > 1: mipAlignSize = getAlignBlockSize(pos + len(output) + 32, alignment) mipAlign_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, mipAlignSize, 0, 0) output += mipAlign_blk_head output += b'\0' * mipAlignSize output += mip_blk_head for i in range(1, len(swizzled_data)): output += swizzled_data[i] return output
def readGFD(f): gfd = GFDData() header = GFDHeader() header.data(f, 0) if header.magic != b'Gfx2': raise ValueError("Invalid file header!") if header.majorVersion == 6: surfBlkType = 0x0A dataBlkType = 0x0B mipBlkType = 0x0C elif header.majorVersion == 7: surfBlkType = 0x0B dataBlkType = 0x0C mipBlkType = 0x0D else: raise ValueError("Unsupported GTX version!") if header.gpuVersion != 2: raise ValueError("Unsupported GPU version!") gfd.majorVersion = header.majorVersion pos = header.size blockB = False blockC = False images = 0 imgInfo = 0 gfd.dim = [] gfd.width = [] gfd.height = [] gfd.depth = [] gfd.numMips = [] gfd.format = [] gfd.aa = [] gfd.use = [] gfd.imageSize = [] gfd.imagePtr = [] gfd.mipSize = [] gfd.mipPtr = [] gfd.tileMode = [] gfd.swizzle = [] gfd.alignment = [] gfd.pitch = [] gfd.compSel = [] gfd.bpp = [] gfd.realSize = [] gfd.dataSize = [] gfd.data = [] gfd.mipOffsets = [] gfd.mipData = {} while pos < len(f): # Loop through the entire file, stop if reached the end of the file. block = GFDBlockHeader() block.data(f, pos) if block.magic != b'BLK{': raise ValueError("Invalid block header!") pos += block.size if block.type_ == surfBlkType: imgInfo += 1 blockB = True surface = GX2Surface() surface.data(f, pos) pos += surface.size if surface.numMips > 14: print("") print("Invalid number of mipmaps for image " + str(imgInfo - 1)) print("") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) mipOffsets = [] for i in range(13): mipOffsets.append( f[i * 4 + pos] << 24 | f[i * 4 + 1 + pos] << 16 | f[i * 4 + 2 + pos] << 8 | f[i * 4 + 3 + pos]) gfd.mipOffsets.append(mipOffsets) pos += 68 if surface.format_ in [0xa, 0xb, 0x19, 0x1a, 0x41a] or surface.format_ in BCn_formats: compSel = [0, 1, 2, 3] elif surface.format_ in [2, 7]: compSel = [0, 5, 5, 1] elif surface.format_ == 1: compSel = [0, 5, 5, 5] elif surface.format_ == 8: compSel = [0, 1, 2, 5] else: compSel = [] for i in range(4): comp = f[pos + i] if comp == 4: # Sorry, but this is unsupported. comp = i compSel.append(comp) pos += 24 gfd.dim.append(surface.dim) gfd.width.append(surface.width) gfd.height.append(surface.height) gfd.depth.append(surface.depth) gfd.numMips.append(surface.numMips) gfd.format.append(surface.format_) gfd.aa.append(surface.aa) gfd.use.append(surface.use) gfd.imageSize.append(surface.imageSize) gfd.imagePtr.append(surface.imagePtr) gfd.mipSize.append(surface.mipSize) gfd.mipPtr.append(surface.mipPtr) gfd.tileMode.append(surface.tileMode) gfd.swizzle.append(surface.swizzle) gfd.alignment.append(surface.alignment) gfd.pitch.append(surface.pitch) gfd.compSel.append(compSel) bpp = roundUp(addrlib.surfaceGetBitsPerPixel(surface.format_), 8) gfd.bpp.append(bpp) if surface.format_ in BCn_formats: gfd.realSize.append(divRoundUp(surface.width, 4) * divRoundUp(surface.height, 4) * (bpp // 8)) else: gfd.realSize.append(surface.width * surface.height * (bpp // 8)) elif block.type_ == dataBlkType: images += 1 blockC = True gfd.dataSize.append(block.dataSize) gfd.data.append(f[pos:pos + block.dataSize]) pos += block.dataSize elif block.type_ == mipBlkType: gfd.mipData[images - 1] = f[pos:pos + block.dataSize] pos += block.dataSize else: pos += block.dataSize if images != imgInfo: print("") print("GX2 Surface and Image data count mismatch.") print("") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if blockB: if not blockC: print("") print("GX2 Surface was found but no Image data was found.") print("") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if not blockB: if not blockC: print("") print("No Image was found in this file.") print("") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) elif blockC: print("") print("Image data was found but no GX2 Surface was found.") print("") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) gfd.numImages = images return gfd
def readFLIM(f): flim = FLIMData() pos = len(f) - 0x28 if f[pos + 4:pos + 6] == b'\xFF\xFE': bom = '<' elif f[pos + 4:pos + 6] == b'\xFE\xFF': bom = '>' header = FLIMHeader(bom) header.data(f, pos) if header.magic != b'FLIM': raise ValueError("Invalid file header!") pos += header.size info = imagHeader(bom) info.data(f, pos) if info.magic != b'imag': raise ValueError("Invalid imag header!") flim.width = info.width flim.height = info.height if info.format_ == 0x00: flim.format = 0x01 flim.compSel = [0, 0, 0, 5] elif info.format_ == 0x01: flim.format = 0x01 flim.compSel = [5, 5, 5, 0] elif info.format_ == 0x02: flim.format = 0x02 flim.compSel = [0, 0, 0, 1] elif info.format_ == 0x03: flim.format = 0x07 flim.compSel = [0, 0, 0, 1] elif info.format_ in [0x05, 0x19]: flim.format = 0x08 flim.compSel = [2, 1, 0, 5] elif info.format_ == 0x06: flim.format = 0x1a flim.compSel = [0, 1, 2, 5] elif info.format_ == 0x07: flim.format = 0x0a flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x08: flim.format = 0x0b flim.compSel = [2, 1, 0, 3] elif info.format_ == 0x09: flim.format = 0x1a flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x0a: flim.format = 0x31 flim.format_ = "ETC1" flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x0C: flim.format = 0x31 flim.format_ = "BC1" flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x0D: flim.format = 0x32 flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x0E: flim.format = 0x33 flim.compSel = [0, 1, 2, 3] elif info.format_ in [0x0F, 0x10]: flim.format = 0x34 flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x11: flim.format = 0x35 flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x14: flim.format = 0x41a flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x15: flim.format = 0x431 flim.format_ = "BC1" flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x16: flim.format = 0x432 flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x17: flim.format = 0x433 flim.compSel = [0, 1, 2, 3] elif info.format_ == 0x18: flim.format = 0x19 flim.compSel = [0, 1, 2, 3] else: print("") print("Unsupported texture format: " + hex(info.format_)) print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) flim.imageSize = info.imageSize # Calculate swizzle and tileMode flim.swizzle, flim.tileMode = computeSwizzleTileMode(info.swizzle_tileMode) if not 1 <= flim.tileMode <= 16: print("") print("Invalid tileMode!") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) flim.alignment = info.alignment surfOut = addrlib.getSurfaceInfo(flim.format, flim.width, flim.height, 1, 1, flim.tileMode, 0, 0) tilingDepth = surfOut.depth if surfOut.tileMode == 3: tilingDepth //= 4 if tilingDepth != 1: print("") print("Unsupported depth!") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) flim.pitch = surfOut.pitch flim.data = f[:info.imageSize] flim.surfOut = surfOut if flim.format in BCn_formats: flim.realSize = ((flim.width + 3) >> 2) * ((flim.height + 3) >> 2) * ( addrlib.surfaceGetBitsPerPixel(flim.format) // 8) else: flim.realSize = flim.width * flim.height * ( addrlib.surfaceGetBitsPerPixel(flim.format) // 8) return flim
def main(): print("BFLIM Extractor v2.3") print("(C) 2016-2019 AboodXD") input_ = sys.argv[-1] if not (input_.endswith('.bflim') or input_.endswith('.dds')): printInfo() toFLIM = False if input_.endswith('.dds'): toFLIM = True if "-o" in sys.argv: output_ = sys.argv[sys.argv.index("-o") + 1] else: output_ = os.path.splitext(input_)[0] + (".bflim" if toFLIM else ".dds") print("") print('Converting: ' + input_) if toFLIM: if "-tileMode" in sys.argv: tileMode = int(sys.argv[sys.argv.index("-tileMode") + 1], 0) else: tileMode = 0 if "-swizzle" in sys.argv: swizzle = int(sys.argv[sys.argv.index("-swizzle") + 1], 0) else: swizzle = 0 if "-SRGB" in sys.argv: SRGB = int(sys.argv[sys.argv.index("-SRGB") + 1], 0) else: SRGB = 0 if SRGB > 1 or not 0 <= tileMode <= 16 or not 0 <= swizzle <= 7: printInfo() data = writeFLIM(input_, tileMode, swizzle, SRGB) with open(output_, "wb+") as output: output.write(data) else: with open(input_, "rb") as inf: inb = inf.read() flim = readFLIM(inb) print("") print(" width = " + str(flim.width)) print(" height = " + str(flim.height)) if flim.format in formats: print(" format = " + formats[flim.format]) else: print(" format = " + hex(flim.format)) print(" imageSize = " + str(flim.imageSize)) print(" tileMode = " + str(flim.tileMode)) print(" swizzle = " + str(flim.swizzle) + ", " + hex(flim.swizzle)) print(" alignment = " + str(flim.alignment)) print(" pitch = " + str(flim.pitch)) bpp = addrlib.surfaceGetBitsPerPixel(flim.format) print("") print(" bits per pixel = " + str(bpp)) print(" bytes per pixel = " + str(bpp // 8)) print(" realSize = " + str(flim.realSize)) hdr, data = get_deswizzled_data(flim) with open(output_, "wb+") as output: output.write(hdr) output.write(data) print('') print('Finished converting: ' + output_)
def writeFLIM(f, tileMode, swizzle_, SRGB): width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS( f, SRGB) if 0 in [width, dataSize] and data == []: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if format_ not in formats: print("") print("Unsupported DDS format!") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) data = data[:dataSize] if format_ == 0xb: data = dds.form_conv.rgba4_to_argb4(data) if not tileMode: tileMode = addrlib.getDefaultGX2TileMode(1, width, height, 1, format_, 0, 1) bpp = addrlib.surfaceGetBitsPerPixel(format_) >> 3 surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) alignment = surfOut.baseAlign padSize = surfOut.surfSize - dataSize data += padSize * b"\x00" tilingDepth = surfOut.depth if surfOut.tileMode == 3: tilingDepth //= 4 if tilingDepth != 1: print("") print("Unsupported depth!") print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) swizzle_tileMode = computeSwizzleTileMode((swizzle_, tileMode)) s = swizzle_ << 8 if tileMode not in [1, 2, 3, 16]: s |= 0xd0000 print("") print(" width = " + str(width)) print(" height = " + str(height)) print(" format = " + formats[format_]) print(" imageSize = " + str(len(data))) print(" tileMode = " + str(tileMode)) print(" swizzle = " + str(s) + ", " + hex(s)) print(" alignment = " + str(alignment)) print(" pitch = " + str(surfOut.pitch)) print("") print(" bits per pixel = " + str(bpp << 3)) print(" bytes per pixel = " + str(bpp)) print(" realSize = " + str(dataSize)) swizzled_data = addrlib.swizzle(width, height, 1, format_, 0, 1, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, 0, 0, data) if format_ == 1: if compSel[3] == 0: format_ = 1 else: format_ = 0 elif format_ == 0x1a: if 5 in compSel: format_ = 6 else: format_ = 9 elif format_ == 0x31: if fourcc == b'ETC1': format_ = 0xa else: format_ = 0xc else: fmt = { 2: 2, 7: 3, 8: 5, 0xa: 7, 0xb: 8, 0x32: 0xd, 0x33: 0xe, 0x34: 0x10, 0x35: 0x11, 0x41a: 0x14, 0x431: 0x15, 0x432: 0x16, 0x433: 0x17, 0x19: 0x18, } format_ = fmt[format_] if format_ == 0: if compSel not in [[0, 0, 0, 5], [0, 5, 5, 5]]: warn_color() elif format_ == 1: if compSel != [5, 5, 5, 0]: warn_color() elif format_ in [2, 3]: if compSel not in [[0, 0, 0, 1], [0, 5, 5, 1]]: warn_color() elif format_ == 5: if compSel != [2, 1, 0, 5]: if compSel == [0, 1, 2, 5]: swizzled_data = dds.form_conv.swapRB_16bpp( swizzled_data, 'rgb565') else: warn_color() elif format_ == 6: if compSel != [0, 1, 2, 5]: if compSel == [2, 1, 0, 5]: swizzled_data = dds.form_conv.swapRB_32bpp( swizzled_data, 'rgba8') else: warn_color() elif format_ == 7: if compSel != [0, 1, 2, 3]: if compSel == [2, 1, 0, 3]: swizzled_data = dds.form_conv.swapRB_16bpp( swizzled_data, 'rgb5a1') else: warn_color() elif format_ == 8: if compSel != [2, 1, 0, 3]: if compSel == [0, 1, 2, 3]: swizzled_data = dds.form_conv.swapRB_16bpp( swizzled_data, 'argb4') else: warn_color() elif format_ in [9, 0x14, 0x18]: if compSel != [0, 1, 2, 3]: if compSel == [2, 1, 0, 3]: if format_ == 0x18: swizzled_data = dds.form_conv.swapRB_32bpp( swizzled_data, 'bgr10a2') else: swizzled_data = dds.form_conv.swapRB_32bpp( swizzled_data, 'rgba8') else: warn_color() head_struct = FLIMHeader('>') head = head_struct.pack(b"FLIM", 0xFEFF, 0x14, 0x2020000, len(swizzled_data) + 0x28, 1) img_head_struct = imagHeader('>') imag_head = img_head_struct.pack(b"imag", 16, width, height, alignment, format_, swizzle_tileMode, len(swizzled_data)) output = swizzled_data + head + imag_head return output
def read(bfresData): assert bfresData[:4] == b"FRES" and bfresData[4:8] != b' ' version = bfresData[4] assert version in [3, 4] group = empty() group.pos = struct.unpack(">i", bfresData[0x24:0x28])[0] if group.pos == 0: return False group.pos += 0x28 group.count = struct.unpack(">i", bfresData[group.pos:group.pos + 4])[0] group.pos += 20 textures = [] for i in range(group.count): nameAddr = struct.unpack( ">i", bfresData[group.pos + 16 * i + 8:group.pos + 16 * i + 12])[0] nameAddr += group.pos + 16 * i + 8 name = bytes_to_string(bfresData, nameAddr) pos = struct.unpack( ">i", bfresData[group.pos + 16 * i + 12:group.pos + 16 * i + 16])[0] pos += group.pos + 16 * i + 12 ftex = empty() ftex.headAddr = pos pos += 4 surface = GX2Surface() surface.data(bfresData, pos) pos += surface.size if version == 4: surface.numMips = 1 elif surface.numMips > 14: continue mipOffsets = [] for j in range(13): mipOffsets.append(bfresData[j * 4 + pos] << 24 | bfresData[j * 4 + 1 + pos] << 16 | bfresData[j * 4 + 2 + pos] << 8 | bfresData[j * 4 + 3 + pos]) pos += 68 compSel = [] compSel2 = [] for j in range(4): comp = bfresData[pos + j] compSel2.append(comp) if comp == 4: # Sorry, but this is unsupported. comp = j compSel.append(comp) pos += 24 ftex.name = name ftex.dim = surface.dim ftex.width = surface.width ftex.height = surface.height ftex.depth = surface.depth ftex.numMips = surface.numMips ftex.format = surface.format_ ftex.aa = surface.aa ftex.use = surface.use ftex.imageSize = surface.imageSize ftex.imagePtr = surface.imagePtr ftex.mipSize = surface.mipSize ftex.mipPtr = surface.mipPtr ftex.tileMode = surface.tileMode ftex.swizzle = surface.swizzle ftex.alignment = surface.alignment ftex.pitch = surface.pitch ftex.compSel = compSel ftex.compSel2 = compSel2 ftex.mipOffsets = mipOffsets ftex.surfInfo = addrlib.getSurfaceInfo(ftex.format, ftex.width, ftex.height, ftex.depth, ftex.dim, ftex.tileMode, ftex.aa, 0) if ftex.format in BCn_formats: ftex.blkWidth, ftex.blkHeight = 4, 4 else: ftex.blkWidth, ftex.blkHeight = 1, 1 ftex.bpp = addrlib.surfaceGetBitsPerPixel(surface.format_) // 8 dataAddr = struct.unpack( ">i", bfresData[ftex.headAddr + 0xB0:ftex.headAddr + 0xB4])[0] dataAddr += ftex.headAddr + 0xB0 ftex.dataAddr = dataAddr ftex.data = bfresData[dataAddr:dataAddr + ftex.imageSize] mipAddr = struct.unpack( ">i", bfresData[ftex.headAddr + 0xB4:ftex.headAddr + 0xB8])[0] if mipAddr and ftex.mipSize: mipAddr += ftex.headAddr + 0xB4 ftex.mipData = bfresData[mipAddr:mipAddr + ftex.mipSize] else: ftex.mipData = b'' textures.append((name, ftex)) return textures
def writeGFD(f): width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS( f) numMips += 1 tileMode = addrlib.getDefaultGX2TileMode(1, width, height, 1, format_, 0, 1) bpp = addrlib.surfaceGetBitsPerPixel(format_) >> 3 surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) alignment = surfOut.baseAlign imageSize = surfOut.surfSize pitch = surfOut.pitch tilingDepth = surfOut.depth if surfOut.tileMode == 3: tilingDepth //= 4 s = 0 if format_ == 0x33: blkWidth, blkHeight = 4, 4 else: blkWidth, blkHeight = 1, 1 swizzled_data = [] mipSize = 0 mipOffsets = [] tiling1dLevel = 0 tiling1dLevelSet = False for mipLevel in range(numMips): offset, size = getCurrentMipOffset_Size(width, height, blkWidth, blkHeight, bpp, mipLevel) data_ = data[offset:offset + size] width_ = max(1, width >> mipLevel) height_ = max(1, height >> mipLevel) if mipLevel: surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, mipLevel) if mipLevel == 1: mipOffsets.append(imageSize) else: mipOffsets.append(mipSize) data_ += b'\0' * (surfOut.surfSize - size) dataAlignBytes = b'\0' * (roundUp(mipSize, surfOut.baseAlign) - mipSize) if mipLevel: mipSize += surfOut.surfSize + len(dataAlignBytes) swizzled_data.append( bytearray(dataAlignBytes) + addrlib.swizzle( width_, height_, 1, format_, 0, 1, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, 0, 0, data_)) if surfOut.tileMode in [1, 2, 3, 16]: tiling1dLevelSet = True if not tiling1dLevelSet: tiling1dLevel += 1 if tiling1dLevelSet: s |= tiling1dLevel << 16 else: s |= 13 << 16 block_head_struct = GFDBlockHeader() gx2surf_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xb, 0x9c, 0, 0) gx2surf_struct = GX2Surface() gx2surf = gx2surf_struct.pack(1, width, height, 1, numMips, format_, 0, 1, imageSize, 0, mipSize, 0, tileMode, s, alignment, pitch) image_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xc, imageSize, 0, 0) mip_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xd, mipSize, 0, 0) output = gx2surf_blk_head + gx2surf if numMips > 1: i = 0 for offset in mipOffsets: output += offset.to_bytes(4, 'big') i += 1 for z in range(14 - i): output += 0.to_bytes(4, 'big') else: output += b'\0' * 56 output += numMips.to_bytes(4, 'big') output += b'\0' * 4 output += 1.to_bytes(4, 'big') for value in compSel: output += value.to_bytes(1, 'big') if format_ == 0x33: output += makeRegsBytearray(width, height, numMips, format_, tileMode, pitch * 4, compSel) else: output += makeRegsBytearray(width, height, numMips, format_, tileMode, pitch, compSel) alignSize = getAlignBlockSize(len(output) + 64, alignment) align_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, alignSize, 0, 0) output += align_blk_head output += b'\0' * alignSize output += image_blk_head output += swizzled_data[0] if numMips > 1: mipAlignSize = getAlignBlockSize(len(output) + 64, alignment) mipAlign_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, mipAlignSize, 0, 0) output += mipAlign_blk_head output += b'\0' * mipAlignSize output += mip_blk_head for i in range(1, len(swizzled_data)): output += swizzled_data[i] return output
def read(file): with open(file, "rb") as inf: f = inf.read() if f[:4] != b"FRES" or f[4:8] == b' ': QtWidgets.QMessageBox.warning(None, "Error", "Invalid file header!") return False version = f[4] if version not in [3, 4]: QtWidgets.QMessageBox.warning(None, "Error", "Unsupported BFRES version!") return False group = empty() group.pos = struct.unpack(">i", f[0x24:0x28])[0] if group.pos == 0: return False group.pos += 0x28 group.count = struct.unpack(">i", f[group.pos:group.pos + 4])[0] group.pos += 20 textures = [] texNames = [] texSizes = [] for i in range(group.count): nameAddr = struct.unpack( ">i", f[group.pos + 16 * i + 8:group.pos + 16 * i + 12])[0] nameAddr += group.pos + 16 * i + 8 name = bytes_to_string(f, nameAddr) pos = struct.unpack(">i", f[group.pos + 16 * i + 12:group.pos + 16 * i + 16])[0] pos += group.pos + 16 * i + 12 ftex = empty() ftex.headAddr = pos pos += 4 surface = GX2Surface() surface.data(f, pos) pos += surface.size if version == 4: surface.numMips = 1 elif surface.numMips > 14: continue mipOffsets = [] for j in range(13): mipOffsets.append(f[j * 4 + pos] << 24 | f[j * 4 + 1 + pos] << 16 | f[j * 4 + 2 + pos] << 8 | f[j * 4 + 3 + pos]) pos += 68 compSel = [] compSel2 = [] for j in range(4): comp = f[pos + j] compSel2.append(comp) if comp == 4: # Sorry, but this is unsupported. comp = j compSel.append(comp) pos += 24 ftex.name = name ftex.dim = surface.dim ftex.width = surface.width ftex.height = surface.height ftex.depth = surface.depth ftex.numMips = surface.numMips ftex.format = surface.format_ ftex.aa = surface.aa ftex.use = surface.use ftex.imageSize = surface.imageSize ftex.imagePtr = surface.imagePtr ftex.mipSize = surface.mipSize ftex.mipPtr = surface.mipPtr ftex.tileMode = surface.tileMode ftex.swizzle = surface.swizzle ftex.alignment = surface.alignment ftex.pitch = surface.pitch ftex.compSel = compSel ftex.compSel2 = compSel2 ftex.mipOffsets = mipOffsets ftex.surfInfo = addrlib.getSurfaceInfo(ftex.format, ftex.width, ftex.height, ftex.depth, ftex.dim, ftex.tileMode, ftex.aa, 0) if ftex.format in globals.BCn_formats: ftex.blkWidth, ftex.blkHeight = 4, 4 else: ftex.blkWidth, ftex.blkHeight = 1, 1 ftex.bpp = addrlib.surfaceGetBitsPerPixel(surface.format_) // 8 dataAddr = struct.unpack(">i", f[ftex.headAddr + 0xB0:ftex.headAddr + 0xB4])[0] dataAddr += ftex.headAddr + 0xB0 ftex.dataAddr = dataAddr ftex.data = f[dataAddr:dataAddr + ftex.imageSize] mipAddr = struct.unpack(">i", f[ftex.headAddr + 0xB4:ftex.headAddr + 0xB8])[0] if mipAddr and ftex.mipSize: mipAddr += ftex.headAddr + 0xB4 ftex.mipData = f[mipAddr:mipAddr + ftex.mipSize] else: ftex.mipData = b'' textures.append(ftex) texNames.append(name) texSizes.append([ftex.imageSize, ftex.mipSize]) globals.fileData = bytearray(f) globals.texSizes = texSizes return textures, texNames
def inject(tex, tileMode, swizzle_, SRGB, importMips, oldImageSize, oldMipSize, f): width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS( f, SRGB) if 0 in [width, dataSize] and data == []: QtWidgets.QMessageBox.warning(None, "Error", "Unsupported DDS file.") return False if format_ not in globals.formats: QtWidgets.QMessageBox.warning(None, "Error", "Unsupported DDS format.") return False elif numMips > 13: QtWidgets.QMessageBox.warning(None, "Error", "Invalid number of mipmaps.") return False if not importMips: numMips = 1 else: if tex.numMips < numMips + 1: QtWidgets.QMessageBox.warning( None, "Warning", "This DDS file has more mipmaps (%d) than the original image (%d)!\n" "Not all mipmaps might be imported." % (numMips, tex.numMips - 1), ) numMips += 1 bpp = addrlib.surfaceGetBitsPerPixel(format_) // 8 surfInfo = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) if surfInfo.depth != 1: QtWidgets.QMessageBox.warning(None, "Error", "Unsupported depth.") return False elif surfInfo.surfSize > oldImageSize: QtWidgets.QMessageBox.warning( None, "Error", 'This DDS has a larger filesize than the original image!', ) return False tex.surfInfo = surfInfo alignment = surfInfo.baseAlign imageSize = surfInfo.surfSize pitch = surfInfo.pitch if tileMode in [1, 2, 3, 16]: s = swizzle_ << 8 else: s = 0xd0000 | swizzle_ << 8 if format_ in globals.BCn_formats: blkWidth, blkHeight = 4, 4 else: blkWidth, blkHeight = 1, 1 mipSize = 0 numMips_ = 1 mipOffsets = [] result = [] for mipLevel in range(numMips): offset, size = getCurrentMipOffset_Size(width, height, blkWidth, blkHeight, bpp, mipLevel) data_ = data[offset:offset + size] width_ = max(1, width >> mipLevel) height_ = max(1, height >> mipLevel) if mipLevel: surfInfo = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, mipLevel) if mipLevel == 1: mipOffsets.append(imageSize) else: mipOffsets.append(mipSize) data_ += b'\0' * (surfInfo.surfSize - size) dataAlignBytes = b'\0' * (roundUp(mipSize, surfInfo.baseAlign) - mipSize) if mipLevel: mipSize += surfInfo.surfSize + len(dataAlignBytes) if mipSize > oldMipSize: mipSize -= surfInfo.surfSize + len(dataAlignBytes) mipLevel -= 1 break result.append( bytearray(dataAlignBytes) + addrlib.swizzle(width_, height_, surfInfo.height, format_, surfInfo .tileMode, s, surfInfo.pitch, surfInfo.bpp, data_)) tex.dim = 1 tex.width = width tex.height = height tex.depth = 1 tex.numMips = mipLevel + 1 tex.format = format_ tex.aa = 0 tex.use = 1 tex.imageSize = imageSize tex.mipSize = mipSize tex.tileMode = tileMode tex.swizzle = s tex.alignment = alignment tex.pitch = pitch tex.compSel = tex.compSel2 = compSel tex.mipOffsets = mipOffsets tex.blkWidth, tex.blkHeight = blkWidth, blkHeight tex.bpp = bpp tex.data = bytes(result[0]) tex.mipData = b''.join(result[1:]) return tex
def writeGFD(f): tileMode = 4 width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS(f) imageData = data[:dataSize] mipData = data[dataSize:] numMips += 1 if format_ == 0x33: align = 0x1EE4 mipAlign = 0x1FC0 else: align = 0x6E4 mipAlign = 0x7C0 bpp = addrlib.surfaceGetBitsPerPixel(format_) >> 3 alignment = 512 * bpp surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) pitch = surfOut.pitch if format_ == 0x33: s = 0x40000 else: s = 0xd0000 swizzled_data = [] imageSize = 0 mipSize = 0 mipOffsets = [] for i in range(numMips): if i == 0: data = imageData imageSize = surfOut.surfSize else: offset, dataSize = get_curr_mip_off_size(width, height, bpp, i, format_ == 0x33) data = mipData[offset:offset + dataSize] surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, i) padSize = surfOut.surfSize - dataSize data += padSize * b"\x00" if i != 0: offset += padSize if i == 1: mipOffsets.append(imageSize) else: mipOffsets.append(offset) mipSize += len(data) swizzled_data.append(addrlib.swizzle(max(1, width >> i), max(1, height >> i), surfOut.height, format_, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, data)) block_head_struct = GFDBlockHeader() gx2surf_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xb, 0x9c, 0, 0) gx2surf_struct = GX2Surface() gx2surf = gx2surf_struct.pack(1, width, height, 1, numMips, format_, 0, 1, imageSize, 0, mipSize, 0, tileMode, s, alignment, pitch) align_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, align, 0, 0) image_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xc, imageSize, 0, 0) mipAlign_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, mipAlign, 0, 0) mip_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xd, mipSize, 0, 0) output = gx2surf_blk_head + gx2surf if numMips > 1: i = 0 for offset in mipOffsets: output += offset.to_bytes(4, 'big') i += 1 for z in range(14 - i): output += (0).to_bytes(4, 'big') else: output += b"\x00" * 56 output += numMips.to_bytes(4, 'big') output += b"\x00" * 4 output += (1).to_bytes(4, 'big') for value in compSel: output += value.to_bytes(1, 'big') output += b"\x00" * 20 output += align_blk_head output += b"\x00" * align output += image_blk_head output += swizzled_data[0] if numMips > 1: output += mipAlign_blk_head output += b"\x00" * mipAlign output += mip_blk_head i = 0 for data in swizzled_data: if i != 0: output += data i += 1 return output
def main(): print("GTX Extractor v5.3") print("(C) 2015-2018 AboodXD") input_ = sys.argv[-1] if not (input_.endswith('.gtx') or input_.endswith('.dds')): printInfo() toGTX = False if input_.endswith('.dds'): toGTX = True if "-o" in sys.argv: output_ = sys.argv[sys.argv.index("-o") + 1] else: output_ = os.path.splitext(input_)[0] + (".gtx" if toGTX else ".dds") if toGTX: if "-tileMode" in sys.argv: tileMode = int(sys.argv[sys.argv.index("-tileMode") + 1], 0) else: tileMode = 4 if "-swizzle" in sys.argv: swizzle = int(sys.argv[sys.argv.index("-swizzle") + 1], 0) else: swizzle = 0 if "-SRGB" in sys.argv: SRGB = int(sys.argv[sys.argv.index("-SRGB") + 1], 0) else: SRGB = 0 multi = False if "-multi" in sys.argv: multi = True numImages = int(sys.argv[sys.argv.index("-multi") + 1], 0) if SRGB > 1 or not 0 <= tileMode <= 16 or not 0 <= swizzle <= 7: printInfo() if "-o" not in sys.argv and "-multi" in sys.argv: output_ = output_[:-5] + ".gtx" with open(output_, "wb+") as output: head_struct = GFDHeader() head = head_struct.pack(b"Gfx2", 32, 7, 1, 2, 1, 0, 0) output.write(head) if multi: input_ = input_[:-5] for i in range(numImages): print("") print('Converting: ' + input_ + str(i) + ".dds") data = writeGFD(input_ + str(i) + ".dds", tileMode, swizzle, SRGB, i, numImages) output.write(data) else: print("") print('Converting: ' + input_) data = writeGFD(input_, tileMode, swizzle, SRGB, 0, 1) output.write(data) block_head_struct = GFDBlockHeader() eof_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 1, 0, 0, 0) output.write(eof_blk_head) else: print("") print('Converting: ' + input_) with open(input_, "rb") as inf: inb = inf.read() compSel = ["R", "G", "B", "A", "0", "1"] gfd = readGFD(inb) for i in range(gfd.numImages): print("") print("// ----- GX2Surface Info ----- ") print(" dim = " + str(gfd.dim[i])) print(" width = " + str(gfd.width[i])) print(" height = " + str(gfd.height[i])) print(" depth = " + str(gfd.depth[i])) print(" numMips = " + str(gfd.numMips[i])) if gfd.format[i] in formats: print(" format = " + formats[gfd.format[i]]) else: print(" format = " + hex(gfd.format[i])) print(" aa = " + str(gfd.aa[i])) print(" use = " + str(gfd.use[i])) print(" imageSize = " + str(gfd.imageSize[i])) print(" mipSize = " + str(gfd.mipSize[i])) print(" tileMode = " + str(gfd.tileMode[i])) print(" swizzle = " + str(gfd.swizzle[i]) + ", " + hex(gfd.swizzle[i])) print(" alignment = " + str(gfd.alignment[i])) print(" pitch = " + str(gfd.pitch[i])) bpp = addrlib.surfaceGetBitsPerPixel(gfd.format[i]) print("") print(" GX2 Component Selector:") print(" Red Channel: " + str(compSel[gfd.compSel[i][0]])) print(" Green Channel: " + str(compSel[gfd.compSel[i][1]])) print(" Blue Channel: " + str(compSel[gfd.compSel[i][2]])) print(" Alpha Channel: " + str(compSel[gfd.compSel[i][3]])) print("") print(" bits per pixel = " + str(bpp)) print(" bytes per pixel = " + str(bpp // 8)) print(" realSize = " + str(gfd.realSize[i])) if gfd.numImages > 1: output_ = os.path.splitext(input_)[0] + str(i) + ".dds" hdr, result = get_deswizzled_data(i, gfd) if hdr == b'' or result == []: pass else: with open(output_, "wb+") as output: output.write(hdr) for data in result: output.write(data) print('') print('Finished converting: ' + input_)
def writeGFD(f, tileMode, swizzle_, SRGB, n, numImages): width, height, format_, fourcc, dataSize, compSel, numMips, data = dds.readDDS( f, SRGB) if 0 in [width, dataSize] and data == []: print("") if n != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if format_ not in formats: print("") print("Unsupported DDS format!") print("") if n != (numImages - 1): print("") print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if numMips > 13: print("") print("Invalid number of mipmaps for " + f) print("") if n != (numImages - 1): print("") print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) imageData = data[:dataSize] mipData = data[dataSize:] numMips += 1 mipAlign = 0 align = 0 if numImages == 1: if format_ in BCn_formats: if format_ in [0x31, 0x431, 0x234, 0x34]: align = 0xEE4 mipAlign = 0xFC0 else: align = 0x1EE4 mipAlign = 0x1FC0 else: align = 0x6E4 mipAlign = 0x7C0 bpp = addrlib.surfaceGetBitsPerPixel(format_) >> 3 alignment = 512 * bpp surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, 0) pitch = surfOut.pitch if surfOut.depth != 1: print("") print("Unsupported depth!") print("") if n != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) if tileMode in [1, 2, 3, 16]: s = 0 else: s = 0xd0000 s |= swizzle_ << 8 if numMips > 1: print("") print("Processing " + str(numMips - 1) + " mipmaps:") swizzled_data = [] imageSize = 0 mipSize = 0 mipOffsets = [] for i in range(numMips): if i == 0: data = imageData imageSize = surfOut.surfSize else: print( str(i) + ": " + str(max(1, width >> i)) + "x" + str(max(1, height >> i))) offset, dataSize = get_curr_mip_off_size(width, height, bpp, i, format_ in BCn_formats) data = mipData[offset:offset + dataSize] surfOut = addrlib.getSurfaceInfo(format_, width, height, 1, 1, tileMode, 0, i) padSize = surfOut.surfSize - dataSize data += padSize * b"\x00" if i != 0: offset += padSize if i == 1: mipOffsets.append(imageSize) else: mipOffsets.append(offset) mipSize += len(data) swizzled_data.append( addrlib.swizzle(max(1, width >> i), max(1, height >> i), surfOut.height, format_, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, data)) compSels = ["R", "G", "B", "A", "0", "1"] print("") print("// ----- GX2Surface Info ----- ") print(" dim = 1") print(" width = " + str(width)) print(" height = " + str(height)) print(" depth = 1") print(" numMips = " + str(numMips)) print(" format = " + formats[format_]) print(" aa = 0") print(" use = 1") print(" imageSize = " + str(imageSize)) print(" mipSize = " + str(mipSize)) print(" tileMode = " + str(tileMode)) print(" swizzle = " + str(s) + ", " + hex(s)) print(" alignment = " + str(alignment)) print(" pitch = " + str(pitch)) print("") print(" GX2 Component Selector:") print(" Red Channel: " + str(compSels[compSel[0]])) print(" Green Channel: " + str(compSels[compSel[1]])) print(" Blue Channel: " + str(compSels[compSel[2]])) print(" Alpha Channel: " + str(compSels[compSel[3]])) print("") print(" bits per pixel = " + str(bpp << 3)) print(" bytes per pixel = " + str(bpp)) print(" realSize = " + str(len(imageData))) if format_ == 1: if compSel not in [[0, 0, 0, 5], [0, 5, 5, 5]]: warn_color() compSel = [0, 5, 5, 5] elif format_ in [2, 7]: if compSel not in [[0, 0, 0, 1], [0, 5, 5, 1]]: warn_color() compSel = [0, 5, 5, 1] elif format_ == 8: if compSel not in [[0, 1, 2, 5], [2, 1, 0, 5]]: warn_color() if compSel[0] == 0 and compSel[2] == 2: swizzled_data = [ dds.form_conv.swapRB_RGB565(data) for data in swizzled_data ] compSel = [0, 1, 2, 5] elif format_ in [0xa, 0xb]: if compSel not in [[0, 1, 2, 3], [2, 1, 0, 3]]: warn_color() if compSel[0] == 0 and compSel[2] == 2: if format_ == 0xb: swizzled_data = [ dds.form_conv.swapRB_RGBA4(data) for data in swizzled_data ] compSel = [0, 1, 2, 3] elif format_ in [0x1a, 0x41a, 0x19]: if compSel not in [[0, 1, 2, 3], [2, 1, 0, 3], [0, 1, 2, 5], [2, 1, 0, 5]]: warn_color() if format_ == 0x19 and compSel[3] == 5: warn_color() if compSel[0] == 2 and compSel[2] == 0: if format_ == 0x19: swizzled_data = [ dds.form_conv.swapRB_RGB10A2(data) for data in swizzled_data ] else: swizzled_data = [ dds.form_conv.swapRB_RGBA8(data) for data in swizzled_data ] compSel = [0, 1, 2, 3] block_head_struct = GFDBlockHeader() gx2surf_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xb, 0x9c, 0, 0) gx2surf_struct = GX2Surface() gx2surf = gx2surf_struct.pack(1, width, height, 1, numMips, format_, 0, 1, imageSize, 0, mipSize, 0, tileMode, s, alignment, pitch) if align: align_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, align, 0, 0) image_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xc, imageSize, 0, 0) if mipAlign: mipAlign_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 2, mipAlign, 0, 0) mip_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xd, mipSize, 0, 0) output = gx2surf_blk_head + gx2surf if numMips > 1: i = 0 for offset in mipOffsets: output += offset.to_bytes(4, 'big') i += 1 for z in range(14 - i): output += 0.to_bytes(4, 'big') else: output += b"\x00" * 56 output += numMips.to_bytes(4, 'big') output += b"\x00" * 4 output += 1.to_bytes(4, 'big') for value in compSel: output += value.to_bytes(1, 'big') output += b"\x00" * 20 if align: output += align_blk_head output += b"\x00" * align output += image_blk_head output += swizzled_data[0] if numMips > 1: if mipAlign: output += mipAlign_blk_head output += b"\x00" * mipAlign output += mip_blk_head i = 0 for data in swizzled_data: if i != 0: output += data i += 1 return output