#!/usr/bin/env python3 """TEXT-Chunk (Texturen) von Level-WADs lesen/schreiben. Aufbau (aus groove.exe 0x4067b0): u32 nPal; nPal x { u32 id, u32 n, u16 col[n], u8 extra[n] } u32 nPages; nPages x { u32 flags, u32 w, u32 h, Daten } flags==0 : w*h Byte (8-Bit, Palette) flags&0x80 : u32 Länge, RLE16 (s16 n: n>0 -> n Literal-u16, n<0 -> nächstes u16 (-n)-mal) sonst : w*h u16 roh u32 nTex; Rest = Textur-Einträge (8 Byte) + Anhang (siehe notes/textures.md) """ import struct import numpy as np def rle_decode(b, npix): out = np.zeros(npix, np.uint16) v = np.frombuffer(b, ' 0: out[p:p + n] = v[i:i + n]; i += n; p += n elif n < 0: out[p:p - n] = v[i]; i += 1; p -= n return out def rle_encode(px): px = np.asarray(px, np.uint16) out, i, N = [], 0, len(px) while i < N: j = i while j + 1 < N and px[j + 1] == px[i] and j - i < 32766: j += 1 if j > i: # Lauf >= 2 out += [(-(j - i + 1)) & 0xffff, int(px[i])]; i = j + 1 continue k = i # Literale bis zum nächsten Lauf while k < N and k - i < 32767 and not (k + 1 < N and px[k + 1] == px[k]): k += 1 out += [k - i] + [int(x) for x in px[i:k]]; i = k return struct.pack('<%dH' % len(out), *out) def parse(d): o = 0 pals = [] n = struct.unpack_from(' Alpha 255, STP=0 (Pixel != 0) -> Alpha 128 (auf Seiten mit Blendmodus = halbtransparent).""" px = px.astype(np.uint32) r = (px & 31) * 255 // 31 g = ((px >> 5) & 31) * 255 // 31 b = ((px >> 10) & 31) * 255 // 31 a = np.where(px == 0, 0, np.where(px & 0x8000, 255, 128)) return np.dstack([r, g, b, a]).astype(np.uint8) def rgba_to_abgr1555(img): """Umkehrung: Alpha < 64 -> 0x0000, 64..191 -> STP=0, >= 192 (oder RGB-Bild) -> STP=1.""" img = np.asarray(img).astype(np.uint32) v = ((img[..., 2] >> 3) << 10) | ((img[..., 1] >> 3) << 5) | (img[..., 0] >> 3) if img.shape[-1] == 4: a = img[..., 3] v = np.where(a >= 192, v | 0x8000, v) v = np.where((a >= 64) & (a < 192) & (v == 0), 0x0421, v) # fast schwarz statt durchsichtig v = np.where(a < 64, 0, v) else: v = v | 0x8000 return v.astype(np.uint16) def tex_entries(tail): """Textur-Einträge (Faces referenzieren diese Indizes): u16 flags, u8 page, u8 clut(0xff), u8 x0, u8 x1, u8 y0, u8 y1 (inklusive Kanten).""" n = struct.unpack_from('