nx_nxa_morph.nx source
↩ module page · 244 lines · 10375 B
1// nx_nxa_morph.nx -- FIGURE CANON morph at BAKE level (SOTA rung 2): applies the operator's
2// proportion canon (bust-dominant hourglass: bust +25pct teardrop volume front-side, waist
3// -8pct, hips UNCHANGED -- never enlarge glutes, no surgery-look hard edges) directly to the
4// NXA VERT section so EVERY consumer (viewers, games, skinning) inherits it. Smooth quartic
5// falloff bumps (integer, no exp); face side found from head-region depth extremes; face and
6// head untouched. Run BEFORE nx_nxa_skin so auto-skin sees the final shape.
7// usage: nx_nxa_morph <in.nxa> <out.nxa>
8// rc: 0 ok, 2 usage, 5 bad nxa, 9 io
9// license_tier: ORIGINAL
10import "nx_syscalls.nx"
11import "nx_nxa.nx"
12const K_MAGIC_4096: i64 = 4096
13const K_MAGIC_4611686018427387903: i64 = 4611686018427387903
14
15func mw(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
16func mn(v: i64) -> i64 {
17 let t: *u8 = sys_mmap(32) as *u8
18 var m: i64 = v; var w: i64 = 0
19 if m<0 { t[w]=45 as u8; w=w+1; m=0-m }
20 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 }
21 let d: *u8 = sys_mmap(32) as *u8
22 var k: i64=0
23 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
24 var j: i64=0
25 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 }
26 sys_write(1,t,w); return 0
27}
28// smooth bump: 4096 * (1 - ((y-c)/w)^2)^2 for |y-c|<w else 0 -- quartic, no trig/exp
29func m_bump(y: i64, c: i64, w: i64) -> i64 {
30 var d: i64 = y - c
31 if d < 0 { d = 0 - d }
32 if d >= w { return 0 }
33 let t: i64 = K_MAGIC_4096 - d*K_MAGIC_4096/w
34 // (1-(d/w)^2)^2 ~ use (2t - t^2/4096) form of 1-(1-t)^2 twice: compute u = 1-(d/w)^2
35 let dw: i64 = d*K_MAGIC_4096/w
36 let u: i64 = K_MAGIC_4096 - dw*dw/K_MAGIC_4096
37 return u*u/K_MAGIC_4096
38}
39
40func main(argc: i64, argv: *i64) -> i64 {
41 if argc < 3 { mw("usage: nx_nxa_morph <in.nxa> <out.nxa>\n" as *u8); return 2 }
42 let lp: *i64 = sys_mmap(16) as *i64
43 let b: *u8 = sys_map_file(argv[1] as *u8, lp)
44 let flen: i64 = lp[0]
45 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
46 if vwo < 0 { mw("bad nxa\n" as *u8); return 5 }
47 let h: *i64 = b as *i64
48 let nv: i64 = h[vwo]
49 // copy VERT payload to a mutable buffer
50 let vwl: i64 = 1 + nv*3
51 let vp: *i64 = sys_mmap(vwl*8 + 64) as *i64
52 var c0: i64 = 0
53 while c0 < vwl { vp[c0] = h[vwo + c0]; c0 = c0 + 1 }
54 let vx: *i64 = ((vp as i64) + 8) as *i64
55 // axes: up = largest extent; lat = larger of the rest; face sign from head-region depth
56 let mnv: *i64 = sys_mmap(64) as *i64
57 let mxv: *i64 = sys_mmap(64) as *i64
58 var a0: i64 = 0
59 while a0 < 3 { mnv[a0] = K_MAGIC_4611686018427387903; mxv[a0] = 0 - K_MAGIC_4611686018427387903; a0 = a0 + 1 }
60 var i0: i64 = 0
61 while i0 < nv {
62 var a1: i64 = 0
63 while a1 < 3 {
64 let v: i64 = vx[i0*3 + a1]
65 if v < mnv[a1] { mnv[a1] = v }
66 if v > mxv[a1] { mxv[a1] = v }
67 a1 = a1 + 1
68 }
69 i0 = i0 + 1
70 }
71 var up: i64 = 0
72 if mxv[1]-mnv[1] > mxv[up]-mnv[up] { up = 1 }
73 if mxv[2]-mnv[2] > mxv[up]-mnv[up] { up = 2 }
74 var lat: i64 = 0
75 if up == 0 { lat = 1 }
76 let o3: i64 = 3 - up - lat
77 var oth: i64 = o3
78 if mxv[o3]-mnv[o3] > mxv[lat]-mnv[lat] { oth = lat; lat = o3 }
79 let H: i64 = mxv[up] - mnv[up]
80 let clat: i64 = (mnv[lat] + mxv[lat]) / 2
81 let coth: i64 = (mnv[oth] + mxv[oth]) / 2
82 // face sign: head band = top 12pct; farthest depth extreme sign
83 var fs: i64 = 1
84 var fm: i64 = 0
85 var i1: i64 = 0
86 while i1 < nv {
87 let y01: i64 = (vx[i1*3 + up] - mnv[up])*1000/H
88 if y01 > 880 {
89 var dz: i64 = vx[i1*3 + oth] - coth
90 var ad: i64 = dz
91 if ad < 0 { ad = 0 - ad }
92 if ad > fm { fm = ad; fs = 1; if dz < 0 { fs = 0 - 1 } }
93 }
94 i1 = i1 + 1
95 }
96 // morph: bust two-lobe teardrop (front only, arms excluded), waist -8pct radial
97 var i2: i64 = 0
98 var moved: i64 = 0
99 while i2 < nv {
100 let y01: i64 = (vx[i2*3 + up] - mnv[up])*1000/H
101 let lx: i64 = vx[i2*3 + lat] - clat
102 let dz: i64 = vx[i2*3 + oth] - coth
103 // waist: radial shrink about the body axis, band c=585 w=90
104 let gw: i64 = m_bump(y01, 585, 90)
105 if gw > 0 {
106 let s: i64 = K_MAGIC_4096 - gw*328/K_MAGIC_4096
107 vx[i2*3 + lat] = clat + lx*s/K_MAGIC_4096
108 vx[i2*3 + oth] = coth + dz*s/K_MAGIC_4096
109 moved = moved + 1
110 }
111 // hips/glutes: the BASE scan is fuller than the benchmark canon (operator: butt huge
112 // vs Emily) -- reduce radially -10pct in the glute band c=465 w=120
113 let gh: i64 = m_bump(y01, 465, 120)
114 if gh > 0 {
115 let sh9: i64 = K_MAGIC_4096 - gh*410/K_MAGIC_4096
116 vx[i2*3 + lat] = clat + (vx[i2*3 + lat] - clat)*sh9/K_MAGIC_4096
117 vx[i2*3 + oth] = coth + (vx[i2*3 + oth] - coth)*sh9/K_MAGIC_4096
118 moved = moved + 1
119 }
120 // bust: front side only, |lat| < .15H; lower lobe c=668 w=110 amp .28, upper lobe
121 // c=715 w=70 amp .10 -- teardrop: full lower pole, gentle upper slope
122 var al: i64 = lx
123 if al < 0 { al = 0 - al }
124 let fr0: i64 = dz*fs
125 if fr0 > 0 { if al < H*150/1000 {
126 var gb: i64 = m_bump(y01, 668, 110)*287/1000 + m_bump(y01, 715, 70)*102/1000
127 if gb > 0 {
128 var fr: i64 = fr0*K_MAGIC_4096/(H*50/1000)
129 if fr > K_MAGIC_4096 { fr = K_MAGIC_4096 }
130 let s2: i64 = K_MAGIC_4096 + gb*fr/K_MAGIC_4096
131 // scale depth about the chest wall (offset .005H toward face) + slight lateral
132 let z0: i64 = coth + fs*H*5/1000
133 let dz2: i64 = vx[i2*3 + oth] - z0
134 vx[i2*3 + oth] = z0 + dz2*s2/K_MAGIC_4096
135 let s3: i64 = K_MAGIC_4096 + gb*fr/K_MAGIC_4096/4
136 vx[i2*3 + lat] = clat + (vx[i2*3 + lat] - clat)*s3/K_MAGIC_4096
137 // teardrop droop: slight downward shift proportional to bump
138 vx[i2*3 + up] = vx[i2*3 + up] - gb*fr/K_MAGIC_4096*(H*12/1000)/K_MAGIC_4096
139 moved = moved + 1
140 }
141 } }
142 i2 = i2 + 1
143 }
144 // CLUS bounds were computed on the unmorphed verts -- recompute per-cluster bbox +
145 // Chebyshev max edge or fsck rightly refuses (RED vertex below cluster bounds)
146 let two: i64 = nxa_find(b, flen, nxa_tag4("TRIS" as *u8))
147 let cwo: i64 = nxa_find(b, flen, nxa_tag4("CLUS" as *u8))
148 var clw: i64 = 0
149 var cpb: *i64 = 0 as *i64
150 if cwo >= 0 { if two >= 0 {
151 let ncl: i64 = h[cwo]
152 clw = 1 + ncl*10
153 cpb = sys_mmap(clw*8 + 64) as *i64
154 var cc0: i64 = 0
155 while cc0 < clw { cpb[cc0] = h[cwo + cc0]; cc0 = cc0 + 1 }
156 let tr: *i64 = ((b as i64) + two*8 + 8) as *i64
157 var cl0: i64 = 0
158 while cl0 < ncl {
159 let cb: i64 = 1 + cl0*10
160 let ts: i64 = cpb[cb]
161 let tc: i64 = cpb[cb+1]
162 var bmn0: i64 = K_MAGIC_4611686018427387903
163 var bmn1: i64 = K_MAGIC_4611686018427387903
164 var bmn2: i64 = K_MAGIC_4611686018427387903
165 var bmx0: i64 = 0 - K_MAGIC_4611686018427387903
166 var bmx1: i64 = 0 - K_MAGIC_4611686018427387903
167 var bmx2: i64 = 0 - K_MAGIC_4611686018427387903
168 var med: i64 = 0
169 var q0: i64 = 0
170 while q0 < tc {
171 var e0: i64 = 0
172 while e0 < 3 {
173 let vi9: i64 = tr[(ts+q0)*3 + e0]
174 var vj9: i64 = tr[(ts+q0)*3]
175 if e0 < 2 { vj9 = tr[(ts+q0)*3 + e0 + 1] }
176 let x9: i64 = vx[vi9*3]
177 let y9: i64 = vx[vi9*3+1]
178 let z9: i64 = vx[vi9*3+2]
179 if x9 < bmn0 { bmn0 = x9 }
180 if y9 < bmn1 { bmn1 = y9 }
181 if z9 < bmn2 { bmn2 = z9 }
182 if x9 > bmx0 { bmx0 = x9 }
183 if y9 > bmx1 { bmx1 = y9 }
184 if z9 > bmx2 { bmx2 = z9 }
185 var ch0: i64 = vx[vi9*3] - vx[vj9*3]
186 if ch0 < 0 { ch0 = 0 - ch0 }
187 var ch1: i64 = vx[vi9*3+1] - vx[vj9*3+1]
188 if ch1 < 0 { ch1 = 0 - ch1 }
189 var ch2: i64 = vx[vi9*3+2] - vx[vj9*3+2]
190 if ch2 < 0 { ch2 = 0 - ch2 }
191 if ch1 > ch0 { ch0 = ch1 }
192 if ch2 > ch0 { ch0 = ch2 }
193 if ch0 > med { med = ch0 }
194 e0 = e0 + 1
195 }
196 q0 = q0 + 1
197 }
198 cpb[cb+2] = bmn0
199 cpb[cb+3] = bmn1
200 cpb[cb+4] = bmn2
201 cpb[cb+5] = bmx0
202 cpb[cb+6] = bmx1
203 cpb[cb+7] = bmx2
204 cpb[cb+9] = med
205 cl0 = cl0 + 1
206 }
207 } }
208 mw("morph verts_touched=" as *u8); mn(moved)
209 mw(" H=" as *u8); mn(H)
210 mw(" up=" as *u8); mn(up)
211 mw(" facesign=" as *u8); mn(fs); mw("\n" as *u8)
212 // write out: same TOC layout; VERT payload replaced + its check and the TOC check redone
213 let ns: i64 = h[2]
214 let otoc: *i64 = ((b as i64) + 32) as *i64
215 let toc: *i64 = sys_mmap(ns*32 + 64) as *i64
216 var t0: i64 = 0
217 while t0 < ns*4 { toc[t0] = otoc[t0]; t0 = t0 + 1 }
218 var ti: i64 = 0
219 while ti < ns {
220 if toc[ti*4] == nxa_tag4("VERT" as *u8) { toc[ti*4+3] = nxa_check2(1, vp, vwl) }
221 if toc[ti*4] == nxa_tag4("CLUS" as *u8) { if clw > 0 { toc[ti*4+3] = nxa_check2(1, cpb, clw) } }
222 ti = ti + 1
223 }
224 let hdr: *i64 = sys_mmap(64) as *i64
225 hdr[0] = h[0]
226 hdr[1] = h[1]
227 hdr[2] = ns
228 hdr[3] = nxa_check2(1, toc, ns*4)
229 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4)
230 if fd < 0 { mw("open out failed\n" as *u8); return 9 }
231 sys_write(fd, hdr as *u8, 32)
232 sys_write(fd, toc as *u8, ns*32)
233 var ci: i64 = 0
234 while ci < ns {
235 var done9: i64 = 0
236 if toc[ci*4] == nxa_tag4("VERT" as *u8) { sys_write(fd, vp as *u8, vwl*8); done9 = 1 }
237 if toc[ci*4] == nxa_tag4("CLUS" as *u8) { if clw > 0 { sys_write(fd, cpb as *u8, clw*8); done9 = 1 } }
238 if done9 == 0 { sys_write(fd, ((b as i64) + toc[ci*4+1]) as *u8, toc[ci*4+2]*8) }
239 ci = ci + 1
240 }
241 sys_close(fd)
242 mw("MORPHED nxa written\n" as *u8)
243 return 0
244}