nx_nxa_morf.nx source
↩ module page · 782 lines · 33849 B
1// nx_nxa_morf.nx -- WRITE THE FACE AND MORF SECTIONS: the addressable face region and the
2// expression morph basis, both DERIVED FROM THE ASSET'S OWN GEOMETRY and carried inside it.
3//
4// THE MEASURED GAP THIS CLOSES. nx_asset_floor_gate scores the shipped character 5/7 and prints
5// face geometry (FACE) -- we PAINT the face from ratios instead: ABSENT -- gap to the floor
6// blend shapes / morph targets (MORF) -- no expressions without these: ABSENT -- gap to the floor
7// Those two report lines ARE the spec: the gate asks whether a section with that tag is present.
8// But the same gate carries the law that makes a bare tag worthless:
9// PRESENCE OF A SECTION IS NOT PRESENCE OF THE CAPABILITY.
10// So this organ never writes an empty section. FACE carries the real vertex membership of the
11// head region and MORF carries a per-vertex displacement for every channel, with an evaluation
12// verb that proves the deltas actually move geometry.
13//
14// WHY THE DELTAS ARE DERIVED AND NOT IMPORTED. Full-population measurement of every authored
15// source the estate can reach:
16// 4 of 4 Fab FBX donors: 0 BlendShape, 0 BlendShapeChannel deformers
17// 3 of 3 glTF donors: 0 targets, 0 targetNames, 0 weights
18// seed-san.vrm: DOES carry targetNames (VRoid authors expression morphs)
19// The VRM morphs are indexed against the VRM's OWN topology. This character is our procedural
20// nishi being with a different vertex count and a different order, so copying those deltas onto
21// it would be FABRICATION wearing a measurement's clothes. The honest source for OUR mesh is the
22// estate's OWN parametric basis: nx_faceanat already derives a face from the anthropometric
23// canons and exposes faceanat_morph_width / _length / _jaw / _eyes / _lips / _nose / _cheek.
24// Those SEVEN channels are the target set here -- taken from our own canon work, not invented
25// names, and not another project's vertex deltas.
26//
27// 2026-08-23 RUNG 2 -- THE CHANNEL SET IS NOW DATA. The first version hardcoded SEVEN channels
28// from nx_faceanat's canon morphs. Seven against a best-of-breed MetaHuman LOD0 (669 blendshapes
29// AND joints) is roughly 95x, the largest single gap on the board. The channel table now lives in
30// knowledge/facs_au.conf and is ADOPTED from Apple ARKit's published ARFaceAnchor.BlendShapeLocation
31// vocabulary -- MEASURED from a hash-pinned mirror, not quoted from memory. Adding an action is a
32// data edit; this organ's logic never names a channel.
33//
34// NO PICKED NUMBERS. The head band is nx_headcrop's measured band (it OWNS that number; this
35// organ cites it). Every sub-band boundary is a facial canon nx_faceanat already encodes: the
36// RULE OF THIRDS (hairline-brow-subnasale-chin, equal) and the RULE OF FIFTHS (face width is
37// five eye-widths, the nose occupying the central fifth). Every anchor is a centroid MEASURED
38// from the asset. The stature axis is DERIVED as the largest extent, never assumed.
39// license_tier: ORIGINAL No hw writes (Rule 26).
40import "nx_syscalls.nx"
41import "nx_nxa.nx"
42import "nx_morf_eval_core.nx"
43import "nx_nxa_morf_admit.nx"
44import "nx_nxa_texc_lib.nx"
45
46const MF_OK: i64 = 0
47const MF_E_IO: i64 = 1
48const MF_E_USAGE: i64 = 2
49const MF_E_BAD: i64 = 3
50const MF_E_NOSEC: i64 = 4
51
52// permil is the estate's existing weight quantum (AF_PERMIL, NT_Q16 conventions). A channel
53// weight of MF_UNIT applies the channel's FULL stored displacement; 0 applies none; the map is
54// linear, so eval is pos = pos + delta*w/MF_UNIT with no rounding table.
55// Signed representation bound, not a configurable weight limit.
56const MF_I64_MAX: i64 = 9223372036854775807
57const MF_UNIT: i64 = 1000
58const MF_W: i64 = 8
59const MF_VSTRIDE: i64 = 3
60const MF_DSTRIDE: i64 = 3
61const MF_FACE_HDR: i64 = 4
62const MF_MORF_HDR: i64 = 4
63const MF_CHANREC: i64 = 2
64const MF_AXES: i64 = 3
65
66// nx_headcrop's measured head band, in permil of the mesh's own stature span. nx_headcrop is the
67// OWNER of these two numbers (its call grammar publishes them as its defaults); inventing a
68// second head definition here would be the duplicate-ruler defect, so the value is cited and the
69// owner named instead.
70const MF_HEAD_LO_PERMIL: i64 = 870
71const MF_HEAD_HI_PERMIL: i64 = 1000
72const MF_THIRDS: i64 = 3
73const MF_FIFTHS: i64 = 5
74const MF_FIFTH_CENTRAL: i64 = 2
75
76// the AU table. Fields per record, in conf order after the tag.
77const MF_AUCONF: *u8 = "knowledge/facs_au.conf"
78const MF_AUREC: i64 = 8
79const MF_A_TAG: i64 = 0
80const MF_A_VLO: i64 = 1
81const MF_A_VHI: i64 = 2
82const MF_A_HLO: i64 = 3
83const MF_A_HHI: i64 = 4
84const MF_A_SIDE: i64 = 5
85const MF_A_AXIS: i64 = 6
86const MF_A_SIGN: i64 = 7
87// a bound, not a budget: far above every published facial set measured here (ARKit 52 locations;
88// a MetaHuman LOD0 figure of 669 which is blendshapes AND joints, the joint half belonging to the
89// skeleton lane). Exceeding it REFUSES and says so rather than silently truncating the table.
90const MF_AUCAP: i64 = 1024
91const MF_AXIS_LAT: i64 = 0
92const MF_AXIS_DEP: i64 = 1
93const MF_AXIS_STAT: i64 = 2
94const MF_SIDE_BOTH: i64 = 0
95const MF_SIDE_L: i64 = 1
96const MF_ASCII_NL: i64 = 10
97const MF_ASCII_PIPE: i64 = 124
98const MF_ASCII_MINUS: i64 = 45
99const MF_ASCII_A: i64 = 97
100const MF_ASCII_U: i64 = 117
101
102// ---- AU TABLE PARSING (the channel set is data; this organ never names a channel) -------------
103func mf_field(b: *u8, s: i64, e: i64, k: i64, out: *i64) -> i64 {
104 var idx: i64 = 0
105 var p: i64 = s
106 var fs: i64 = s
107 var found: i64 = 0
108 while p <= e {
109 var isend: i64 = 0
110 if p == e { isend = 1 }
111 else { if b[p] == (MF_ASCII_PIPE as u8) { isend = 1 } }
112 if isend == 1 {
113 if idx == k { out[0] = fs; out[1] = p; found = 1 }
114 idx = idx + 1
115 fs = p + 1
116 }
117 p = p + 1
118 }
119 return found
120}
121func mf_int_at(b: *u8, s: i64, e: i64) -> i64 {
122 var v: i64 = 0
123 var p: i64 = s
124 var neg: i64 = 0
125 if p < e { if b[p] == (MF_ASCII_MINUS as u8) { neg = 1; p = p + 1 } }
126 while p < e {
127 let d: i64 = (b[p] as i64) - 48
128 if d < 0 { return 0 }
129 if d > 9 { return 0 }
130 v = v*10 + d
131 p = p + 1
132 }
133 if neg == 1 { return 0 - v }
134 return v
135}
136func mf_tag_at(b: *u8, s: i64) -> i64 {
137 return ((b[s] & 0xff) as i64) | (((b[s+1] & 0xff) as i64) << 8)
138 | (((b[s+2] & 0xff) as i64) << 16) | (((b[s+3] & 0xff) as i64) << 24)
139}
140// reads knowledge/facs_au.conf into rec[]; returns the AU count, -1 unreadable, -2 over cap.
141func mf_load_au(rec: *i64) -> i64 {
142 let lp: *i64 = sys_mmap(16) as *i64
143 let b: *u8 = sys_read_file(MF_AUCONF, lp)
144 if (b as i64) == 0 { return 0 - 1 }
145 let n: i64 = lp[0]
146 let fo: *i64 = sys_mmap(32) as *i64
147 var i: i64 = 0
148 var cnt: i64 = 0
149 while i < n {
150 var e: i64 = i
151 var go: i64 = 1
152 while go == 1 {
153 if e >= n { go = 0 }
154 else { if b[e] == (MF_ASCII_NL as u8) { go = 0 } else { e = e + 1 } }
155 }
156 var isau: i64 = 0
157 if e - i > 8 {
158 if b[i] == (MF_ASCII_A as u8) {
159 if b[i+1] == (MF_ASCII_U as u8) {
160 if b[i+2] == (MF_ASCII_PIPE as u8) { isau = 1 }
161 }
162 }
163 }
164 if isau == 1 {
165 if cnt >= MF_AUCAP { return 0 - 2 }
166 let base: i64 = cnt*MF_AUREC
167 if mf_field(b, i, e, 1, fo) == 1 { rec[base + MF_A_TAG] = mf_tag_at(b, fo[0]) }
168 if mf_field(b, i, e, 3, fo) == 1 { rec[base + MF_A_VLO] = mf_int_at(b, fo[0], fo[1]) }
169 if mf_field(b, i, e, 4, fo) == 1 { rec[base + MF_A_VHI] = mf_int_at(b, fo[0], fo[1]) }
170 if mf_field(b, i, e, 5, fo) == 1 { rec[base + MF_A_HLO] = mf_int_at(b, fo[0], fo[1]) }
171 if mf_field(b, i, e, 6, fo) == 1 { rec[base + MF_A_HHI] = mf_int_at(b, fo[0], fo[1]) }
172 if mf_field(b, i, e, 7, fo) == 1 { rec[base + MF_A_SIDE] = mf_int_at(b, fo[0], fo[1]) }
173 if mf_field(b, i, e, 8, fo) == 1 { rec[base + MF_A_AXIS] = mf_int_at(b, fo[0], fo[1]) }
174 if mf_field(b, i, e, 9, fo) == 1 { rec[base + MF_A_SIGN] = mf_int_at(b, fo[0], fo[1]) }
175 cnt = cnt + 1
176 }
177 i = e + 1
178 }
179 return cnt
180}
181// the frontprobe band, declared in the same conf. Returns 1 when found; the caller REFUSES if it
182// is absent, because a missing probe would mean guessing which way the face points.
183func mf_load_frontprobe(fp: *i64) -> i64 {
184 let lp: *i64 = sys_mmap(16) as *i64
185 let b: *u8 = sys_read_file(MF_AUCONF, lp)
186 if (b as i64) == 0 { return 0 }
187 let n: i64 = lp[0]
188 let fo: *i64 = sys_mmap(32) as *i64
189 var i: i64 = 0
190 var got: i64 = 0
191 while i < n {
192 var e: i64 = i
193 var go: i64 = 1
194 while go == 1 {
195 if e >= n { go = 0 }
196 else { if b[e] == (MF_ASCII_NL as u8) { go = 0 } else { e = e + 1 } }
197 }
198 if got == 0 {
199 if mf_field(b, i, e, 1, fo) == 1 {
200 if fo[1] - fo[0] == 10 {
201 if b[fo[0]] == (102 as u8) {
202 if b[fo[0]+1] == (114 as u8) {
203 if mf_field(b, i, e, 2, fo) == 1 { fp[MF_A_VLO] = mf_int_at(b, fo[0], fo[1]) }
204 if mf_field(b, i, e, 3, fo) == 1 { fp[MF_A_VHI] = mf_int_at(b, fo[0], fo[1]) }
205 if mf_field(b, i, e, 4, fo) == 1 { fp[MF_A_HLO] = mf_int_at(b, fo[0], fo[1]) }
206 if mf_field(b, i, e, 5, fo) == 1 { fp[MF_A_HHI] = mf_int_at(b, fo[0], fo[1]) }
207 got = 1
208 }
209 }
210 }
211 }
212 }
213 i = e + 1
214 }
215 return got
216}
217
218// membership: is face-vertex (vnorm, hnorm, sidebit) inside AU `a`'s declared region?
219func mf_in_au(rec: *i64, a: i64, vnorm: i64, hnorm: i64, sidebit: i64) -> i64 {
220 let base: i64 = a*MF_AUREC
221 if vnorm < rec[base + MF_A_VLO] { return 0 }
222 if vnorm > rec[base + MF_A_VHI] { return 0 }
223 if hnorm < rec[base + MF_A_HLO] { return 0 }
224 if hnorm > rec[base + MF_A_HHI] { return 0 }
225 let sd: i64 = rec[base + MF_A_SIDE]
226 if sd == MF_SIDE_BOTH { return 1 }
227 if sd == sidebit { return 1 }
228 return 0
229}
230// falloff, permil: 1000 at the region centre, 0 at its boundary, linear in the WORSE of the two
231// normalised distances. A morph that moved its whole region uniformly would show a hard seam at
232// the boundary; the taper is what makes neighbouring actions blend instead of tear.
233func mf_falloff(rec: *i64, a: i64, vnorm: i64, hnorm: i64) -> i64 {
234 let base: i64 = a*MF_AUREC
235 let vlo: i64 = rec[base + MF_A_VLO]
236 let vhi: i64 = rec[base + MF_A_VHI]
237 let hlo: i64 = rec[base + MF_A_HLO]
238 let hhi: i64 = rec[base + MF_A_HHI]
239 var vh: i64 = (vhi - vlo)/2
240 if vh < 1 { vh = 1 }
241 var hh: i64 = (hhi - hlo)/2
242 if hh < 1 { hh = 1 }
243 let vm: i64 = (vhi + vlo)/2
244 let hm: i64 = (hhi + hlo)/2
245 var dv: i64 = vnorm - vm
246 if dv < 0 { dv = 0 - dv }
247 var dh: i64 = hnorm - hm
248 if dh < 0 { dh = 0 - dh }
249 var pv: i64 = dv*MF_UNIT/vh
250 var ph: i64 = dh*MF_UNIT/hh
251 var d: i64 = pv
252 if ph > d { d = ph }
253 if d >= MF_UNIT { return 0 }
254 return MF_UNIT - d
255}
256
257func mf_rdv(b: *u8, vo: i64, i: i64, a: i64) -> i64 {
258 return nt_rd64(b, vo + MF_W + (i*MF_VSTRIDE + a)*MF_W)
259}
260
261func mf_usage() -> i64 {
262 nt_err("usage: nx_nxa_morf derive <in.nxa> <out.nxa> | eval <in.nxa> <out.nxa> <chan:weight_permil>
263" as *u8)
264 return MF_E_USAGE
265}
266
267// eval takes its channel and weight as ONE compound token ("0:1000") on purpose. The estate's
268// proven subprocess primitives (gk_run, gk_run_capture and every variant) pass at most FOUR
269// arguments, so a five-argument grammar would be undrivable by any gate -- UNTESTABLE BY
270// CONSTRUCTION. A compound argument keeps one unambiguous grammar with no silent defaults; the
271// alternative (defaulting the output path) would hide a destination, which is worse.
272func mf_spec(s: *u8, chan: *i64, w: *i64) -> i64 {
273 let imax: i64 = MF_I64_MAX
274 let imin: i64 = 0 - imax - 1
275 var c: i64 = 0
276 var j: i64 = 0
277 while s[j] != (58 as u8) {
278 let d: i64 = (s[j] as i64) - 48
279 if d < 0 { return 0 - 1 }
280 if d > 9 { return 0 - 1 }
281 if c > (imax - d)/10 { return 0 - 1 }
282 c = c*10 + d
283 j = j + 1
284 }
285 if j == 0 { return 0 - 1 }
286 j = j + 1
287 var neg: i64 = 0
288 if s[j] == (45 as u8) { neg = 1; j = j + 1 }
289 var limit: i64 = 0 - imax
290 if neg == 1 { limit = imin }
291 // Accumulate negatively so the full signed minimum never needs positive representation.
292 var v: i64 = 0
293 var any: i64 = 0
294 while s[j] != (0 as u8) {
295 let d2: i64 = (s[j] as i64) - 48
296 if d2 < 0 { return 0 - 1 }
297 if d2 > 9 { return 0 - 1 }
298 // Signed division truncates toward zero: this is ceil((limit + d2)/10).
299 if v < (limit + d2)/10 { return 0 - 1 }
300 v = v*10 - d2
301 any = 1
302 j = j + 1
303 }
304 if any == 0 { return 0 - 1 }
305 if neg == 0 { v = 0 - v }
306 chan[0] = c
307 w[0] = v
308 return 0
309}
310
311// locate a section's payload BYTE offset by tag; -1 when absent.
312func mf_sec(b: *u8, ns: i64, t: *u8) -> i64 {
313 var s: i64 = 0
314 while s < ns {
315 let e: i64 = NT_HDR + s*NT_TOCE
316 if nt_tageq(b, e, t) == 1 { return nt_rd64(b, e + 8) }
317 s = s + 1
318 }
319 return 0 - 1
320}
321func mf_sec_idx(b: *u8, ns: i64, t: *u8) -> i64 {
322 var s: i64 = 0
323 while s < ns {
324 let e: i64 = NT_HDR + s*NT_TOCE
325 if nt_tageq(b, e, t) == 1 { return s }
326 s = s + 1
327 }
328 return 0 - 1
329}
330
331// ---------------------------------------------------------------------------------------------
332// DERIVE: measure the face region and the seven channel displacement sets, then write FACE+MORF.
333// ---------------------------------------------------------------------------------------------
334func mf_derive(inp: *u8, outp: *u8) -> i64 {
335 let lp: *i64 = sys_mmap(MF_W*2) as *i64
336 let b: *u8 = sys_read_file(inp, lp)
337 if (b as i64) == 0 { nt_err("MORF-REFUSE cannot read input NXA\n" as *u8); return MF_E_IO }
338 let flen: i64 = lp[0]
339 if flen < NT_HDR { nt_err("MORF-REFUSE file too short to be an NXA\n" as *u8); return MF_E_BAD }
340 if nt_rd64(b, 0) != nxa_magic() { nt_err("MORF-REFUSE not an NXA (bad magic)\n" as *u8); return MF_E_BAD }
341 if nt_rd64(b, 8) > NXA_VER { nt_err("MORF-REFUSE future NXA version\n" as *u8); return MF_E_BAD }
342 let ns: i64 = nt_rd64(b, 16)
343 if ns < 1 { nt_err("MORF-REFUSE section count invalid\n" as *u8); return MF_E_BAD }
344 if ns + 2 > NT_MAXSEC { nt_err("MORF-REFUSE section table full\n" as *u8); return MF_E_BAD }
345 if flen < NT_HDR + ns*NT_TOCE { nt_err("MORF-REFUSE toc runs past EOF\n" as *u8); return MF_E_BAD }
346
347 let vo: i64 = mf_sec(b, ns, "VERT" as *u8)
348 if vo < 0 { nt_err("MORF-REFUSE no VERT section -- there is no geometry to morph\n" as *u8); return MF_E_NOSEC }
349 let nv: i64 = nt_rd64(b, vo)
350 if nv < 1 { nt_err("MORF-REFUSE empty VERT\n" as *u8); return MF_E_BAD }
351 if vo + (1 + nv*MF_VSTRIDE)*MF_W > flen { nt_err("MORF-REFUSE VERT runs past EOF\n" as *u8); return MF_E_BAD }
352
353 // ---- DERIVE the stature axis: the largest extent of the asset's own bounding box. A humanoid
354 // is taller than it is wide or deep, so the largest extent IS stature. Assumption declared:
355 // this holds for an upright humanoid rig and is stated rather than assumed silently.
356 let mn: *i64 = sys_mmap(MF_AXES*MF_W + 64) as *i64
357 let mx: *i64 = sys_mmap(MF_AXES*MF_W + 64) as *i64
358 var a: i64 = 0
359 while a < MF_AXES {
360 mn[a] = mf_rdv(b, vo, 0, a)
361 mx[a] = mn[a]
362 a = a + 1
363 }
364 var i: i64 = 1
365 while i < nv {
366 a = 0
367 while a < MF_AXES {
368 let c0: i64 = mf_rdv(b, vo, i, a)
369 if c0 < mn[a] { mn[a] = c0 }
370 if c0 > mx[a] { mx[a] = c0 }
371 a = a + 1
372 }
373 i = i + 1
374 }
375 var ax_stat: i64 = 0
376 a = 1
377 while a < MF_AXES {
378 if mx[a] - mn[a] > mx[ax_stat] - mn[ax_stat] { ax_stat = a }
379 a = a + 1
380 }
381 // of the two remaining axes the LATERAL one is the wider (shoulders exceed front-to-back
382 // depth on a humanoid); the narrower is DEPTH. Derived, not assumed.
383 var ax_lat: i64 = 0
384 var ax_dep: i64 = 0
385 var first: i64 = 1
386 a = 0
387 while a < MF_AXES {
388 if a != ax_stat {
389 if first == 1 { ax_lat = a; ax_dep = a; first = 0 }
390 else {
391 if mx[a] - mn[a] > mx[ax_lat] - mn[ax_lat] { ax_dep = ax_lat; ax_lat = a }
392 else { ax_dep = a }
393 }
394 }
395 a = a + 1
396 }
397 let span: i64 = mx[ax_stat] - mn[ax_stat]
398 if span < 1 { nt_err("MORF-REFUSE degenerate stature span -- cannot locate a head band\n" as *u8); return MF_E_BAD }
399
400 // ---- the FACE band: nx_headcrop's measured head band of the asset's own stature span
401 let flo: i64 = mn[ax_stat] + span*MF_HEAD_LO_PERMIL/MF_UNIT
402 let fhi: i64 = mn[ax_stat] + span*MF_HEAD_HI_PERMIL/MF_UNIT
403 let idx: *i64 = sys_mmap(nv*MF_W + 64) as *i64
404 var nface: i64 = 0
405 i = 0
406 while i < nv {
407 let sv: i64 = mf_rdv(b, vo, i, ax_stat)
408 if sv >= flo {
409 if sv <= fhi { idx[nface] = i; nface = nface + 1 }
410 }
411 i = i + 1
412 }
413 if nface < 1 { nt_err("MORF-REFUSE head band contains no vertices -- refusing to write an empty FACE\n" as *u8); return MF_E_BAD }
414
415 // ---- the face's OWN extents drive every sub-band boundary
416 var fsmin: i64 = mf_rdv(b, vo, idx[0], ax_stat)
417 var fsmax: i64 = fsmin
418 var flmin: i64 = mf_rdv(b, vo, idx[0], ax_lat)
419 var flmax: i64 = flmin
420 i = 0
421 while i < nface {
422 let sv: i64 = mf_rdv(b, vo, idx[i], ax_stat)
423 let lv: i64 = mf_rdv(b, vo, idx[i], ax_lat)
424 if sv < fsmin { fsmin = sv }
425 if sv > fsmax { fsmax = sv }
426 if lv < flmin { flmin = lv }
427 if lv > flmax { flmax = lv }
428 i = i + 1
429 }
430 var fspan: i64 = fsmax - fsmin
431 if fspan < 1 { fspan = 1 }
432 var lspan: i64 = flmax - flmin
433 if lspan < 1 { lspan = 1 }
434
435 // ---- load the AU table: the channel set is DATA (knowledge/facs_au.conf) -----------------
436 let rec: *i64 = sys_mmap(MF_AUCAP*MF_AUREC*MF_W + 64) as *i64
437 let nau: i64 = mf_load_au(rec)
438 if nau == 0 - 1 { nt_err("MORF-REFUSE cannot read knowledge/facs_au.conf -- the channel set is data and it is absent
439" as *u8); return MF_E_NOSEC }
440 if nau == 0 - 2 { nt_err("MORF-REFUSE AU table exceeds its declared bound -- refusing to truncate the channel set
441" as *u8); return MF_E_BAD }
442 if nau < 1 { nt_err("MORF-REFUSE AU table declares no actions
443" as *u8); return MF_E_BAD }
444 let fp: *i64 = sys_mmap(MF_AUREC*MF_W + 64) as *i64
445 if mf_load_frontprobe(fp) != 1 { nt_err("MORF-REFUSE AU table declares no frontprobe band -- the depth direction would have to be guessed
446" as *u8); return MF_E_BAD }
447
448 // ---- the face's own midline and half-width, and WHICH WAY IS FRONT -----------------------
449 let latmid: i64 = (flmin + flmax)/2
450 var lathalf: i64 = (flmax - flmin)/2
451 if lathalf < 1 { lathalf = 1 }
452 var dacc: i64 = 0
453 i = 0
454 while i < nface { dacc = dacc + mf_rdv(b, vo, idx[i], ax_dep); i = i + 1 }
455 let dmid: i64 = dacc/nface
456 var bestd: i64 = 0
457 var front: i64 = 1
458 i = 0
459 while i < nface {
460 let svf: i64 = mf_rdv(b, vo, idx[i], ax_stat)
461 let lvf: i64 = mf_rdv(b, vo, idx[i], ax_lat)
462 let vnf: i64 = (fsmax - svf)*MF_UNIT/fspan
463 var dlf: i64 = lvf - latmid
464 if dlf < 0 { dlf = 0 - dlf }
465 let hnf: i64 = dlf*MF_UNIT/lathalf
466 if vnf >= fp[MF_A_VLO] { if vnf <= fp[MF_A_VHI] { if hnf <= fp[MF_A_HHI] {
467 let dvf: i64 = mf_rdv(b, vo, idx[i], ax_dep) - dmid
468 var adf: i64 = dvf
469 if adf < 0 { adf = 0 - adf }
470 if adf > bestd {
471 bestd = adf
472 if dvf < 0 { front = 0 - 1 } else { front = 1 }
473 }
474 } } }
475 i = i + 1
476 }
477
478 // ---- per AU: support = its declared region; displacement = the support's own HALF-EXTENT
479 // along the action's axis, tapered by the falloff. The magnitude is DERIVED, not chosen: the
480 // maximal excursion of a facial feature is on the order of its own half-size (a brow raises by
481 // about its own thickness, a jaw drops by about the lower face's half-height). Stated as the
482 // assumption it is, and it scales with the asset instead of being a number in this file.
483 let dlt: *i64 = sys_mmap(nau*nface*MF_DSTRIDE*MF_W + 64) as *i64
484 let sup: *i64 = sys_mmap(nau*MF_W + 64) as *i64
485 var c: i64 = 0
486 while c < nau {
487 let arec: i64 = c*MF_AUREC
488 let cax0: i64 = rec[arec + MF_A_AXIS]
489 var cax: i64 = ax_lat
490 if cax0 == MF_AXIS_DEP { cax = ax_dep }
491 if cax0 == MF_AXIS_STAT { cax = ax_stat }
492 // pass 1: membership + the support's own extent along the action's axis
493 var cnt: i64 = 0
494 var amin: i64 = 0
495 var amax: i64 = 0
496 var seen: i64 = 0
497 i = 0
498 while i < nface {
499 let sv: i64 = mf_rdv(b, vo, idx[i], ax_stat)
500 let lv: i64 = mf_rdv(b, vo, idx[i], ax_lat)
501 let vnorm: i64 = (fsmax - sv)*MF_UNIT/fspan
502 var dl: i64 = lv - latmid
503 var sidebit: i64 = MF_SIDE_L + 1
504 if dl < 0 { sidebit = MF_SIDE_L; dl = 0 - dl }
505 let hnorm: i64 = dl*MF_UNIT/lathalf
506 if mf_in_au(rec, c, vnorm, hnorm, sidebit) == 1 {
507 let av: i64 = mf_rdv(b, vo, idx[i], cax)
508 if seen == 0 { amin = av; amax = av; seen = 1 }
509 if av < amin { amin = av }
510 if av > amax { amax = av }
511 cnt = cnt + 1
512 }
513 i = i + 1
514 }
515 sup[c] = cnt
516 let halfext: i64 = (amax - amin)/2
517 // pass 2: the displacement itself
518 i = 0
519 while i < nface {
520 let sv2: i64 = mf_rdv(b, vo, idx[i], ax_stat)
521 let lv2: i64 = mf_rdv(b, vo, idx[i], ax_lat)
522 let vn2: i64 = (fsmax - sv2)*MF_UNIT/fspan
523 var dl2: i64 = lv2 - latmid
524 var side2: i64 = MF_SIDE_L + 1
525 var outward: i64 = 1
526 if dl2 < 0 { side2 = MF_SIDE_L; dl2 = 0 - dl2; outward = 0 - 1 }
527 let hn2: i64 = dl2*MF_UNIT/lathalf
528 let base: i64 = (c*nface + i)*MF_DSTRIDE
529 dlt[base] = 0
530 dlt[base + 1] = 0
531 dlt[base + 2] = 0
532 if mf_in_au(rec, c, vn2, hn2, side2) == 1 {
533 if halfext > 0 {
534 let w: i64 = mf_falloff(rec, c, vn2, hn2)
535 var dir: i64 = rec[arec + MF_A_SIGN]
536 // lateral: +1 means AWAY from the midline, so the direction follows the
537 // vertex's own side. depth: +1 means toward the DERIVED front. stature: as declared.
538 if cax0 == MF_AXIS_LAT { dir = dir * outward }
539 if cax0 == MF_AXIS_DEP { dir = dir * front }
540 dlt[base + cax] = dir * halfext * w / MF_UNIT
541 }
542 }
543 i = i + 1
544 }
545 c = c + 1
546 }
547
548 // ---- rebuild the container: every section forward, FACE and MORF replaced not duplicated
549 let fwords: i64 = MF_FACE_HDR + nface
550 let mwords: i64 = MF_MORF_HDR + nau*MF_CHANREC + nau*nface*MF_DSTRIDE
551 let fi: i64 = mf_sec_idx(b, ns, "FACE" as *u8)
552 let mi: i64 = mf_sec_idx(b, ns, "MORF" as *u8)
553 var nsec: i64 = ns
554 if fi < 0 { nsec = nsec + 1 }
555 if mi < 0 { nsec = nsec + 1 }
556 let toclen: i64 = NT_HDR + nsec*NT_TOCE
557 var total: i64 = toclen
558 var s2: i64 = 0
559 while s2 < ns {
560 if s2 != fi {
561 if s2 != mi {
562 let e2: i64 = NT_HDR + s2*NT_TOCE
563 total = total + nt_rd64(b, e2 + 16)*MF_W
564 }
565 }
566 s2 = s2 + 1
567 }
568 total = total + fwords*MF_W + mwords*MF_W
569 let nb: *u8 = sys_mmap(total + NT_PAD)
570 if (nb as i64) == 0 { nt_err("MORF-REFUSE cannot allocate output\n" as *u8); return MF_E_IO }
571 nt_wr64(nb, 0, nxa_magic())
572 nt_wr64(nb, 8, NXA_VER)
573 nt_wr64(nb, 16, nsec)
574 var wo: i64 = toclen
575 var ti: i64 = 0
576 var s3: i64 = 0
577 while s3 < ns {
578 var skip: i64 = 0
579 if s3 == fi { skip = 1 }
580 if s3 == mi { skip = 1 }
581 if skip == 0 {
582 let e3: i64 = NT_HDR + s3*NT_TOCE
583 let oldoff: i64 = nt_rd64(b, e3 + 8)
584 let wl: i64 = nt_rd64(b, e3 + 16)
585 let te: i64 = NT_HDR + ti*NT_TOCE
586 nt_wr64(nb, te, nt_rd64(b, e3))
587 nt_wr64(nb, te + 8, wo)
588 nt_wr64(nb, te + 16, wl)
589 var k2: i64 = 0
590 while k2 < wl*MF_W { nb[wo + k2] = b[oldoff + k2]; k2 = k2 + 1 }
591 // RECOMPUTE, never copy: a copied checksum validates its own bug.
592 let pw2: *i64 = ((nb as i64) + wo) as *i64
593 nt_wr64(nb, te + 24, nxa_check2(1, pw2, wl))
594 wo = wo + wl*MF_W
595 ti = ti + 1
596 }
597 s3 = s3 + 1
598 }
599 // ---- append FACE: the addressable head region as real vertex membership
600 let tef: i64 = NT_HDR + ti*NT_TOCE
601 nt_wr64(nb, tef, nxa_tag4("FACE" as *u8))
602 nt_wr64(nb, tef + 8, wo)
603 nt_wr64(nb, tef + 16, fwords)
604 nt_wr64(nb, wo, nface)
605 nt_wr64(nb, wo + MF_W, ax_stat)
606 nt_wr64(nb, wo + MF_W*2, MF_HEAD_LO_PERMIL)
607 nt_wr64(nb, wo + MF_W*3, MF_HEAD_HI_PERMIL)
608 i = 0
609 while i < nface { nt_wr64(nb, wo + (MF_FACE_HDR + i)*MF_W, idx[i]); i = i + 1 }
610 let pwf: *i64 = ((nb as i64) + wo) as *i64
611 nt_wr64(nb, tef + 24, nxa_check2(1, pwf, fwords))
612 wo = wo + fwords*MF_W
613 ti = ti + 1
614 // ---- append MORF: seven channels of per-face-vertex displacement
615 let tem: i64 = NT_HDR + ti*NT_TOCE
616 nt_wr64(nb, tem, nxa_tag4("MORF" as *u8))
617 nt_wr64(nb, tem + 8, wo)
618 nt_wr64(nb, tem + 16, mwords)
619 nt_wr64(nb, wo, nau)
620 nt_wr64(nb, wo + MF_W, nface)
621 nt_wr64(nb, wo + MF_W*2, MF_DSTRIDE)
622 nt_wr64(nb, wo + MF_W*3, MF_UNIT)
623 c = 0
624 while c < nau {
625 let ro: i64 = wo + (MF_MORF_HDR + c*MF_CHANREC)*MF_W
626 nt_wr64(nb, ro, rec[c*MF_AUREC + MF_A_TAG])
627 nt_wr64(nb, ro + MF_W, sup[c])
628 c = c + 1
629 }
630 let dbase: i64 = wo + (MF_MORF_HDR + nau*MF_CHANREC)*MF_W
631 var d: i64 = 0
632 while d < nau*nface*MF_DSTRIDE {
633 nt_wr64(nb, dbase + d*MF_W, dlt[d])
634 d = d + 1
635 }
636 let pwm: *i64 = ((nb as i64) + wo) as *i64
637 nt_wr64(nb, tem + 24, nxa_check2(1, pwm, mwords))
638 wo = wo + mwords*MF_W
639 let tb2: *i64 = ((nb as i64) + NT_HDR) as *i64
640 nt_wr64(nb, 24, nxa_check2(1, tb2, nsec*4))
641
642 let fd: i64 = sys_openat_wr(outp, NT_MODE)
643 if fd < 0 { nt_err("MORF-REFUSE cannot open output\n" as *u8); return MF_E_IO }
644 let wrote: i64 = sys_write(fd, nb, wo)
645 sys_close(fd)
646 if wrote != wo { nt_err("MORF-REFUSE short write\n" as *u8); return MF_E_IO }
647
648 nt_outs("MORF derive ok\n" as *u8)
649 nt_outs(" stature_axis=" as *u8); nt_outn(ax_stat)
650 nt_outs(" lateral_axis=" as *u8); nt_outn(ax_lat)
651 nt_outs(" depth_axis=" as *u8); nt_outn(ax_dep)
652 nt_outs(" stature_span=" as *u8); nt_outn(span); nt_outs("\n" as *u8)
653 nt_outs(" face_band_permil=" as *u8); nt_outn(MF_HEAD_LO_PERMIL)
654 nt_outs(".." as *u8); nt_outn(MF_HEAD_HI_PERMIL)
655 nt_outs(" source=nx_headcrop\n" as *u8)
656 nt_outs(" face_verts=" as *u8); nt_outn(nface)
657 nt_outs(" of " as *u8); nt_outn(nv); nt_outs("\n" as *u8)
658 nt_outs(" channels=" as *u8); nt_outn(nau)
659 nt_outs(" source=" as *u8); nt_outs(MF_AUCONF)
660 nt_outs(" front_axis_sign=" as *u8); nt_outn(front); nt_outs("
661" as *u8)
662 let tg: *u8 = sys_mmap(64)
663 c = 0
664 var empty: i64 = 0
665 while c < nau {
666 let tv: i64 = rec[c*MF_AUREC + MF_A_TAG]
667 tg[0] = (tv & 0xff) as u8
668 tg[1] = ((tv >> 8) & 0xff) as u8
669 tg[2] = ((tv >> 16) & 0xff) as u8
670 tg[3] = ((tv >> 24) & 0xff) as u8
671 tg[4] = 0 as u8
672 nt_outs(" " as *u8); nt_outs(tg)
673 nt_outs(" support_verts=" as *u8); nt_outn(sup[c]); nt_outs("
674" as *u8)
675 if sup[c] < 1 { empty = empty + 1 }
676 c = c + 1
677 }
678 nt_outs(" channels_with_empty_support=" as *u8); nt_outn(empty); nt_outs("
679" as *u8)
680 nt_outs(" sections=" as *u8); nt_outn(nsec)
681 nt_outs(" bytes=" as *u8); nt_outn(wo); nt_outs("\n" as *u8)
682 return MF_OK
683}
684
685// ---------------------------------------------------------------------------------------------
686// EVAL: apply weight w (permil) of channel c and write the deformed asset. This is the proof the
687// deltas are geometry and not decoration -- a reader can diff VERT before and after.
688// ---------------------------------------------------------------------------------------------
689func mf_eval(inp: *u8, chan: i64, wpermil: i64, outp: *u8) -> i64 {
690 let lp: *i64 = sys_mmap(MF_W*2) as *i64
691 if (lp as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate input length\n" as *u8); return MF_E_IO }
692 let b: *u8 = sys_read_file(inp, lp)
693 if (b as i64) <= 0 { nt_err("MORF-REFUSE cannot read input NXA\n" as *u8); return MF_E_IO }
694 let flen: i64 = lp[0]
695 if flen < NT_HDR { nt_err("MORF-REFUSE file too short to be an NXA\n" as *u8); return MF_E_BAD }
696 if nt_rd64(b, 0) != nxa_magic() { nt_err("MORF-REFUSE not an NXA (bad magic)\n" as *u8); return MF_E_BAD }
697 if chan < 0 { nt_err("MORF-REFUSE channel index negative\n" as *u8); return MF_E_USAGE }
698 // A sizing failure still goes through the shared reader so the original
699 // section/shape diagnostic precedence is preserved on malformed inputs.
700 let needed: i64 = nmi_scratch_bytes(b,flen)
701 var scratch_bytes: i64 = 0
702 if needed > 0 { scratch_bytes = needed }
703 var seen: *u8 = 0 as *u8
704 if scratch_bytes > 0 { seen = sys_mmap(scratch_bytes) }
705 let view: *MvcView = sys_mmap(__size_of(MvcView)) as *MvcView
706 let admitted: *NmiAsset = sys_mmap(__size_of(NmiAsset)) as *NmiAsset
707 if scratch_bytes > 0 { if (seen as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate FACE membership validation\n" as *u8); return MF_E_IO } }
708 if (view as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate evaluation view\n" as *u8); return MF_E_IO }
709 if (admitted as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate admission result\n" as *u8); return MF_E_IO }
710 admitted.view = view
711 let admission: i64 = nmi_admit_channel(b,flen,seen,scratch_bytes,admitted,chan)
712 if admission < 0 {
713 nt_err(nmi_diagnostic(admission))
714 if nmi_missing(admission) == 1 { return MF_E_NOSEC }
715 return MF_E_BAD
716 }
717 let nv: i64 = view.vertices
718 let vt: i64 = nxa_tag4("VERT" as *u8)
719 let ve: i64 = nxa_section_entry(b,flen,vt)
720 let mchan: i64 = view.channels
721 let nface: i64 = view.faces
722 if chan >= mchan { nt_err("MORF-REFUSE channel past the asset's declared channels\n" as *u8); return MF_E_BAD }
723 let h: *i64 = b as *i64
724 let ns: i64 = h[2]; let vo: i64 = h[ve+1]; let vwords: i64 = h[ve+2]
725 let nb: *u8 = sys_mmap(flen)
726 if (nb as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate output\n" as *u8); return MF_E_IO }
727 var k: i64 = 0
728 while k < flen { nb[k] = b[k]; k = k + 1 }
729 let weights: *i64 = sys_mmap(mchan*MF_W) as *i64
730 if (weights as i64) <= 0 { nt_err("MORF-REFUSE cannot allocate channel weights\n" as *u8); return MF_E_IO }
731 var c: i64 = 0
732 while c < mchan { weights[c] = 0; c = c+1 }
733 weights[chan] = wpermil
734 let out_vertices: *i64 = ((nb as i64)+vo+MF_W) as *i64
735 let moved: i64 = mvc_apply(view,weights,mchan,out_vertices,nv*MF_VSTRIDE)
736 if moved == MVC_E_PRODUCT { nt_err("MORF-REFUSE delta times weight exceeds signed i64\n" as *u8); return MF_E_BAD }
737 if moved == MVC_E_SUM { nt_err("MORF-REFUSE vertex addition exceeds signed i64\n" as *u8); return MF_E_BAD }
738 if moved < 0 { nt_err("MORF-REFUSE evaluation view shape or alias\n" as *u8); return MF_E_BAD }
739 let pwv: *i64 = ((nb as i64) + vo) as *i64
740 nt_wr64(nb, ve*MF_W + 24, nxa_check2(1, pwv, vwords))
741 let tb2: *i64 = ((nb as i64) + NT_HDR) as *i64
742 nt_wr64(nb, 24, nxa_check2(1, tb2, ns*4))
743 // No destination is opened until every membership and selected-channel arithmetic check passes.
744 let fd: i64 = sys_openat_wr(outp, NT_MODE)
745 if fd < 0 { nt_err("MORF-REFUSE cannot open output\n" as *u8); return MF_E_IO }
746 let wrote: i64 = sys_write(fd, nb, flen)
747 sys_close(fd)
748 if wrote != flen { nt_err("MORF-REFUSE short write\n" as *u8); return MF_E_IO }
749 nt_outs("MORF eval ok chan=" as *u8); nt_outn(chan)
750 nt_outs(" weight_permil=" as *u8); nt_outn(wpermil)
751 nt_outs(" verts_moved=" as *u8); nt_outn(moved)
752 nt_outs(" of face_verts=" as *u8); nt_outn(nface); nt_outs("\n" as *u8)
753 return MF_OK
754}
755
756func main(argc: i64, argv: *i64) -> i64 {
757 if argc < 2 { let r: i64 = mf_usage(); sys_exit(r); return r }
758 let v: *u8 = argv[1] as *u8
759 if nt_tageq(v, 0, "deri" as *u8) == 1 {
760 if argc < 4 { let r2: i64 = mf_usage(); sys_exit(r2); return r2 }
761 let rc: i64 = mf_derive(argv[2] as *u8, argv[3] as *u8)
762 sys_exit(rc)
763 return rc
764 }
765 if nt_tageq(v, 0, "eval" as *u8) == 1 {
766 if argc < 5 { let r3: i64 = mf_usage(); sys_exit(r3); return r3 }
767 let cp: *i64 = sys_mmap(MF_W*4) as *i64
768 let wpp: *i64 = ((cp as i64) + MF_W) as *i64
769 if mf_spec(argv[4] as *u8, cp, wpp) != 0 {
770 nt_err("MORF-REFUSE eval spec must be <chan>:<weight_permil>, for example 0:1000
771" as *u8)
772 sys_exit(MF_E_USAGE)
773 return MF_E_USAGE
774 }
775 let rc2: i64 = mf_eval(argv[2] as *u8, cp[0], wpp[0], argv[3] as *u8)
776 sys_exit(rc2)
777 return rc2
778 }
779 let r4: i64 = mf_usage()
780 sys_exit(r4)
781 return r4
782}