Crusader_Decomp/tools/vram_analyze.py

60 lines
2 KiB
Python
Raw Permalink Normal View History

2026-04-12 14:45:08 +02:00
from collections import deque
IN_PATH = r"K:\ghidra\Crusader_Decomp\binary\Crusader - No Remorse Memdump Weapons.bin"
W,H = 1024,512
import os
with open(IN_PATH,'rb') as f:
data = f.read()
count = min(len(data)//2, W*H)
# build mask of non-black pixels
mask = bytearray(W*H)
for i in range(count):
off = i*2
val = data[off] | (data[off+1]<<8)
b = (val & 0x1F) << 3
g = ((val >>5) & 0x1F) << 3
r = ((val >>10) & 0x1F) << 3
if r|g|b:
mask[i] = 1
# flood-fill connected components (4-neigh)
visited = bytearray(W*H)
bbs = []
for idx in range(W*H):
if mask[idx] and not visited[idx]:
q = deque([idx])
visited[idx]=1
xs = []
ys = []
while q:
v = q.popleft()
y = v // W
x = v % W
xs.append(x); ys.append(y)
# neighbors
for dx,dy in ((1,0),(-1,0),(0,1),(0,-1)):
nx = x+dx; ny = y+dy
if 0<=nx<W and 0<=ny<H:
ni = ny*W+nx
if mask[ni] and not visited[ni]:
visited[ni]=1
q.append(ni)
x0,x1 = min(xs), max(xs)
y0,y1 = min(ys), max(ys)
area = len(xs)
start_idx = y0*W + x0
end_idx = y1*W + x1
start_off = start_idx*2
end_off = (end_idx+1)*2 - 1
bbs.append((x0,y0,x1,y1,area,start_off,end_off))
# sort by area descending
bbs.sort(key=lambda x: -x[4])
print('Found', len(bbs), 'components')
for i,(x0,y0,x1,y1,area,so,eo) in enumerate(bbs[:20]):
print(f'[{i}] box=({x0},{y0})-({x1},{y1}) area={area} bytes=0x{so:06x}-0x{eo:06x}')
# Save the top few as small BMP crops for inspection
from PIL import Image
img = Image.open(r"K:\ghidra\Crusader_Decomp\binary\vram_weapons.png")
for i,(x0,y0,x1,y1,area,so,eo) in enumerate(bbs[:12]):
crop = img.crop((x0,y0,x1+1,y1+1))
out = r"K:\ghidra\Crusader_Decomp\binary\crop_%02d.png"%i
crop.save(out)
print('wrote', out)