#!/usr/bin/env python3
"""Discriminate the two competing punch-chunk role models from the authored eye:
  Model A (mask/hull):  visible = g1 (coarse hull) MINUS g0 silhouette (g0 = dmg_set mask)
  Model B (lattice):    visible = g0 alone (g1/g2 hidden as 'damage plates')
For each mech render, per punch patch set:
  cov0  = screen coverage of g0 (if ~solid over the view, drawing it opaque blinds -> kills B)
  cov1  = coverage of g1
  covA  = coverage of (g1 AND NOT g0)  -> Model A visible frame
  openA = fraction of g1 footprint punched open by g0
Also save a visual 3-panel per mech: g0 | g1 | A-composite.
"""
import os, re, math, sys, struct
import numpy as np
from PIL import Image
import importlib.util
spec = importlib.util.spec_from_file_location("pg", os.path.join(os.path.dirname(__file__), "punch_geom.py"))
# punch_geom.py runs a loop on import; import its parse via exec of the functions only
src = open(os.path.join(os.path.dirname(__file__), "punch_geom.py")).read()
src = src.split("for path in sys.argv")[0]
ns = {}
exec(src, ns)
parse = ns["parse"]

ROOT = r"C:\git\bt411"
MECHS = {"madcat":("MAD","MAX"), "bhk1":("BLH","BLX"), "thor":("THR","THX"),
         "owens":("OWN","OWX"), "sunder":("SND","SNX"), "loki":("LOK","LOX"),
         "vulture":("VUL","VUX"), "avatar":("AVA","AVX")}
W, H = 320, 240

def jointeye(skl_path):
    t = open(skl_path, encoding="latin1").read()
    m = re.search(r"\[jointeye\]", t)
    blk = t[m.start():m.start()+400]
    g = lambda k: float((re.search(rf"{k}=([-\d.e]+)", blk) or [None,"0"])[1])
    return np.array((g("tranx"), g("trany"), g("tranz")))

def raster_mask(tris, eye, fwd):
    """double-sided coverage rasterization -> bool mask"""
    up = np.array([0.,1.,0.])
    r = np.cross(up, fwd); r /= np.linalg.norm(r); u2 = np.cross(fwd, r)
    tanf = math.tan(math.radians(75)/2); aspect = W/H
    m = np.zeros((H,W), bool)
    for tri in tris:
        s = []
        ok = True
        for p in tri:
            d = p - eye
            cx, cy, cz = np.dot(d,r), np.dot(d,u2), np.dot(d,fwd)
            if cz <= 0.02: ok = False; break
            s.append((cx/(cz*tanf*aspect)*0.5*W + 0.5*W, -cy/(cz*tanf)*0.5*H + 0.5*H))
        if not ok: continue
        (ax,ay),(bx,by),(cx,cy) = s
        x0=max(0,int(min(ax,bx,cx))); x1=min(W-1,int(math.ceil(max(ax,bx,cx))))
        y0=max(0,int(min(ay,by,cy))); y1=min(H-1,int(math.ceil(max(ay,by,cy))))
        den=(by-cy)*(ax-cx)+(cx-bx)*(ay-cy)
        if abs(den)<1e-9 or x1<x0 or y1<y0: continue
        for py in range(y0,y1+1):
            for px in range(x0,x1+1):
                w0=((by-cy)*(px+.5-cx)+(cx-bx)*(py+.5-cy))/den
                w1=((cy-ay)*(px+.5-cx)+(ax-cx)*(py+.5-cy))/den
                w2=1-w0-w1
                if w0>=-1e-6 and w1>=-1e-6 and w2>=-1e-6: m[py,px]=True
    return m

def tris_of(g):
    V = g["verts"]
    return [np.array([V[a][:3],V[b][:3],V[c][:3]]) for (a,b,c) in g["faces"] if max(a,b,c)<len(V)]

rows = []
for name,(pfx,xpfx) in MECHS.items():
    eye = jointeye(os.path.join(ROOT,"content","VIDEO",pfx+".SKL"))
    P = parse(os.path.join(ROOT,"content","VIDEO","GEO",xpfx+"_COP.BGF"))
    views = [("fwd", np.array([0.,0.,-1.]))]
    if name == "madcat": views.append(("rear", np.array([0.,0.,1.])))
    for vname, fwd in views:
        m0 = np.zeros((H,W),bool); m1 = np.zeros((H,W),bool)
        for pt in P:
            if not pt["punch"] or len(pt["geoms"])<3: continue
            m0 |= raster_mask(tris_of(pt["geoms"][0]), eye, fwd)
            m1 |= raster_mask(tris_of(pt["geoms"][1]), eye, fwd)
        A = m1 & ~m0
        tot = W*H
        cov0 = m0.sum()/tot*100; cov1 = m1.sum()/tot*100; covA = A.sum()/tot*100
        openA = (m1&m0).sum()/max(1,m1.sum())*100
        print(f"{name:8s} {vname:4s}  g0(maskB-drawn?)={cov0:5.1f}%  g1(hull)={cov1:5.1f}%  "
              f"A=hull-minus-mask visible={covA:5.1f}%  hull punched open={openA:5.1f}%")
        img = np.zeros((H, W*3, 3), np.uint8); img[:] = (150,160,190)  # 'sky'
        img[:, :W][m0] = (200,60,40)       # g0 footprint
        img[:, W:2*W][m1] = (60,60,70)     # g1 footprint
        pane = np.zeros((H,W,3),np.uint8); pane[:] = (150,160,190); pane[A] = (35,25,45)
        img[:, 2*W:] = pane                 # Model A composite
        rows.append((f"{name}-{vname}", img))

out = np.concatenate([r[1] for r in rows], 0)
Image.fromarray(out).save(os.path.join(os.path.dirname(__file__), "PUNCH_ROLES.png"))
print("order:", [r[0] for r in rows])
print("panels: LEFT g0 footprint (red) | MID g1 hull footprint (grey) | RIGHT Model A visible (dark = frame)")
