code wiki / _hdl_build / nx_bodybench.nx

nx_bodybench.nx source

↩ module page · 482 lines · 25306 B

1// nx_bodybench.nx -- ★SOVEREIGN BODY JUDGE, registerable as an MCP tool. Moves the shape ruler OFF the dev 2// laptop (it was PowerShell + System.Drawing) INTO a NishiLang organ that runs on the NAS: any agent, plan or 3// workflow can now measure a generated body against the BodyParts3D oracle with ONE call and get a permil 4// verdict back as JSON -- no image round-trip, no third-party runtime, no human in the loop. That is what 5// "it needs to scale" means: the measurement is a service, not a person at a keyboard. 6// 7// OOP, tagged-dispatch (NOT struct fn-pointer fields -- seq715: obj.fn(args) compiles and does NOT call): 8// * MeshView -- an object that renders ONE mesh at ONE yaw into coverage + per-pixel normal buffers 9// (a minimal measurement rasterizer: projection + edge-function fill + z-buffer + normal; 10// no shading/shadow/floor/texture -- those are display concerns, not measurement). 11// * Judge -- a small hierarchy dispatched by KIND: J_SILH (silhouette IoU) and J_NORMAL (normal-field 12// angular agreement). judge_eval(kind, ...) is the polymorphic entry; add a kind to extend. 13// * BodyBench -- orchestrates: renders ours+oracle at yaw 0 and 90, runs each judge, emits per-judge permil 14// and the HONEST HEADLINE = MIN over judges (hold several judges, publish the minimum). 15// 16// nx_bodybench <ours.nxmesh> <oracle.nxmesh> [W] [H] 17// -> {"front_iou":..,"side_iou":..,"shape":..,"headline":..,"self_iou":1000,"self_shape":1000, ...} 18// The self_* fields are a built-in NON-VACUITY proof: ours-vs-ours must score 1000/1000 or the ruler is broken. 19// license_tier: ORIGINAL expect_exit: 0 20import "nx_syscalls.nx" 21import "nx_itoa_lib.nx" // shared MSB-first emitter (zero-alloc) 22 23const BB_Q14: i64 = 16384 24const BB_ZFAR: i64 = 2000000000 25const BB_BIG: i64 = 2000000000 26const BB_M8388607: i64 = 8388607 27const BB_M8388608: i64 = 8388608 28const BB_POSQ0: i64 = 4096 29const BB_TARGET: i64 = 200000 30const BB_MAGIC_40500: i64 = 40500 31const BB_ACOSN: i64 = 8192 // acos LUT resolution over cos in [-Q14,+Q14] 32const BB_DETR: i64 = 2 // detail-judge window radius -> a (2R+1)^2 = 5x5 neighbourhood; big 33 // enough to catch muscle/feature-scale normal variation, small enough 34 // to stay local. The one magic knob of the detail judge (rule 11). 35 36func bb_streq(a: *u8, b: *u8) -> i64 { 37 var i: i64 = 0 38 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 39 if b[i] != (0 as u8) { return 0 } 40 return 1 41} 42func bb_satoi(s: *u8) -> i64 { 43 var i: i64 = 0; var n: i64 = 0; var sg: i64 = 1 44 if s[0] == (45 as u8) { sg = 0 - 1; i = 1 } 45 while s[i] != (0 as u8) { let c: i64 = s[i] as i64; if c >= 48 { if c <= 57 { n = n*10 + (c-48) } } i = i + 1 } 46 return n*sg 47} 48func bb_hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n+1 } sys_write(1, s, n); return 0 } 49// MIGRATED to the shared emitter (debt 1785563586). The old body mmapped a scratch buffer 50// per call and never freed it. At PAGE granularity that is 4096B leaked PER CALL -- the 51// defect that took 28.5GB of a 36GB host in nx_ts_lumadiff (2MB input, ~3.66M calls). 52// nxi_* is MSB-first, allocates NOTHING, and emits identical bytes including the sign. 53func bb_pn(v: i64) -> i64 { nxi_out(v); return 0 } 54func bb_rdbits(b: *u8, o: i64) -> i64 { 55 return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24) 56} 57func bb_f32mul(b: *u8, o: i64, mul: i64) -> i64 { 58 let bits: i64 = bb_rdbits(b, o) 59 let sign: i64 = (bits>>31) & 1 60 let exp: i64 = (bits>>23) & 255 61 let mant: i64 = bits & BB_M8388607 62 if exp == 0 { return 0 } 63 let m: i64 = (mant | BB_M8388608) * mul 64 var e: i64 = exp - 127 - 23 65 var v: i64 = 0 66 if e >= 0 { v = m << e } else { let sh: i64 = 0 - e; v = (m + (1 << (sh-1))) >> sh } 67 if sign == 1 { v = 0 - v } 68 return v 69} 70func bb_isqrt(v: i64) -> i64 { if v <= 0 { return 0 } var x: i64 = v; var y: i64 = (x+1)/2; while y < x { x = y; y = (x + v/x)/2 } return x } 71func bb_wrap(d: i64) -> i64 { var x: i64 = d % 360; if x < 0 { x = x + 360 } return x } 72func bb_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } 73func bb_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } 74// Bhaskara-I degree sine, Q14, exact at 0/30/90/150/180 -- our own integer trig, no float, no table literal. 75func bb_sin_fill(t: *i64) -> i64 { 76 var d: i64 = 0 77 while d < 180 { let P: i64 = d*(180-d); t[d] = BB_Q14*4*P/BB_MAGIC_40500; t[d+180] = 0-t[d]; d = d+1 } 78 return 0 79} 80// acos LUT: degree (0..180) as a function of cos, quantised into BB_ACOSN bins over cos in [-Q14,+Q14]. 81// Built by walking degrees (cos is monotonically decreasing) and forward-filling, so every bin resolves. 82func bb_acos_fill(acosT: *i64, sinT: *i64) -> i64 { 83 var i: i64 = 0 84 while i < BB_ACOSN { acosT[i] = 0-1; i = i+1 } 85 var d: i64 = 0 86 while d <= 180 { 87 let c: i64 = sinT[bb_wrap(d+90)] // cos(d) in Q14, +Q14 at 0, -Q14 at 180 88 var idx: i64 = (c + BB_Q14)*(BB_ACOSN-1)/(2*BB_Q14) 89 if idx < 0 { idx = 0 } 90 if idx >= BB_ACOSN { idx = BB_ACOSN-1 } 91 acosT[idx] = d 92 d = d + 1 93 } 94 // forward-fill from the high-cos end (idx high = small angle) downward 95 var last: i64 = 0 96 var j: i64 = BB_ACOSN-1 97 while j >= 0 { if acosT[j] < 0 { acosT[j] = last } else { last = acosT[j] } j = j - 1 } 98 return 0 99} 100func bb_acos_deg(acosT: *i64, dotq: i64) -> i64 { 101 var c: i64 = dotq 102 if c > BB_Q14 { c = BB_Q14 } 103 if c < 0-BB_Q14 { c = 0-BB_Q14 } 104 var idx: i64 = (c + BB_Q14)*(BB_ACOSN-1)/(2*BB_Q14) 105 if idx < 0 { idx = 0 } 106 if idx >= BB_ACOSN { idx = BB_ACOSN-1 } 107 return acosT[idx] 108} 109 110// ============================ MeshView ============================ 111// Render ONE mesh at ONE yaw into cov[] (0/1) and nbx/nby/nbz[] (Q14 camera-facing normal per pixel). 112// Framing REPLICATES nx_anat_sov 'fit' mode EXACTLY: scale-invariant precision (pass 0), full AABB (pass 1), 113// height-only camera distance -- so two meshes of equal stature render at equal on-screen height and the 114// silhouette IoU measures SHAPE, not scale. (This is the fair-ruler fix that stopped the ruler moving with 115// the thing it measured.) Returns the coverage pixel count. 116func mv_render(mb: *u8, ntris: i64, triBase: i64, lidBase: i64, W: i64, H: i64, yaw: i64, sinT: *i64, 117 cov: *i64, nbx: *i64, nby: *i64, nbz: *i64) -> i64 { 118 let ysin: i64 = sinT[bb_wrap(yaw)] 119 let ycos: i64 = sinT[bb_wrap(yaw+90)] 120 // pass 0: scale-invariant working precision 121 var q0mn: i64 = BB_BIG; var q0mx: i64 = 0-BB_BIG 122 var t0: i64 = 0 123 while t0 < ntris { 124 let o0: i64 = triBase + t0*84 125 var c0: i64 = 0 126 while c0 < 3 { let vq: i64 = bb_f32mul(mb, o0 + c0*4, BB_POSQ0); if vq<q0mn {q0mn=vq} if vq>q0mx {q0mx=vq} c0 = c0+1 } 127 t0 = t0 + 1 128 } 129 var span0: i64 = q0mx - q0mn 130 if span0 < 1 { span0 = 1 } 131 var posq: i64 = BB_POSQ0 * BB_TARGET / span0 132 if posq < 1 { posq = 1 } 133 // pass 1: full AABB -> centroid + halfH 134 var mnx: i64 = BB_BIG; var mny: i64 = BB_BIG; var mnz: i64 = BB_BIG 135 var mxx: i64 = 0-BB_BIG; var mxy: i64 = 0-BB_BIG; var mxz: i64 = 0-BB_BIG 136 var t: i64 = 0 137 while t < ntris { 138 var v: i64 = 0 139 while v < 3 { 140 let o: i64 = triBase + t*84 + v*12 141 let x: i64 = bb_f32mul(mb,o,posq); let y: i64 = bb_f32mul(mb,o+4,posq); let z: i64 = bb_f32mul(mb,o+8,posq) 142 if x<mnx {mnx=x} if x>mxx {mxx=x} if y<mny {mny=y} if y>mxy {mxy=y} if z<mnz {mnz=z} if z>mxz {mxz=z} 143 v = v + 1 144 } 145 t = t + 1 146 } 147 let cx0: i64 = (mnx+mxx)/2; let cy0: i64 = (mny+mxy)/2; let cz0: i64 = (mnz+mxz)/2 148 let halfH: i64 = (mxy-mny)/2 149 let FOCAL: i64 = H 150 var dist: i64 = 2*halfH*118/100 // 'fit': height-only framing 151 if dist < 1 { dist = 1 } 152 let cxh: i64 = W/2; let cyh: i64 = H/2 153 // clear buffers 154 let npx: i64 = W*H 155 let zb: *i64 = sys_mmap(npx*8) as *i64 156 var p: i64 = 0 157 while p < npx { cov[p]=0; zb[p]=BB_ZFAR; nbx[p]=0; nby[p]=0; nbz[p]=BB_Q14; p = p+1 } 158 // pass 2: rasterize (measurement only) 159 var cnt: i64 = 0 160 t = 0 161 while t < ntris { 162 let ob: i64 = triBase + t*84 163 let rx0v: i64 = bb_f32mul(mb,ob,posq)-cx0; let y0: i64 = bb_f32mul(mb,ob+4,posq)-cy0; let rz0v: i64 = bb_f32mul(mb,ob+8,posq)-cz0 164 let rx1v: i64 = bb_f32mul(mb,ob+12,posq)-cx0; let y1: i64 = bb_f32mul(mb,ob+16,posq)-cy0; let rz1v: i64 = bb_f32mul(mb,ob+20,posq)-cz0 165 let rx2v: i64 = bb_f32mul(mb,ob+24,posq)-cx0; let y2: i64 = bb_f32mul(mb,ob+28,posq)-cy0; let rz2v: i64 = bb_f32mul(mb,ob+32,posq)-cz0 166 let x0: i64 = (rx0v*ycos + rz0v*ysin)/BB_Q14; let z0: i64 = (rz0v*ycos - rx0v*ysin)/BB_Q14 167 let x1: i64 = (rx1v*ycos + rz1v*ysin)/BB_Q14; let z1: i64 = (rz1v*ycos - rx1v*ysin)/BB_Q14 168 let x2: i64 = (rx2v*ycos + rz2v*ysin)/BB_Q14; let z2: i64 = (rz2v*ycos - rx2v*ysin)/BB_Q14 169 let d0: i64 = dist - z0; let d1: i64 = dist - z1; let d2: i64 = dist - z2 170 if d0 > 0 { if d1 > 0 { if d2 > 0 { 171 let sx0: i64 = cxh + (x0*FOCAL)/d0; let sy0: i64 = cyh - (y0*FOCAL)/d0 172 let sx1: i64 = cxh + (x1*FOCAL)/d1; let sy1: i64 = cyh - (y1*FOCAL)/d1 173 let sx2: i64 = cxh + (x2*FOCAL)/d2; let sy2: i64 = cyh - (y2*FOCAL)/d2 174 var area: i64 = (sx1-sx0)*(sy2-sy0) - (sx2-sx0)*(sy1-sy0) 175 if area != 0 { 176 let q0x: i64 = bb_f32mul(mb,ob+36,BB_Q14); let n0y: i64 = bb_f32mul(mb,ob+40,BB_Q14); let q0z: i64 = bb_f32mul(mb,ob+44,BB_Q14) 177 let q1x: i64 = bb_f32mul(mb,ob+48,BB_Q14); let n1y: i64 = bb_f32mul(mb,ob+52,BB_Q14); let q1z: i64 = bb_f32mul(mb,ob+56,BB_Q14) 178 let q2x: i64 = bb_f32mul(mb,ob+60,BB_Q14); let n2y: i64 = bb_f32mul(mb,ob+64,BB_Q14); let q2z: i64 = bb_f32mul(mb,ob+68,BB_Q14) 179 let n0x: i64 = (q0x*ycos + q0z*ysin)/BB_Q14; let n0z: i64 = (q0z*ycos - q0x*ysin)/BB_Q14 180 let n1x: i64 = (q1x*ycos + q1z*ysin)/BB_Q14; let n1z: i64 = (q1z*ycos - q1x*ysin)/BB_Q14 181 let n2x: i64 = (q2x*ycos + q2z*ysin)/BB_Q14; let n2z: i64 = (q2z*ycos - q2x*ysin)/BB_Q14 182 var bxmn: i64 = bb_max(0, bb_min(sx0, bb_min(sx1,sx2))) 183 var bxmx: i64 = bb_min(W-1, bb_max(sx0, bb_max(sx1,sx2))) 184 var bymn: i64 = bb_max(0, bb_min(sy0, bb_min(sy1,sy2))) 185 var bymx: i64 = bb_min(H-1, bb_max(sy0, bb_max(sy1,sy2))) 186 var sgn: i64 = 1 187 if area < 0 { sgn = 0-1 } 188 let aabs: i64 = area*sgn 189 var py2: i64 = bymn 190 while py2 <= bymx { 191 var px2: i64 = bxmn 192 while px2 <= bxmx { 193 let e0: i64 = ((sx2-sx1)*(py2-sy1) - (sy2-sy1)*(px2-sx1))*sgn 194 let e1: i64 = ((sx0-sx2)*(py2-sy2) - (sy0-sy2)*(px2-sx2))*sgn 195 let e2: i64 = ((sx1-sx0)*(py2-sy0) - (sy1-sy0)*(px2-sx0))*sgn 196 if e0 >= 0 { if e1 >= 0 { if e2 >= 0 { 197 let depth: i64 = (e0*d0 + e1*d1 + e2*d2)/aabs 198 let idx: i64 = py2*W + px2 199 if depth < zb[idx] { 200 var nx: i64 = (e0*n0x + e1*n1x + e2*n2x)/aabs 201 var ny: i64 = (e0*n0y + e1*n1y + e2*n2y)/aabs 202 var nz: i64 = (e0*n0z + e1*n1z + e2*n2z)/aabs 203 var nl: i64 = bb_isqrt(nx*nx + ny*ny + nz*nz) 204 if nl < 1 { nl = 1 } 205 nx = nx*BB_Q14/nl; ny = ny*BB_Q14/nl; nz = nz*BB_Q14/nl 206 if nz < 0 { nx = 0-nx; ny = 0-ny; nz = 0-nz } 207 if cov[idx] == 0 { cnt = cnt + 1 } 208 zb[idx] = depth; cov[idx] = 1; nbx[idx] = nx; nby[idx] = ny; nbz[idx] = nz 209 } 210 }}} 211 px2 = px2 + 1 212 } 213 py2 = py2 + 1 214 } 215 } 216 }}} 217 t = t + 1 218 } 219 return cnt 220} 221 222// ============================ Judge ============================ 223const J_SILH: i64 = 1 224const J_NORMAL: i64 = 2 225// Polymorphic entry. Returns a permil (0..1000). Extend by adding a KIND and a branch. 226func judge_eval(kind: i64, npx: i64, covA: *i64, covB: *i64, 227 nax: *i64, nay: *i64, naz: *i64, nbx: *i64, nby: *i64, nbz: *i64, acosT: *i64) -> i64 { 228 var p: i64 = 0 229 if kind == J_SILH { 230 var inter: i64 = 0; var uni: i64 = 0 231 while p < npx { 232 let a: i64 = covA[p]; let b: i64 = covB[p] 233 if a==1 { if b==1 { inter = inter+1 } } 234 if a==1 { uni = uni+1 } else { if b==1 { uni = uni+1 } } 235 p = p + 1 236 } 237 if uni < 1 { uni = 1 } 238 return 1000*inter/uni 239 } 240 if kind == J_NORMAL { 241 var sumdeg: i64 = 0; var cnt: i64 = 0 242 while p < npx { 243 if covA[p]==1 { if covB[p]==1 { 244 let dotq: i64 = (nax[p]*nbx[p] + nay[p]*nby[p] + naz[p]*nbz[p])/BB_Q14 245 sumdeg = sumdeg + bb_acos_deg(acosT, dotq) 246 cnt = cnt + 1 247 }} 248 p = p + 1 249 } 250 if cnt < 1 { cnt = 1 } 251 let meandeg: i64 = sumdeg/cnt 252 var permil: i64 = 1000 - meandeg*1000/90 // matches the laptop ruler: 1 - meanDeg/90 253 if permil < 0 { permil = 0 } 254 return permil 255 } 256 return 0 257} 258 259// ★DETAIL JUDGE (surface-structure agreement). Silhouette IoU and front-view normal agreement are both 260// BLIND to missing surface detail: a smooth mannequin overlaps a real human's outline ~85% and its 261// mostly-camera-facing normals agree ~93%, so those judges cannot see that the face, hands, feet and muscle 262// definition are ABSENT. This fills a per-pixel LOCAL NORMAL VARIANCE (how busy the surface is in a small 263// window) -- high where anatomy creates normal swings (nostril, knuckle, muscle border), ~0 on a smooth tube. 264func bb_detail_fill(W: i64, H: i64, cov: *i64, nx: *i64, ny: *i64, nz: *i64, out: *i64) -> i64 { 265 var y: i64 = 0 266 while y < H { 267 var x: i64 = 0 268 while x < W { 269 let p: i64 = y*W + x 270 if cov[p] == 1 { 271 var sx: i64 = 0; var sy: i64 = 0; var sz: i64 = 0 272 var qx: i64 = 0; var qy: i64 = 0; var qz: i64 = 0; var c: i64 = 0 273 var dy: i64 = 0-BB_DETR 274 while dy <= BB_DETR { 275 var dx: i64 = 0-BB_DETR 276 while dx <= BB_DETR { 277 let yy: i64 = y+dy; let xx: i64 = x+dx 278 if yy>=0 { if yy<H { if xx>=0 { if xx<W { 279 let q: i64 = yy*W+xx 280 if cov[q]==1 { 281 let ax: i64 = nx[q]; let ay: i64 = ny[q]; let az: i64 = nz[q] 282 sx=sx+ax; sy=sy+ay; sz=sz+az 283 qx=qx+ax*ax/BB_Q14; qy=qy+ay*ay/BB_Q14; qz=qz+az*az/BB_Q14 284 c=c+1 285 } 286 }}}} 287 dx=dx+1 288 } 289 dy=dy+1 290 } 291 if c < 2 { out[p]=0 } else { 292 let vx: i64 = qx/c - (sx/c)*(sx/c)/BB_Q14 // var = E[n^2]-E[n]^2, n^2 pre-scaled by Q14 293 let vy: i64 = qy/c - (sy/c)*(sy/c)/BB_Q14 294 let vz: i64 = qz/c - (sz/c)*(sz/c)/BB_Q14 295 var v: i64 = vx+vy+vz 296 if v < 0 { v = 0 } 297 out[p] = v 298 } 299 } else { out[p]=0 } 300 x=x+1 301 } 302 y=y+1 303 } 304 return 0 305} 306// score the two detail fields as an intersection-over-union in VARIANCE space over the shared coverage: 307// identical detail -> 1000; smooth-where-oracle-is-detailed -> punished; AND noisy-where-oracle-is-smooth -> 308// punished symmetrically, so it CANNOT be gamed by adding noise (the FBM-texture Goodhart that once fooled 309// the statistical grader scores ZERO here unless the noise lands exactly where the oracle has real detail). 310func bb_detail_score(npx: i64, covA: *i64, covB: *i64, dA: *i64, dB: *i64) -> i64 { 311 var num: i64 = 0; var den: i64 = 0; var p: i64 = 0 312 while p < npx { 313 if covA[p]==1 { if covB[p]==1 { 314 var df: i64 = dA[p]-dB[p]; if df<0 { df=0-df } 315 num = num + df 316 den = den + dA[p] + dB[p] 317 }} 318 p = p + 1 319 } 320 if den < 1 { den = 1 } 321 var s: i64 = 1000 - 1000*num/den 322 if s < 0 { s = 0 } 323 return s 324} 325 326// HEAD-REGION DETAIL. A whole-body average cannot see a head-sized change: four new facial bases moved the 327// body number by -1 while the face visibly gained shadowed eye sockets. This restricts the detail score to 328// the top band of the rendered figure. 329// NOTE ON THE STANDING LAW "a horizontal image band is not an anatomical region": that law was earned on 330// MID-body bands, where a row merely CONTAINS the arms and hands. It does not apply to the top band -- at 331// the crown of a standing figure nothing but the head is present, so here the band IS the region. Stated 332// explicitly because the general law is right and this is a genuine exception, not an oversight. 333func bb_detail_head(W: i64, H: i64, covA: *i64, covB: *i64, dA: *i64, dB: *i64, frac: i64) -> i64 { 334 var ymin: i64 = 0-1 335 var ymax: i64 = 0-1 336 var y: i64 = 0 337 while y < H { 338 var x: i64 = 0 339 var any: i64 = 0 340 while x < W { let p: i64 = y*W+x; if covA[p]==1 { any=1 } else { if covB[p]==1 { any=1 } } x=x+1 } 341 if any == 1 { if ymin < 0 { ymin = y } ymax = y } 342 y = y+1 343 } 344 if ymin < 0 { return 0 } 345 let ycut: i64 = ymin + (ymax-ymin)*frac/1000 346 var num: i64 = 0 347 var den: i64 = 0 348 y = ymin 349 while y <= ycut { 350 var x2: i64 = 0 351 while x2 < W { 352 let p2: i64 = y*W+x2 353 if covA[p2]==1 { if covB[p2]==1 { 354 var df: i64 = dA[p2]-dB[p2] 355 if df < 0 { df = 0-df } 356 num = num + df 357 den = den + dA[p2] + dB[p2] 358 }} 359 x2 = x2+1 360 } 361 y = y+1 362 } 363 if den < 1 { den = 1 } 364 var sc: i64 = 1000 - 1000*num/den 365 if sc < 0 { sc = 0 } 366 return sc 367} 368func bb_emit_kv(name: *u8, v: i64, last: i64) -> i64 { 369 bb_hw("\x22" as *u8); bb_hw(name); bb_hw("\x22:" as *u8); bb_pn(v) 370 if last == 0 { bb_hw("," as *u8) } 371 return 0 372} 373 374func main(argc: i64, argv: *i64) -> i64 { 375 if argc < 3 { bb_hw("{\x22error\x22:\x22usage: nx_bodybench <ours.nxmesh> <oracle.nxmesh> [W] [H]\x22}\n" as *u8); return 2 } 376 let oursp: *u8 = argv[1] as *u8 377 let oracp: *u8 = argv[2] as *u8 378 var W: i64 = 620 379 var H: i64 = 950 380 if argc > 3 { W = bb_satoi(argv[3] as *u8) } 381 if argc > 4 { H = bb_satoi(argv[4] as *u8) } 382 let sinT: *i64 = sys_mmap(400*8) as *i64 383 bb_sin_fill(sinT) 384 let acosT: *i64 = sys_mmap(BB_ACOSN*8) as *i64 385 bb_acos_fill(acosT, sinT) 386 387 let l1: *i64 = sys_mmap(16) as *i64 388 let l2: *i64 = sys_mmap(16) as *i64 389 let mo: *u8 = sys_read_file(oursp, l1) 390 let mr: *u8 = sys_read_file(oracp, l2) 391 if (mo as i64) == 0 { bb_hw("{\x22error\x22:\x22cannot read ours\x22}\n" as *u8); return 3 } 392 if (mr as i64) == 0 { bb_hw("{\x22error\x22:\x22cannot read oracle\x22}\n" as *u8); return 3 } 393 let oNt: i64 = bb_rdbits(mo, 12); let oNl: i64 = bb_rdbits(mo, 8) 394 let rNt: i64 = bb_rdbits(mr, 12); let rNl: i64 = bb_rdbits(mr, 8) 395 let oTB: i64 = 16 + oNl*24; let oLB: i64 = oTB + oNt*84 396 let rTB: i64 = 16 + rNl*24; let rLB: i64 = rTB + rNt*84 397 398 let npx: i64 = W*H 399 // four coverage buffers (ours/oracle at yaw 0 and 90) + normals for the yaw-0 pair 400 let coA0: *i64 = sys_mmap(npx*8) as *i64 401 let coB0: *i64 = sys_mmap(npx*8) as *i64 402 let coA9: *i64 = sys_mmap(npx*8) as *i64 403 let coB9: *i64 = sys_mmap(npx*8) as *i64 404 let axn: *i64 = sys_mmap(npx*8) as *i64; let ayn: *i64 = sys_mmap(npx*8) as *i64; let azn: *i64 = sys_mmap(npx*8) as *i64 405 let bxn: *i64 = sys_mmap(npx*8) as *i64; let byn: *i64 = sys_mmap(npx*8) as *i64; let bzn: *i64 = sys_mmap(npx*8) as *i64 406 // scratch normals for the yaw-90 renders (silhouette only needs coverage) 407 let sxn: *i64 = sys_mmap(npx*8) as *i64; let syn: *i64 = sys_mmap(npx*8) as *i64; let szn: *i64 = sys_mmap(npx*8) as *i64 408 409 mv_render(mo, oNt, oTB, oLB, W, H, 0, sinT, coA0, axn, ayn, azn) 410 mv_render(mr, rNt, rTB, rLB, W, H, 0, sinT, coB0, bxn, byn, bzn) 411 mv_render(mo, oNt, oTB, oLB, W, H, 90, sinT, coA9, sxn, syn, szn) 412 mv_render(mr, rNt, rTB, rLB, W, H, 90, sinT, coB9, sxn, syn, szn) 413 414 let front: i64 = judge_eval(J_SILH, npx, coA0, coB0, axn,ayn,azn, bxn,byn,bzn, acosT) 415 let side: i64 = judge_eval(J_SILH, npx, coA9, coB9, axn,ayn,azn, bxn,byn,bzn, acosT) 416 let shape: i64 = judge_eval(J_NORMAL, npx, coA0, coB0, axn,ayn,azn, bxn,byn,bzn, acosT) 417 // ★DETAIL judge -- MULTI-VIEW so it credits the WHOLE surface, not just the front. Front-only detail was 418 // blind to back muscles and let a body with a defined front but a smooth back read the same as a fully 419 // detailed one. Detail is now the mean of FRONT (yaw 0) and BACK (yaw 180) surface-structure agreement. 420 let dA: *i64 = sys_mmap(npx*8) as *i64 421 let dB: *i64 = sys_mmap(npx*8) as *i64 422 bb_detail_fill(W, H, coA0, axn, ayn, azn, dA) 423 bb_detail_fill(W, H, coB0, bxn, byn, bzn, dB) 424 let detail_front: i64 = bb_detail_score(npx, coA0, coB0, dA, dB) 425 // head is roughly the top 13 percent of a standing figure (1 of 7.5 heads) 426 let detail_head: i64 = bb_detail_head(W, H, coA0, coB0, dA, dB, 130) 427 428 // self-checks use the FRONT normals -- compute them BEFORE the back render overwrites axn/bxn. 429 let self_iou: i64 = judge_eval(J_SILH, npx, coA0, coA0, axn,ayn,azn, axn,ayn,azn, acosT) 430 let self_shp: i64 = judge_eval(J_NORMAL, npx, coA0, coA0, axn,ayn,azn, axn,ayn,azn, acosT) 431 let self_det: i64 = bb_detail_score(npx, coA0, coA0, dA, dA) 432 433 // BACK view (yaw 180): reuse the normal buffers now that the front judges are done. 434 let coA18: *i64 = sys_mmap(npx*8) as *i64 435 let coB18: *i64 = sys_mmap(npx*8) as *i64 436 mv_render(mo, oNt, oTB, oLB, W, H, 180, sinT, coA18, axn, ayn, azn) 437 mv_render(mr, rNt, rTB, rLB, W, H, 180, sinT, coB18, bxn, byn, bzn) 438 let dA2: *i64 = sys_mmap(npx*8) as *i64 439 let dB2: *i64 = sys_mmap(npx*8) as *i64 440 bb_detail_fill(W, H, coA18, axn, ayn, azn, dA2) 441 bb_detail_fill(W, H, coB18, bxn, byn, bzn, dB2) 442 let detail_back: i64 = bb_detail_score(npx, coA18, coB18, dA2, dB2) 443 let detail: i64 = (detail_front + detail_back)/2 444 // THREE-QUARTER VIEW (yaw 45). A front view is structurally blind to LATERAL surface: anatomically 445 // correct ribs are zero at the sternum and live on the flank, so front-only detail scored them DOWN 446 // (381 -> 378) for being right. Judging structure with a camera that cannot see it is a broken 447 // instrument, not a failed feature. ADDITIVE field -- the headline is untouched so every number 448 // published before this stays comparable. 449 let coA45: *i64 = sys_mmap(npx*8) as *i64 450 let coB45: *i64 = sys_mmap(npx*8) as *i64 451 mv_render(mo, oNt, oTB, oLB, W, H, 45, sinT, coA45, axn, ayn, azn) 452 mv_render(mr, rNt, rTB, rLB, W, H, 45, sinT, coB45, bxn, byn, bzn) 453 let dA3: *i64 = sys_mmap(npx*8) as *i64 454 let dB3: *i64 = sys_mmap(npx*8) as *i64 455 bb_detail_fill(W, H, coA45, axn, ayn, azn, dA3) 456 bb_detail_fill(W, H, coB45, bxn, byn, bzn, dB3) 457 let detail_q: i64 = bb_detail_score(npx, coA45, coB45, dA3, dB3) 458 let quarter_iou: i64 = judge_eval(J_SILH, npx, coA45, coB45, axn,ayn,azn, bxn,byn,bzn, acosT) 459 460 // HONEST HEADLINE = MIN over ALL judges, detail included. Silhouette/shape flatter a smooth mannequin; 461 // detail is what drags the number down to what the eye actually sees. 462 var headline: i64 = bb_min(front, bb_min(side, bb_min(shape, detail))) 463 464 bb_hw("{" as *u8) 465 bb_emit_kv("front_iou" as *u8, front, 0) 466 bb_emit_kv("side_iou" as *u8, side, 0) 467 bb_emit_kv("shape" as *u8, shape, 0) 468 bb_emit_kv("detail" as *u8, detail, 0) 469 bb_emit_kv("detail_front" as *u8, detail_front, 0) 470 bb_emit_kv("detail_back" as *u8, detail_back, 0) 471 bb_emit_kv("detail_quarter" as *u8, detail_q, 0) 472 bb_emit_kv("detail_head" as *u8, detail_head, 0) 473 bb_emit_kv("quarter_iou" as *u8, quarter_iou, 0) 474 bb_emit_kv("headline" as *u8, headline, 0) 475 bb_emit_kv("self_iou" as *u8, self_iou, 0) 476 bb_emit_kv("self_shape" as *u8, self_shp, 0) 477 bb_emit_kv("self_detail" as *u8, self_det, 0) 478 bb_emit_kv("W" as *u8, W, 0) 479 bb_emit_kv("H" as *u8, H, 0) 480 bb_hw("\x22judges\x22:\x22front_iou,side_iou,shape,DETAIL=mean(front,back) (MIN=headline); detail = local-normal-variance IoU vs oracle, NOT blind to a smooth mannequin\x22,\x22ruler\x22:\x22sovereign nx_bodybench -- dual-render coverage+normal, height-fit framing, integer acos LUT; NO image round-trip, NO 3rd-party\x22}\n" as *u8) 481 return 0 482}