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 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 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 imageSize = surfOut.surfSize pitch = surfOut.pitch tilingDepth = surfOut.depth if surfOut.tileMode == 3: tilingDepth //= 4 if tilingDepth != 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) s = 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 = [] 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: 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_, 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 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] 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)) 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 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