nx_nxa_garment.nx source
↩ module page · 252 lines · 9686 B
1// nx_nxa_garment.nx -- FITTED GARMENT GENERATOR (SOTA garment rung): builds a dress mesh
2// fitted to the character BY MEASUREMENT (per-row body cross-section radii sampled from
3// VERT + ease margin -- tooling, per-character, no hand constants beyond the ease profile),
4// from underbust to mid-thigh with hem flare. Appends GVRT (rest verts, mesh space), GTRI,
5// GPIN (top-ring verts pinned; viewer binds pins to the chest frame). The viewer sims it
6// with general edge-list XPBD -- the same machinery future GarmentCode ingests will use.
7// usage: nx_nxa_garment <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"
12import "nx_itrig.nx"
13import "nx_gm_cloth_lib.nx"
14const K_MAGIC_4611686018427387903: i64 = 4611686018427387903
15const K_MAGIC_4096: i64 = 4096
16const K_MAGIC_100000000: i64 = 100000000
17const K_MAGIC_65536: i64 = 65536
18
19const GU: i64 = 36 // columns around the body
20const GV: i64 = 18 // rows above-bust..hem (one-layer strapless dress)
21
22func gw9(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
23func gn9(v: i64) -> i64 {
24 let t: *u8 = sys_mmap(32) as *u8
25 var m: i64 = v; var w: i64 = 0
26 if m<0 { t[w]=45 as u8; w=w+1; m=0-m }
27 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 }
28 let d: *u8 = sys_mmap(32) as *u8
29 var k: i64=0
30 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
31 var j: i64=0
32 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 }
33 sys_write(1,t,w); return 0
34}
35func gs_eq(a: *u8, b: *u8) -> i64 {
36 var i: i64 = 0
37 while a[i] != (0 as u8) { if a[i] != b[i] { return 0 } i = i + 1 }
38 if b[i] != (0 as u8) { return 0 }
39 return 1
40}
41
42func main(argc: i64, argv: *i64) -> i64 {
43 // PG29 wiring: `nx_nxa_garment xpbdcheck` exercises gm_xpbd_step on a two-vert edge -- a real
44 // in-organ call of the solver this organ's watch row names, so the /compare flip is backed by
45 // wiring. The full physics proof is nx_gm_xpbd_gate; this verb only proves reachability.
46 if argc >= 2 { if gs_eq(argv[1] as *u8, "xpbdcheck" as *u8) == 1 {
47 let v2: *i64 = sys_mmap(6*8) as *i64
48 let ve: *i64 = sys_mmap(6*8) as *i64
49 let ed: *i64 = sys_mmap(GM_EROW*8) as *i64
50 let bk: *i64 = sys_mmap(6*8) as *i64
51 v2[0]=0; v2[1]=0; v2[2]=0; v2[3]=200; v2[4]=0; v2[5]=0
52 var z9: i64 = 0
53 while z9 < 6 { ve[z9]=0; z9=z9+1 }
54 ed[0]=0; ed[1]=1; ed[2]=100; ed[3]=GM_C_STRUCT // rest 100, stretched to 200
55 let d0: i64 = gm_dist(v2, 0, 1)
56 gm_xpbd_step_banked(v2, ve, 2, ed, 1, 0 as *i64, 0, 0, 16666, 8, 0, 0, bk)
57 let d1: i64 = gm_dist(v2, 0, 1)
58 gw9("GM-XPBD-CHECK before=" as *u8); gn9(d0)
59 gw9(" after=" as *u8); gn9(d1)
60 gw9(" rest=100 converged=" as *u8)
61 var ok9: i64 = 0
62 if d1 < d0 { if d1 >= 95 { if d1 <= 105 { ok9 = 1 } } }
63 gn9(ok9); gw9("\n" as *u8)
64 if ok9 == 1 { return 0 }
65 return 1
66 } }
67 if argc < 3 { gw9("usage: nx_nxa_garment <in.nxa> <out.nxa> | xpbdcheck\n" as *u8); return 2 }
68 let lp: *i64 = sys_mmap(16) as *i64
69 let b: *u8 = sys_map_file(argv[1] as *u8, lp)
70 let flen: i64 = lp[0]
71 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
72 if vwo < 0 { gw9("bad nxa\n" as *u8); return 5 }
73 let h: *i64 = b as *i64
74 let nv: i64 = h[vwo]
75 let vx: *i64 = ((b as i64) + vwo*8 + 8) as *i64
76 // measure: z-up models; body extents
77 var mn2: i64 = K_MAGIC_4611686018427387903
78 var mx2: i64 = 0 - K_MAGIC_4611686018427387903
79 var mnx: i64 = K_MAGIC_4611686018427387903
80 var mxx: i64 = 0 - K_MAGIC_4611686018427387903
81 var mny: i64 = K_MAGIC_4611686018427387903
82 var mxy: i64 = 0 - K_MAGIC_4611686018427387903
83 var i0: i64 = 0
84 while i0 < nv {
85 if vx[i0*3] < mnx { mnx = vx[i0*3] }
86 if vx[i0*3] > mxx { mxx = vx[i0*3] }
87 if vx[i0*3+1] < mny { mny = vx[i0*3+1] }
88 if vx[i0*3+1] > mxy { mxy = vx[i0*3+1] }
89 if vx[i0*3+2] < mn2 { mn2 = vx[i0*3+2] }
90 if vx[i0*3+2] > mx2 { mx2 = vx[i0*3+2] }
91 i0 = i0 + 1
92 }
93 let H: i64 = mx2 - mn2
94 let cx: i64 = (mnx + mxx)/2
95 let cy: i64 = (mny + mxy)/2
96 // rows: y01 from 775 (above bust, armpit line -- strapless top edge) down to 370
97 // (mid-thigh); per row measure the body's MAX radius from the axis within the band
98 // (torso only: |x-cx| < .16H so T-pose arms never inflate the top rows) + ease
99 let rowz: *i64 = sys_mmap(GV*8 + 64) as *i64
100 let rowr: *i64 = sys_mmap(GV*8 + 64) as *i64
101 var r0: i64 = 0
102 while r0 < GV {
103 let y01: i64 = 758 - r0*388/(GV-1)
104 rowz[r0] = mn2 + H*y01/1000
105 var best: i64 = 0
106 var i1: i64 = 0
107 while i1 < nv {
108 let dz9: i64 = vx[i1*3+2] - rowz[r0]
109 var az9: i64 = dz9
110 if az9 < 0 { az9 = 0 - az9 }
111 if az9 < H*12/1000 {
112 let dx9: i64 = vx[i1*3] - cx
113 let dy9: i64 = vx[i1*3+1] - cy
114 var ax9: i64 = dx9
115 if ax9 < 0 { ax9 = 0 - ax9 }
116 if ax9 < H*115/1000 {
117 let rr9: i64 = dx9*dx9 + dy9*dy9
118 if rr9 > best { best = rr9 }
119 }
120 }
121 i1 = i1 + 1
122 }
123 // isqrt via itrig-free Newton (small local)
124 var xq: i64 = K_MAGIC_4096
125 if best > K_MAGIC_100000000 { xq = K_MAGIC_65536 }
126 var itn: i64 = 0
127 while itn < 30 {
128 if xq > 0 { let yq: i64 = (xq + best/xq)/2; if yq > 0 { xq = yq } }
129 itn = itn + 1
130 }
131 // ease (pattern-making literature): a fitted woven skirt carries 5-10cm of hip ease
132 // -- on this figure's ~105cm hip that is 5-9pct. Surplus fabric is what BUCKLES into
133 // folds; a zero-ease shrink-wrap can only cone. Flare grows over the last 7 rows.
134 var ease: i64 = 62
135 if r0 > GV-8 { ease = 62 + (r0-(GV-8))*48 }
136 rowr[r0] = xq + xq*ease/1000
137 r0 = r0 + 1
138 }
139 gw9("rows=" as *u8); gn9(GV)
140 gw9(" r_top=" as *u8); gn9(rowr[0])
141 gw9(" r_hip=" as *u8); gn9(rowr[12])
142 gw9(" r_hem=" as *u8); gn9(rowr[GV-1]); gw9("\n" as *u8)
143 // build ring-grid mesh: GU columns x GV rows; slight ellipse (y depth 82pct of x width)
144 let gnv: i64 = GU*GV
145 let gvp: *i64 = sys_mmap((1 + gnv*3)*8 + 64) as *i64
146 gvp[0] = gnv
147 var rr0: i64 = 0
148 while rr0 < GV {
149 var u0: i64 = 0
150 while u0 < GU {
151 let ang: i64 = u0*2*IT_PI/GU
152 let cs9: i64 = it_cos4096(ang)
153 let sn9b: i64 = it_sin4096(ang)
154 let idx: i64 = (rr0*GU + u0)*3
155 gvp[1 + idx] = cx + rowr[rr0]*cs9/K_MAGIC_4096
156 gvp[1 + idx + 1] = cy + rowr[rr0]*82/100*sn9b/K_MAGIC_4096
157 gvp[1 + idx + 2] = rowz[rr0]
158 u0 = u0 + 1
159 }
160 rr0 = rr0 + 1
161 }
162 // tris: two per quad, wrapping in u
163 let gnt: i64 = GU*(GV-1)*2
164 let gtp: *i64 = sys_mmap((1 + gnt*3)*8 + 64) as *i64
165 gtp[0] = gnt
166 var tw9: i64 = 0
167 var rr1: i64 = 0
168 while rr1 < GV-1 {
169 var u1: i64 = 0
170 while u1 < GU {
171 let a9: i64 = rr1*GU + u1
172 var u2: i64 = u1 + 1
173 if u2 >= GU { u2 = 0 }
174 let b9: i64 = rr1*GU + u2
175 let c9: i64 = (rr1+1)*GU + u1
176 let d9: i64 = (rr1+1)*GU + u2
177 gtp[1 + tw9*3] = a9
178 gtp[1 + tw9*3 + 1] = c9
179 gtp[1 + tw9*3 + 2] = b9
180 tw9 = tw9 + 1
181 gtp[1 + tw9*3] = b9
182 gtp[1 + tw9*3 + 1] = c9
183 gtp[1 + tw9*3 + 2] = d9
184 tw9 = tw9 + 1
185 u1 = u1 + 1
186 }
187 rr1 = rr1 + 1
188 }
189 // pins: the whole top row
190 let gnp: i64 = GU
191 let gpp: *i64 = sys_mmap((1 + gnp)*8 + 64) as *i64
192 gpp[0] = gnp
193 var p0: i64 = 0
194 while p0 < gnp { gpp[1 + p0] = p0; p0 = p0 + 1 }
195 gw9("garment verts=" as *u8); gn9(gnv)
196 gw9(" tris=" as *u8); gn9(gnt)
197 gw9(" pins=" as *u8); gn9(gnp); gw9("\n" as *u8)
198 // append GVRT/GTRI/GPIN
199 let ons: i64 = h[2]
200 let otoc: *i64 = ((b as i64) + 32) as *i64
201 let ns2: i64 = ons + 3
202 let hdr: *i64 = sys_mmap(64) as *i64
203 let toc: *i64 = sys_mmap(ns2*32 + 64) as *i64
204 var o: i64 = 32 + ns2*32
205 var ti: i64 = 0
206 while ti < ons {
207 toc[ti*4] = otoc[ti*4]
208 toc[ti*4+1] = o
209 toc[ti*4+2] = otoc[ti*4+2]
210 toc[ti*4+3] = otoc[ti*4+3]
211 o = o + otoc[ti*4+2]*8
212 ti = ti + 1
213 }
214 let gvl: i64 = 1 + gnv*3
215 let gtl: i64 = 1 + gnt*3
216 let gpl: i64 = 1 + gnp
217 toc[ti*4] = nxa_tag4("GVRT" as *u8)
218 toc[ti*4+1] = o
219 toc[ti*4+2] = gvl
220 toc[ti*4+3] = nxa_check2(1, gvp, gvl)
221 o = o + gvl*8
222 ti = ti + 1
223 toc[ti*4] = nxa_tag4("GTRI" as *u8)
224 toc[ti*4+1] = o
225 toc[ti*4+2] = gtl
226 toc[ti*4+3] = nxa_check2(1, gtp, gtl)
227 o = o + gtl*8
228 ti = ti + 1
229 toc[ti*4] = nxa_tag4("GPIN" as *u8)
230 toc[ti*4+1] = o
231 toc[ti*4+2] = gpl
232 toc[ti*4+3] = nxa_check2(1, gpp, gpl)
233 hdr[0] = nxa_magic()
234 hdr[1] = NXA_VER
235 hdr[2] = ns2
236 hdr[3] = nxa_check2(1, toc, ns2*4)
237 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4)
238 if fd < 0 { gw9("open out failed\n" as *u8); return 9 }
239 sys_write(fd, hdr as *u8, 32)
240 sys_write(fd, toc as *u8, ns2*32)
241 var ci: i64 = 0
242 while ci < ons {
243 sys_write(fd, ((b as i64) + otoc[ci*4+1]) as *u8, otoc[ci*4+2]*8)
244 ci = ci + 1
245 }
246 sys_write(fd, gvp as *u8, gvl*8)
247 sys_write(fd, gtp as *u8, gtl*8)
248 sys_write(fd, gpp as *u8, gpl*8)
249 sys_close(fd)
250 gw9("NXA+GARMENT written sections=" as *u8); gn9(ns2); gw9("\n" as *u8)
251 return 0
252}