def writeGFD(data, width, height, compSel): imageData = bytes(data) surfOut = addrlib.getSurfaceInfo(0x1a, width, height, 1, 1, 4, 0, 0) alignment = surfOut.baseAlign imageSize = surfOut.surfSize pitch = surfOut.pitch imageData += b'\0' * (surfOut.surfSize - len(data)) result = addrlib.swizzle( width, height, 1, 0x1a, 0, 1, surfOut.tileMode, 0, surfOut.pitch, surfOut.bpp, 0, 0, imageData, ) 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, 1, 0x1a, 0, 1, imageSize, 0, 0, 0, 4, s, alignment, pitch) image_blk_head = block_head_struct.pack(b"BLK{", 32, 1, 0, 0xc, imageSize, 0, 0) output = gx2surf_blk_head + gx2surf output += b'\0' * 56 output += 1.to_bytes(4, 'big') output += b'\0' * 4 output += 1.to_bytes(4, 'big') for value in compSel: output += value.to_bytes(1, 'big') output += makeRegsBytearray(width, height, 1, 0x1a, 4, 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 += result return output
def untileTex(tex): surfInfo = tex.surfInfo data = tex.data[:surfInfo.surfSize] result = [] for mipLevel in range(tex.numMips): width = max(1, tex.width >> mipLevel) height = max(1, tex.height >> mipLevel) size = ceil(width / tex.blkWidth) * ceil( height / tex.blkHeight) * tex.bpp if mipLevel != 0: mipOffset = tex.mipOffsets[mipLevel - 1] if mipLevel == 1: mipOffset -= surfInfo.surfSize surfInfo = addrlib.getSurfaceInfo(tex.format, tex.width, tex.height, tex.depth, tex.dim, tex.tileMode, tex.aa, mipLevel) data = tex.mipData[mipOffset:mipOffset + surfInfo.surfSize] result_ = addrlib.deswizzle( width, height, surfInfo.height, tex.format, surfInfo.tileMode, tex.swizzle, surfInfo.pitch, surfInfo.bpp, data, ) result.append(result_[:size]) return result
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_ == 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_ == 0x0F: flim.format = 0x34 flim.compSel = [0, 0, 0, 5] elif info.format_ == 0x10: flim.format = 0x34 flim.compSel = [5, 5, 5, 0] elif info.format_ == 0x11: flim.format = 0x35 flim.compSel = [0, 0, 0, 1] 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: raise NotImplementedError("Unsupported texture format: " + hex(info.format_)) flim.imageSize = info.imageSize # Calculate swizzle and tileMode flim.swizzle, flim.tileMode = computeSwizzleTileMode(info.swizzle_tileMode) flim.alignment = info.alignment surfOut = addrlib.getSurfaceInfo(flim.format, flim.width, flim.height, 1, 1, flim.tileMode, 0, 0) if surfOut.depth != 1: raise NotImplementedError("Unsupported depth!") flim.pitch = surfOut.pitch flim.data = f[:info.imageSize] flim.surfOut = surfOut return flim
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 get_deswizzled_data(i, gfd): majorVersion = gfd.majorVersion numImages = gfd.numImages numMips = gfd.numMips[i] width = gfd.width[i] height = gfd.height[i] depth = gfd.depth[i] dim = gfd.dim[i] format_ = gfd.format[i] aa = gfd.aa[i] tileMode = gfd.tileMode[i] swizzle_ = gfd.swizzle[i] compSel = gfd.compSel[i] data = gfd.data[i] realSize = gfd.realSize[i] mipOffsets = gfd.mipOffsets[i] surfOut = addrlib.getSurfaceInfo(format_, width, height, depth, dim, tileMode, aa, 0) bpp = divRoundUp(surfOut.bpp, 8) try: mipData = gfd.mipData[i] except KeyError: mipData = b'' if format_ in formats: if aa != 0: print("") print("Unsupported aa!") print("") if i != (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_ == 0x00: print("") print("Invalid texture format!") print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'', [] else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) else: if format_ in [0x1a, 0x41a]: format__ = 28 elif format_ == 0x19: format__ = 24 elif format_ == 0x8: format__ = 85 elif format_ == 0xa: format__ = 86 elif format_ == 0xb: format__ = 115 elif format_ == 0x1: format__ = 61 elif format_ == 0x7: format__ = 49 elif format_ == 0x2: format__ = 112 elif format_ in [0x31, 0x431]: format__ = "BC1" elif format_ in [0x32, 0x432]: format__ = "BC2" elif format_ in [0x33, 0x433]: format__ = "BC3" elif format_ == 0x34: format__ = "BC4U" elif format_ == 0x234: format__ = "BC4S" elif format_ == 0x35: format__ = "BC5U" elif format_ == 0x235: format__ = "BC5S" if surfOut.depth != 1: print("") print("Unsupported depth!") print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'', b'', b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) 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 result = [] for mipLevel in range(numMips): width_ = max(1, width >> mipLevel) height_ = max(1, height >> mipLevel) size = divRoundUp(width_, blkWidth) * divRoundUp(height_, blkHeight) * bpp if mipLevel != 0: print(str(mipLevel) + ": " + str(width_) + "x" + str(height_)) mipOffset = mipOffsets[mipLevel - 1] if mipLevel == 1: mipOffset -= surfOut.surfSize surfOut = addrlib.getSurfaceInfo(format_, width, height, depth, dim, tileMode, aa, mipLevel) data = mipData[mipOffset:mipOffset + surfOut.surfSize] result_ = addrlib.deswizzle( width_, height_, surfOut.height, format_, surfOut.tileMode, swizzle_, surfOut.pitch, surfOut.bpp, data, ) result.append(result_[:size]) hdr = dds.generateHeader(numMips, width, height, format__, compSel, realSize, format_ in BCn_formats) else: print("") print("Unsupported texture format_: " + hex(format_)) print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) hdr, result = b'', [] else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) return hdr, result
def writeFLIM(f, tileMode, swizzle_, SRGB): # Read the DDS file width, height, format__, fourcc, dataSize, compSel, numMips, data = dds.readDDS( f, SRGB) # Check if it was read correctly if 0 in [width, dataSize] and data == []: return b'' # Check if the texture format is supported if format__ not in formats: return b'' # Remove the mipmap data if it exists data = data[:dataSize] # GTX format -> BFLIM format # GTX format: 1 # if alpha: BFLIM format: 0 # else: BFLIM format: 1 if format__ == 1: if compSel[3] == 0: format_ = 1 else: format_ = 0 # GTX format: 0x1a # if one value is 0: BFLIM format: 6 (BAD CHOICE) # else: BFLIM format: 9 elif format__ == 0x1a: if 5 in compSel: format_ = 6 else: format_ = 9 # GTX format: 0x31 # if ETC1: BFLIM format: 0xa # else: BFLIM format: 0xc elif format__ == 0x31: if fourcc == b'ETC1': format_ = 0xa else: format_ = 0xc # GTX format: (key) -> BFLIM format: (value) else: fmt = { 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__] # Check if colors are messed up or if R and B are swapped if format_ == 0: if compSel not in [[0, 0, 0, 5], [0, 5, 5, 5]]: warn_color(f) elif format_ == 1: if compSel != [5, 5, 5, 0]: warn_color(f) elif format_ in [2, 3]: if compSel not in [[0, 0, 0, 1], [0, 5, 5, 1]]: warn_color(f) elif format_ == 5: if compSel != [2, 1, 0, 5]: if compSel == [0, 1, 2, 5]: # Swap R and B data = dds.form_conv.swapRB_16bpp(data, 'rgb565') else: warn_color(f) elif format_ == 6: if compSel != [0, 1, 2, 5]: if compSel == [2, 1, 0, 5]: # Swap R and B data = dds.form_conv.swapRB_32bpp(data, 'rgba8') else: warn_color(f) elif format_ == 7: if compSel != [0, 1, 2, 3]: if compSel == [2, 1, 0, 3]: # Swap R and B data = dds.form_conv.swapRB_16bpp(data, 'rgb5a1') else: warn_color(f) elif format_ == 8: if compSel != [2, 1, 0, 3]: if compSel == [0, 1, 2, 3]: # Swap R and B data = dds.form_conv.swapRB_16bpp(data, 'argb4') else: warn_color(f) elif format_ in [9, 0x14, 0x18]: if compSel != [0, 1, 2, 3]: if compSel == [2, 1, 0, 3]: if format_ == 0x18: # Swap R and B data = dds.form_conv.swapRB_32bpp(data, 'bgr10a2') else: # Swap R and B data = dds.form_conv.swapRB_32bpp(data, 'rgba8') else: warn_color(f) # Get the Surface Info surfOut = addrlib.getSurfaceInfo(format__, width, height, 1, 1, tileMode, 0, 0) # Depths other than 1 are not supported if surfOut.depth != 1: return b'' # Pad the data padSize = surfOut.surfSize - len(data) data += padSize * b"\x00" # Pack the swizzle value and tileMode z = (swizzle_, tileMode) swizzle_tileMode = computeSwizzleTileMode(z) # Get the swizzle value used for (de)swizzling if tileMode in [1, 2, 3, 16]: s = swizzle_ << 8 else: s = 0xd0000 | (swizzle_ << 8) # Swizzle the data swizzled_data = addrlib.swizzle(width, height, surfOut.height, format__, surfOut.tileMode, s, surfOut.pitch, surfOut.bpp, data) # Get the alignment value alignment = surfOut.baseAlign # Pack the file header head_struct = FLIMHeader() head = head_struct.pack(b"FLIM", 0xFEFF, 0x14, 0x2020000, len(swizzled_data) + 0x28, 1) # Pack the `imag` header img_head_struct = imagHeader() imag_head = img_head_struct.pack(b"imag", 16, width, height, alignment, format_, swizzle_tileMode, len(swizzled_data)) # Build the file output = b"".join([swizzled_data, head, imag_head]) return output
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 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
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(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 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 calcSurfaceSizeAndAlignment(self): # Calculate the best tileMode if set to default if self.tileMode == GX2TileMode.Default: self.tileMode = GX2TileMode(addrlib.getDefaultGX2TileMode( self.dim.value, self.width, self.height, self.depth, self.format.value, self.aa.value, self.use.value, )) # Calculate the surface info for the base level surfInfo = addrlib.getSurfaceInfo( self.format.value, self.width, self.height, self.depth, self.dim.value, self.tileMode.value, self.aa.value, 0, ) # Set the image size, alignment and pitch self.imageSize = surfInfo.surfSize self.alignment = surfInfo.baseAlign self.pitch = surfInfo.pitch # Ensure pipe and bank swizzle is valid self.swizzle &= 0x0700 # Calculate the swizzle 1D tiling start level, mip size, mip offsets and tiling1dLevel = 0 tiling1dLevelSet = GX2TileMode(surfInfo.tileMode) in ( GX2TileMode.Linear_Aligned, GX2TileMode.Linear_Special, GX2TileMode.Tiled_1D_Thin1, GX2TileMode.Tiled_1D_Thick, ) if not tiling1dLevelSet: tiling1dLevel += 1 self.mipSize = 0 for mipLevel in range(1, self.numMips): # Calculate the surface info for the mip level surfInfo = addrlib.getSurfaceInfo( self.format.value, self.width, self.height, self.depth, self.dim.value, self.tileMode.value, self.aa.value, mipLevel, ) # Make sure the level is aligned self.mipSize = roundUp(self.mipSize, surfInfo.baseAlign) # Set the offset of the level ## Level 1 offset is used to place the mip data (levels 1+) after the image data (level 0) ## The value is the minimum size of the image data + padding to ensure the mip data is aligned if mipLevel == 1: # Level 1 alignment should suffice to ensure all the other levels are aligned as well self.mipOffset[0] = roundUp(self.imageSize, surfInfo.baseAlign) else: # Level offset should be the size of all previous levels (aligned) self.mipOffset[mipLevel - 1] = self.mipSize # Increase the total mip size by this level's size self.mipSize += surfInfo.surfSize # Calculate the swizzle 1D tiling start level for tiled surfaces if not tiling1dLevelSet: # Check if the tiling mode switched to 1D tiling tileMode = GX2TileMode(surfInfo.tileMode) if tileMode in (GX2TileMode.Tiled_1D_Thin1, GX2TileMode.Tiled_1D_Thick): tiling1dLevelSet = True else: tiling1dLevel += 1 ## If the tiling mode never switched to 1D tiling, set the start level to 13 (observed from existing files) if not tiling1dLevelSet: tiling1dLevel = 13 self.swizzle |= tiling1dLevel << 16 # Clear the unused mip offsets for mipLevel in range(self.numMips, 14): self.mipOffset[mipLevel - 1] = 0
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 copySurface(src, dst): ### Check requirements ### assert dst.dim == src.dim assert dst.width == src.width assert dst.height == src.height assert dst.depth <= src.depth assert dst.numMips <= src.numMips assert dst.format == src.format ### Check if the two surfaces are the same ### ### (If they are, we can just copy the data over) ### # Conditions to check are: # 1. tileMode is the same (and swizzle is the same for non-linear tiling) # 2a. depth is the same (and mipmaps count is the same for depths higher than 1) # 2b. depth differs, but mipmaps count is 1 for both surfaces # These two conditions ensure we can safely slice the source data for the dest data # The depths condition can be ignored if we slice with the depth in mind, # but that is currently not supported if (src.tileMode == dst.tileMode and (src.tileMode in (GX2TileMode.Linear_Aligned, GX2TileMode.Linear_Special) or ((src.swizzle >> 8) & 7) == ((dst.swizzle >> 8) & 7)) and ((src.depth == dst.depth and (src.depth == 1 or src.numMips == dst.numMips)) or src.numMips == 1)): # No need to process anything, just copy the data over dst.imageData = src.imageData[:dst.imageSize] dst.mipData = src.mipData[:dst.mipSize] return ### Untile the source data ### levels = [] # Calculate the surface info for the base level surfInfo = addrlib.getSurfaceInfo( src.format.value, src.width, src.height, src.depth, src.dim.value, src.tileMode.value, src.aa.value, 0, ) # Get the depth used for tiling tileMode = GX2TileMode(surfInfo.tileMode) tilingDepth = surfInfo.depth if tileMode in (GX2TileMode.Tiled_1D_Thick, GX2TileMode.Tiled_2D_Thick, GX2TileMode.Tiled_2B_Thick, GX2TileMode.Tiled_3D_Thick, GX2TileMode.Tiled_3B_Thick): tilingDepth = divRoundUp(tilingDepth, 4) # Depths higher than 1 are currently not supported assert tilingDepth == 1 # Block width and height for the format blkWidth, blkHeight = (4, 4) if src.format.isCompressed() else (1, 1) # Bytes-per-pixel bpp = divRoundUp(surfInfo.bpp, 8) # Untile the base level result = addrlib.deswizzle( src.width, src.height, 1, src.format.value, 0, src.use.value, surfInfo.tileMode, src.swizzle, surfInfo.pitch, surfInfo.bpp, 0, 0, src.imageData, ) # Make sure it's the correct size size = divRoundUp(src.width, blkWidth) * divRoundUp(src.height, blkHeight) * bpp assert len(result) >= size levels.append(result[:size]) # Untile the other levels (mipmaps) offset = 0 for mipLevel in range(1, dst.numMips): # Calculate the width and height of the mip level width = max(1, src.width >> mipLevel) height = max(1, src.height >> mipLevel) # Calculate the surface info for the mip level surfInfo = addrlib.getSurfaceInfo( src.format.value, src.width, src.height, src.depth, src.dim.value, src.tileMode.value, src.aa.value, mipLevel, ) # Untile the mip level result = addrlib.deswizzle( width, height, 1, src.format.value, 0, src.use.value, surfInfo.tileMode, src.swizzle, surfInfo.pitch, surfInfo.bpp, 0, 0, src.mipData[offset:offset + surfInfo.surfSize], ) # Make sure it's the correct size size = divRoundUp(width, blkWidth) * divRoundUp(height, blkHeight) * bpp assert len(result) >= size levels.append(result[:size]) # Set the offset of the next level if mipLevel < src.numMips - 1: offset = src.mipOffset[mipLevel] ### Tile the destination data ### # Calculate the surface info for the base level surfInfo = addrlib.getSurfaceInfo( dst.format.value, dst.width, dst.height, dst.depth, dst.dim.value, dst.tileMode.value, dst.aa.value, 0, ) # Get the depth used for tiling tileMode = GX2TileMode(surfInfo.tileMode) tilingDepth = surfInfo.depth if tileMode in (GX2TileMode.Tiled_1D_Thick, GX2TileMode.Tiled_2D_Thick, GX2TileMode.Tiled_2B_Thick, GX2TileMode.Tiled_3D_Thick, GX2TileMode.Tiled_3B_Thick): tilingDepth = divRoundUp(tilingDepth, 4) # Depths higher than 1 are currently not supported assert tilingDepth == 1 # Block width and height for the format blkWidth, blkHeight = (4, 4) if dst.format.isCompressed() else (1, 1) # Bytes-per-pixel bpp = divRoundUp(surfInfo.bpp, 8) # Tile the base level dst.imageData = addrlib.swizzle( dst.width, dst.height, 1, dst.format.value, 0, dst.use.value, surfInfo.tileMode, dst.swizzle, surfInfo.pitch, surfInfo.bpp, 0, 0, levels[0].ljust(surfInfo.surfSize, b'\0'), )[:surfInfo.surfSize] # Tile the other levels (mipmaps) mipData = bytearray() for mipLevel in range(1, dst.numMips): # Calculate the width and height of the mip level width = max(1, dst.width >> mipLevel) height = max(1, dst.height >> mipLevel) # Calculate the surface info for the mip level surfInfo = addrlib.getSurfaceInfo( dst.format.value, dst.width, dst.height, dst.depth, dst.dim.value, dst.tileMode.value, dst.aa.value, mipLevel, ) if mipLevel != 1: mipData += b'\0' * (dst.mipOffset[mipLevel - 1] - len(mipData)) # Untile the mip level mipData += addrlib.swizzle( width, height, 1, dst.format.value, 0, dst.use.value, surfInfo.tileMode, dst.swizzle, surfInfo.pitch, surfInfo.bpp, 0, 0, levels[mipLevel].ljust(surfInfo.surfSize, b'\0'), )[:surfInfo.surfSize] dst.mipData = bytes(mipData)
def get_deswizzled_data(i, gfd): majorVersion = gfd.majorVersion numImages = gfd.numImages numMips = gfd.numMips[i] width = gfd.width[i] height = gfd.height[i] depth = gfd.depth[i] dim = gfd.dim[i] format_ = gfd.format[i] aa = gfd.aa[i] tileMode = gfd.tileMode[i] swizzle_ = gfd.swizzle[i] compSel = gfd.compSel[i] data = gfd.data[i] realSize = gfd.realSize[i] surfOut = addrlib.getSurfaceInfo(format_, width, height, depth, dim, tileMode, aa, 0) bpp = (surfOut.bpp + 7) // 8 mipOffsets = gfd.mipOffsets[i] try: mipData = gfd.mipData[i] except KeyError: mipData = b'' if format_ in formats: if aa != 0: print("") print("Unsupported aa!") print("") if i != (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_ == 0x00: print("") print("Invalid texture format!") print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'', [] else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) else: if format_ == 0x1a or format_ == 0x41a: format__ = 28 elif format_ == 0x19: format__ = 24 elif format_ == 0x8: format__ = 85 elif format_ == 0xa: format__ = 86 elif format_ == 0xb: format__ = 115 elif format_ == 0x1: format__ = 61 elif format_ == 0x7: format__ = 49 elif format_ == 0x2: format__ = 112 elif format_ == 0x31 or format_ == 0x431: format__ = "BC1" elif format_ == 0x32 or format_ == 0x432: format__ = "BC2" elif format_ == 0x33 or format_ == 0x433: format__ = "BC3" elif format_ == 0x34: format__ = "BC4U" elif format_ == 0x234: format__ = "BC4S" elif format_ == 0x35: format__ = "BC5U" elif format_ == 0x235: format__ = "BC5S" if surfOut.depth != 1: print("") print("Unsupported depth!") print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) return b'', b'', b'' else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) print("") print("Processing " + str(numMips - 1) + " mipmaps:") result = [] for level in range(numMips): if format_ in BCn_formats: size = ((max(1, width >> level) + 3) >> 2) * ( (max(1, height >> level) + 3) >> 2) * bpp else: size = max(1, width >> level) * max(1, height >> level) * bpp if level != 0: print( str(level) + ": " + str(max(1, width >> level)) + "x" + str(max(1, height >> level))) if level == 1: mipOffset = mipOffsets[level - 1] - surfOut.surfSize else: mipOffset = mipOffsets[level - 1] surfOut = addrlib.getSurfaceInfo(format_, width, height, depth, dim, tileMode, aa, level) data = mipData[mipOffset:mipOffset + surfOut.surfSize] deswizzled = addrlib.deswizzle(max(1, width >> level), max(1, height >> level), surfOut.height, format_, surfOut.tileMode, swizzle_, surfOut.pitch, surfOut.bpp, data) data = deswizzled[:size] result.append(data) if format_ == 8: result = [dds.form_conv.swapRB_RGB565(data) for data in result] elif format_ == 0xa: if majorVersion == 6: result = [ dds.form_conv.swapRB_RGB5A1(data) for data in result ] else: result = [ dds.form_conv.toDDSrgb5a1(data) for data in result ] elif format_ == 0xb: result = [dds.form_conv.swapRB_RGBA4(data) for data in result] hdr = dds.generateHeader(numMips, width, height, format__, compSel, realSize, format_ in BCn_formats) else: print("") print("Unsupported texture format_: " + hex(format_)) print("") if i != (numImages - 1): print("Continuing in 5 seconds...") time.sleep(5) hdr, result = b'', [] else: print("Exiting in 5 seconds...") time.sleep(5) sys.exit(1) return hdr, result