Example #1
0
    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
Example #4
0
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