484 lines
19 KiB
Python
484 lines
19 KiB
Python
"""
|
||
extract_vb_doom.py
|
||
|
||
Parse vb_doom.c arrays, extract graphics into separate C files:
|
||
- face_sprites.c/h (3 face expressions, 3x4 tiles each)
|
||
- fist_sprites.c/h (4 fist frames)
|
||
- pistol_sprites.c/h (pistol red + black, 2 frames each)
|
||
- vb_doom.c (HUD-only: UI bar, numbers, transitions)
|
||
|
||
Also computes the new VRAM layout and prints updated CHAR_START values.
|
||
"""
|
||
|
||
import re, os, sys
|
||
|
||
SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__))
|
||
VB_DOOM_SOURCE = os.path.join(SCRIPT_DIR, "grit_conversions", "vb_doom.c")
|
||
VB_DOOM_FALLBACK = os.path.join(SCRIPT_DIR, "src", "vbdoom", "assets", "images", "vb_doom.c")
|
||
OUTPUT_DIR = os.path.join(SCRIPT_DIR, "src", "vbdoom", "assets", "images")
|
||
|
||
MAP_COLS = 48
|
||
BYTES_PER_ROW = MAP_COLS * 2 # 96
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Parsing
|
||
# ---------------------------------------------------------------------------
|
||
|
||
def parse_hex_array(filepath, array_name):
|
||
"""Parse a C hex array, return list of ints."""
|
||
with open(filepath, 'r') as f:
|
||
text = f.read()
|
||
pattern = rf'{re.escape(array_name)}\[\d+\].*?=\s*\{{(.*?)\}};'
|
||
m = re.search(pattern, text, re.DOTALL)
|
||
if not m:
|
||
raise ValueError(f"Array '{array_name}' not found in {filepath}")
|
||
return [int(x, 16) for x in re.findall(r'0x[0-9A-Fa-f]+', m.group(1))]
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Helpers
|
||
# ---------------------------------------------------------------------------
|
||
|
||
def char_of(entry):
|
||
"""Char index from a BGMap u16 entry (bits 0-10)."""
|
||
return entry & 0x07FF
|
||
|
||
|
||
def remap(entry, new_char):
|
||
"""Replace char bits of a BGMap u16 entry, keep flags/palette."""
|
||
return (entry & 0xF800) | (new_char & 0x07FF)
|
||
|
||
|
||
def tile_words(tiles_u32, char_idx):
|
||
"""Return the 4 u32 words for one 8x8 tile."""
|
||
o = char_idx * 4
|
||
return tiles_u32[o:o + 4]
|
||
|
||
|
||
def collect_chars(map_u16, regions):
|
||
"""Collect unique non-zero char indices from (byte_off, nbytes) regions."""
|
||
chars = set()
|
||
for boff, nbytes in regions:
|
||
for i in range(0, nbytes, 2):
|
||
idx = (boff + i) // 2
|
||
if idx < len(map_u16):
|
||
c = char_of(map_u16[idx])
|
||
if c != 0:
|
||
chars.add(c)
|
||
return chars
|
||
|
||
|
||
def collect_entries(map_u16, regions):
|
||
"""Collect map entries in order from (byte_off, nbytes) regions."""
|
||
entries = []
|
||
for boff, nbytes in regions:
|
||
for i in range(0, nbytes, 2):
|
||
idx = (boff + i) // 2
|
||
entries.append(map_u16[idx] if idx < len(map_u16) else 0)
|
||
return entries
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# C code generation
|
||
# ---------------------------------------------------------------------------
|
||
|
||
def fmt_tiles(name, data_u32, comment=""):
|
||
"""Generate C tile array."""
|
||
lines = []
|
||
if comment:
|
||
lines.append(f"/* {comment} */")
|
||
lines.append(f"const unsigned int {name}[{len(data_u32)}]"
|
||
f" __attribute__((aligned(4))) =")
|
||
lines.append("{")
|
||
for i in range(0, len(data_u32), 8):
|
||
chunk = data_u32[i:i + 8]
|
||
s = ",".join(f"0x{v:08X}" for v in chunk)
|
||
comma = "," if i + 8 < len(data_u32) else ""
|
||
lines.append(f"\t{s}{comma}")
|
||
lines.append("};")
|
||
return "\n".join(lines)
|
||
|
||
|
||
def fmt_map(name, data_u16, comment=""):
|
||
"""Generate C map array."""
|
||
lines = []
|
||
if comment:
|
||
lines.append(f"/* {comment} */")
|
||
lines.append(f"const unsigned short {name}[{len(data_u16)}]"
|
||
f" __attribute__((aligned(4))) =")
|
||
lines.append("{")
|
||
for i in range(0, len(data_u16), 8):
|
||
chunk = data_u16[i:i + 8]
|
||
s = ",".join(f"0x{v:04X}" for v in chunk)
|
||
comma = "," if i + 8 < len(data_u16) else ""
|
||
lines.append(f"\t{s}{comma}")
|
||
lines.append("};")
|
||
return "\n".join(lines)
|
||
|
||
|
||
# ---------------------------------------------------------------------------
|
||
# Main
|
||
# ---------------------------------------------------------------------------
|
||
|
||
def main():
|
||
vb_doom_c = VB_DOOM_SOURCE if os.path.isfile(VB_DOOM_SOURCE) else VB_DOOM_FALLBACK
|
||
print(f"Using source: {vb_doom_c}")
|
||
tiles_u32 = parse_hex_array(vb_doom_c, "vb_doomTiles")
|
||
map_u16 = parse_hex_array(vb_doom_c, "vb_doomMap")
|
||
num_tiles = len(tiles_u32) // 4
|
||
print(f"Parsed {num_tiles} tiles, {len(map_u16)} map entries")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 1. Define regions (byte_offset, num_bytes) into vb_doomMap
|
||
# -----------------------------------------------------------------------
|
||
|
||
# -- HUD --
|
||
hud_regions = []
|
||
for r in range(4): # UI bar rows 0-3
|
||
hud_regions.append((r * 96, 96))
|
||
hud_regions.append((4 * 96, 2)) # black tile (row 4 col 0)
|
||
hud_regions.append((16 * 96, 46)) # large nums row 16 (cols 0-22, incl ":")
|
||
hud_regions.append((17 * 96, 46)) # large nums row 17 (cols 0-22, incl ":")
|
||
hud_regions.append((18 * 96, 22)) # small nums row 18 (normal digits 0-9)
|
||
hud_regions.append((19 * 96, 20)) # bright digits 0-9 (row 19)
|
||
hud_regions.append((20 * 96, 20)) # rectangled digits 0-9 (row 20)
|
||
for r in range(20, 28): # transition tiles rows 20-27
|
||
hud_regions.append((r * 96 + 31 * 2, 8)) # cols 31-34
|
||
hud_regions.append((25 * 96 + 39 * 2, 4)) # wall tiles row 25 cols 39-40
|
||
|
||
# -- Faces (3 faces × 4 rows × 3 entries) --
|
||
face_regions = []
|
||
for face_id in range(3):
|
||
wf = face_id * 384
|
||
for rb in [400, 496, 592, 688]:
|
||
face_regions.append((rb + wf, 6))
|
||
|
||
# -- Fists (4 frames) --
|
||
fist_fdefs = [
|
||
(96 * 22, 30, 6), # frame 0 idle
|
||
(96 * 22 + 30, 22, 6), # frame 1 attack 1
|
||
(96 * 13 + 48, 28, 7), # frame 2 attack 2
|
||
(96 * 28, 34, 8), # frame 3 attack 3
|
||
]
|
||
fist_per_frame = []
|
||
for sp, xt, nr in fist_fdefs:
|
||
fist_per_frame.append([(sp + r * 96, xt) for r in range(nr)])
|
||
|
||
# -- Pistol red (2 frames) --
|
||
pist_fdefs = [
|
||
(96 * 9, 16, 7), # idle
|
||
(96 * 5 + 22, 16, 11), # shooting
|
||
]
|
||
pist_per_frame = []
|
||
for sp, xt, nr in pist_fdefs:
|
||
pist_per_frame.append([(sp + r * 96, xt) for r in range(nr)])
|
||
|
||
# -- Pistol black (2 frames) --
|
||
pistb_fdefs = [
|
||
(96 * 28 + 34, 16, 8), # idle black
|
||
(96 * 28 + 50, 16, 8), # shooting black
|
||
]
|
||
pistb_per_frame = []
|
||
for sp, xt, nr in pistb_fdefs:
|
||
pistb_per_frame.append([(sp + r * 96, xt) for r in range(nr)])
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 2. Collect unique chars per group
|
||
# -----------------------------------------------------------------------
|
||
hud_chars = collect_chars(map_u16, hud_regions) | {0}
|
||
|
||
face_chars = collect_chars(map_u16, face_regions)
|
||
|
||
fist_chars = set()
|
||
for fr in fist_per_frame:
|
||
fist_chars |= collect_chars(map_u16, fr)
|
||
|
||
pist_chars = set()
|
||
for fr in pist_per_frame:
|
||
pist_chars |= collect_chars(map_u16, fr)
|
||
|
||
pistb_chars = set()
|
||
for fr in pistb_per_frame:
|
||
pistb_chars |= collect_chars(map_u16, fr)
|
||
|
||
pistol_all = pist_chars | pistb_chars
|
||
weapon_max = max(len(fist_chars), len(pistol_all))
|
||
|
||
H = len(hud_chars)
|
||
F = len(face_chars)
|
||
W = weapon_max
|
||
|
||
# Use the ACTUAL game VRAM layout char starts.
|
||
# Faces use 12 dynamic chars (from sprites/faces/face_sprites.h).
|
||
# The large gap between faces and weapons is intentional.
|
||
FACE_CS = H # face chars immediately after HUD
|
||
WEAP_CS = 544 # game's WEAPON_CHAR_START (doomgfx.h)
|
||
ZOMBIE_CS = 983 # game's ZOMBIE_CHAR_START (doomgfx.h)
|
||
PICKUP_CS = ZOMBIE_CS + 5 * 64 # 1303 (5 enemy slots x 64 chars each)
|
||
WALL_CS = 1327 # game's WALL_TEX_CHAR_START (wall_textures.h)
|
||
|
||
print(f"\nChars per group: HUD={H} Face={F} Weapon={W}"
|
||
f" (fists={len(fist_chars)}, pistol={len(pistol_all)})")
|
||
print(f"\nNew VRAM layout:")
|
||
print(f" HUD 0 - {H-1}")
|
||
print(f" Faces {FACE_CS} - {FACE_CS+F-1}")
|
||
print(f" Weapon {WEAP_CS} - {WEAP_CS+W-1}")
|
||
print(f" Enemies {ZOMBIE_CS} - {ZOMBIE_CS+191}")
|
||
print(f" Pickups {PICKUP_CS} - {PICKUP_CS+35}")
|
||
print(f" Wall textures {WALL_CS} - {WALL_CS+511}")
|
||
after_walls = WALL_CS + 512
|
||
print(f" After walls {after_walls} (free: {2048-after_walls})")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 3. Build remappings old_char -> new_char
|
||
# -----------------------------------------------------------------------
|
||
hud_sorted = sorted(hud_chars)
|
||
hud_rm = {old: new for new, old in enumerate(hud_sorted)}
|
||
|
||
face_sorted = sorted(face_chars)
|
||
face_rm = {0: 0}
|
||
for i, c in enumerate(face_sorted):
|
||
face_rm[c] = FACE_CS + i
|
||
|
||
fist_sorted = sorted(fist_chars)
|
||
fist_rm = {0: 0}
|
||
for i, c in enumerate(fist_sorted):
|
||
fist_rm[c] = WEAP_CS + i
|
||
|
||
pistol_sorted = sorted(pistol_all)
|
||
pistol_rm = {0: 0}
|
||
for i, c in enumerate(pistol_sorted):
|
||
pistol_rm[c] = WEAP_CS + i
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 4. Generate HUD-only vb_doom.c
|
||
# -----------------------------------------------------------------------
|
||
hud_tile_data = []
|
||
for c in hud_sorted:
|
||
hud_tile_data.extend(tile_words(tiles_u32, c))
|
||
|
||
hud_map_out = [0] * len(map_u16)
|
||
for boff, nbytes in hud_regions:
|
||
for i in range(0, nbytes, 2):
|
||
idx = (boff + i) // 2
|
||
if idx < len(map_u16):
|
||
e = map_u16[idx]
|
||
c = char_of(e)
|
||
if c in hud_rm:
|
||
hud_map_out[idx] = remap(e, hud_rm[c])
|
||
|
||
# Zero weapon slot positions (cols 17-19, rows 1-2) - drawn dynamically by drawWeaponSlotNumbers
|
||
for row in (1, 2):
|
||
for col in (17, 18, 19):
|
||
idx = row * MAP_COLS + col
|
||
hud_map_out[idx] = 0
|
||
|
||
# Zero dynamic ammo positions (cols 40-42, rows 0-3) so static placeholders
|
||
# don't show before drawUpdatedAmmo writes the real digits there
|
||
for row in range(4):
|
||
for col in (40, 41, 42):
|
||
hud_map_out[row * MAP_COLS + col] = 0
|
||
|
||
hud_c_path = os.path.join(OUTPUT_DIR, "vb_doom.c")
|
||
with open(hud_c_path, 'w') as f:
|
||
f.write("/*\n")
|
||
f.write(" * vb_doom -- HUD-only tileset (auto-generated by extract_vb_doom.py)\n")
|
||
f.write(f" * {H} tiles, {H*16} bytes tile data\n")
|
||
f.write(f" * {len(hud_map_out)} map entries (48x46), non-HUD entries zeroed\n")
|
||
f.write(" */\n\n")
|
||
f.write(fmt_tiles("vb_doomTiles", hud_tile_data,
|
||
f"{H} HUD tiles"))
|
||
f.write("\n\n")
|
||
f.write(fmt_map("vb_doomMap", hud_map_out,
|
||
"48x46 map -- HUD entries only"))
|
||
f.write("\n")
|
||
print(f"\nWrote {hud_c_path} ({H} tiles, {H*16} bytes)")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 5. Generate face_sprites.c/h
|
||
# -----------------------------------------------------------------------
|
||
face_tile_data = []
|
||
for c in face_sorted:
|
||
face_tile_data.extend(tile_words(tiles_u32, c))
|
||
|
||
# Compact face map: 3 faces × 4 rows × 3 entries = 36 entries
|
||
face_map_out = []
|
||
for face_id in range(3):
|
||
wf = face_id * 384
|
||
for rb in [400, 496, 592, 688]:
|
||
for i in range(0, 6, 2):
|
||
idx = (rb + wf + i) // 2
|
||
e = map_u16[idx]
|
||
c = char_of(e)
|
||
face_map_out.append(remap(e, face_rm.get(c, 0)) if c in face_rm else 0)
|
||
|
||
face_c = os.path.join(OUTPUT_DIR, "face_sprites.c")
|
||
with open(face_c, 'w') as f:
|
||
f.write("/* Face sprite tiles -- auto-generated by extract_vb_doom.py */\n\n")
|
||
f.write(fmt_tiles("faceTiles", face_tile_data, f"{F} face tiles"))
|
||
f.write("\n\n")
|
||
f.write(fmt_map("faceMap", face_map_out,
|
||
"3 faces x 4 rows x 3 cols = 36 entries"))
|
||
f.write("\n")
|
||
|
||
face_h = os.path.join(OUTPUT_DIR, "face_sprites.h")
|
||
with open(face_h, 'w') as f:
|
||
f.write("#ifndef __FACE_SPRITES_H__\n#define __FACE_SPRITES_H__\n\n")
|
||
f.write(f"#define FACE_CHAR_START {FACE_CS}\n")
|
||
f.write(f"#define FACE_TILE_COUNT {F}\n")
|
||
f.write(f"#define FACE_TILE_BYTES {F*16}\n")
|
||
f.write(f"#define FACE_MAP_ENTRIES 36 /* 3 faces x 12 tiles */\n\n")
|
||
f.write(f"extern const unsigned int faceTiles[{len(face_tile_data)}];\n")
|
||
f.write(f"extern const unsigned short faceMap[{len(face_map_out)}];\n\n")
|
||
f.write("#endif\n")
|
||
print(f"Wrote {face_c} ({F} tiles)")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 6. Generate fist_sprites.c/h
|
||
# -----------------------------------------------------------------------
|
||
fist_tile_data = []
|
||
for c in fist_sorted:
|
||
fist_tile_data.extend(tile_words(tiles_u32, c))
|
||
|
||
fist_frame_maps = []
|
||
fist_frame_sizes = [] # (width_entries, rows)
|
||
for fi, (sp, xt, nr) in enumerate(fist_fdefs):
|
||
w_entries = xt // 2
|
||
fmap = []
|
||
for r in range(nr):
|
||
for i in range(0, xt, 2):
|
||
idx = (sp + r * 96 + i) // 2
|
||
e = map_u16[idx]
|
||
c = char_of(e)
|
||
fmap.append(remap(e, fist_rm.get(c, 0)) if c in fist_rm else 0)
|
||
fist_frame_maps.append(fmap)
|
||
fist_frame_sizes.append((w_entries, nr))
|
||
|
||
fist_c = os.path.join(OUTPUT_DIR, "fist_sprites.c")
|
||
with open(fist_c, 'w') as f:
|
||
f.write("/* Fist sprite tiles -- auto-generated by extract_vb_doom.py */\n\n")
|
||
f.write(fmt_tiles("fistTiles", fist_tile_data,
|
||
f"{len(fist_sorted)} fist tiles"))
|
||
for fi, fm in enumerate(fist_frame_maps):
|
||
f.write("\n\n")
|
||
we, nr = fist_frame_sizes[fi]
|
||
f.write(fmt_map(f"fistFrame{fi}Map", fm,
|
||
f"frame {fi}: {we} cols x {nr} rows"))
|
||
f.write("\n")
|
||
|
||
fist_h = os.path.join(OUTPUT_DIR, "fist_sprites.h")
|
||
with open(fist_h, 'w') as f:
|
||
f.write("#ifndef __FIST_SPRITES_H__\n#define __FIST_SPRITES_H__\n\n")
|
||
f.write(f"#define FIST_TILE_COUNT {len(fist_sorted)}\n")
|
||
f.write(f"#define FIST_TILE_BYTES {len(fist_sorted)*16}\n\n")
|
||
f.write(f"extern const unsigned int fistTiles[{len(fist_tile_data)}];\n\n")
|
||
f.write(f"#define FIST_FRAME_COUNT 4\n")
|
||
for fi, (we, nr) in enumerate(fist_frame_sizes):
|
||
xt = we * 2
|
||
f.write(f"#define FIST_F{fi}_XTILES {xt}\n")
|
||
f.write(f"#define FIST_F{fi}_ROWS {nr}\n")
|
||
f.write(f"extern const unsigned short fistFrame{fi}Map[{len(fist_frame_maps[fi])}];\n")
|
||
f.write("\n#endif\n")
|
||
print(f"Wrote {fist_c} ({len(fist_sorted)} tiles)")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 7. Generate pistol_sprites.c/h (red + black combined tile data)
|
||
# -----------------------------------------------------------------------
|
||
pistol_tile_data = []
|
||
for c in pistol_sorted:
|
||
pistol_tile_data.extend(tile_words(tiles_u32, c))
|
||
|
||
# Red frames
|
||
pist_frame_maps = []
|
||
pist_frame_sizes = []
|
||
for fi, (sp, xt, nr) in enumerate(pist_fdefs):
|
||
we = xt // 2
|
||
fmap = []
|
||
for r in range(nr):
|
||
for i in range(0, xt, 2):
|
||
idx = (sp + r * 96 + i) // 2
|
||
e = map_u16[idx]
|
||
c = char_of(e)
|
||
fmap.append(remap(e, pistol_rm.get(c, 0)) if c in pistol_rm else 0)
|
||
pist_frame_maps.append(fmap)
|
||
pist_frame_sizes.append((we, nr))
|
||
|
||
# Black frames
|
||
pistb_frame_maps = []
|
||
pistb_frame_sizes = []
|
||
for fi, (sp, xt, nr) in enumerate(pistb_fdefs):
|
||
we = xt // 2
|
||
fmap = []
|
||
for r in range(nr):
|
||
for i in range(0, xt, 2):
|
||
idx = (sp + r * 96 + i) // 2
|
||
e = map_u16[idx]
|
||
c = char_of(e)
|
||
fmap.append(remap(e, pistol_rm.get(c, 0)) if c in pistol_rm else 0)
|
||
pistb_frame_maps.append(fmap)
|
||
pistb_frame_sizes.append((we, nr))
|
||
|
||
pist_c = os.path.join(OUTPUT_DIR, "pistol_sprites.c")
|
||
with open(pist_c, 'w') as f:
|
||
f.write("/* Pistol sprite tiles (red + black) -- auto-generated */\n\n")
|
||
f.write(fmt_tiles("pistolTiles", pistol_tile_data,
|
||
f"{len(pistol_sorted)} pistol tiles (red+black)"))
|
||
# Red frame maps
|
||
for fi, fm in enumerate(pist_frame_maps):
|
||
f.write("\n\n")
|
||
we, nr = pist_frame_sizes[fi]
|
||
f.write(fmt_map(f"pistolRedFrame{fi}Map", fm,
|
||
f"red frame {fi}: {we} cols x {nr} rows"))
|
||
# Black frame maps
|
||
for fi, fm in enumerate(pistb_frame_maps):
|
||
f.write("\n\n")
|
||
we, nr = pistb_frame_sizes[fi]
|
||
f.write(fmt_map(f"pistolBlackFrame{fi}Map", fm,
|
||
f"black frame {fi}: {we} cols x {nr} rows"))
|
||
f.write("\n")
|
||
|
||
pist_h = os.path.join(OUTPUT_DIR, "pistol_sprites.h")
|
||
with open(pist_h, 'w') as f:
|
||
f.write("#ifndef __PISTOL_SPRITES_H__\n#define __PISTOL_SPRITES_H__\n\n")
|
||
f.write(f"#define PISTOL_TILE_COUNT {len(pistol_sorted)}\n")
|
||
f.write(f"#define PISTOL_TILE_BYTES {len(pistol_sorted)*16}\n\n")
|
||
f.write(f"extern const unsigned int pistolTiles[{len(pistol_tile_data)}];\n\n")
|
||
f.write("/* Red layer frames */\n")
|
||
for fi, (we, nr) in enumerate(pist_frame_sizes):
|
||
xt = we * 2
|
||
f.write(f"#define PISTOL_RED_F{fi}_XTILES {xt}\n")
|
||
f.write(f"#define PISTOL_RED_F{fi}_ROWS {nr}\n")
|
||
f.write(f"extern const unsigned short pistolRedFrame{fi}Map"
|
||
f"[{len(pist_frame_maps[fi])}];\n")
|
||
f.write("\n/* Black layer frames */\n")
|
||
for fi, (we, nr) in enumerate(pistb_frame_sizes):
|
||
xt = we * 2
|
||
f.write(f"#define PISTOL_BLK_F{fi}_XTILES {xt}\n")
|
||
f.write(f"#define PISTOL_BLK_F{fi}_ROWS {nr}\n")
|
||
f.write(f"extern const unsigned short pistolBlackFrame{fi}Map"
|
||
f"[{len(pistb_frame_maps[fi])}];\n")
|
||
f.write("\n#endif\n")
|
||
print(f"Wrote {pist_c} ({len(pistol_sorted)} tiles)")
|
||
|
||
# -----------------------------------------------------------------------
|
||
# 8. Print summary of defines to update in C headers
|
||
# -----------------------------------------------------------------------
|
||
print("\n" + "=" * 60)
|
||
print("UPDATE THESE DEFINES IN C HEADERS:")
|
||
print("=" * 60)
|
||
print(f" doomgfx.h:")
|
||
print(f" #define ZOMBIE_CHAR_START {ZOMBIE_CS}")
|
||
print(f" #define WEAPON_CHAR_START {WEAP_CS}")
|
||
print(f" pickup.h (or doomgfx.h):")
|
||
print(f" #define PICKUP_CHAR_START {PICKUP_CS}")
|
||
print(f" wall_textures.h:")
|
||
print(f" #define WALL_TEX_CHAR_START {WALL_CS}")
|
||
print(f" doomgfx.c loadDoomGfxToMem:")
|
||
print(f" copymem size = {H * 16} (was 14224)")
|
||
print("=" * 60)
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|