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 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 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 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 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 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 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 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