import struct
d=open("content/VIDEO/GEO/BLX_COP.BGF","rb").read()
def walk(d,p,end,depth,out):
    while p+3<=end:
        tw=struct.unpack_from("<H",d,p)[0]; p+=2
        cid=tw&0x2fff
        lw=4 if(tw&0x8000)else(2 if(tw&0x4000)else 1)
        if p+lw>end:return
        ln=d[p] if lw==1 else (struct.unpack_from("<H",d,p)[0] if lw==2 else struct.unpack_from("<I",d,p)[0])
        p+=lw
        if p+ln>end:return
        out.append((depth,cid,p,ln,d[p:p+ln]))
        if cid in (0x03,0x40,0x41,0x42,0x46,0x20,0x30,0x31,0x10,0x70,0x48,0x21):
            walk(d,p,p+ln,depth+1,out)
        p+=ln
        if cid==0x0005:break
out=[]; walk(d,8,len(d),0,out)

# For each PMESH: read verts (XYZ_UV, stride20), faces from PCONN(ppf) + CONN(tris)
# Collect global stats: uv range, bbox, boundary edges per pmesh
import collections
pm_idx=0
tot_uv_min=[1e9,1e9]; tot_uv_max=[-1e9,-1e9]
bbmin=[1e9]*3; bbmax=[-1e9]*3
i=0
while i < len(out):
    depth,cid,p,ln,body=out[i]
    if cid==0x88:  # vertex XYZ_UV inside a pmesh
        cnt=ln//20
        verts=[struct.unpack_from("<5f",body,k*20) for k in range(cnt)]
        # gather following face chunks until next vertex/pmesh boundary
        faces=[]
        j=i+1
        while j<len(out):
            d2,c2,p2,l2,b2=out[j]
            if c2 in (0x88,0x89,0x8A,0x80,0x81,0x82): break
            if c2==0x004d and l2>=1:  # PCONN
                ppf=b2[0]; n=(l2-1)//4
                idx=[struct.unpack_from("<i",b2,1+k*4)[0] for k in range(n)]
                for f in range(0,n-ppf+1,ppf):
                    faces.append(idx[f:f+ppf])
            elif c2==0x0047 and l2>=12:  # CONN trilist
                n=l2//4
                idx=[struct.unpack_from("<i",b2,k*4)[0] for k in range(n)]
                for f in range(0,n-2,3):
                    faces.append(idx[f:f+3])
            elif c2 in (0x42,0x46,0x40,0x41): break
            j+=1
        pm_idx+=1
        # stats
        for v in verts:
            for a in range(3):
                bbmin[a]=min(bbmin[a],v[a]); bbmax[a]=max(bbmax[a],v[a])
            tot_uv_min[0]=min(tot_uv_min[0],v[3]); tot_uv_max[0]=max(tot_uv_max[0],v[3])
            tot_uv_min[1]=min(tot_uv_min[1],v[4]); tot_uv_max[1]=max(tot_uv_max[1],v[4])
        # boundary edges
        edge=collections.Counter()
        for f in faces:
            for k in range(len(f)):
                a,b=f[k],f[(k+1)%len(f)]
                edge[(min(a,b),max(a,b))]+=1
        boundary=[e for e,c in edge.items() if c==1]
        print(f"PMESH#{pm_idx}: verts={cnt} faces={len(faces)} edges={len(edge)} boundary_edges={len(boundary)}")
    i+=1
print(f"\nGLOBAL bbox X[{bbmin[0]:.2f},{bbmax[0]:.2f}] Y[{bbmin[1]:.2f},{bbmax[1]:.2f}] Z[{bbmin[2]:.2f},{bbmax[2]:.2f}]")
print(f"GLOBAL UV  U[{tot_uv_min[0]:.4f},{tot_uv_max[0]:.4f}] V[{tot_uv_min[1]:.4f},{tot_uv_max[1]:.4f}]")
