1
0
Fork 0
mirror of https://github.com/zeldaret/oot.git synced 2025-08-24 16:01:26 +00:00
oot/tools/assets/n64yatc.py
Dragorn421 8411c34b38
wip: New assets system tm
Builds gc-eu-mq-dbg OK from clean after
1) make setup
2) python3 -m tools.assets.extract -j
3) replace 0x80A8E610 with sShadowTex in extracted/gc-eu-mq-dbg/assets/overlays/ovl_En_Jsjutan/sShadowMaterialDL.inc.c
4) make various symbols in extracted data like sTex static
2025-02-05 16:31:29 +01:00

203 lines
5.8 KiB
Python

# n64 yet another texture converter
# TODO replace with a C implementation
# FIXME use all tools as packages or idk
try:
from .n64 import G_IM_FMT, G_IM_SIZ
except ImportError:
from n64 import G_IM_FMT, G_IM_SIZ
def convert(
data: bytes,
from_fmt: G_IM_FMT,
from_siz: G_IM_SIZ,
to_fmt: G_IM_FMT,
to_siz: G_IM_SIZ,
):
if from_fmt == to_fmt == G_IM_FMT.CI:
if from_siz == to_siz:
return bytes(data)
elif from_siz == G_IM_SIZ._4b and to_siz == G_IM_SIZ._8b:
data_ci4 = data
data_ci8 = bytearray(len(data_ci4) * 2)
i = 0
for d in data_ci4:
data_ci8[i] = d >> 4
i += 1
data_ci8[i] = d & 0xF
i += 1
return data_ci8
elif from_siz == G_IM_SIZ._8b and to_siz == G_IM_SIZ._4b:
data_ci8 = data
assert len(data_ci8) % 2 == 0
data_ci4 = bytearray(len(data_ci8) // 2)
i = 0
while i < len(data_ci8):
d1, d2 = data_ci8[i : i + 2]
assert d1 < 16
assert d2 < 16
data_ci4[i // 2] = (d1 << 4) | d2
i += 2
return data_ci4
else:
raise NotImplementedError("ci", from_siz, to_siz)
else:
assert G_IM_FMT.CI not in (
from_fmt,
to_fmt,
), "Can't convert between a CI format and a non-CI format"
assert (
len(data) * 8 % from_siz.bpp == 0
), "data size is not a multiple of pixel size"
n_pixels = len(data) * 8 // from_siz.bpp
data_rgba32 = bytearray(4 * n_pixels)
_i = [0]
def push():
i = _i[0]
data_rgba32[4 * i : 4 * i + 4] = (r, g, b, a)
i += 1
_i[0] = i
f = (from_fmt, from_siz)
if f == (G_IM_FMT.RGBA, G_IM_SIZ._32b):
data_rgba32[:] = data
elif f == (G_IM_FMT.RGBA, G_IM_SIZ._16b):
while (i := _i[0]) < n_pixels:
d1, d2 = data[i * 2 : i * 2 + 2]
r = (d1 & 0b1111_1000) >> 3
g = ((d1 & 0b0000_0111) << 2) | ((d2 & 0b1100_0000) >> 6)
b = (d2 & 0b0011_1110) >> 1
a = d2 & 1
r = (r << 3) | (r >> 2)
g = (g << 3) | (g >> 2)
b = (b << 3) | (b >> 2)
a = a * 255
push()
elif f == (G_IM_FMT.IA, G_IM_SIZ._16b):
while (i := _i[0]) < n_pixels:
d1, d2 = data[i * 2 : i * 2 + 2]
i = d1
a = d2
r = i
g = i
b = i
a = a
push()
elif f == (G_IM_FMT.IA, G_IM_SIZ._8b):
while (i := _i[0]) < n_pixels:
d = data[i]
i = d >> 4
a = d & 0x0F
i = (i << 4) | i
a = (a << 4) | a
r = i
g = i
b = i
a = a
push()
elif f == (G_IM_FMT.IA, G_IM_SIZ._4b):
while (i := _i[0]) < n_pixels:
assert i % 2 == 0
d = data[i // 2]
for dh in (d >> 4, d & 0xF):
i = dh >> 1
a = dh & 1
i = (i << 5) | (i << 2) | (i >> 1)
a = a * 255
r = i
g = i
b = i
a = a
push()
elif f == (G_IM_FMT.I, G_IM_SIZ._8b):
while (i := _i[0]) < n_pixels:
d = data[i]
i = d
r = i
g = i
b = i
a = i
push()
elif f == (G_IM_FMT.I, G_IM_SIZ._4b):
while (i := _i[0]) < n_pixels:
assert i % 2 == 0
d = data[i // 2]
for dh in (d >> 4, d & 0xF):
i = dh
i = (i << 4) | i
r = i
g = i
b = i
a = i
push()
else:
raise NotImplementedError("from", from_fmt, from_siz)
assert n_pixels * to_siz.bpp % 8 == 0
data_to = bytearray(n_pixels * to_siz.bpp // 8)
for i in range(n_pixels):
r, g, b, a = data_rgba32[i * 4 : i * 4 + 4]
y = round(sum((r, g, b)) / 3) # bad but w/e
t = (to_fmt, to_siz)
if t == (G_IM_FMT.RGBA, G_IM_SIZ._32b):
data_to[4 * i : 4 * i + 4] = r, g, b, a
elif t == (G_IM_FMT.RGBA, G_IM_SIZ._16b):
r = r >> 3
g = g >> 3
b = b >> 3
a = round(a / 255)
d1 = (r << 3) | (g >> 2)
d2 = ((g & 0b11) << 6) | (b << 1) | a
data_to[2 * i : 2 * i + 2] = d1, d2
elif t == (G_IM_FMT.IA, G_IM_SIZ._16b):
a = a
d1 = y
d2 = a
data_to[i * 2 : i * 2 + 2] = d1, d2
elif t == (G_IM_FMT.IA, G_IM_SIZ._8b):
y = y >> 4
a = a >> 4
d = (y << 4) | a
data_to[i] = d
elif t == (G_IM_FMT.IA, G_IM_SIZ._4b):
y = y >> 5
a = round(a / 255)
d = (y << 1) | a
data_to[i // 2] |= (d << 4) if i % 2 == 0 else d
elif t == (G_IM_FMT.I, G_IM_SIZ._8b):
d = y
data_to[i] = d
elif t == (G_IM_FMT.I, G_IM_SIZ._4b):
y = y >> 4
d = y
data_to[i // 2] |= (d << 4) if i % 2 == 0 else d
else:
raise NotImplementedError("to", to_fmt, to_siz)
return data_to