nx_avatar_splat.nx source
↩ module page · 643 lines · 35824 B
1// nx_avatar_splat.nx -- ★THE LEAP (charsim R25; operator 2026-08-16: "dont build iterative junk, you
2// can get us there from all the published research without gumby layers and then we can iterate on
3// the last miles"). GENOME -> ANTHROPOMETRIC BODY MESH -> GAUSSIAN SPLAT COAT -> PORTRAIT PNG.
4//
5// A COMPOSITION OF PROVEN PARTS, ZERO NEW ALGORITHMS -- the published GaussianAvatars/HumanSplat
6// architecture (mesh -> per-element gaussians -> splat) that nx_gsplat_face_gate already proves at
7// face scale on this estate's own stack, generalized to the full body:
8// nx_body_gen (forked; anthropometric .nxmesh from stature + the FEMALE canon knowledge/canon_f.dat;
9// every non-genome knob passed = body_gen's OWN defaults, transcribed from its main:
10// RS 28, SUB 4, RLF 1000, FAT 250 -- so only stature and canon vary from stock)
11// nx_skin_ita (published ITA -> L*a*b* -> sRGB skin albedo; genome skin bits, face/torso region dl)
12// nx_gsplat (sovereign integer 3DGS: one ANISOTROPIC surface-flattened gaussian per triangle,
13// normal from the winding, tangent radius DERIVED from the triangle's own mean edge)
14// nx_png (write_png, the face gate's own call)
15// Genome bit layout TRANSCRIBED from the documented MC_GENE map: skin tone bits 9-10, height bits 5-6.
16// Female stature band cited (ANSUR/NHANES women P5..P95 ~ 1505..1730mm): bits 0..3 -> 1520 + 70*b mm.
17//
18// ⚠DUPLICATE-DECODER DEBT, NAMED: av_rdbits/av_f32mul are the FOURTH inline copy of the NXMSH2 f32
19// decode (anat_sov, bodybench, curvebench carry the others). Extracting nx_nxmesh_lib and migrating
20// all four is the named follow-on; a fifth copy is forbidden.
21// LAST-MILE (after the leap, by order): photofit color refinement (gs_color_grad_step), hair as splat
22// volume, head-band eye/mouth features, wasm delivery budget, yaw/pose drive via nx_gsplat4d_lib.
23// nx_avatar_splat <out.png> [gene]
24import "nx_syscalls.nx"
25import "nx_itoa_lib.nx"
26import "nx_tool_run.nx"
27import "nx_itrig.nx"
28import "nx_gsplat.nx"
29import "nx_skin_ita.nx"
30import "nx_png.nx"
31
32const AV_BODYGEN: *u8 = "/volume1/homes/elderwesto/nishihost/nx_body_gen.elf"
33const AV_CANON: *u8 = "/volume1/homes/elderwesto/nishihost/knowledge/canon_f.dat" // ABSOLUTE: this
34 // organ runs under nx_sov_build_run (CWD anchored to buildroot/)
35 // AND as a promoted tool (CWD nishihost) -- a relative path is
36 // correct in exactly one of those and silently wrong in the other
37const AV_MESH: *u8 = "/tmp/avatar_splat.nxmesh"
38const AV_OUTCAP: i64 = 65536
39const AV_TIMEOUT_MS: i64 = 120000
40const AV_POSQ0: i64 = 4096 // fixed pre-pass precision (anat_sov's own scale-invariance pattern)
41const AV_SPAN: i64 = 1200 // normalized max-axis span in gsplat model units
42const AV_TARGET: i64 = 200000 // DECODE precision target (anat_sov's own AS_TARGET, transcribed):
43 // the f32 multiplier must stay an integer >= 1 for millimetre
44 // meshes, so decode at this span and rescale to AV_SPAN at
45 // coat-build time -- targeting 1200 directly truncates posq to 0
46const AV_CAMZ: i64 = 2 // R = 2048: half-height on screen = 586*600/2048 = 171 of 192 px
47 // -- 89 percent frame fill, DERIVED from GFOCAL/GHH, not tasted
48const AV_F32_MANT_SCALE: i64 = 8388608
49const AV_F32_MANT_MASK: i64 = 8388607
50const AV_BIG: i64 = 2000000000
51const AV_OP: i64 = 235 // splat opacity: the face gate's proven value, transcribed
52const AV_RTAN_NUM: i64 = 1 // tangent radius = mean edge / 2: 3-sigma still covers 1.5 edges
53const AV_RTAN_DEN: i64 = 2 // (closed surface holds) -- 3/4 melted every feature, measured by
54 // the operator's own verdict on v1 ("looks like a monster")
55const AV_SKIN_SH: i64 = 9 // MC_GENE skin bits (transcribed)
56const AV_SKIN_MASK: i64 = 3
57const AV_HGT_SH: i64 = 5 // MC_GENE height bits (transcribed)
58const AV_HGT_MASK: i64 = 3
59const AV_STAT_BASE_MM: i64 = 1520 // ANSUR/NHANES female stature band, P5..P95 in 4 stops
60const AV_STAT_STEP_MM: i64 = 70
61const AV_LIGHT_X: i64 = 0-121 // the face gate's proven key light direction, transcribed
62const AV_LIGHT_Y: i64 = 191
63const AV_LIGHT_Z: i64 = 0-121
64const AV_HEAD_BAND: i64 = 2 // head = top 2/15 of stature -- the 7.5-head canon unit
65const AV_HEAD_DEN: i64 = 15
66
67// ---- v2 (2026-08-19, GR2 leg 2): SHADING + HAIR ARE POLICY AND LIVE IN A CONF, NOT IN CODE ----
68// knowledge/avatar_splat.conf is the SSOT; the named defaults below reproduce the v1 render exactly
69// when the conf is absent (announced), so behaviour never silently changes with a missing file.
70const AV_CONF: *u8 = "knowledge/avatar_splat.conf"
71const AV_PERMIL: i64 = 1000
72const AV_NFX: i64 = 256 // the fx256 unit-normal scale gs_set_aniso declares
73const AV_DEF_SH_AMB: i64 = 130 // v1 shipped shade base
74const AV_DEF_SH_GAIN: i64 = 90 // v1 shipped lambert gain
75const AV_DEF_SH_MIN: i64 = 70 // v1 shipped shade floor
76const AV_DEF_SH_MAX: i64 = 255
77const AV_DEF_HAIR_ON: i64 = 0 // hair OFF by default = v1 behaviour; the conf turns it on
78const AV_DEF_HAIR_TOP_PERMIL: i64 = 550
79const AV_DEF_HAIR_LEN_PERMIL: i64 = 1400
80const AV_DEF_HAIR_RAD_PERMIL: i64 = 60
81const AV_DEF_HAIR_STEP_PERMIL: i64 = 1200 // step between strand discs, permil of disc radius
82const AV_DEF_HAIR_SEED_EVERY: i64 = 3
83const AV_DEF_HAIR_DROOP: i64 = 820
84const AV_DEF_HAIR_R: i64 = 144 // measured mean of the banked WebGL reference's hair band
85const AV_DEF_HAIR_G: i64 = 118 // (cjc_ref_rig_03, 10330 px, 2026-08-19) -- a measurement, not a taste
86const AV_DEF_HAIR_B: i64 = 89
87const AV_DEF_HAIR_JITTER: i64 = 28
88const AV_DEF_HAIR_FACE_Z: i64 = 1 // +z is the face (measured, y90 profile 2026-08-19)
89const AV_DEF_HAIR_CROWN_PERMIL: i64 = 300
90const AV_DEF_HAIR_DROOP_BASE: i64 = 0 // v1-equivalent: no initial bend
91const AV_DEF_HAIR_CROWN_BACK: i64 = 0 // v1-equivalent: no backward sweep on face-side crown strands
92const AV_DEF_SKIN_JITTER: i64 = 0 // v1-equivalent: no per-splat skin variation
93const AV_DEF_FACE_ON: i64 = 0 // v1-equivalent: no face features
94const AV_DEF_EYE_LINE_PERMIL: i64 = 450 // eye line below head top, permil of head height
95const AV_DEF_EYE_SEP_PERMIL: i64 = 420 // eye separation, permil of head width at the eye line
96const AV_DEF_EYE_RAD_PERMIL: i64 = 70 // sclera radius, permil of head height
97const AV_DEF_MOUTH_LINE_PERMIL: i64 = 760
98const AV_DEF_MOUTH_W_PERMIL: i64 = 280 // mouth half-width, permil of head width
99const AV_FACE_GAUSS: i64 = 16 // fixed feature budget added to the buffer bound
100const AV_HAIR_HASH_A: i64 = 1103515245 // the estate's LCG constants (charjudge gate), per-strand jitter
101const AV_HAIR_HASH_C: i64 = 12345
102const AV_HAIR_HASH_M: i64 = 2147483647
103
104// anchored key=value conf reader (same contract as the census organ's cjp_conf_int; the shared-lib
105// extraction of this fourth copy is the named nx_conf_lib debt beside the NXMSH2 one in the header)
106func av_conf_int(cf: *u8, n: i64, key: *u8, def: i64) -> i64 {
107 var kn: i64 = 0
108 while key[kn] != (0 as u8) { kn = kn + 1 }
109 var i: i64 = 0
110 while i < n {
111 var e: i64 = i
112 var go: i64 = 1
113 while go == 1 { if e >= n { go = 0 } else { if (cf[e] as i64) == 10 { go = 0 } else { e = e + 1 } } }
114 if (cf[i] as i64) != 35 {
115 if e - i > kn {
116 var k: i64 = 0
117 var hit: i64 = 1
118 while k < kn { if cf[i+k] != key[k] { hit = 0; k = kn } if hit == 1 { k = k + 1 } }
119 if hit == 1 { if (cf[i+kn] as i64) == 61 {
120 var q: i64 = i + kn + 1
121 var neg: i64 = 0
122 if q < e { if (cf[q] as i64) == 45 { neg = 1; q = q + 1 } }
123 var v: i64 = 0
124 var got: i64 = 0
125 var g2: i64 = 1
126 while g2 == 1 {
127 if q >= e { g2 = 0 } else {
128 let c: i64 = cf[q] as i64
129 if c >= 48 { if c <= 57 { v = v*10 + (c-48); got = 1; q = q + 1 } else { g2 = 0 } } else { g2 = 0 }
130 }
131 }
132 if got == 1 { if neg == 1 { return 0 - v } return v }
133 } }
134 }
135 }
136 i = e + 1
137 }
138 return def
139}
140
141func av_len(s: *u8) -> i64 { var n: i64 = 0; while s[n] != (0 as u8) { n = n + 1 } return n }
142func av_puts(s: *u8) -> i64 { sys_write(1, s, av_len(s)); return 0 }
143func av_pn(v: i64) -> i64 { nxi_out(v); return 0 }
144func av_num(d: *u8, off: i64, v: i64) -> i64 {
145 var x: i64 = v
146 var ng: i64 = 0
147 if x < 0 { ng = 1; x = 0 - x }
148 let tmp: *u8 = sys_mmap(32) as *u8
149 var n: i64 = 0
150 if x == 0 { tmp[0] = 48 as u8; n = 1 }
151 while x > 0 { tmp[n] = (48 + x % 10) as u8; x = x / 10; n = n + 1 }
152 var o: i64 = off
153 if ng == 1 { d[o] = 45 as u8; o = o + 1 }
154 var i: i64 = n
155 while i > 0 { d[o] = tmp[i-1]; o = o + 1; i = i - 1 }
156 d[o] = 0 as u8
157 return o - off + 1
158}
159func av_rdbits(b: *u8, o: i64) -> i64 {
160 return (b[o] as i64) | ((b[o+1] as i64)<<8) | ((b[o+2] as i64)<<16) | ((b[o+3] as i64)<<24)
161}
162func av_f32mul(b: *u8, o: i64, mul: i64) -> i64 {
163 let bits: i64 = av_rdbits(b, o)
164 let sign: i64 = (bits>>31) & 1
165 let exp: i64 = (bits>>23) & 255
166 let mant: i64 = bits & AV_F32_MANT_MASK
167 if exp == 0 { return 0 }
168 let m: i64 = (mant | AV_F32_MANT_SCALE) * mul
169 var e: i64 = exp - 127 - 23
170 var v: i64 = 0
171 if e >= 0 { v = m << e } else { let sh: i64 = 0 - e; v = (m + (1 << (sh-1))) >> sh }
172 if sign == 1 { v = 0 - v }
173 return v
174}
175
176func main(argc: i64, argv: *i64) -> i64 {
177 if argc < 2 {
178 av_puts("usage: nx_avatar_splat <out.png> [gene]\n" as *u8)
179 return 2
180 }
181 // body_gen reads its shape-basis and canon confs as BARE paths -- they resolve against CWD, and
182 // its every proven caller (nx_bodyfit, the registered surface) runs it from the serving root.
183 // Anchor there BEFORE the fork so this organ behaves identically under nx_sov_build_run (which
184 // anchors CWD to buildroot/) and as a promoted tool. Announced on failure, not silent.
185 if sys_chdir("/volume1/homes/elderwesto/nishihost" as *u8) != 0 {
186 av_puts("AVATAR-SPLAT REFUSE: cannot chdir to the serving root\n" as *u8)
187 return 4
188 }
189 let outp: *u8 = argv[1] as *u8
190 var gene: i64 = 0
191 if argc > 2 { let gs2: *u8 = argv[2] as *u8; var gi: i64 = 0; while gs2[gi] != (0 as u8) { gene = gene*10 + (gs2[gi] as i64) - 48; gi = gi + 1 } }
192 // argv[3] = camera yaw in DEGREES (multi-view: the anat_sov judge's own pattern); it-units for gsplat
193 var yawd: i64 = 0
194 if argc > 3 { let ys2: *u8 = argv[3] as *u8; var yi: i64 = 0; while ys2[yi] != (0 as u8) { yawd = yawd*10 + (ys2[yi] as i64) - 48; yi = yi + 1 } }
195 let yawit: i64 = yawd * IT_PI / 180
196 // argv[4] = subcutaneous-fat knob 0..1000 for body_gen (default = body_gen's own 250). A GENOME-LANE
197 // parameter, not a tuned constant: bodyfit's conf envelope is the legal band and its SEARCH is the
198 // v2 chooser -- this argv exists so a caller can pass a searched value instead of the stock default.
199 var fatv: i64 = 250
200 if argc > 4 { fatv = 0; let fs2: *u8 = argv[4] as *u8; var fi: i64 = 0; while fs2[fi] != (0 as u8) { fatv = fatv*10 + (fs2[fi] as i64) - 48; fi = fi + 1 } }
201 if fatv < 0 { fatv = 0 }
202 if fatv > 1000 { fatv = 1000 }
203 // argv[5] = relief per-mille (default = body_gen's own 1000). Same genome-lane contract as fat:
204 // the value to pass is the bodyfit SEARCH's pick, mapped through knowledge/bodyfit.conf's envelope.
205 var rlfv: i64 = 1000
206 if argc > 5 { rlfv = 0; let rs3: *u8 = argv[5] as *u8; var ri: i64 = 0; while rs3[ri] != (0 as u8) { rlfv = rlfv*10 + (rs3[ri] as i64) - 48; ri = ri + 1 } }
207 if rlfv < 0 { rlfv = 0 }
208 if rlfv > 1200 { rlfv = 1200 }
209 let hbits: i64 = (gene >> AV_HGT_SH) & AV_HGT_MASK
210 let hmm: i64 = AV_STAT_BASE_MM + AV_STAT_STEP_MM * hbits
211 let shue: i64 = ((gene >> AV_SKIN_SH) & AV_SKIN_MASK) * SI_GENE_MAX / AV_SKIN_MASK
212
213 // ---- 1. GENERATE (fork nx_body_gen, bodyfit's own tr_run_capture_to pattern) ----
214 let nums: *u8 = sys_mmap(256) as *u8
215 var no: i64 = 0
216 let a_h: i64 = (nums as i64) + no; no = no + av_num(nums, no, hmm)
217 let a_rs: i64 = (nums as i64) + no; no = no + av_num(nums, no, 28)
218 let a_sub: i64 = (nums as i64) + no; no = no + av_num(nums, no, 4)
219 let a_rlf: i64 = (nums as i64) + no; no = no + av_num(nums, no, rlfv)
220 let a_fat: i64 = (nums as i64) + no; no = no + av_num(nums, no, fatv)
221 let av1: *i64 = sys_mmap(128) as *i64
222 av1[0] = AV_BODYGEN as i64
223 av1[1] = AV_MESH as i64
224 av1[2] = a_h
225 av1[3] = a_rs
226 av1[4] = a_sub
227 av1[5] = a_rlf
228 av1[6] = AV_CANON as i64
229 av1[7] = a_fat
230 av1[8] = 0
231 let cap: *u8 = sys_mmap(AV_OUTCAP) as *u8
232 let clen: *i64 = sys_mmap(16) as *i64
233 clen[0] = 0
234 if tr_run_capture_to(AV_BODYGEN, av1, cap, AV_OUTCAP, clen, AV_TIMEOUT_MS) != 0 {
235 av_puts("AVATAR-SPLAT REFUSE: nx_body_gen failed -- its output follows (a refusal that hides\n" as *u8)
236 av_puts("the child's own words costs the next reader the whole investigation):\n" as *u8)
237 if clen[0] > 0 { sys_write(1, cap, clen[0]) }
238 return 4
239 }
240
241 // ---- 2. READ the NXMSH2 (header: nlayers at 8, ntris at 12; tris at 16+nlayers*24, stride 84,
242 // verts 3x3xf32 at record start -- the layout anat_sov's framing passes read) ----
243 let lenp: *i64 = sys_mmap(16) as *i64
244 let mb: *u8 = sys_read_file(AV_MESH, lenp)
245 if (mb as i64) == 0 { av_puts("AVATAR-SPLAT REFUSE: cannot read mesh\n" as *u8); return 4 }
246 let nlayers: i64 = av_rdbits(mb, 8)
247 let ntris: i64 = av_rdbits(mb, 12)
248 let triBase: i64 = 16 + nlayers*24
249 if ntris < 1 { av_puts("AVATAR-SPLAT REFUSE: empty mesh\n" as *u8); return 4 }
250
251 // pass 0: measure at fixed precision, derive posq so the max-axis span == AV_SPAN (anat_sov's own
252 // scale-invariance pattern -- a metre mesh and a millimetre mesh land identically)
253 var mn0: i64 = AV_BIG
254 var mx0: i64 = 0-AV_BIG
255 var t0: i64 = 0
256 while t0 < ntris {
257 var c0: i64 = 0
258 while c0 < 9 {
259 let vq: i64 = av_f32mul(mb, triBase + t0*84 + c0*4, AV_POSQ0)
260 if vq < mn0 { mn0 = vq }
261 if vq > mx0 { mx0 = vq }
262 c0 = c0 + 1
263 }
264 t0 = t0 + 1
265 }
266 var span0: i64 = mx0 - mn0
267 if span0 < 1 { span0 = 1 }
268 let posq: i64 = AV_POSQ0 * AV_TARGET / span0
269 if posq < 1 { av_puts("AVATAR-SPLAT REFUSE: mesh span overflows the decode target\n" as *u8); return 4 }
270
271 // pass 1: AABB at working precision -> center offsets
272 var mnx: i64 = AV_BIG; var mny: i64 = AV_BIG; var mnz: i64 = AV_BIG
273 var mxx: i64 = 0-AV_BIG; var mxy: i64 = 0-AV_BIG; var mxz: i64 = 0-AV_BIG
274 var t1: i64 = 0
275 while t1 < ntris {
276 var v1: i64 = 0
277 while v1 < 3 {
278 let o: i64 = triBase + t1*84 + v1*12
279 let x: i64 = av_f32mul(mb, o, posq)
280 let y: i64 = av_f32mul(mb, o+4, posq)
281 let z: i64 = av_f32mul(mb, o+8, posq)
282 if x < mnx { mnx = x } if x > mxx { mxx = x }
283 if y < mny { mny = y } if y > mxy { mxy = y }
284 if z < mnz { mnz = z } if z > mxz { mxz = z }
285 v1 = v1 + 1
286 }
287 t1 = t1 + 1
288 }
289 let cx: i64 = (mnx+mxx)/2
290 let cy: i64 = (mny+mxy)/2
291 let cz: i64 = (mnz+mxz)/2
292 let headline: i64 = mxy - (mxy-mny)*AV_HEAD_BAND/AV_HEAD_DEN // above this y = the head band
293
294 // ---- v2 policy load (shading + hair). Conf absent => v1 defaults, announced. ----
295 let avcl: *i64 = sys_mmap(16) as *i64
296 avcl[0] = 0
297 var avcf: *u8 = sys_read_file(AV_CONF, avcl)
298 var avcn: i64 = 0
299 var conf_src: *u8 = "defaults" as *u8
300 if (avcf as i64) != 0 { avcn = avcl[0]; conf_src = AV_CONF } else { avcf = sys_mmap(16); avcf[0] = 0 as u8 }
301 let sh_amb: i64 = av_conf_int(avcf, avcn, "shade_ambient" as *u8, AV_DEF_SH_AMB)
302 let sh_gain: i64 = av_conf_int(avcf, avcn, "shade_gain" as *u8, AV_DEF_SH_GAIN)
303 let sh_min: i64 = av_conf_int(avcf, avcn, "shade_min" as *u8, AV_DEF_SH_MIN)
304 let sh_max: i64 = av_conf_int(avcf, avcn, "shade_max" as *u8, AV_DEF_SH_MAX)
305 let hair_on: i64 = av_conf_int(avcf, avcn, "hair_on" as *u8, AV_DEF_HAIR_ON)
306 let hair_top: i64 = av_conf_int(avcf, avcn, "hair_top_permil" as *u8, AV_DEF_HAIR_TOP_PERMIL)
307 let hair_len_pm: i64 = av_conf_int(avcf, avcn, "hair_len_permil" as *u8, AV_DEF_HAIR_LEN_PERMIL)
308 let hair_rad_pm: i64 = av_conf_int(avcf, avcn, "hair_rad_permil" as *u8, AV_DEF_HAIR_RAD_PERMIL)
309 let hair_step_pm: i64 = av_conf_int(avcf, avcn, "hair_step_permil" as *u8, AV_DEF_HAIR_STEP_PERMIL)
310 var hair_seed_every: i64 = av_conf_int(avcf, avcn, "hair_seed_every" as *u8, AV_DEF_HAIR_SEED_EVERY)
311 if hair_seed_every < 1 { hair_seed_every = 1 }
312 let hair_droop: i64 = av_conf_int(avcf, avcn, "hair_droop_permil" as *u8, AV_DEF_HAIR_DROOP)
313 let hair_r: i64 = av_conf_int(avcf, avcn, "hair_r" as *u8, AV_DEF_HAIR_R)
314 let hair_g: i64 = av_conf_int(avcf, avcn, "hair_g" as *u8, AV_DEF_HAIR_G)
315 let hair_b: i64 = av_conf_int(avcf, avcn, "hair_b" as *u8, AV_DEF_HAIR_B)
316 let hair_jit: i64 = av_conf_int(avcf, avcn, "hair_tone_jitter" as *u8, AV_DEF_HAIR_JITTER)
317 // face side measured 2026-08-19 (y90 profile: bust+toes at screen-left = +z): strands never seed on
318 // the face half except the crown band, so the face stays visible under the fringe
319 let hair_face_z: i64 = av_conf_int(avcf, avcn, "hair_face_z" as *u8, AV_DEF_HAIR_FACE_Z)
320 let hair_crown: i64 = av_conf_int(avcf, avcn, "hair_crown_permil" as *u8, AV_DEF_HAIR_CROWN_PERMIL)
321 let hair_droop0: i64 = av_conf_int(avcf, avcn, "hair_droop_base_permil" as *u8, AV_DEF_HAIR_DROOP_BASE)
322 let hair_crown_back: i64 = av_conf_int(avcf, avcn, "hair_crown_back_permil" as *u8, AV_DEF_HAIR_CROWN_BACK)
323 let skin_jit: i64 = av_conf_int(avcf, avcn, "skin_tone_jitter" as *u8, AV_DEF_SKIN_JITTER)
324 let face_on: i64 = av_conf_int(avcf, avcn, "face_on" as *u8, AV_DEF_FACE_ON)
325 let eye_line: i64 = av_conf_int(avcf, avcn, "eye_line_permil" as *u8, AV_DEF_EYE_LINE_PERMIL)
326 let eye_sep: i64 = av_conf_int(avcf, avcn, "eye_sep_permil" as *u8, AV_DEF_EYE_SEP_PERMIL)
327 let eye_rad: i64 = av_conf_int(avcf, avcn, "eye_rad_permil" as *u8, AV_DEF_EYE_RAD_PERMIL)
328 let mouth_line: i64 = av_conf_int(avcf, avcn, "mouth_line_permil" as *u8, AV_DEF_MOUTH_LINE_PERMIL)
329 let mouth_w: i64 = av_conf_int(avcf, avcn, "mouth_w_permil" as *u8, AV_DEF_MOUTH_W_PERMIL)
330 // head geometry in the decode domain; every hair dimension DERIVES from it (no absolute units)
331 let head_h: i64 = mxy - headline
332 var hair_len: i64 = head_h * hair_len_pm / AV_PERMIL
333 var hair_rad: i64 = head_h * hair_rad_pm / AV_PERMIL
334 if hair_rad < 1 { hair_rad = 1 }
335 var hair_step: i64 = hair_rad * hair_step_pm / AV_PERMIL
336 if hair_step < 1 { hair_step = 1 }
337 var hair_seg: i64 = 0
338 if hair_on == 1 { hair_seg = hair_len / hair_step + 1 }
339 let scalp_y: i64 = mxy - head_h * hair_top / AV_PERMIL // scalp = centroid y above this
340
341 // ---- 3. THE COAT: one anisotropic gaussian per triangle -- centroid position, winding normal,
342 // tangent radius from the triangle's OWN mean edge, ITA albedo shaded by the key light ----
343 // CAMERA-RELATIVE KEY LIGHT: the light must ride with the camera or every rotated view is lit
344 // from behind (the yaw-180 render proved it: front view, chest in its own shadow). A model-space
345 // vector that lands at the face gate's key direction IN CAMERA SPACE is the inverse of the
346 // projection rotation: mx = LX*cos + LZ*sin, mz = -LX*sin + LZ*cos.
347 let sy4l: i64 = it_sin4096(yawit)
348 let cy4l: i64 = it_cos4096(yawit)
349 let mlx: i64 = (AV_LIGHT_X*cy4l + AV_LIGHT_Z*sy4l)/4096
350 let mlz: i64 = (0-AV_LIGHT_X*sy4l + AV_LIGHT_Z*cy4l)/4096
351 let mly: i64 = AV_LIGHT_Y
352 let ab3: *i64 = sys_mmap(24) as *i64
353 si_albedo_of_gene(shue, si_dl_of_region(0), ab3)
354 let fr0: i64 = ab3[0]; let fg0: i64 = ab3[1]; let fb0: i64 = ab3[2]
355 si_albedo_of_gene(shue, si_dl_of_region(1), ab3)
356 let tr0: i64 = ab3[0]; let tg0: i64 = ab3[1]; let tb0: i64 = ab3[2]
357 // count the scalp seeds BEFORE allocating. This pass counts EVERY strided scalp seed; the emission
358 // pass below additionally drops face-half seeds, so this is a declared UPPER BOUND on the buffer,
359 // and ng tracks the exact count -- an over-allocation can never corrupt, an under-allocation would.
360 var nseed: i64 = 0
361 if hair_on == 1 {
362 var tc: i64 = 0
363 var scalp_i: i64 = 0
364 while tc < ntris {
365 let oc: i64 = triBase + tc*84
366 let cyv: i64 = (av_f32mul(mb, oc+4, posq) + av_f32mul(mb, oc+16, posq) + av_f32mul(mb, oc+28, posq))/3
367 if cyv > scalp_y {
368 if scalp_i % hair_seed_every == 0 { nseed = nseed + 1 }
369 scalp_i = scalp_i + 1
370 }
371 tc = tc + 1
372 }
373 }
374 let gauss: *i64 = sys_mmap((ntris + nseed*hair_seg + AV_FACE_GAUSS)*12*8) as *i64
375 var ng: i64 = 0
376 var t: i64 = 0
377 while t < ntris {
378 let o: i64 = triBase + t*84
379 let ax: i64 = av_f32mul(mb, o, posq) - cx
380 let ay: i64 = av_f32mul(mb, o+4, posq) - cy
381 let az: i64 = av_f32mul(mb, o+8, posq) - cz
382 let bx: i64 = av_f32mul(mb, o+12, posq) - cx
383 let by: i64 = av_f32mul(mb, o+16, posq) - cy
384 let bz: i64 = av_f32mul(mb, o+20, posq) - cz
385 let ex: i64 = av_f32mul(mb, o+24, posq) - cx
386 let ey: i64 = av_f32mul(mb, o+28, posq) - cy
387 let ez: i64 = av_f32mul(mb, o+32, posq) - cz
388 let px: i64 = (ax+bx+ex)/3
389 let py: i64 = (ay+by+ey)/3
390 let pz: i64 = (az+bz+ez)/3
391 var nx: i64 = (by-ay)*(ez-az) - (bz-az)*(ey-ay)
392 var ny: i64 = (bz-az)*(ex-ax) - (bx-ax)*(ez-az)
393 var nz: i64 = (bx-ax)*(ey-ay) - (by-ay)*(ex-ax)
394 let nl: i64 = gs_isqrt(nx*nx + ny*ny + nz*nz)
395 if nl > 0 {
396 let e1: i64 = gs_isqrt((bx-ax)*(bx-ax) + (by-ay)*(by-ay) + (bz-az)*(bz-az))
397 let e2: i64 = gs_isqrt((ex-bx)*(ex-bx) + (ey-by)*(ey-by) + (ez-bz)*(ez-bz))
398 let e3: i64 = gs_isqrt((ax-ex)*(ax-ex) + (ay-ey)*(ay-ey) + (az-ez)*(az-ez))
399 var rt: i64 = (e1+e2+e3)/3 * AV_RTAN_NUM / AV_RTAN_DEN
400 if rt < 1 { rt = 1 }
401 let nfx: i64 = nx*256/nl
402 let nfy: i64 = ny*256/nl
403 let nfz: i64 = nz*256/nl
404 var cr: i64 = tr0; var cg: i64 = tg0; var cb2: i64 = tb0
405 if py > headline - cy { cr = fr0; cg = fg0; cb2 = fb0 }
406 // per-splat skin micro-variation: the flat-run killer. Same LCG as the hair jitter; the
407 // amplitude is conf policy and 0 reproduces v1 exactly.
408 if skin_jit > 0 {
409 let ssh2: i64 = (t * AV_HAIR_HASH_A + AV_HAIR_HASH_C) % AV_HAIR_HASH_M
410 let sj: i64 = (ssh2 % (skin_jit*2+1)) - skin_jit
411 cr = cr + sj
412 cg = cg + sj
413 cb2 = cb2 + sj
414 if cr < 0 { cr = 0 }
415 if cr > 255 { cr = 255 }
416 if cg < 0 { cg = 0 }
417 if cg > 255 { cg = 255 }
418 if cb2 < 0 { cb2 = 0 }
419 if cb2 > 255 { cb2 = 255 }
420 }
421 // lambert on the face-gate's key light, its own shade band (70..255 scaled onto albedo)
422 // cos(normal,light) in permil: dt2/(|n|*|L|). The face gate's dt/glen form assumed the
423 // small surface-nets gradients; these decode-domain cross products are ~1e10, so that
424 // form underflows to a flat ambient -- the first render proved it as a shadeless cutout.
425 let dt2: i64 = nx*mlx + ny*mly + nz*mlz
426 let ll: i64 = gs_isqrt(mlx*mlx + mly*mly + mlz*mlz)
427 var cosp: i64 = 0
428 if nl > 0 { if ll > 0 { cosp = dt2/nl*1000/ll } }
429 if cosp > 1000 { cosp = 1000 }
430 if cosp < 0-1000 { cosp = 0-1000 }
431 var sh: i64 = sh_amb + cosp*sh_gain/AV_PERMIL
432 if sh < sh_min { sh = sh_min }
433 if sh > sh_max { sh = sh_max }
434 // rescale from the decode domain (span AV_TARGET) into the splat model box (span AV_SPAN)
435 var rtm: i64 = rt * AV_SPAN / AV_TARGET
436 if rtm < 1 { rtm = 1 }
437 gs_set_aniso(gauss, ng, px*AV_SPAN/AV_TARGET, py*AV_SPAN/AV_TARGET, pz*AV_SPAN/AV_TARGET, nfx, nfy, nfz, rtm, cr*sh/255, cg*sh/255, cb2*sh/255, AV_OP)
438 ng = ng + 1
439 }
440 t = t + 1
441 }
442
443 // ---- 3b. HAIR AS SPLAT VOLUME (GR2 leg 2): a strand = a chain of small discs whose normal rides
444 // the strand direction (a coin-stack tube through gs_set_aniso -- zero new primitives).
445 // Seeds = every Nth scalp triangle by the conf's declared generative density, applied over
446 // the WHOLE scalp population; direction starts along the surface normal and bends to
447 // gravity by hair_droop per unit progress; per-strand tone jitter from the LCG hash. ----
448 var nhair: i64 = 0
449 if hair_on == 1 {
450 var th: i64 = 0
451 var scalp_j: i64 = 0
452 while th < ntris {
453 let oh: i64 = triBase + th*84
454 let hax: i64 = av_f32mul(mb, oh, posq) - cx
455 let hay: i64 = av_f32mul(mb, oh+4, posq) - cy
456 let haz: i64 = av_f32mul(mb, oh+8, posq) - cz
457 let hbx: i64 = av_f32mul(mb, oh+12, posq) - cx
458 let hby: i64 = av_f32mul(mb, oh+16, posq) - cy
459 let hbz: i64 = av_f32mul(mb, oh+20, posq) - cz
460 let hex: i64 = av_f32mul(mb, oh+24, posq) - cx
461 let hey: i64 = av_f32mul(mb, oh+28, posq) - cy
462 let hez: i64 = av_f32mul(mb, oh+32, posq) - cz
463 let hcy: i64 = (hay+hby+hey)/3 + cy
464 if hcy > scalp_y {
465 var take: i64 = 0
466 if scalp_j % hair_seed_every == 0 { take = 1 }
467 scalp_j = scalp_j + 1
468 // the face half carries no seeds unless this triangle sits in the crown band
469 let hpz0: i64 = (haz+hbz+hez)/3
470 var faceside: i64 = 0
471 if hair_face_z > 0 { if hpz0 > 0 { faceside = 1 } }
472 if hair_face_z < 0 { if hpz0 < 0 { faceside = 1 } }
473 var crown: i64 = 0
474 if hcy > mxy - head_h*hair_crown/AV_PERMIL { crown = 1 }
475 if faceside == 1 { if crown == 0 { take = 0 } }
476 if take == 1 {
477 var hpx: i64 = (hax+hbx+hex)/3
478 var hpy: i64 = (hay+hby+hey)/3
479 var hpz: i64 = (haz+hbz+hez)/3
480 var hnx: i64 = (hby-hay)*(hez-haz) - (hbz-haz)*(hey-hay)
481 var hny: i64 = (hbz-haz)*(hex-hax) - (hbx-hax)*(hez-haz)
482 var hnz: i64 = (hbx-hax)*(hey-hay) - (hby-hay)*(hex-hax)
483 let hnl: i64 = gs_isqrt(hnx*hnx + hny*hny + hnz*hnz)
484 if hnl > 0 {
485 hnx = hnx*AV_PERMIL/hnl
486 hny = hny*AV_PERMIL/hnl
487 hnz = hnz*AV_PERMIL/hnl
488 // a face-side CROWN strand sweeps backward so the fringe clears the face
489 if faceside == 1 {
490 hnz = (hnz*(AV_PERMIL-hair_crown_back) + (0-hair_face_z*AV_PERMIL)*hair_crown_back) / AV_PERMIL
491 }
492 let hsh: i64 = (th * AV_HAIR_HASH_A + AV_HAIR_HASH_C) % AV_HAIR_HASH_M
493 let jit: i64 = (hsh % (hair_jit*2+1)) - hair_jit
494 var hr: i64 = hair_r + jit
495 var hg: i64 = hair_g + jit
496 var hb: i64 = hair_b + jit
497 if hr < 0 { hr = 0 }
498 if hr > 255 { hr = 255 }
499 if hg < 0 { hg = 0 }
500 if hg > 255 { hg = 255 }
501 if hb < 0 { hb = 0 }
502 if hb > 255 { hb = 255 }
503 var sgk: i64 = 0
504 while sgk < hair_seg {
505 let prog: i64 = sgk * AV_PERMIL / hair_seg
506 var bend: i64 = hair_droop0 + (hair_droop - hair_droop0) * prog / AV_PERMIL
507 if bend > AV_PERMIL { bend = AV_PERMIL }
508 var dx: i64 = hnx * (AV_PERMIL - bend) / AV_PERMIL
509 var dy: i64 = hny * (AV_PERMIL - bend) / AV_PERMIL - bend
510 var dz: i64 = hnz * (AV_PERMIL - bend) / AV_PERMIL
511 let dl: i64 = gs_isqrt(dx*dx + dy*dy + dz*dz)
512 if dl > 0 {
513 hpx = hpx + dx * hair_step / dl
514 hpy = hpy + dy * hair_step / dl
515 hpz = hpz + dz * hair_step / dl
516 let hdt: i64 = dx*mlx + dy*mly + dz*mlz
517 let hll: i64 = gs_isqrt(mlx*mlx + mly*mly + mlz*mlz)
518 var hcos: i64 = 0
519 if hll > 0 { hcos = hdt/dl*AV_PERMIL/hll }
520 if hcos < 0 { hcos = 0 - hcos }
521 var hs2: i64 = sh_amb + hcos*sh_gain/AV_PERMIL
522 if hs2 < sh_min { hs2 = sh_min }
523 if hs2 > sh_max { hs2 = sh_max }
524 var hrt: i64 = hair_rad * AV_SPAN / AV_TARGET
525 if hrt < 1 { hrt = 1 }
526 gs_set_aniso(gauss, ng, hpx*AV_SPAN/AV_TARGET, hpy*AV_SPAN/AV_TARGET, hpz*AV_SPAN/AV_TARGET, dx*AV_NFX/dl, dy*AV_NFX/dl, dz*AV_NFX/dl, hrt, hr*hs2/255, hg*hs2/255, hb*hs2/255, AV_OP)
527 ng = ng + 1
528 nhair = nhair + 1
529 }
530 sgk = sgk + 1
531 }
532 }
533 }
534 }
535 th = th + 1
536 }
537 }
538
539 // ---- 3c. FACE FEATURES (GR2 leg 3, first tooth): eye pair + mouth ANCHORED TO THE MEASURED HEAD
540 // GEOMETRY -- the GaussianAvatars idea (features ride the mesh) at lowest order. Every
541 // position derives from the head band's own extents; nothing is an absolute pixel. ----
542 if face_on == 1 {
543 // head-band extents (model-centred coords)
544 var fhx0: i64 = AV_BIG
545 var fhx1: i64 = 0-AV_BIG
546 var fhz1: i64 = 0-AV_BIG
547 var fhz0: i64 = AV_BIG
548 var tf: i64 = 0
549 while tf < ntris {
550 let of2: i64 = triBase + tf*84
551 let fyc: i64 = (av_f32mul(mb, of2+4, posq) + av_f32mul(mb, of2+16, posq) + av_f32mul(mb, of2+28, posq))/3
552 if fyc > headline {
553 let fxc: i64 = (av_f32mul(mb, of2, posq) + av_f32mul(mb, of2+12, posq) + av_f32mul(mb, of2+24, posq))/3 - cx
554 let fzc: i64 = (av_f32mul(mb, of2+8, posq) + av_f32mul(mb, of2+20, posq) + av_f32mul(mb, of2+32, posq))/3 - cz
555 if fxc < fhx0 { fhx0 = fxc }
556 if fxc > fhx1 { fhx1 = fxc }
557 if fzc > fhz1 { fhz1 = fzc }
558 if fzc < fhz0 { fhz0 = fzc }
559 }
560 tf = tf + 1
561 }
562 let head_w: i64 = fhx1 - fhx0
563 var facez: i64 = fhz1
564 if hair_face_z < 0 { facez = fhz0 }
565 let eye_y: i64 = (mxy - cy) - head_h * eye_line / AV_PERMIL
566 let mouth_y: i64 = (mxy - cy) - head_h * mouth_line / AV_PERMIL
567 let ex_off: i64 = head_w * eye_sep / (AV_PERMIL*2)
568 var er: i64 = head_h * eye_rad / AV_PERMIL
569 if er < 1 { er = 1 }
570 // outward-facing normal so the discs face the camera at the front view
571 var fnz: i64 = AV_NFX
572 if hair_face_z < 0 { fnz = 0 - AV_NFX }
573 // z stacking: sclera on the skin, iris a step out, pupil another step, sized from the radius
574 let zs: i64 = er / 2
575 var side: i64 = 0
576 while side < 2 {
577 var exc: i64 = ex_off
578 if side == 1 { exc = 0 - ex_off }
579 gs_set_aniso(gauss, ng, exc*AV_SPAN/AV_TARGET, eye_y*AV_SPAN/AV_TARGET, (facez+zs)*AV_SPAN/AV_TARGET, 0, 0, fnz, er*AV_SPAN/AV_TARGET, 242, 240, 234, AV_OP)
580 ng = ng + 1
581 gs_set_aniso(gauss, ng, exc*AV_SPAN/AV_TARGET, eye_y*AV_SPAN/AV_TARGET, (facez+zs*2)*AV_SPAN/AV_TARGET, 0, 0, fnz, er*55*AV_SPAN/(AV_TARGET*100), 96, 64, 40, AV_OP)
582 ng = ng + 1
583 gs_set_aniso(gauss, ng, exc*AV_SPAN/AV_TARGET, eye_y*AV_SPAN/AV_TARGET, (facez+zs*3)*AV_SPAN/AV_TARGET, 0, 0, fnz, er*25*AV_SPAN/(AV_TARGET*100), 22, 18, 16, AV_OP)
584 ng = ng + 1
585 side = side + 1
586 }
587 // mouth: one wide low disc in a lip tone derived from the face albedo (redder, darker)
588 var mw: i64 = head_w * mouth_w / AV_PERMIL
589 if mw < 1 { mw = 1 }
590 var lipr: i64 = fr0 * 88 / 100
591 var lipg: i64 = fg0 * 55 / 100
592 var lipb: i64 = fb0 * 55 / 100
593 if lipr > 255 { lipr = 255 }
594 gs_set_aniso(gauss, ng, 0, mouth_y*AV_SPAN/AV_TARGET, (facez+zs)*AV_SPAN/AV_TARGET, 0, 0, fnz, mw*AV_SPAN/AV_TARGET, lipr, lipg, lipb, AV_OP)
595 ng = ng + 1
596 }
597
598 // ---- 4. SPLAT (the face gate's exact buffer recipe, aniso lane) ----
599 let W: i64 = gs_w()
600 let H: i64 = gs_h()
601 let npx: i64 = W*H
602 let fb: *i64 = sys_mmap(npx*8) as *i64
603 let acc: *i64 = sys_mmap(npx*3*8) as *i64
604 let trans: *i64 = sys_mmap(npx*8) as *i64
605 let depth: *i64 = sys_mmap(ng*8) as *i64
606 let sxb: *i64 = sys_mmap(ng*8) as *i64
607 let syb: *i64 = sys_mmap(ng*8) as *i64
608 let pa: *i64 = sys_mmap(ng*8) as *i64
609 let pb: *i64 = sys_mmap(ng*8) as *i64
610 let pc: *i64 = sys_mmap(ng*8) as *i64
611 let pdet: *i64 = sys_mmap(ng*8) as *i64
612 let order: *i64 = sys_mmap(ng*8) as *i64
613 let count: *i64 = sys_mmap((gs_nb()+2)*8) as *i64
614 let explut: *i64 = sys_mmap(gs_expn()*8) as *i64
615 gs_build_explut(explut)
616 gs_render_aniso(gauss, ng, yawit, AV_CAMZ, fb, acc, trans, depth, sxb, syb, pa, pb, pc, pdet, order, count, explut, 26, 28, 44)
617 // A WRITE THAT IS NOT CHECKED IS A SUCCESS THAT IS NOT EARNED: the v2 first run wrote into a
618 // nonexistent ../sites path, write_png failed, and this organ still printed wrote= -- measured
619 // 2026-08-19. The announce line now only exists when the artifact does.
620 let wrc: i64 = write_png(fb, W, H, outp)
621 if wrc != 0 {
622 av_puts("AVATAR-SPLAT REFUSE: write_png failed rc=" as *u8); av_pn(wrc)
623 av_puts(" path=" as *u8); av_puts(outp)
624 av_puts(" (cwd is the nishihost serving root -- pass sites/... not ../sites/...)\n" as *u8)
625 sys_unlinkat(AV_MESH)
626 return 4
627 }
628 sys_unlinkat(AV_MESH)
629
630 av_puts("AVATAR-SPLAT canon=" as *u8); av_puts(AV_CANON)
631 av_puts(" gene=" as *u8); av_pn(gene)
632 av_puts(" height_mm=" as *u8); av_pn(hmm)
633 av_puts(" skin_hue=" as *u8); av_pn(shue)
634 av_puts(" ntris=" as *u8); av_pn(ntris)
635 av_puts(" gaussians=" as *u8); av_pn(ng)
636 av_puts(" hair_gaussians=" as *u8); av_pn(nhair)
637 av_puts(" policy=" as *u8); av_puts(conf_src)
638 av_puts(" span0=" as *u8); av_pn(span0)
639 av_puts(" posq=" as *u8); av_pn(posq)
640 av_puts(" wrote=" as *u8); av_puts(outp)
641 av_puts("\n" as *u8)
642 return 0
643}