code wiki / _hdl_build / nx_anat_sov.nx

nx_anat_sov.nx source

↩ module page · 1094 lines · 61323 B

1// nx_anat_sov.nx -- ★SOVEREIGN NishiLang render of the 8-layer anatomical being (NXMSH2), the PRODUCT half of 2// GX-11: the integer twin of the CUDA benchmark (/world/anatomy_gpu). 100% integer, own f32 decoder, own 3// barycentric z-buffer rasterizer, own PNG -- NO CUDA, NO GPU, NO 3rd-party. Measured against the CUDA 4// reference by the SAME invariants: intact occludes the interior, explode shows all 8 systems, stereo has 5// horizontal disparity. Stereo is OFF-AXIS (parallel, convergence at the model) -- an UPGRADE over the 6// benchmark's toe-in (no keystone). Reads knowledge/being_full.nxmesh; writes a PNG + a JSON stats line. 7// nx_anat_sov <mesh> <intact|explode|skin|layerN> <C|L|R> <W> <H> <out.png> 8// license_tier: ORIGINAL expect_exit: 0 9import "nx_syscalls.nx" 10import "nx_png.nx" 11const AS_LIGHT_FALLOFF_K: i64 = 40000 12const AS_PERFUSION_DEN: i64 = 100000 13const AS_BHASKARA_K: i64 = 40500 14const AS_F32_MANT_MASK: i64 = 8388607 15const AS_F32_MANT_SCALE: i64 = 8388608 16const AS_HASH_P1: i64 = 73856093 17const AS_HASH_P2: i64 = 19349663 18const AS_HASH_P3: i64 = 83492791 19const AS_I32_MAX: i64 = 2147483647 20const AS_NOISE_A: i64 = 15731 21const AS_NOISE_B: i64 = 789221 22const AS_NOISE_C: i64 = 1376312589 23const AS_Q16_ONE: i64 = 65536 24const AS_MAGIC_2000000000: i64 = 2000000000 25const AS_KEY_LIGHT_X: i64 = 5423 26const AS_KEY_LIGHT_Y: i64 = 9487 27const AS_KEY_LIGHT_Z: i64 = 12206 28const AS_FILL_LIGHT_X: i64 = 10160 29const AS_FILL_LIGHT_Y: i64 = 4064 30const AS_FILL_LIGHT_Z: i64 = 12190 31const AS_LIT_CEIL: i64 = 1280 32const AS_Q10_ONE: i64 = 1024 33 34// ★seq630 ROOT FIX: positions were decoded to WHOLE model units (mul=1), so any mesh authored in metres 35// rather than millimetres collapsed EVERY coordinate to 0 -> degenerate AABB -> rad=0 -> smE=0 -> integer 36// divide-by-zero -> SIGFPE. (Found on Vh-f-heart, whose coords all lie within +-0.5.) Decoding positions at 37// posq sub-units keeps sub-unit meshes alive; the renderer auto-frames, so absolute scale is irrelevant 38// and only precision matters. Texture lookups divide back to model units so texel size is unchanged. 39const AS_POSQ0: i64 = 4096 40const AS_TARGET: i64 = 200000 41const AS_ZFAR: i64 = 2000000000 42const AS_Q14: i64 = 16384 43// ★A CRASH ON NO ARGS IS INDISTINGUISHABLE FROM A BROKEN CAPABILITY. The usage line at the head of this 44// file declares six REQUIRED arguments -- <mesh> <mode> <eye> <W> <H> <out.png> -- so the highest argv 45// index main must dereference unconditionally is 6 (outp). argc counts argv[0], so the minimum admissible 46// argc is that index + 1. DERIVED from the arity above, not chosen: change the usage line and this moves. 47const AS_ARGV_LAST_REQUIRED: i64 = 6 48const AS_ARGC_MIN: i64 = AS_ARGV_LAST_REQUIRED + 1 49const AS_EXIT_USAGE: i64 = 3 // 0 ok - 2 operational (cannot read mesh) - 3 usage, the estate's usage/SKIP code 50 51// ★AROUSAL PERFUSION HOOK (permil, 0 = OFF and the renderer behaves EXACTLY as before). 52// Declared at the top because a module flag read by a function defined above it resolves to 53// GARBAGE in this compiler -- the documented forward-static-ref trap. 54// 55// Physiology, not a tint: rising perfusion raises dermal oxyhaemoglobin, which absorbs strongly in 56// BLUE (Soret ~415nm) and GREEN (542/577nm) and only weakly above 600nm. So the arousal signature 57// is G and B falling while R barely moves -- the same Beer-Lambert asymmetry nx_arousal_skin_lib 58// derives, applied here to the REAL generated body instead of a private SDF proxy. 59// Set via as_set_perfusion(); every existing caller leaves it 0 and is unaffected. 60static AS_PERF: i64 61func as_set_perfusion(p: i64) -> i64 { 62 var v: i64 = p 63 if v < 0 { v = 0 } 64 if v > 1000 { v = 1000 } 65 AS_PERF = v 66 return AS_PERF 67} 68func as_get_perfusion() -> i64 { return AS_PERF } 69 70// ★THE FLUSH HAS A PROPAGATION ORDER; A GLOBAL TINT IS NOT AROUSAL. The first cut of the hook above 71// scaled every skin pixel by the same AS_PERF, which reddens the whole body at once -- exactly the 72// "visually inert" defect nx_arousal_skin_lib warns about, reproduced in the renderer. Masters & 73// Johnson flush appears in a FIXED ORDER (genital -> submammary -> breast -> torso -> face -> 74// extremities), and that order is the diagnostic signal a therapist reads. Rendering it as one 75// uniform wash throws the information away. 76// 77// ★WHY STATURE FRACTION AND NOT ANCHOR LITERALS: nx_arousal_skin_lib's sk_anchor_* are fx1024 78// literals welded to the SDF proxy, which is why that lib could never be pointed at another rig. 79// Site here is derived from NORMALISED HEIGHT over the mesh's own AABB -- the same per-mille-of- 80// stature convention the anthropometric canon already uses -- so it is subject-independent BY 81// CONSTRUCTION: any body, any stature, any species with a canon reads its own sites correctly. 82// Thresholds are the SAME numbers sk_thresh() returns, so the two cannot drift. 83static AS_YMIN: i64 84static AS_YSPAN: i64 85static AS_XCTR: i64 86static AS_XHALF: i64 87func as_set_body_span(ymin: i64, ymax: i64, xctr: i64, xhalf: i64) -> i64 { 88 AS_YMIN = ymin 89 AS_YSPAN = ymax - ymin 90 if AS_YSPAN < 1 { AS_YSPAN = 1 } 91 AS_XCTR = xctr 92 AS_XHALF = xhalf 93 if AS_XHALF < 1 { AS_XHALF = 1 } 94 return AS_YSPAN 95} 96// M&J site thresholds (identical to sk_thresh) at their stature fractions, inverse-distance weighted 97// so boundaries are CONTINUOUS -- a hard per-site lookup paints rectangular bands on skin. 98// ★THE FLUSH-SITE CANON IS DATA (2026-08-14). These two functions were an if-ladder: a five-row lookup 99// table written as control flow. Ten anatomical numbers that could not be revised, reviewed or varied 100// without a rebuild -- and a sixth site could not be expressed at all, because the ladder ends in an 101// unconditional return. They now live in knowledge/anat_flush_sites.conf, and the site COUNT comes from 102// the file, so adding a site is a data edit. 103// ★THE WEIGHTING ARITHMETIC BELOW IS UNCHANGED TERM FOR TERM: the acceptance proof for this move is a 104// BIT-IDENTICAL render against the banked pre-refactor PNG. 105static AS_NSITE: i64 106static AS_ASF: i64 107static AS_ATH: i64 108static AS_EXTTH: i64 109static AS_FBTH: i64 110func as_rdint(b: *u8, pos: *i64, end: i64) -> i64 { 111 var i: i64 = pos[0] 112 var go: i64 = 1 113 while go == 1 { 114 if i >= end { go = 0 } else { 115 let c: i64 = b[i] as i64 116 if c == 45 { go = 0 } else { if c >= 48 { if c <= 57 { go = 0 } else { i = i+1 } } else { i = i+1 } } 117 } 118 } 119 var sg: i64 = 1 120 if i < end { if (b[i] as i64) == 45 { sg = 0-1; i = i+1 } } 121 var v: i64 = 0 122 var g2: i64 = 1 123 while g2 == 1 { 124 if i >= end { g2 = 0 } else { 125 let c2: i64 = b[i] as i64 126 if c2 >= 48 { if c2 <= 57 { v = v*10 + (c2-48); i = i+1 } else { g2 = 0 } } else { g2 = 0 } 127 } 128 } 129 pos[0] = i 130 return v*sg 131} 132func as_load_sites() -> i64 { 133 if AS_NSITE > 0 { return AS_NSITE } 134 let asf: *i64 = sys_mmap(64*8) as *i64 135 let ath: *i64 = sys_mmap(64*8) as *i64 136 AS_ASF = asf as i64 137 AS_ATH = ath as i64 138 let ln: *i64 = sys_mmap(16) as *i64 139 let b: *u8 = sys_read_file("knowledge/anat_flush_sites.conf" as *u8, ln) 140 if (b as i64) == 0 { 141 as_hw("ANAT-REFUSE cannot read knowledge/anat_flush_sites.conf -- the flush-site canon is REQUIRED, refusing to render on an empty site table\n" as *u8) 142 sys_exit(7) 143 } 144 let len: i64 = ln[0] 145 let pos: *i64 = sys_mmap(16) as *i64 146 var n: i64 = 0 147 var i: i64 = 0 148 var bol: i64 = 1 149 while i < len { 150 if bol == 1 { 151 if (b[i] as i64) == 65 { 152 pos[0] = i+1 153 let idx: i64 = as_rdint(b,pos,len) 154 let sfv: i64 = as_rdint(b,pos,len) 155 let thv: i64 = as_rdint(b,pos,len) 156 if idx >= 0 { if idx < 64 { 157 asf[idx] = sfv 158 ath[idx] = thv 159 if idx + 1 > n { n = idx + 1 } 160 } } 161 i = pos[0] 162 } 163 if (b[i] as i64) == 88 { 164 pos[0] = i+1 165 AS_EXTTH = as_rdint(b,pos,len) 166 AS_FBTH = as_rdint(b,pos,len) 167 i = pos[0] 168 } 169 } 170 if (b[i] as i64) == 10 { bol = 1 } else { bol = 0 } 171 i = i + 1 172 } 173 if n < 1 { 174 as_hw("ANAT-REFUSE anat_flush_sites.conf declares no A rows -- refusing to render on an empty site table\n" as *u8) 175 sys_exit(7) 176 } 177 AS_NSITE = n 178 return n 179} 180func as_anchor_sf(i: i64) -> i64 { let a: *i64 = AS_ASF as *i64; return a[i] } 181func as_anchor_th(i: i64) -> i64 { let a: *i64 = AS_ATH as *i64; return a[i] } 182// sf = stature fraction permil (0 sole, 1000 crown); latp = lateral fraction permil from midline. 183// Extremities (threshold 800) flush LAST: limbs are reached by blending toward that anchor with 184// lateral distance, so an arm held away from the torso is correctly late, not painted by height. 185func as_flush_thresh(sf: i64, latp: i64) -> i64 { 186 // the site COUNT is the file's, not a literal 5: a canon that declares a sixth site now gets one. 187 let ns: i64 = as_load_sites() 188 var num: i64 = 0 189 var den: i64 = 0 190 var i: i64 = 0 191 while i < ns { 192 let d: i64 = (sf - as_anchor_sf(i)) / 8 193 let d2: i64 = d*d + 4 194 let w: i64 = AS_LIGHT_FALLOFF_K / d2 195 num = num + w * as_anchor_th(i) 196 den = den + w 197 i = i + 1 198 } 199 var th: i64 = AS_FBTH 200 if den > 0 { th = num / den } 201 // lateral blend toward the extremity threshold 202 var lb: i64 = latp 203 if lb > 1000 { lb = 1000 } 204 if lb < 0 { lb = 0 } 205 return (th * (1000 - lb) + AS_EXTTH * lb) / 1000 206} 207 208func as_streq(a: *u8, b: *u8) -> i64 { 209 var i: i64 = 0 210 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 } 211 if b[i] != (0 as u8) { return 0 } 212 return 1 213} 214func as_satoi(s: *u8) -> i64 { 215 var i: i64 = 0; var n: i64 = 0; var sg: i64 = 1 216 if s[0] == (45 as u8) { sg = 0 - 1; i = 1 } 217 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 } 218 return n*sg 219} 220func as_hw(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n+1 } sys_write(1, s, n); return 0 } 221func as_pn(v: i64) -> i64 { 222 let b: *u8 = sys_mmap(32); var x: i64 = v; var ng: i64 = 0 223 if x < 0 { ng = 1; x = 0 - x } 224 var i: i64 = 31 225 if x == 0 { b[i] = 48 as u8; i = i - 1 } 226 while x > 0 { b[i] = (48 + x%10) as u8; x = x/10; i = i - 1 } 227 if ng == 1 { b[i] = 45 as u8; i = i - 1 } 228 sys_write(1, (b as i64 + i + 1) as *u8, 31 - i); return 0 229} 230func as_rdbits(b: *u8, o: i64) -> i64 { 231 return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24) 232} 233// decode IEEE-754 float32 at byte offset o, return round(value * mul) as integer 234func as_f32mul(b: *u8, o: i64, mul: i64) -> i64 { 235 let bits: i64 = as_rdbits(b, o) 236 let sign: i64 = (bits>>31) & 1 237 let exp: i64 = (bits>>23) & 255 238 let mant: i64 = bits & AS_F32_MANT_MASK 239 if exp == 0 { return 0 } 240 let m: i64 = (mant | AS_F32_MANT_SCALE) * mul 241 var e: i64 = exp - 127 - 23 242 var v: i64 = 0 243 if e >= 0 { v = m << e } else { let sh: i64 = 0 - e; v = (m + (1 << (sh-1))) >> sh } 244 if sign == 1 { v = 0 - v } 245 return v 246} 247func as_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 } 248// ---- GX-13 integer texture engine: lattice value-noise FBM over WORLD position ---- 249// The hardened grader (ns_assess2) names scale (multi-scale detail) + MSCN as our weak axes; real surfaces 250// carry detail at every octave. 4 octaves of smooth value noise = coherent (NOT white noise) so the 251// coherence gate is respected by construction. 252func tx_h3(ix: i64, iy: i64, iz: i64) -> i64 { 253 var v: i64 = (ix*AS_HASH_P1) ^ (iy*AS_HASH_P2) ^ (iz*AS_HASH_P3) 254 v = v & AS_I32_MAX 255 v = (v * (v*v*AS_NOISE_A + AS_NOISE_B) + AS_NOISE_C) & AS_I32_MAX 256 return (v >> 16) & 255 257} 258func tx_floordiv(x: i64, s: i64) -> i64 { var q: i64 = x/s; if x < 0 { if x % s != 0 { q = q - 1 } } return q } 259func tx_lerp(a: i64, b: i64, t8: i64) -> i64 { return a + (b-a)*t8/256 } 260func tx_vnoise(x: i64, y: i64, z: i64, s: i64) -> i64 { 261 let lx: i64 = tx_floordiv(x,s); let ly: i64 = tx_floordiv(y,s); let lz: i64 = tx_floordiv(z,s) 262 var fx: i64 = (x - lx*s)*256/s; var fy: i64 = (y - ly*s)*256/s; var fz: i64 = (z - lz*s)*256/s 263 fx = fx*fx*(768 - 2*fx)/AS_Q16_ONE; fy = fy*fy*(768 - 2*fy)/AS_Q16_ONE; fz = fz*fz*(768 - 2*fz)/AS_Q16_ONE 264 let c000: i64 = tx_h3(lx,ly,lz); let c100: i64 = tx_h3(lx+1,ly,lz) 265 let c010: i64 = tx_h3(lx,ly+1,lz); let c110: i64 = tx_h3(lx+1,ly+1,lz) 266 let c001: i64 = tx_h3(lx,ly,lz+1); let c101: i64 = tx_h3(lx+1,ly,lz+1) 267 let c011: i64 = tx_h3(lx,ly+1,lz+1); let c111: i64 = tx_h3(lx+1,ly+1,lz+1) 268 let a0: i64 = tx_lerp(tx_lerp(c000,c100,fx), tx_lerp(c010,c110,fx), fy) 269 let a1: i64 = tx_lerp(tx_lerp(c001,c101,fx), tx_lerp(c011,c111,fx), fy) 270 return tx_lerp(a0, a1, fz) 271} 272func tx_fbm(x: i64, y: i64, z: i64) -> i64 { 273 let n1: i64 = tx_vnoise(x,y,z,128) 274 let n2: i64 = tx_vnoise(x,y,z,40) 275 let n3: i64 = tx_vnoise(x,y,z,12) 276 let n4: i64 = tx_vnoise(x,y,z,4) 277 return (n1*3 + n2*3 + n3*2 + n4*2) / 10 278} 279// ★MULTI-VIEW judge support: Bhaskara-I degree sine, Q14, exact at 0/30/90/150/180. A single view is blind 280// to depth-axis error entirely -- body THICKNESS never appears in a front silhouette -- so the judge must be 281// able to turn the model. Our own integer trig, no float, no lookup-table literals. 282func as_sin_fill(t: *i64) -> i64 { 283 var d: i64 = 0 284 while d < 180 { let P: i64 = d*(180-d); t[d] = AS_Q14*4*P/AS_BHASKARA_K; t[d+180] = 0-t[d]; d = d+1 } 285 return 0 286} 287func as_wrap(d: i64) -> i64 { var x: i64 = d % 360; if x < 0 { x = x + 360 } return x } 288func as_min(a: i64, b: i64) -> i64 { if a < b { return a } return b } 289func as_max(a: i64, b: i64) -> i64 { if a > b { return a } return b } 290 291// ---- GX-39 piece 2: SCREEN-SPACE AMBIENT OCCLUSION over the finished z-buffer (contact darkening) ---- 292// PORTED from nx_swgpu sg_ssao (the opposite-pairs design) per the debt row -- port, not rewrite. 293// Why pairs: a naive "is my neighbour nearer" test darkens every receding plane (the classic SSAO false 294// positive that greys floors). In a genuine cavity BOTH opposite samples are nearer; on a plane or slope 295// one is nearer and the other farther, so it scores zero. No normal buffer, nothing added to the raster 296// inner loop -- a pure post-pass, so it cannot regress the rasterizer. 297// SCALE-FREE bounds (bounds are DERIVED, never taste): the bias (depth-noise floor) and far cutoff 298// (a distant surface is a DIFFERENT object, not an occluder -- this is what stops silhouettes being 299// ringed with false shadow) derive from the MEASURED body depth range of the frame (lb>=0 pixels only, 300// so the receding floor cannot inflate the windows), and the ring radii derive from H, so one code path 301// grounds any mesh scale at any render size. AO still APPLIES to floor pixels -- that is exactly what 302// plants the feet (contact darkening where body meets ground). 303// Runs ONLY on the shaded path (never nmap: the mechanistic shape-judge input stays pure geometry), so 304// the geometric bench cannot move BY CONSTRUCTION -- and it is proven anyway by byte-identical 305// nx_bodybench output before/after. 306const AS_AO_STRENGTH: i64 = 140 // occ 8/8 attenuates to (256-140)/256 before the floor below 307const AS_AO_ATT_FLOOR: i64 = 64 // never crush a cavity to black (the donor's floor, kept) 308 309// separable integer box blur over an N x N grid (edge-clamped) -- the soft-shadow field builder 310func as_boxblur(src: *i64, tmp: *i64, dst: *i64, N: i64, r: i64) -> i64 { 311 let span: i64 = 2*r + 1 312 var z4: i64 = 0 313 while z4 < N { 314 var x4: i64 = 0 315 while x4 < N { 316 var acc: i64 = 0 317 var k4: i64 = 0 - r 318 while k4 <= r { 319 var xx: i64 = x4 + k4 320 if xx < 0 { xx = 0 } 321 if xx >= N { xx = N - 1 } 322 acc = acc + src[z4*N + xx] 323 k4 = k4 + 1 324 } 325 tmp[z4*N + x4] = acc/span 326 x4 = x4 + 1 327 } 328 z4 = z4 + 1 329 } 330 z4 = 0 331 while z4 < N { 332 var x4: i64 = 0 333 while x4 < N { 334 var acc: i64 = 0 335 var k4: i64 = 0 - r 336 while k4 <= r { 337 var zz: i64 = z4 + k4 338 if zz < 0 { zz = 0 } 339 if zz >= N { zz = N - 1 } 340 acc = acc + tmp[zz*N + x4] 341 k4 = k4 + 1 342 } 343 dst[z4*N + x4] = acc/span 344 x4 = x4 + 1 345 } 346 z4 = z4 + 1 347 } 348 return 0 349} 350func as_ssao(fb: *i64, zb: *i64, lb: *i64, W2: i64, H2: i64) -> i64 { 351 let npx2: i64 = W2*H2 352 var zmn: i64 = AS_ZFAR; var zmx: i64 = 0 353 var q2: i64 = 0 354 while q2 < npx2 { 355 if lb[q2] >= 0 { 356 let d0: i64 = zb[q2] 357 if d0 < zmn { zmn = d0 } 358 if d0 > zmx { zmx = d0 } 359 } 360 q2 = q2 + 1 361 } 362 let rng: i64 = zmx - zmn 363 if rng < 128 { return 0 } // degenerate/flat frame: nothing meaningful to occlude 364 let bias: i64 = rng/128 // below ~0.8pct of body depth it is depth noise, not a cavity 365 let far2: i64 = rng/6 // beyond ~17pct of body depth it is a different surface 366 var r1: i64 = H2/128; if r1 < 2 { r1 = 2 } // tight ring: contact seams 367 var rw: i64 = H2/56; if rw < 4 { rw = 4 } // wide ring: broad cavities 368 let d1r: i64 = r1*707/1000 + 1 369 let dwr: i64 = rw*707/1000 + 1 370 let ax: *i64 = sys_mmap(16*8) as *i64 371 let ay: *i64 = sys_mmap(16*8) as *i64 372 // 8 opposite pairs: entries s and s+8 are mirrors (the donor's layout, radii derived above) 373 ax[0]=r1; ay[0]=0; ax[1]=d1r; ay[1]=d1r; ax[2]=0; ay[2]=r1; ax[3]=0-d1r; ay[3]=d1r 374 ax[4]=rw; ay[4]=0; ax[5]=dwr; ay[5]=dwr; ax[6]=0; ay[6]=rw; ax[7]=0-dwr; ay[7]=dwr 375 ax[8]=0-r1; ay[8]=0; ax[9]=0-d1r; ay[9]=0-d1r; ax[10]=0; ay[10]=0-r1; ax[11]=d1r; ay[11]=0-d1r 376 ax[12]=0-rw; ay[12]=0; ax[13]=0-dwr; ay[13]=0-dwr; ax[14]=0; ay[14]=0-rw; ax[15]=dwr; ay[15]=0-dwr 377 var y3: i64 = 0 378 while y3 < H2 { 379 var x3: i64 = 0 380 while x3 < W2 { 381 let idx3: i64 = y3*W2 + x3 382 let d: i64 = zb[idx3] 383 if d < AS_ZFAR { 384 var occ: i64 = 0 385 var s: i64 = 0 386 while s < 8 { 387 var near1: i64 = 0 388 var near2: i64 = 0 389 let x1: i64 = x3 + ax[s] 390 let y1: i64 = y3 + ay[s] 391 if x1 >= 0 { if x1 < W2 { if y1 >= 0 { if y1 < H2 { 392 let dd1: i64 = zb[y1*W2 + x1] 393 if dd1 < AS_ZFAR { let df: i64 = d - dd1; if df > bias { if df < far2 { near1 = 1 } } } 394 }}}} 395 let x2: i64 = x3 + ax[s+8] 396 let y2: i64 = y3 + ay[s+8] 397 if x2 >= 0 { if x2 < W2 { if y2 >= 0 { if y2 < H2 { 398 let dd2: i64 = zb[y2*W2 + x2] 399 if dd2 < AS_ZFAR { let df2: i64 = d - dd2; if df2 > bias { if df2 < far2 { near2 = 1 } } } 400 }}}} 401 if near1 == 1 { if near2 == 1 { occ = occ + 1 } } // BOTH sides nearer = a real cavity 402 s = s + 1 403 } 404 if occ > 0 { 405 var att: i64 = 256 - occ*AS_AO_STRENGTH/8 406 if att < AS_AO_ATT_FLOOR { att = AS_AO_ATT_FLOOR } 407 let v: i64 = fb[idx3] 408 let r: i64 = (v % 256)*att/256 409 let g: i64 = ((v/256) % 256)*att/256 410 let b: i64 = ((v/AS_Q16_ONE) % 256)*att/256 411 fb[idx3] = r + g*256 + b*AS_Q16_ONE 412 } 413 } 414 x3 = x3 + 1 415 } 416 y3 = y3 + 1 417 } 418 return 0 419} 420 421// ---- GX-39 piece 4: DEPTH OF FIELD keyed on the finished z-buffer ---- 422// The last light-transport piece the debt names. Photographic focus: the BODY (the measured lb>=0 423// depth band) stays sharp; floor and backdrop blur with distance from the focus plane, radius derived 424// from H and the measured body depth range (bounds-derived, never taste). Gather guard: a sample only 425// contributes if ITS OWN circle of confusion reaches the target pixel, so the sharp subject can never 426// smear into the background (the classic DoF halo artifact, foreclosed by construction). Shaded path 427// only -- the nmap shape-judge input stays pure geometry. 428func as_dof(fb: *i64, zb: *i64, lb: *i64, W2: i64, H2: i64) -> i64 { 429 let npx2: i64 = W2*H2 430 var zmn: i64 = AS_ZFAR; var zmx: i64 = 0; var zsum: i64 = 0; var zn: i64 = 0 431 var q2: i64 = 0 432 while q2 < npx2 { 433 if lb[q2] >= 0 { 434 let d0: i64 = zb[q2] 435 if d0 < zmn { zmn = d0 } 436 if d0 > zmx { zmx = d0 } 437 zsum = zsum + d0; zn = zn + 1 438 } 439 q2 = q2 + 1 440 } 441 if zn < 1 { return 0 } 442 let rng: i64 = zmx - zmn 443 if rng < 128 { return 0 } 444 let focus: i64 = zsum/zn 445 var maxr: i64 = H2/192; if maxr < 2 { maxr = 2 } 446 let cocb: *i64 = sys_mmap(npx2*8) as *i64 // circle of confusion per pixel (0 = in focus) 447 let srcb: *i64 = sys_mmap(npx2*8) as *i64 // blur reads the unmodified frame 448 q2 = 0 449 while q2 < npx2 { 450 srcb[q2] = fb[q2] 451 var dz: i64 = zb[q2] - focus 452 if dz < 0 { dz = 0 - dz } 453 var coc: i64 = 0 454 if dz > rng/2 { coc = (dz - rng/2)*maxr/(rng*2) } 455 if coc > maxr { coc = maxr } 456 cocb[q2] = coc 457 q2 = q2 + 1 458 } 459 var y3: i64 = 0 460 while y3 < H2 { 461 var x3: i64 = 0 462 while x3 < W2 { 463 let idx3: i64 = y3*W2 + x3 464 let c0: i64 = cocb[idx3] 465 if c0 >= 1 { 466 var ar: i64 = 0; var ag: i64 = 0; var ab: i64 = 0; var an: i64 = 0 467 var dy6: i64 = 0 - c0 468 while dy6 <= c0 { 469 var dx6: i64 = 0 - c0 470 while dx6 <= c0 { 471 let x6: i64 = x3 + dx6 472 let y6: i64 = y3 + dy6 473 if x6 >= 0 { if x6 < W2 { if y6 >= 0 { if y6 < H2 { 474 let si: i64 = y6*W2 + x6 475 var rr: i64 = dx6; if rr < 0 { rr = 0 - rr } 476 var r7: i64 = dy6; if r7 < 0 { r7 = 0 - r7 } 477 if r7 > rr { rr = r7 } 478 if cocb[si] >= rr { 479 let v: i64 = srcb[si] 480 ar = ar + (v % 256) 481 ag = ag + ((v/256) % 256) 482 ab = ab + ((v/AS_Q16_ONE) % 256) 483 an = an + 1 484 } 485 }}}} 486 dx6 = dx6 + 1 487 } 488 dy6 = dy6 + 1 489 } 490 if an > 0 { fb[idx3] = ar/an + (ag/an)*256 + (ab/an)*AS_Q16_ONE } 491 } 492 x3 = x3 + 1 493 } 494 y3 = y3 + 1 495 } 496 return 0 497} 498 499func main(argc: i64, argv: *i64) -> i64 { 500 // ★GUARD argc BEFORE THE FIRST argv DEREFERENCE. Without this, `nx_anat_sov` with no arguments read 501 // argv[1] off the end of the vector and died with SIGSEGV -- and a registered organ that crashes on 502 // its usage path reads to every caller as "this capability is broken", not as "you called it wrong". 503 if argc < AS_ARGC_MIN { 504 as_hw("usage: nx_anat_sov <mesh> <intact|explode|skin|layerN> <C|L|R> <W> <H> <out.png> [nmap] [yawdeg] [fit] [perfusion_permil]\n" as *u8) 505 return AS_EXIT_USAGE 506 } 507 let meshp: *u8 = argv[1] as *u8 508 let mode: *u8 = argv[2] as *u8 509 // argv[7]=="nmap" -> emit a NORMAL MAP instead of a shaded image (mechanistic shape-judge input) 510 var nmap: i64 = 0 511 if argc > 7 { let np7: *u8 = argv[7] as *u8; if np7[0] == (110 as u8) { nmap = 1 } } 512 // argv[8] = yaw degrees about the vertical axis (multi-view judge) 513 var yawd: i64 = 0 514 if argc > 8 { yawd = as_satoi(argv[8] as *u8) } 515 // argv[9]=="fit" -> height-only framing (fair, scale-normalised comparison for the judges) 516 var fith: i64 = 0 517 if argc > 9 { let f9: *u8 = argv[9] as *u8; if f9[0] == (102 as u8) { fith = 1 } } 518 // argv[10] = AROUSAL PERFUSION in permil (absent or 0 => renderer behaves EXACTLY as before). 519 // Physiology, not a tint: added dermal oxyhaemoglobin absorbs strongly in blue (Soret ~415nm) 520 // and green (542/577nm) and only weakly above 600nm, so flush is G and B FALLING rather than 521 // red being added. Colour-only, so the shape and detail judges cannot move. 522 if argc > 10 { as_set_perfusion(as_satoi(argv[10] as *u8)) } 523 let sinT: *i64 = sys_mmap(400*8) as *i64 524 as_sin_fill(sinT) 525 let ysin: i64 = sinT[as_wrap(yawd)] 526 let ycos: i64 = sinT[as_wrap(yawd+90)] 527 let eye: *u8 = argv[3] as *u8 528 let W: i64 = as_satoi(argv[4] as *u8) 529 let H: i64 = as_satoi(argv[5] as *u8) 530 let outp: *u8 = argv[6] as *u8 531 532 let lenp: *i64 = sys_mmap(16) as *i64 533 let mb: *u8 = sys_read_file(meshp, lenp) 534 if (mb as i64) == 0 { as_hw("{\x22error\x22:\x22cannot read mesh\x22}\n" as *u8); return 2 } 535 // header 536 let nlayers: i64 = as_rdbits(mb, 8) 537 let ntris: i64 = as_rdbits(mb, 12) 538 // layer table: name16 off4 cnt4 ; tris base after it 539 let triBase: i64 = 16 + nlayers*24 540 let lidBase: i64 = triBase + ntris*84 541 // per-layer visibility + explode offset (x) 542 let vis: *i64 = sys_mmap(nlayers*8) as *i64 543 let loffx: *i64 = sys_mmap(nlayers*8) as *i64 544 var L0: i64 = 0 545 while L0 < nlayers { vis[L0] = 1; loffx[L0] = 0; L0 = L0 + 1 } 546 var only: i64 = 0 - 1 547 if as_streq(mode, "skin" as *u8) == 1 { only = 0 } 548 if mode[0] == (108 as u8) { if mode[1] == (97 as u8) { only = as_satoi((mode as i64 + 5) as *u8) } } // "layerN" 549 if only >= 0 { var i: i64 = 0; while i < nlayers { vis[i] = 0; i = i + 1 } vis[only] = 1 } 550 551 // ★seq630 pass 0: MEASURE the mesh at a fixed high precision, then choose the working precision so the 552 // model always spans ~AS_TARGET integer units. A metre-scale mesh and a millimetre-scale mesh then get 553 // the SAME effective resolution -- scale-invariant by construction instead of assuming millimetres. 554 var q0mn: i64 = AS_MAGIC_2000000000 555 var q0mx: i64 = 0-AS_MAGIC_2000000000 556 var t0: i64 = 0 557 while t0 < ntris { 558 let o0: i64 = triBase + t0*84 559 var c0: i64 = 0 560 while c0 < 3 { 561 let vq: i64 = as_f32mul(mb, o0 + c0*4, AS_POSQ0) 562 if vq < q0mn { q0mn = vq } 563 if vq > q0mx { q0mx = vq } 564 c0 = c0 + 1 565 } 566 t0 = t0 + 1 567 } 568 var span0: i64 = q0mx - q0mn 569 if span0 < 1 { span0 = 1 } 570 var posq: i64 = AS_POSQ0 * AS_TARGET / span0 571 if posq < 1 { posq = 1 } 572 573 // pass 1: full AABB over all verts -> centroid + radius 574 var mnx: i64 = AS_MAGIC_2000000000; var mny: i64 = AS_MAGIC_2000000000; var mnz: i64 = AS_MAGIC_2000000000 575 var mxx: i64 = 0-AS_MAGIC_2000000000; var mxy: i64 = 0-AS_MAGIC_2000000000; var mxz: i64 = 0-AS_MAGIC_2000000000 576 var t: i64 = 0 577 while t < ntris { 578 var v: i64 = 0 579 while v < 3 { 580 let o: i64 = triBase + t*84 + v*12 581 let x: i64 = as_f32mul(mb, o, posq); let y: i64 = as_f32mul(mb, o+4, posq); let z: i64 = as_f32mul(mb, o+8, posq) 582 if x < mnx { mnx = x } if x > mxx { mxx = x } 583 if y < mny { mny = y } if y > mxy { mxy = y } 584 if z < mnz { mnz = z } if z > mxz { mxz = z } 585 v = v + 1 586 } 587 t = t + 1 588 } 589 let cx0: i64 = (mnx+mxx)/2; let cy0: i64 = (mny+mxy)/2; let cz0: i64 = (mnz+mxz)/2 590 var rad: i64 = (mxx-mnx)/2 591 if (mxy-mny)/2 > rad { rad = (mxy-mny)/2 } 592 if (mxz-mnz)/2 > rad { rad = (mxz-mnz)/2 } 593 if rad < 1 { rad = 1 } // seq630: a degenerate mesh must never reach a divisor 594 // explode offsets (fan along X), step 0.62*rad, centered 595 if as_streq(mode, "explode" as *u8) == 1 { 596 let step: i64 = (rad*62)/100 597 var i: i64 = 0 598 while i < nlayers { loffx[i] = (i*2 - (nlayers-1)) * step / 2; i = i + 1 } 599 } 600 601 // pass 2: visible AABB (centered + offset) -> framing 602 var vmnx: i64 = AS_MAGIC_2000000000; var vmny: i64 = AS_MAGIC_2000000000; var vmnz: i64 = AS_MAGIC_2000000000 603 var vmxx: i64 = 0-AS_MAGIC_2000000000; var vmxy: i64 = 0-AS_MAGIC_2000000000; var vmxz: i64 = 0-AS_MAGIC_2000000000 604 t = 0 605 while t < ntris { 606 let L: i64 = as_rdbits(mb, lidBase + t*4) & 255 607 if vis[L] == 1 { 608 var v: i64 = 0 609 while v < 3 { 610 let o: i64 = triBase + t*84 + v*12 611 let x: i64 = as_f32mul(mb,o,posq) - cx0 + loffx[L] 612 let y: i64 = as_f32mul(mb,o+4,posq) - cy0 613 let z: i64 = as_f32mul(mb,o+8,posq) - cz0 614 if x < vmnx { vmnx = x } if x > vmxx { vmxx = x } 615 if y < vmny { vmny = y } if y > vmxy { vmxy = y } 616 if z < vmnz { vmnz = z } if z > vmxz { vmxz = z } 617 v = v + 1 618 } 619 } 620 t = t + 1 621 } 622 let halfW: i64 = (vmxx-vmnx)/2; let halfH: i64 = (vmxy-vmny)/2 623 let vcx: i64 = (vmnx+vmxx)/2; let vcy: i64 = (vmny+vmxy)/2 624 // arousal sites are read off THIS mesh's own extent, so the field follows whatever body is loaded 625 as_set_body_span(vmny, vmxy, vcx, halfW) 626 let FOCAL: i64 = H // tan(halffov_v)=0.5 627 var dist: i64 = 2*halfH 628 let dw: i64 = 2*halfW*H/W 629 if dw > dist { dist = dw } 630 dist = dist*118/100 + (vmxz-vmnz)/2 631 // ★FAIR-RULER FIX: auto-framing that depends on WIDTH or DEPTH silently rescales the render, so a change 632 // to body thickness moved the camera and shrank the figure -- the front silhouette score fell 834->624 from 633 // a depth edit that cannot affect a front outline. That was the RULER moving, not the shape. 'fit' frames 634 // on HEIGHT ALONE, so two meshes of the same stature render at the same scale and IoU measures shape only. 635 if fith == 1 { dist = 2*halfH*118/100 } 636 if dist < 1 { dist = 1 } // seq630: never divide by a degenerate framing distance 637 // off-axis (parallel) stereo eye offset in X 638 var ex: i64 = 0 639 if eye[0] == (76 as u8) { ex = 0 - (dist*32)/1000 } // 'L' 640 if eye[0] == (82 as u8) { ex = (dist*32)/1000 } // 'R' 641 642 // framebuffers 643 let npx: i64 = W*H 644 let fb: *i64 = sys_mmap(npx*8) as *i64 645 let zb: *i64 = sys_mmap(npx*8) as *i64 646 let lb: *i64 = sys_mmap(npx*8) as *i64 647 var p: i64 = 0 648 while p < npx { 649 let py: i64 = p / W 650 let px1: i64 = p % W 651 // smooth full-precision vertical gradient (the old 10-level g caused visible BANDING -- eyeball-found) 652 // + subtle backdrop grain (paper-texture scale, +-4 levels; coherent value noise, not white noise) 653 let bgt: i64 = tx_vnoise(px1*4, py*4, 17, 24) / 32 - 4 654 var br: i64 = 34 + (56*(H-py))/H + bgt 655 var bgc: i64 = 41 + (69*(H-py))/H + bgt 656 var bbl: i64 = 56 + (94*(H-py))/H + bgt 657 if br<0 {br=0} if bgc<0 {bgc=0} if bbl<0 {bbl=0} 658 fb[p] = br + bgc*256 + bbl*AS_Q16_ONE 659 zb[p] = AS_ZFAR; lb[p] = 0 - 1; p = p + 1 660 } 661 662 // lights (Q14 unit) 663 let l1x: i64 = 0-AS_KEY_LIGHT_X; let l1y: i64 = AS_KEY_LIGHT_Y; let l1z: i64 = AS_KEY_LIGHT_Z 664 let l2x: i64 = AS_FILL_LIGHT_X; let l2y: i64 = 0-AS_FILL_LIGHT_Y; let l2z: i64 = AS_FILL_LIGHT_Z 665 let cxh: i64 = W/2; let cyh: i64 = H/2 666 // half-vector for specular (headlight view (0,0,1)), computed ONCE 667 var hx: i64 = l1x; var hy: i64 = l1y; var hz: i64 = l1z + AS_Q14 668 let hl: i64 = as_isqrt(hx*hx + hy*hy + hz*hz) 669 hx = hx*AS_Q14/hl; hy = hy*AS_Q14/hl; hz = hz*AS_Q14/hl 670 671 // ---- GX-15 rung A: GROUND PLANE + PROJECTED CONTACT SHADOW (the floating-figure fix) ---- 672 // Real geometry-derived shadow: every visible triangle is projected along light L1 onto the floor 673 // plane y=floorY and splatted into a floor-space mask; floor pixels darken where masked. 674 let floorY: i64 = vmny 675 let smN: i64 = 192 676 var smE: i64 = rad*3 677 if smE < 1 { smE = 1 } // seq630: fail-safe -- the shadow grid divides by 2*smE 678 let sm: *i64 = sys_mmap(smN*smN*8) as *i64 679 let qgx: *i64 = sys_mmap(64) as *i64 680 let qgz: *i64 = sys_mmap(64) as *i64 681 let qgy: *i64 = sys_mmap(64) as *i64 682 t = 0 683 while t < ntris { 684 let L: i64 = as_rdbits(mb, lidBase + t*4) & 255 685 if vis[L] == 1 { 686 let ob: i64 = triBase + t*84 687 var v: i64 = 0 688 while v < 3 { 689 let o: i64 = ob + v*12 690 let px3: i64 = as_f32mul(mb,o,posq) - cx0 + loffx[L] 691 let py3: i64 = as_f32mul(mb,o+4,posq) - cy0 692 let pz3: i64 = as_f32mul(mb,o+8,posq) - cz0 693 let sx3: i64 = px3 - (py3 - floorY)*l1x/l1y 694 let sz3: i64 = pz3 - (py3 - floorY)*l1z/l1y 695 qgx[v] = (sx3 + smE)*smN/(2*smE) 696 qgz[v] = (sz3 + smE)*smN/(2*smE) 697 qgy[v] = py3 - floorY 698 v = v + 1 699 } 700 var a2: i64 = (qgx[1]-qgx[0])*(qgz[2]-qgz[0]) - (qgx[2]-qgx[0])*(qgz[1]-qgz[0]) 701 var sg2: i64 = 1 702 if a2 < 0 { sg2 = 0 - 1 } 703 if a2 != 0 { 704 var gxmn: i64 = as_max(0, as_min(qgx[0], as_min(qgx[1], qgx[2]))) 705 var gxmx: i64 = as_min(smN-1, as_max(qgx[0], as_max(qgx[1], qgx[2]))) 706 var gzmn: i64 = as_max(0, as_min(qgz[0], as_min(qgz[1], qgz[2]))) 707 var gzmx: i64 = as_min(smN-1, as_max(qgz[0], as_max(qgz[1], qgz[2]))) 708 var gz: i64 = gzmn 709 while gz <= gzmx { 710 var gx: i64 = gxmn 711 while gx <= gxmx { 712 let f0: i64 = ((qgx[2]-qgx[1])*(gz-qgz[1]) - (qgz[2]-qgz[1])*(gx-qgx[1]))*sg2 713 let f1: i64 = ((qgx[0]-qgx[2])*(gz-qgz[2]) - (qgz[0]-qgz[2])*(gx-qgx[2]))*sg2 714 let f2: i64 = ((qgx[1]-qgx[0])*(gz-qgz[0]) - (qgz[1]-qgz[0])*(gx-qgx[0]))*sg2 715 if f0 >= 0 { if f1 >= 0 { if f2 >= 0 { 716 // GX-39 piece 3: store MAX OCCLUDER HEIGHT per cell (was a 1-bit mask) so 717 // the penumbra can grow with height like a real area light 718 var hrel: i64 = qgy[0] 719 if qgy[1] > hrel { hrel = qgy[1] } 720 if qgy[2] > hrel { hrel = qgy[2] } 721 if hrel < 1 { hrel = 1 } 722 if hrel > sm[gz*smN+gx] { sm[gz*smN+gx] = hrel } 723 }}} 724 gx = gx + 1 725 } 726 gz = gz + 1 727 } 728 } 729 } 730 t = t + 1 731 } 732 // ---- GX-39 piece 3: SOFT AREA SHADOW fields ---- 733 // sm now stores MAX OCCLUDER HEIGHT per cell (0 = unshadowed). Two separable integer box blurs of 734 // the coverage build a SHARP field (kills grid-cell blockiness only) and a WIDE field (the 735 // penumbra); each floor pixel blends between them by the LOCAL occluder height -- feet stay crisply 736 // planted while the head's shadow feathers wide, the real area-light signature. nmap renders keep 737 // the legacy hard 4-tap lookup so the mechanistic shape-judge input stays bit-stable. 738 let smc: i64 = smN*smN 739 let cov: *i64 = sys_mmap(smc*8) as *i64 740 let bt1: *i64 = sys_mmap(smc*8) as *i64 741 let bs1: *i64 = sys_mmap(smc*8) as *i64 742 let bs2: *i64 = sys_mmap(smc*8) as *i64 743 var ci: i64 = 0 744 while ci < smc { if sm[ci] > 0 { cov[ci] = AS_Q10_ONE } ci = ci + 1 } 745 as_boxblur(cov, bt1, bs1, smN, 1) 746 as_boxblur(cov, bt1, bs2, smN, 4) 747 748 // analytic floor pass: per-pixel ray/plane, textured, shadow-masked, distance-faded to bg 749 var fp: i64 = 0 750 while fp < npx { 751 let py2: i64 = fp / W 752 let px2: i64 = fp % W 753 let rdy: i64 = cyh - py2 754 if rdy < 0 { 755 let t16: i64 = floorY*AS_Q16_ONE/rdy 756 let wx: i64 = ex + t16*(px2-cxh)/AS_Q16_ONE 757 let wz: i64 = dist + t16*(0-FOCAL)/AS_Q16_ONE 758 if wx > 0-smE { if wx < smE { if wz > 0-smE { if wz < smE { 759 let depth: i64 = dist - wz 760 if depth > 0 { 761 let tv: i64 = tx_fbm(wx/posq, floorY/posq, wz/posq) 762 let f: i64 = 928 + tv/2 763 var fr: i64 = 118*f/AS_Q10_ONE; var fg: i64 = 110*f/AS_Q10_ONE; var fbv: i64 = 101*f/AS_Q10_ONE 764 let gx: i64 = (wx + smE)*smN/(2*smE) 765 let gz: i64 = (wz + smE)*smN/(2*smE) 766 var dk: i64 = AS_Q10_ONE 767 if nmap == 0 { 768 // soft area shadow: blend sharp->wide by local occluder height (3x3 max so the 769 // penumbra field has no holes), then darken by the blended coverage 770 var hL: i64 = 0 771 var dz5: i64 = 0 - 1 772 while dz5 <= 1 { 773 var dx5: i64 = 0 - 1 774 while dx5 <= 1 { 775 let gx5: i64 = gx + dx5 776 let gz5: i64 = gz + dz5 777 if gx5 >= 0 { if gx5 < smN { if gz5 >= 0 { if gz5 < smN { 778 if sm[gz5*smN+gx5] > hL { hL = sm[gz5*smN+gx5] } 779 }}}} 780 dx5 = dx5 + 1 781 } 782 dz5 = dz5 + 1 783 } 784 // a shadow cast from a third of stature up is fully soft (height-derived, not taste) 785 var hpen: i64 = (vmxy - vmny)/3 786 if hpen < 1 { hpen = 1 } 787 var wgt: i64 = hL*AS_Q10_ONE/hpen 788 if wgt > AS_Q10_ONE { wgt = AS_Q10_ONE } 789 let sv: i64 = (bs1[gz*smN+gx]*(AS_Q10_ONE-wgt) + bs2[gz*smN+gx]*wgt)/AS_Q10_ONE 790 dk = AS_Q10_ONE - sv*44/100 791 } else { 792 // legacy hard 4-tap, bit-stable for the shape-judge floor (sm holds heights now, 793 // so count occupied cells rather than summing raw values) 794 var sh: i64 = 0 795 if sm[gz*smN+gx] > 0 { sh = sh + 1 } 796 if gx+1 < smN { if sm[gz*smN+gx+1] > 0 { sh = sh + 1 } } 797 if gz+1 < smN { if sm[(gz+1)*smN+gx] > 0 { sh = sh + 1 } } 798 if gx > 0 { if sm[gz*smN+gx-1] > 0 { sh = sh + 1 } } 799 dk = AS_Q10_ONE - sh*110 800 } 801 fr = fr*dk/AS_Q10_ONE; fg = fg*dk/AS_Q10_ONE; fbv = fbv*dk/AS_Q10_ONE 802 // distance fade toward the backdrop colour 803 let dxtra: i64 = t16/AS_Q16_ONE 804 let ff: i64 = smE*AS_Q10_ONE/(smE + dxtra*3) 805 let obr: i64 = 34 + (56*(H-py2))/H 806 let obg: i64 = 41 + (69*(H-py2))/H 807 let obb: i64 = 56 + (94*(H-py2))/H 808 fr = (fr*ff + obr*(AS_Q10_ONE-ff))/AS_Q10_ONE 809 fg = (fg*ff + obg*(AS_Q10_ONE-ff))/AS_Q10_ONE 810 fbv = (fbv*ff + obb*(AS_Q10_ONE-ff))/AS_Q10_ONE 811 if fr>255 {fr=255} if fg>255 {fg=255} if fbv>255 {fbv=255} 812 fb[fp] = fr + fg*256 + fbv*AS_Q16_ONE 813 zb[fp] = depth 814 } 815 }}}} 816 } 817 fp = fp + 1 818 } 819 820 // pass 3: rasterize 821 t = 0 822 while t < ntris { 823 let L: i64 = as_rdbits(mb, lidBase + t*4) & 255 824 if vis[L] == 1 { 825 let ob: i64 = triBase + t*84 826 // 3 verts: centered pos + offset ; normal Q14 ; color 0..255 (per-vertex, we use v0's colour = flat) 827 let rx0v: i64 = as_f32mul(mb,ob,posq) - cx0 + loffx[L]; let y0: i64 = as_f32mul(mb,ob+4,posq) - cy0; let rz0v: i64 = as_f32mul(mb,ob+8,posq) - cz0 828 let rx1v: i64 = as_f32mul(mb,ob+12,posq)- cx0 + loffx[L]; let y1: i64 = as_f32mul(mb,ob+16,posq)- cy0; let rz1v: i64 = as_f32mul(mb,ob+20,posq)- cz0 829 let rx2v: i64 = as_f32mul(mb,ob+24,posq)- cx0 + loffx[L]; let y2: i64 = as_f32mul(mb,ob+28,posq)- cy0; let rz2v: i64 = as_f32mul(mb,ob+32,posq)- cz0 830 // multi-view: yaw about the vertical axis so the judge can inspect the depth axis a front view hides 831 let x0: i64 = (rx0v*ycos + rz0v*ysin)/AS_Q14; let z0: i64 = (rz0v*ycos - rx0v*ysin)/AS_Q14 832 let x1: i64 = (rx1v*ycos + rz1v*ysin)/AS_Q14; let z1: i64 = (rz1v*ycos - rx1v*ysin)/AS_Q14 833 let x2: i64 = (rx2v*ycos + rz2v*ysin)/AS_Q14; let z2: i64 = (rz2v*ycos - rx2v*ysin)/AS_Q14 834 // depths from camera (looking -z, camera at +z=dist) 835 let d0: i64 = dist - z0; let d1: i64 = dist - z1; let d2: i64 = dist - z2 836 if d0 > 0 { if d1 > 0 { if d2 > 0 { 837 // project (off-axis stereo) 838 let conv: i64 = ex*FOCAL/dist 839 let sx0: i64 = cxh + ((x0-ex)*FOCAL)/d0 + conv; let sy0: i64 = cyh - (y0*FOCAL)/d0 840 let sx1: i64 = cxh + ((x1-ex)*FOCAL)/d1 + conv; let sy1: i64 = cyh - (y1*FOCAL)/d1 841 let sx2: i64 = cxh + ((x2-ex)*FOCAL)/d2 + conv; let sy2: i64 = cyh - (y2*FOCAL)/d2 842 var area: i64 = (sx1-sx0)*(sy2-sy0) - (sx2-sx0)*(sy1-sy0) 843 if area != 0 { 844 // GX-15 rung B: per-VERTEX normals decoded once per tri, interpolated per PIXEL (kills faceting) 845 let q0x: i64 = as_f32mul(mb,ob+36,AS_Q14); let n0y: i64 = as_f32mul(mb,ob+40,AS_Q14); let q0z: i64 = as_f32mul(mb,ob+44,AS_Q14) 846 let q1x: i64 = as_f32mul(mb,ob+48,AS_Q14); let n1y: i64 = as_f32mul(mb,ob+52,AS_Q14); let q1z: i64 = as_f32mul(mb,ob+56,AS_Q14) 847 let q2x: i64 = as_f32mul(mb,ob+60,AS_Q14); let n2y: i64 = as_f32mul(mb,ob+64,AS_Q14); let q2z: i64 = as_f32mul(mb,ob+68,AS_Q14) 848 // normals must yaw with the geometry, or lighting/normal-maps detach from the surface 849 let n0x: i64 = (q0x*ycos + q0z*ysin)/AS_Q14; let n0z: i64 = (q0z*ycos - q0x*ysin)/AS_Q14 850 let n1x: i64 = (q1x*ycos + q1z*ysin)/AS_Q14; let n1z: i64 = (q1z*ycos - q1x*ysin)/AS_Q14 851 let n2x: i64 = (q2x*ycos + q2z*ysin)/AS_Q14; let n2z: i64 = (q2z*ycos - q2x*ysin)/AS_Q14 852 let cr: i64 = as_f32mul(mb,ob+72,255); let cg: i64 = as_f32mul(mb,ob+76,255); let cbb: i64 = as_f32mul(mb,ob+80,255) 853 // bbox 854 var bxmn: i64 = as_max(0, as_min(sx0, as_min(sx1,sx2))) 855 var bxmx: i64 = as_min(W-1, as_max(sx0, as_max(sx1,sx2))) 856 var bymn: i64 = as_max(0, as_min(sy0, as_min(sy1,sy2))) 857 var bymx: i64 = as_min(H-1, as_max(sy0, as_max(sy1,sy2))) 858 var sgn: i64 = 1 859 if area < 0 { sgn = 0 - 1 } 860 let aabs: i64 = area*sgn 861 var py2: i64 = bymn 862 while py2 <= bymx { 863 var px2: i64 = bxmn 864 while px2 <= bxmx { 865 let e0: i64 = ((sx2-sx1)*(py2-sy1) - (sy2-sy1)*(px2-sx1))*sgn 866 let e1: i64 = ((sx0-sx2)*(py2-sy2) - (sy0-sy2)*(px2-sx2))*sgn 867 let e2: i64 = ((sx1-sx0)*(py2-sy0) - (sy1-sy0)*(px2-sx0))*sgn 868 if e0 >= 0 { if e1 >= 0 { if e2 >= 0 { 869 let depth: i64 = (e0*d0 + e1*d1 + e2*d2)/aabs 870 let idx: i64 = py2*W + px2 871 if depth < zb[idx] { 872 // per-pixel WORLD position -> multi-octave texture (GX-13) 873 let wx: i64 = (e0*x0 + e1*x1 + e2*x2)/aabs 874 let wy: i64 = (e0*y0 + e1*y1 + e2*y2)/aabs 875 let wz: i64 = (e0*z0 + e1*z1 + e2*z2)/aabs 876 let tv: i64 = tx_fbm(wx/posq, wy/posq, wz/posq) 877 let f: i64 = 896 + tv 878 // GX-15 rung B: smooth interpolated normal per pixel 879 var nx: i64 = (e0*n0x + e1*n1x + e2*n2x)/aabs 880 var ny: i64 = (e0*n0y + e1*n1y + e2*n2y)/aabs 881 var nz: i64 = (e0*n0z + e1*n1z + e2*n2z)/aabs 882 var nl: i64 = as_isqrt(nx*nx + ny*ny + nz*nz) 883 if nl < 1 { nl = 1 } 884 nx = nx*AS_Q14/nl; ny = ny*AS_Q14/nl; nz = nz*AS_Q14/nl 885 if nz < 0 { nx = 0-nx; ny = 0-ny; nz = 0-nz } 886 // ★SKIN MICRO-BUMP: perturb the shading normal by a high-frequency noise 887 // gradient over world position -- pore/wrinkle-scale relief that catches 888 // light, so skin stops reading as smooth plastic. Renderer-only (the mesh 889 // and the bench are untouched); two octaves for skin, coarser everywhere. 890 if L == 0 { 891 let mx: i64 = wx/posq; let my: i64 = wy/posq; let mz: i64 = wz/posq 892 let gx1: i64 = tx_vnoise(mx+1,my,mz,3) - tx_vnoise(mx-1,my,mz,3) 893 let gy1: i64 = tx_vnoise(mx,my+1,mz,3) - tx_vnoise(mx,my-1,mz,3) 894 let gx2: i64 = tx_vnoise(mx+2,my,mz,7) - tx_vnoise(mx-2,my,mz,7) 895 let gy2: i64 = tx_vnoise(mx,my+2,mz,7) - tx_vnoise(mx,my-2,mz,7) 896 nx = nx + (gx1*16 + gx2*10)/10 // fine micro-relief only -- subtle, not mottled 897 ny = ny + (gy1*16 + gy2*10)/10 898 var nl2: i64 = as_isqrt(nx*nx + ny*ny + nz*nz) 899 if nl2 < 1 { nl2 = 1 } 900 nx = nx*AS_Q14/nl2; ny = ny*AS_Q14/nl2; nz = nz*AS_Q14/nl2 901 } 902 let dot1: i64 = (nx*l1x + ny*l1y + nz*l1z)/AS_Q14 903 var d1l: i64 = as_max(0, dot1) 904 // GX-15 rung C: SKIN responds like flesh -- wrap diffuse (SSS signature, proven Gx rung) 905 if L == 0 { 906 d1l = (dot1 + 4*AS_Q14/10)*717/AS_Q10_ONE 907 if d1l < 0 { d1l = 0 } 908 } 909 let d2l: i64 = as_max(0, (nx*l2x + ny*l2y + nz*l2z)/AS_Q14) 910 // ★ENVIRONMENT AMBIENT (GX-38). The ambient term was the CONSTANT 225 -- 911 // every surface got the same fill regardless of which way it faced, which 912 // is the single strongest reason these renders read as CG on a backdrop. 913 // Real ambient is a hemisphere: a surface facing up sees sky, one facing 914 // down sees only the dim bounce off the ground. This is the cosine-weighted 915 // sky-visibility term of an environment light, integer and sovereign -- 916 // shading only, so it cannot move the geometric bench by construction. 917 let skyw: i64 = (AS_Q14 + ny)/2 918 let ambi: i64 = 96 + 258*skyw/AS_Q14 919 var lit: i64 = ambi + 676*d1l/AS_Q14 + 256*d2l/AS_Q14 920 // soft FRONT FILL for skin: camera-facing surfaces get a gentle lift so 921 // downward/shadowed features (the mouth, under-chin) don't crush to black. 922 if L == 0 { lit = lit + 210*nz/AS_Q14 } 923 if lit > AS_LIT_CEIL { lit = AS_LIT_CEIL } 924 var r2: i64 = cr*lit*f/(AS_Q10_ONE*AS_Q10_ONE) 925 var g2: i64 = cg*lit*f/(AS_Q10_ONE*AS_Q10_ONE) 926 var b2: i64 = cbb*lit*f/(AS_Q10_ONE*AS_Q10_ONE) 927 // PER-CHANNEL ENVIRONMENT (GX-39). The hemisphere above is a SCALAR, so it 928 // brightens up-facing surfaces but cannot carry what actually reads as real 929 // light: sky is COOL and ground bounce is WARM, so a real body is subtly blue 930 // toward the top and orange underneath. Applied as a fraction of the surface 931 // colour itself, so it is scale-free and tints rather than washes out. 932 // Shading only, so the geometric bench must not move. 933 let gndw: i64 = AS_Q14 - skyw 934 let warm: i64 = (gndw*90 - skyw*25)/AS_Q14 935 let cool: i64 = (skyw*95 - gndw*30)/AS_Q14 936 r2 = r2 + r2*warm/1000 937 g2 = g2 + g2*(warm/3 + cool/4)/1000 938 b2 = b2 + b2*cool/1000 939 // ★SUBSURFACE SCATTERING (skin=layer0): light scatters INSIDE flesh and red 940 // penetrates deepest, so the terminator and the shadowed side glow warm/red 941 // instead of going dead-grey -- the single biggest "skin not clay" signature. 942 // sss rises smoothly as the surface turns away from the key light. 943 if L == 0 { 944 var sss: i64 = AS_Q14*55/100 - dot1 945 if sss < 0 { sss = 0 } 946 if sss > AS_Q14 { sss = AS_Q14 } 947 r2 = r2 + cr*sss*46/(AS_Q14*100) // red bleed (deepest) -- strong 948 g2 = g2 + cg*sss*14/(AS_Q14*100) // a little green 949 b2 = b2 - cbb*sss*10/(AS_Q14*100) // pull blue -> warmer shadows 950 // ★AROUSAL PERFUSION: added haemoglobin absorbs G and B far 951 // more than R, so flush is G/B FALLING, not red being added. 952 // AS_PERF defaults 0 -> this block is a no-op for every 953 // existing caller and the geometric bench cannot move. 954 // ★GATED BY THE PROPAGATION FIELD, not applied flat: local flush is how 955 // far systemic perfusion EXCEEDS this site's threshold, so at low drive 956 // only genital/submammary tissue colours and the face/limbs stay clear, 957 // and the order emerges instead of the whole body reddening at once. 958 if AS_PERF > 0 { 959 let sfr: i64 = (wy - AS_YMIN)*1000/AS_YSPAN 960 var lxd: i64 = wx - AS_XCTR 961 if lxd < 0 { lxd = 0 - lxd } 962 let latf: i64 = lxd*1000/AS_XHALF 963 let thr: i64 = as_flush_thresh(sfr, latf) 964 var fl: i64 = 0 965 if AS_PERF > thr { fl = (AS_PERF - thr)*1000/(1000 - thr) } 966 if fl > 1000 { fl = 1000 } 967 r2 = r2 - r2*fl*4/AS_PERFUSION_DEN 968 g2 = g2 - g2*fl*30/AS_PERFUSION_DEN 969 b2 = b2 - b2*fl*40/AS_PERFUSION_DEN 970 } 971 // ★real skin is EVEN, not blotchy: only a whisper of fine grain (the coarse 972 // blotch variation read as diseased mottling at body scale = a regression, removed) 973 let cf: i64 = tx_vnoise(wx*3/posq, wy*3/posq, wz*3/posq, 5) 974 r2 = r2 + (cf-128)*4/255 975 g2 = g2 + (cf-128)*2/255 976 // ★SUBCUTANEOUS VEINS shown THROUGH skin translucency (blue-green: flesh 977 // absorbs red). A domain-warped LEVEL-SET = branching wavy lines, gated by 978 // a low-freq THIN-SKIN mask so veins only surface in patches (forearms/ 979 // chest/hands), not everywhere. Inside-out -- real vasculature under the 980 // skin, which Infinigen's single-surface creatures cannot show. 981 let vmx: i64 = wx/posq; let vmy: i64 = wy/posq; let vmz: i64 = wz/posq 982 // coarse + x-COMPRESSED (vein LINES run lengthwise along the limb/torso) + 983 // strong domain warp so the contour meanders -> long thin veins, not speckle 984 let warp: i64 = (tx_vnoise(vmx, vmy, vmz, 26) - 128)*3 985 let vf: i64 = tx_vnoise(vmx*3 + warp, vmy + warp/3, vmz, 40) 986 var ridge: i64 = vf - 128; if ridge < 0 { ridge = 0-ridge } 987 let thin: i64 = tx_vnoise(vmx, vmy, vmz, 80) 988 if ridge < 10 { if thin > 140 { 989 let vein: i64 = (10 - ridge)*(thin - 140)/10 990 r2 = r2 - vein*20/100 991 g2 = g2 - vein*4/100 992 b2 = b2 + vein*15/100 993 }} 994 } 995 // ★BONE MATERIAL (layer 2), colour-only, same doctrine as the skin stack 996 // (sec27/30): the geometric bench cannot move. Operator 2026-08-10: "it looks 997 // like a cartoon" -- root cause was that the ENTIRE material stack applied only 998 // to skin, so the skull rendered flat diffuse + weak sheen = toon shading. 999 if L == 2 { 1000 // (1) porosity/trabecular grain at two scales; blue dampened so the 1001 // grain reads mineral, not noise 1002 let bng1: i64 = tx_vnoise(wx*5/posq, wy*5/posq, wz*5/posq, 11) 1003 let bng2: i64 = tx_vnoise(wx*13/posq, wy*13/posq, wz*13/posq, 7) 1004 let bgrain: i64 = (bng1-128)*10/255 + (bng2-128)*6/255 1005 r2 = r2 + bgrain; g2 = g2 + bgrain; b2 = b2 + bgrain*2/3 1006 // (2) shallow subsurface warmth at the terminator: bone is translucent 1007 // too, far shallower than flesh -- a faint warm lift, no red flood 1008 var bss: i64 = AS_Q14*45/100 - dot1 1009 if bss < 0 { bss = 0 } 1010 if bss > AS_Q14 { bss = AS_Q14 } 1011 r2 = r2 + cr*bss*18/(AS_Q14*100) 1012 g2 = g2 + cg*bss*9/(AS_Q14*100) 1013 b2 = b2 - cbb*bss*6/(AS_Q14*100) 1014 // (3) matte mineral, not plastic: desaturate toward grey where the sky 1015 // light dies instead of holding a uniform ivory 1016 let bdk: i64 = AS_Q14 - skyw 1017 g2 = g2 - g2*bdk*4/(AS_Q14*100) 1018 b2 = b2 - b2*bdk*8/(AS_Q14*100) 1019 } 1020 // subtle Blinn specular sheen (half-vector precomputed) 1021 let ndh: i64 = as_max(0, (nx*hx + ny*hy + nz*hz)/AS_Q14) 1022 let s2s: i64 = ndh*ndh/AS_Q14 1023 let s4s: i64 = s2s*s2s/AS_Q14 1024 let s8s: i64 = s4s*s4s/AS_Q14 1025 var spq: i64 = s8s*52/AS_Q14 1026 if L == 0 { spq = s8s*80/AS_Q14 } 1027 // bone: wider satin lobe at lower energy -- mineral sheen, not plastic gloss 1028 if L == 2 { spq = s4s*38/AS_Q14 } 1029 r2 = r2 + spq; g2 = g2 + spq; b2 = b2 + spq 1030 if r2>255 {r2=255} if g2>255 {g2=255} if b2>255 {b2=255} 1031 if r2<0 {r2=0} if g2<0 {g2=0} if b2<0 {b2=0} 1032 // ★MECHANISTIC SHAPE JUDGE (no VLM): 'nmap' writes the surface NORMAL as 1033 // colour instead of shading it. Silhouette IoU is provably blind to depth 1034 // and to surface shape -- two bodies with identical outlines can have 1035 // completely different surfaces. Comparing normal FIELDS measures the shape 1036 // itself, mechanically, with no learned model anywhere in the loop. 1037 if nmap == 1 { 1038 r2 = (nx + AS_Q14)*255/(2*AS_Q14) 1039 g2 = (ny + AS_Q14)*255/(2*AS_Q14) 1040 b2 = (nz + AS_Q14)*255/(2*AS_Q14) 1041 } 1042 zb[idx] = depth; fb[idx] = r2 + g2*256 + b2*AS_Q16_ONE; lb[idx] = L 1043 } 1044 }}} 1045 px2 = px2 + 1 1046 } 1047 py2 = py2 + 1 1048 } 1049 } 1050 }}} 1051 } 1052 t = t + 1 1053 } 1054 1055 // GX-39 piece 2: contact-darkening AO post-pass -- shaded path ONLY (the nmap shape-judge input 1056 // must stay pure geometry, which is also why the geometric bench cannot move) 1057 if nmap == 0 { as_ssao(fb, zb, lb, W, H) } 1058 // GX-39 piece 4: depth of field -- photographic focus on the body; floor/backdrop blur by distance 1059 if nmap == 0 { as_dof(fb, zb, lb, W, H) } 1060 1061 write_png(fb, W, H, outp) 1062 1063 // stats 1064 let lpx: *i64 = sys_mmap(nlayers*8) as *i64 1065 var i2: i64 = 0 1066 while i2 < nlayers { lpx[i2] = 0; i2 = i2 + 1 } 1067 var bg: i64 = 0; var fg: i64 = 0; var cxs: i64 = 0 1068 var dmn: i64 = AS_ZFAR; var dmx: i64 = 0; var dsm: i64 = 0 1069 var q: i64 = 0 1070 while q < npx { 1071 let L: i64 = lb[q] 1072 if L < 0 { bg = bg + 1 } else { 1073 lpx[L] = lpx[L] + 1; fg = fg + 1; cxs = cxs + (q % W) 1074 let d: i64 = zb[q] 1075 if d < dmn { dmn = d } if d > dmx { dmx = d } dsm = dsm + d 1076 } 1077 q = q + 1 1078 } 1079 var cxv: i64 = 0 - 1; var dmean: i64 = 0 - 1 1080 if fg > 0 { cxv = cxs/fg; dmean = dsm/fg } 1081 as_hw("{\x22impl\x22:\x22sovereign-nishilang-integer\x22,\x22mode\x22:\x22" as *u8); as_hw(mode) 1082 as_hw("\x22,\x22eye\x22:\x22" as *u8); as_hw(eye) 1083 as_hw("\x22,\x22W\x22:" as *u8); as_pn(W); as_hw(",\x22H\x22:" as *u8); as_pn(H) 1084 as_hw(",\x22ntris\x22:" as *u8); as_pn(ntris) 1085 as_hw(",\x22bg_frac_permil\x22:" as *u8); as_pn(bg*1000/npx) 1086 as_hw(",\x22fg_pix\x22:" as *u8); as_pn(fg) 1087 as_hw(",\x22centroid_x\x22:" as *u8); as_pn(cxv) 1088 as_hw(",\x22depth_min\x22:" as *u8); as_pn(dmn); as_hw(",\x22depth_mean\x22:" as *u8); as_pn(dmean); as_hw(",\x22depth_max\x22:" as *u8); as_pn(dmx) 1089 as_hw(",\x22layer_pix\x22:[" as *u8) 1090 var k: i64 = 0 1091 while k < nlayers { if k > 0 { as_hw("," as *u8) } as_pn(lpx[k]); k = k + 1 } 1092 as_hw("]}\n" as *u8) 1093 return 0 1094}