89 lines
2.7 KiB
Python
89 lines
2.7 KiB
Python
IN_BIN = r"K:\ghidra\Crusader_Decomp\binary\Crusader - No Remorse Memdump Weapons.bin"
|
|
W,H = 1024,512
|
|
TOP, BOT = 44, 92 # y range (inclusive start, exclusive end)
|
|
import os
|
|
with open(IN_BIN,'rb') as f:
|
|
data = f.read()
|
|
count = min(len(data)//2, W*H)
|
|
# build mask for this row range
|
|
col_counts = [0]*W
|
|
for y in range(TOP, BOT):
|
|
for x in range(W):
|
|
i = y*W + x
|
|
if i < count:
|
|
off = i*2
|
|
val = data[off] | (data[off+1]<<8)
|
|
if val & 0x7fff:
|
|
col_counts[x] += 1
|
|
# find runs where col_counts exceeds threshold
|
|
maxc = max(col_counts)
|
|
thr = max(3, int(maxc*0.2))
|
|
runs = []
|
|
inside=False
|
|
for x,c in enumerate(col_counts):
|
|
if c>thr and not inside:
|
|
sx = x; inside=True
|
|
if c<=thr and inside:
|
|
ex = x-1; inside=False; runs.append((sx,ex))
|
|
if inside: runs.append((sx,W-1))
|
|
print('max per-col count', maxc, 'threshold', thr)
|
|
print('runs:', runs)
|
|
# compute byte offsets and produce crops (no PIL)
|
|
import struct, zlib
|
|
OUT_DIR = r"K:\ghidra\Crusader_Decomp\binary\hud_candidates"
|
|
os.makedirs(OUT_DIR, exist_ok=True)
|
|
with open(IN_BIN,'rb') as f:
|
|
bin_data = f.read()
|
|
# build full rows RGB
|
|
rows = []
|
|
for y in range(H):
|
|
row = bytearray()
|
|
for x in range(W):
|
|
i = y*W + x
|
|
if i < count:
|
|
off = i*2
|
|
val = bin_data[off] | (bin_data[off+1]<<8)
|
|
b = (val & 0x1F) << 3
|
|
g = ((val >>5)&0x1F) << 3
|
|
r = ((val >>10)&0x1F) << 3
|
|
else:
|
|
r=g=b=0
|
|
row.extend([r,g,b])
|
|
rows.append(bytes(row))
|
|
# for each run, create a crop with padding
|
|
for i,(sx,ex) in enumerate(runs):
|
|
pad = 8
|
|
x0 = max(0, sx-pad)
|
|
x1 = min(W-1, ex+pad)
|
|
y0 = TOP; y1 = BOT-1
|
|
w = x1 - x0 + 1
|
|
h = y1 - y0 + 1
|
|
rawrows = []
|
|
for y in range(y0, y1+1):
|
|
rawrows.append(b"\x00" + rows[y][x0*3:(x0+w)*3])
|
|
raw = b"".join(rawrows)
|
|
comp = zlib.compress(raw,9)
|
|
def chunk(t,d):
|
|
out = struct.pack('>I', len(d)) + t + d
|
|
import zlib
|
|
crc = zlib.crc32(t + d) & 0xffffffff
|
|
out += struct.pack('>I', crc)
|
|
return out
|
|
png = b"\x89PNG\r\n\x1a\n"
|
|
png += chunk(b'IHDR', struct.pack('>IIBBBBB', w, h, 8, 2, 0, 0, 0))
|
|
png += chunk(b'IDAT', comp)
|
|
png += chunk(b'IEND', b'')
|
|
out = os.path.join(OUT_DIR, f'cand_{i}_{x0}_{y0}.png')
|
|
with open(out,'wb') as f:
|
|
f.write(png)
|
|
start_idx = y0*W + x0
|
|
end_idx = y1*W + x1
|
|
so = start_idx*2
|
|
eo = (end_idx+1)*2 -1
|
|
print(f'wrote {out} box=({x0},{y0})-({x1},{y1}) bytes=0x{so:06x}-0x{eo:06x} col_counts_max={max(col_counts[x0:x1+1])}')
|
|
|
|
# also print top columns with counts
|
|
top_cols = sorted(((c,x) for x,c in enumerate(col_counts)), reverse=True)[:30]
|
|
print('\nTop columns (count,x):')
|
|
for c,x in top_cols:
|
|
print(c,x)
|