code wiki / (root) / nx_nxa_morf.nx

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}