CMP and RGBA8 fail spectacuarly, but at least you get *something* outputted

This commit is contained in:
icefire 2009-06-17 09:00:03 -07:00
parent 35f394563f
commit 30410fa33c

228
TPL.py
View File

@ -12,9 +12,9 @@ from common import *
class TPL(): class TPL():
"""This is the class to generate TPL texutres from PNG images, and to convert TPL textures to PNG images. The parameter file specifies the filename of the source, either a PNG image or a TPL image. """This is the class to generate TPL texutres from PNG images, and to convert TPL textures to PNG images. The parameter file specifies the filename of the source, either a PNG image or a TPL image.
Currently supported are the following formats to convert from TPL: RGBA8, RGB565, RGB5A3, I4, I8, IA4, IA8. Currently not supported are: CI4, CI8, CMP. Currently supported are the following formats to convert from TPL: RGBA8, RGB565, RGB5A3, CI4, CI8, I4, I8, IA4, IA8. Currently not supported are: CMP, CI14X2.
Currently support to convert to TPL: RGBA8. Currently not supported are: RGB565, RGB5A3, I4, I8, IA4, IA8, CI4, CI8, CMP. Currently support to convert to TPL: RGBA8. Currently not supported are: RGB565, RGB5A3, I4, I8, IA4, IA8, CI4, CI8, CMP, CI14X2.
There are still some bugs in either the RGBA8 conversion to or from TPL. This causes stretched and distorted images with some files and images dimensions.""" There are still some bugs in either the RGBA8 conversion to or from TPL. This causes stretched and distorted images with some files and images dimensions."""
@ -28,7 +28,7 @@ class TPL():
__endian__ = Struct.BE __endian__ = Struct.BE
def __format__(self): def __format__(self):
self.header_offset = Struct.uint32 self.header_offset = Struct.uint32
self.pallete_offset = Struct.uint32 self.palette_offset = Struct.uint32
class TPLTextureHeader(Struct): class TPLTextureHeader(Struct):
__endian__ = Struct.BE __endian__ = Struct.BE
def __format__(self): def __format__(self):
@ -43,6 +43,14 @@ class TPL():
self.min_lod = Struct.uint8 self.min_lod = Struct.uint8
self.max_lod = Struct.uint8 self.max_lod = Struct.uint8
self.unpacked = Struct.uint8 self.unpacked = Struct.uint8
class TPLPaletteHeader(Struct):
__endian__ = Struct.BE
def __format__(self):
self.nitems = Struct.uint16
self.unpacked = Struct.uint8
self.pad = Struct.uint8
self.format = Struct.uint32
self.offset = Struct.uint32
def __init__(self, file): def __init__(self, file):
self.file = file self.file = file
def toTPL(self, outfile, width = 0, height = 0): #single texture only def toTPL(self, outfile, width = 0, height = 0): #single texture only
@ -134,11 +142,15 @@ class TPL():
header.unpack(data[pos:pos + len(header)]) header.unpack(data[pos:pos + len(header)])
pos += len(header) pos += len(header)
palette_offsets = []
for i in range(header.ntextures): for i in range(header.ntextures):
tmp = self.TPLTexture() tmp = self.TPLTexture()
tmp.unpack(data[pos:pos + len(tmp)]) tmp.unpack(data[pos:pos + len(tmp)])
textures.append(tmp) textures.append(tmp)
pos += len(tmp) pos += len(tmp)
if(tmp.palette_offset > 0):
palette_offsets.append(tmp.palette_offset)
if(header.ntextures > 1): if(header.ntextures > 1):
raise ValueError("Only one texture supported. Don't touch me!") raise ValueError("Only one texture supported. Don't touch me!")
@ -175,6 +187,44 @@ class TPL():
tpldata = struct.unpack(">" + str(w * h * 2) + "H", data[tex.data_off:tex.data_off + (w * h * 4)]) tpldata = struct.unpack(">" + str(w * h * 2) + "H", data[tex.data_off:tex.data_off + (w * h * 4)])
rgbdata = self.RGBA8((w, h), tpldata) rgbdata = self.RGBA8((w, h), tpldata)
elif(tex.format == 8 or tex.format == 9 or tex.format == 10):
palhead = self.TPLPaletteHeader()
offs = palette_offsets.pop(0)
palhead.unpack(data[offs:offs + len(palhead)])
tpldata = struct.unpack(">" + str(palhead.nitems) + "H", data[palhead.offset:palhead.offset + (palhead.nitems * 2)])
if(palhead.format == 0):
palette_data = self.IA8((palhead.nitems, 1), tpldata)[0]
elif(palhead.format == 1):
palette_data = self.RGB565((palhead.nitems, 1), tpldata)[0]
elif(palhead.format == 2):
palette_data = self.RGB5A3((palhead.nitems, 1), tpldata)[0]
paldata = []
for i in range(0, palhead.nitems * 4, 4):
tmp = 0
tmp |= palette_data[i + 0] << 24
tmp |= palette_data[i + 1] << 16
tmp |= palette_data[i + 2] << 8
tmp |= palette_data[i + 3] << 0
paldata.append(tmp)
if(tex.format == 8):
tpldata = struct.unpack(">" + str((w * h) / 2) + "B", data[tex.data_off:tex.data_off + ((w * h) / 2)])
rgbdata = self.CI4((w, h), tpldata, paldata)
if(tex.format == 9):
tpldata = struct.unpack(">" + str(w * h) + "B", data[tex.data_off:tex.data_off + (w * h * 1)])
rgbdata = self.CI8((w, h), tpldata, paldata)
if(tex.format == 10):
tpldata = struct.unpack(">" + str(w * h) + "H", data[tex.data_off:tex.data_off + (w * h * 2)])
rgbdata = self.CI14X2((w, h), tpldata, paldata)
elif(tex.format == 14):
sz = ((w + 7) >> 3) * ((w + 7) >> 3) * 32
print sz
print len(data[tex.data_off:])
tpldata = struct.unpack(">" + str(sz / 2) + "H", data[tex.data_off:tex.data_off + sz])
rgbdata = self.CMP((w, h), tpldata)
else: else:
raise TypeError("Unsupported TPL Format: " + str(tex.format)) raise TypeError("Unsupported TPL Format: " + str(tex.format))
@ -403,4 +453,176 @@ class TPL():
out[y1][(x1 * 4) + 2] = b out[y1][(x1 * 4) + 2] = b
out[y1][(x1 * 4) + 3] = a out[y1][(x1 * 4) + 3] = a
return out return out
def CI4(self, (w, h), jar, pal):
out = [[0 for i in range(w * 4)] for i in range(h)]
i = 0
for y in range(0, h, 8):
for x in range(0, w, 8):
for y1 in range(y, y + 8):
for x1 in range(x, x + 8, 2):
if(y1 >= h or x1 >= w):
continue
pixel = jar[i]
r = (pal[pixel] & 0xFF000000) >> 24
g = (pal[pixel] & 0x00FF0000) >> 16
b = (pal[pixel] & 0x0000FF00) >> 8
a = (pal[pixel] & 0x000000FF) >> 0
out[y1][(x1 * 4) + 0] = r
out[y1][(x1 * 4) + 1] = g
out[y1][(x1 * 4) + 2] = b
out[y1][(x1 * 4) + 3] = a
if(y1 >= h or x1 >= w):
continue
pixel = jar[i]
i += 1
r = (pal[pixel] & 0xFF000000) >> 24
g = (pal[pixel] & 0x00FF0000) >> 16
b = (pal[pixel] & 0x0000FF00) >> 8
a = (pal[pixel] & 0x000000FF) >> 0
out[y1][((x1 + 1) * 4) + 0] = r
out[y1][((x1 + 1) * 4) + 1] = g
out[y1][((x1 + 1) * 4) + 2] = b
out[y1][((x1 + 1) * 4) + 3] = a
return out
def CI8(self, (w, h), jar, pal):
out = [[0 for i in range(w * 4)] for i in range(h)]
i = 0
for y in range(0, h, 4):
for x in range(0, w, 8):
for y1 in range(y, y + 4):
for x1 in range(x, x + 8):
if(y1 >= h or x1 >= w):
continue
pixel = jar[i]
i += 1
r = (pal[pixel] & 0xFF000000) >> 24
g = (pal[pixel] & 0x00FF0000) >> 16
b = (pal[pixel] & 0x0000FF00) >> 8
a = (pal[pixel] & 0x000000FF) >> 0
out[y1][(x1 * 4) + 0] = r
out[y1][(x1 * 4) + 1] = g
out[y1][(x1 * 4) + 2] = b
out[y1][(x1 * 4) + 3] = a
return out
def icolor(self, a, b, fa, fb, fc):
c = 0
for i in range(0, 32, 8):
xa = (a >> i) & 0xff
xb = (b >> i) & 0xff
xc = min(255, max(0, int((xa * fa + xb * fb) / fc)))
c |= xc << i
return c
def single565(self, pixel):
r = ((pixel >> 11) & 0x1F) << 3
g = ((pixel >> 5) & 0x3F) << 2
b = ((pixel >> 0) & 0x1F) << 3
a = 255
return (r << 24) | (g << 16) | (b << 8) | (a << 0)
def CMP(self, (w, h), jar):
out = [[0 for i in range(w * 4)] for i in range(h)]
pos = 0
ofs = 0
rgb = [0 for i in range(4)]
dst = [0 for i in range(w * h)]
for y in range(0, h, 8):
for x in range(0, w, 8):
maxw = min(w - x, 8)
for k in range(2):
for l in range(2):
rgb[0] = self.single565(jar[pos])
pos += 1
rgb[1] = self.single565(jar[pos])
pos += 1
if(jar[pos + 0] > jar[pos + 1]):
rgb[2] = self.icolor(rgb[0], rgb[1], 2, 1, 3) | 0xFF000000
rgb[3] = self.icolor(rgb[1], rgb[0], 2, 1, 3) | 0xFF000000
else:
rgb[2] = self.icolor(rgb[0], rgb[1], 0.5, 0.5, 1) | 0xFF000000
#rgb[3] = self.icolor(rgb[1], rgb[0], 2, 1, 3) & ~0xFF000000
rgb[3] = 0
# color selection (00, 01, 10, 11)
cm = jar[pos:pos + 2]
pixels = []
for pix in cm:
pixels.append(pix >> 8)
pixels.append(pix & 0xFF)
pos += 2
for n in range(4):
# one row (4 texels)
if(ofs < (w * h)):
if(maxw > 0 + l * 4):
dst[ofs] = rgb[(pixels[n] & 0xc0) >> 6]
ofs += 1
if(maxw > 1 + l * 4):
dst[ofs] = rgb[(pixels[n] & 0x30) >> 4]
ofs += 1
if(maxw > 2 + l * 4):
dst[ofs] = rgb[(pixels[n] & 0x0c) >> 2]
ofs += 1
if(maxw > 3 + l * 4):
dst[ofs] = rgb[(pixels[n] & 0x03) >> 0]
ofs += 1
num_rows = 0
num_tiles = 0
for i in range(w * h):
pixel = dst[i]
tile_offset = i % 16 # where are we in the tile?
if(i % 16 == 0 and i != 0): # if we are at the end of a tile...
num_tiles += 1 # ...move on to the next one!
if(num_tiles != 0 and (w / 4) == num_tiles): # if we are at the end of a row of tiles...
num_tiles = 0 # ...reset!
tile_offset = 0 # ...reset!
num_rows += 4 # plus four because each tile is four high
x = (tile_offset % 4) + (num_tiles * 4) # num_tiles part to not overwrite tiles earlier in this row, tile_offset to find how far on the x we are in this row in the tile
y = (num_rows) + (tile_offset / 4) # num_rows to not overwrite tiles above, tile_offset to show how many rows in the current tile we are
#print "tile %u of %u on row %u of %u (%u, %u): 0x%08x" % (num_tiles + 1, w / 4, (num_rows / 4) + 1, h / 4, x, y, pixel)
r = (pixel & 0xFF000000) >> 24
g = (pixel & 0x00FF0000) >> 16
b = (pixel & 0x0000FF00) >> 8
a = (pixel & 0x000000FF) >> 0
out[y][(x * 4) + 0] = r
out[y][(x * 4) + 1] = g
out[y][(x * 4) + 2] = b
out[y][(x * 4) + 3] = a
return out
def CI14X2(self, (w, h), jar):
out = [[0 for i in range(w * 4)] for i in range(h)]
i = 0
for y in range(0, h, 4):
for x in range(0, w, 4):
for y1 in range(y, y + 4):
for x1 in range(x, x + 4):
if(y1 >= h or x1 >= w):
continue
pixel = jar[i]
i += 1
r = (pal[pixel & 0x3FFF] & 0xFF000000) >> 24
g = (pal[pixel & 0x3FFF] & 0x00FF0000) >> 16
b = (pal[pixel & 0x3FFF] & 0x0000FF00) >> 8
a = (pal[pixel & 0x3FFF] & 0x000000FF) >> 0
out[y1][(x1 * 4) + 0] = r
out[y1][(x1 * 4) + 1] = g
out[y1][(x1 * 4) + 2] = b
out[y1][(x1 * 4) + 3] = a
return out