decode_pvrt: add support for twiddled textures

This commit is contained in:
Zack Buhman 2025-11-25 15:05:58 -06:00
parent ed66e93e07
commit 67aa9b3ea9

View File

@ -11,23 +11,21 @@ class PVRT:
texture_type: int texture_type: int
width: int width: int
height: int height: int
codebook: list[int] data: list[int]
indices: list[int]
def parse_pvrt_header(buf): def parse_pvrt_header(buf):
header = buf[0:16] header = buf[0:16]
codebook = buf[16:codebook_size + 16] #codebook = buf[16:codebook_size + 16]
indices = buf[codebook_size + 16:] #indices = buf[codebook_size + 16:]
data = buf[16:]
assert len(header) == 16 assert len(header) == 16
assert len(codebook) == codebook_size
assert header[0:4] == b"PVRT" assert header[0:4] == b"PVRT"
unpacked = struct.unpack('<LLHH', header[4:]) unpacked = struct.unpack('<LLHH', header[4:])
texture_data_size, texture_type, width, height = unpacked texture_data_size, texture_type, width, height = unpacked
print(texture_data_size) #print(texture_data_size)
print(hex(texture_type)) #print("texture type", hex(texture_type))
print(width) #print(width)
print(height) #print(height)
#assert len(indices) + len(codebook) == texture_data_size - 8, (len(indices) + len(codebook), texture_data_size - 8) #assert len(indices) + len(codebook) == texture_data_size - 8, (len(indices) + len(codebook), texture_data_size - 8)
#assert len(indices) == width * height / 4, (len(indices), width * height / 4) #assert len(indices) == width * height / 4, (len(indices), width * height / 4)
return PVRT( return PVRT(
@ -35,8 +33,7 @@ def parse_pvrt_header(buf):
texture_type, texture_type,
width, width,
height, height,
codebook, data,
indices,
) )
def rgb24(color): def rgb24(color):
@ -97,7 +94,9 @@ def from_xy(x, y, width, height):
return twiddle_ix return twiddle_ix
def decode_vq_indices(codebook, indices, width, height): def decode_vq_indices(data, width, height):
codebook = data[:codebook_size]
indices = data[codebook_size:]
canvas = [0] * width * height canvas = [0] * width * height
for ty in range(height // 2): for ty in range(height // 2):
for tx in range(width // 2): for tx in range(width // 2):
@ -114,16 +113,29 @@ def decode_vq_indices(codebook, indices, width, height):
canvas[di] = codeword[3] canvas[di] = codeword[3]
return canvas return canvas
def decode_twiddled(data, width, height):
canvas = [0] * width * height
for y in range(height):
for x in range(width):
ix = from_xy(x, y, width, height) * 2
color, = struct.unpack("<H", data[ix:ix+2])
canvas[y * width + x] = rgb24(color)
return canvas
in_filename = sys.argv[1] in_filename = sys.argv[1]
out_filename = sys.argv[2] out_filename = sys.argv[2]
with open(in_filename, 'rb') as f: with open(in_filename, 'rb') as f:
buf = f.read() buf = f.read()
pvrt = parse_pvrt_header(buf) pvrt = parse_pvrt_header(buf)
canvas = decode_vq_indices(pvrt.codebook, pvrt.indices, pvrt.width, pvrt.height) print(pvrt.texture_data_size, hex(pvrt.texture_type), pvrt.width, pvrt.height)
#canvas = decode_vq_indices(buf[:256 * 4 * 2], buf[256*4*2:], 256, 256) if (pvrt.texture_type & 0xff00) == 0x300: # vq
print(pvrt.texture_data_size, pvrt.texture_type, pvrt.width, pvrt.height) canvas = decode_vq_indices(pvrt.data, pvrt.width, pvrt.height)
elif (pvrt.texture_type & 0xff00) == 0x100: # twiddled
canvas = decode_twiddled(pvrt.data, pvrt.width, pvrt.height)
else:
assert False, ("unsupported texture type:", hex(pvrt.texture_type))
palimage = Image.new('RGB', (pvrt.width, pvrt.height)) palimage = Image.new('RGB', (pvrt.width, pvrt.height))
#palimage = Image.new('RGB', (256, 256))
palimage.putdata(canvas) palimage.putdata(canvas)
palimage.save(out_filename) palimage.save(out_filename)