nx_nxa_garment.nx source
↩ module page · 220 lines · 8220 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"
13const K_MAGIC_4611686018427387903: i64 = 4611686018427387903
14const K_MAGIC_4096: i64 = 4096
15const K_MAGIC_100000000: i64 = 100000000
16const K_MAGIC_65536: i64 = 65536
17
18const GU: i64 = 36 // columns around the body
19const GV: i64 = 18 // rows above-bust..hem (one-layer strapless dress)
20
21func gw9(s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(1,s,n); return 0 }
22func gn9(v: i64) -> i64 {
23 let t: *u8 = sys_mmap(32) as *u8
24 var m: i64 = v; var w: i64 = 0
25 if m<0 { t[w]=45 as u8; w=w+1; m=0-m }
26 if m==0 { t[0]=48 as u8; sys_write(1,t,1); return 0 }
27 let d: *u8 = sys_mmap(32) as *u8
28 var k: i64=0
29 while m>0 { d[k]=(48+(m%10)) as u8; m=m/10; k=k+1 }
30 var j: i64=0
31 while j<k { t[w]=d[k-1-j]; w=w+1; j=j+1 }
32 sys_write(1,t,w); return 0
33}
34func main(argc: i64, argv: *i64) -> i64 {
35 if argc < 3 { gw9("usage: nx_nxa_garment <in.nxa> <out.nxa>\n" as *u8); return 2 }
36 let lp: *i64 = sys_mmap(16) as *i64
37 let b: *u8 = sys_map_file(argv[1] as *u8, lp)
38 let flen: i64 = lp[0]
39 let vwo: i64 = nxa_find(b, flen, nxa_tag4("VERT" as *u8))
40 if vwo < 0 { gw9("bad nxa\n" as *u8); return 5 }
41 let h: *i64 = b as *i64
42 let nv: i64 = h[vwo]
43 let vx: *i64 = ((b as i64) + vwo*8 + 8) as *i64
44 // measure: z-up models; body extents
45 var mn2: i64 = K_MAGIC_4611686018427387903
46 var mx2: i64 = 0 - K_MAGIC_4611686018427387903
47 var mnx: i64 = K_MAGIC_4611686018427387903
48 var mxx: i64 = 0 - K_MAGIC_4611686018427387903
49 var mny: i64 = K_MAGIC_4611686018427387903
50 var mxy: i64 = 0 - K_MAGIC_4611686018427387903
51 var i0: i64 = 0
52 while i0 < nv {
53 if vx[i0*3] < mnx { mnx = vx[i0*3] }
54 if vx[i0*3] > mxx { mxx = vx[i0*3] }
55 if vx[i0*3+1] < mny { mny = vx[i0*3+1] }
56 if vx[i0*3+1] > mxy { mxy = vx[i0*3+1] }
57 if vx[i0*3+2] < mn2 { mn2 = vx[i0*3+2] }
58 if vx[i0*3+2] > mx2 { mx2 = vx[i0*3+2] }
59 i0 = i0 + 1
60 }
61 let H: i64 = mx2 - mn2
62 let cx: i64 = (mnx + mxx)/2
63 let cy: i64 = (mny + mxy)/2
64 // rows: y01 from 775 (above bust, armpit line -- strapless top edge) down to 370
65 // (mid-thigh); per row measure the body's MAX radius from the axis within the band
66 // (torso only: |x-cx| < .16H so T-pose arms never inflate the top rows) + ease
67 let rowz: *i64 = sys_mmap(GV*8 + 64) as *i64
68 let rowr: *i64 = sys_mmap(GV*8 + 64) as *i64
69 var r0: i64 = 0
70 while r0 < GV {
71 let y01: i64 = 758 - r0*388/(GV-1)
72 rowz[r0] = mn2 + H*y01/1000
73 var best: i64 = 0
74 var i1: i64 = 0
75 while i1 < nv {
76 let dz9: i64 = vx[i1*3+2] - rowz[r0]
77 var az9: i64 = dz9
78 if az9 < 0 { az9 = 0 - az9 }
79 if az9 < H*12/1000 {
80 let dx9: i64 = vx[i1*3] - cx
81 let dy9: i64 = vx[i1*3+1] - cy
82 var ax9: i64 = dx9
83 if ax9 < 0 { ax9 = 0 - ax9 }
84 if ax9 < H*115/1000 {
85 let rr9: i64 = dx9*dx9 + dy9*dy9
86 if rr9 > best { best = rr9 }
87 }
88 }
89 i1 = i1 + 1
90 }
91 // isqrt via itrig-free Newton (small local)
92 var xq: i64 = K_MAGIC_4096
93 if best > K_MAGIC_100000000 { xq = K_MAGIC_65536 }
94 var itn: i64 = 0
95 while itn < 30 {
96 if xq > 0 { let yq: i64 = (xq + best/xq)/2; if yq > 0 { xq = yq } }
97 itn = itn + 1
98 }
99 // ease (pattern-making literature): a fitted woven skirt carries 5-10cm of hip ease
100 // -- on this figure's ~105cm hip that is 5-9pct. Surplus fabric is what BUCKLES into
101 // folds; a zero-ease shrink-wrap can only cone. Flare grows over the last 7 rows.
102 var ease: i64 = 62
103 if r0 > GV-8 { ease = 62 + (r0-(GV-8))*48 }
104 rowr[r0] = xq + xq*ease/1000
105 r0 = r0 + 1
106 }
107 gw9("rows=" as *u8); gn9(GV)
108 gw9(" r_top=" as *u8); gn9(rowr[0])
109 gw9(" r_hip=" as *u8); gn9(rowr[12])
110 gw9(" r_hem=" as *u8); gn9(rowr[GV-1]); gw9("\n" as *u8)
111 // build ring-grid mesh: GU columns x GV rows; slight ellipse (y depth 82pct of x width)
112 let gnv: i64 = GU*GV
113 let gvp: *i64 = sys_mmap((1 + gnv*3)*8 + 64) as *i64
114 gvp[0] = gnv
115 var rr0: i64 = 0
116 while rr0 < GV {
117 var u0: i64 = 0
118 while u0 < GU {
119 let ang: i64 = u0*2*IT_PI/GU
120 let cs9: i64 = it_cos4096(ang)
121 let sn9b: i64 = it_sin4096(ang)
122 let idx: i64 = (rr0*GU + u0)*3
123 gvp[1 + idx] = cx + rowr[rr0]*cs9/K_MAGIC_4096
124 gvp[1 + idx + 1] = cy + rowr[rr0]*82/100*sn9b/K_MAGIC_4096
125 gvp[1 + idx + 2] = rowz[rr0]
126 u0 = u0 + 1
127 }
128 rr0 = rr0 + 1
129 }
130 // tris: two per quad, wrapping in u
131 let gnt: i64 = GU*(GV-1)*2
132 let gtp: *i64 = sys_mmap((1 + gnt*3)*8 + 64) as *i64
133 gtp[0] = gnt
134 var tw9: i64 = 0
135 var rr1: i64 = 0
136 while rr1 < GV-1 {
137 var u1: i64 = 0
138 while u1 < GU {
139 let a9: i64 = rr1*GU + u1
140 var u2: i64 = u1 + 1
141 if u2 >= GU { u2 = 0 }
142 let b9: i64 = rr1*GU + u2
143 let c9: i64 = (rr1+1)*GU + u1
144 let d9: i64 = (rr1+1)*GU + u2
145 gtp[1 + tw9*3] = a9
146 gtp[1 + tw9*3 + 1] = c9
147 gtp[1 + tw9*3 + 2] = b9
148 tw9 = tw9 + 1
149 gtp[1 + tw9*3] = b9
150 gtp[1 + tw9*3 + 1] = c9
151 gtp[1 + tw9*3 + 2] = d9
152 tw9 = tw9 + 1
153 u1 = u1 + 1
154 }
155 rr1 = rr1 + 1
156 }
157 // pins: the whole top row
158 let gnp: i64 = GU
159 let gpp: *i64 = sys_mmap((1 + gnp)*8 + 64) as *i64
160 gpp[0] = gnp
161 var p0: i64 = 0
162 while p0 < gnp { gpp[1 + p0] = p0; p0 = p0 + 1 }
163 gw9("garment verts=" as *u8); gn9(gnv)
164 gw9(" tris=" as *u8); gn9(gnt)
165 gw9(" pins=" as *u8); gn9(gnp); gw9("\n" as *u8)
166 // append GVRT/GTRI/GPIN
167 let ons: i64 = h[2]
168 let otoc: *i64 = ((b as i64) + 32) as *i64
169 let ns2: i64 = ons + 3
170 let hdr: *i64 = sys_mmap(64) as *i64
171 let toc: *i64 = sys_mmap(ns2*32 + 64) as *i64
172 var o: i64 = 32 + ns2*32
173 var ti: i64 = 0
174 while ti < ons {
175 toc[ti*4] = otoc[ti*4]
176 toc[ti*4+1] = o
177 toc[ti*4+2] = otoc[ti*4+2]
178 toc[ti*4+3] = otoc[ti*4+3]
179 o = o + otoc[ti*4+2]*8
180 ti = ti + 1
181 }
182 let gvl: i64 = 1 + gnv*3
183 let gtl: i64 = 1 + gnt*3
184 let gpl: i64 = 1 + gnp
185 toc[ti*4] = nxa_tag4("GVRT" as *u8)
186 toc[ti*4+1] = o
187 toc[ti*4+2] = gvl
188 toc[ti*4+3] = nxa_check2(1, gvp, gvl)
189 o = o + gvl*8
190 ti = ti + 1
191 toc[ti*4] = nxa_tag4("GTRI" as *u8)
192 toc[ti*4+1] = o
193 toc[ti*4+2] = gtl
194 toc[ti*4+3] = nxa_check2(1, gtp, gtl)
195 o = o + gtl*8
196 ti = ti + 1
197 toc[ti*4] = nxa_tag4("GPIN" as *u8)
198 toc[ti*4+1] = o
199 toc[ti*4+2] = gpl
200 toc[ti*4+3] = nxa_check2(1, gpp, gpl)
201 hdr[0] = nxa_magic()
202 hdr[1] = NXA_VER
203 hdr[2] = ns2
204 hdr[3] = nxa_check2(1, toc, ns2*4)
205 let fd: i64 = sys_openat_wr(argv[2] as *u8, 0x1a4)
206 if fd < 0 { gw9("open out failed\n" as *u8); return 9 }
207 sys_write(fd, hdr as *u8, 32)
208 sys_write(fd, toc as *u8, ns2*32)
209 var ci: i64 = 0
210 while ci < ons {
211 sys_write(fd, ((b as i64) + otoc[ci*4+1]) as *u8, otoc[ci*4+2]*8)
212 ci = ci + 1
213 }
214 sys_write(fd, gvp as *u8, gvl*8)
215 sys_write(fd, gtp as *u8, gtl*8)
216 sys_write(fd, gpp as *u8, gpl*8)
217 sys_close(fd)
218 gw9("NXA+GARMENT written sections=" as *u8); gn9(ns2); gw9("\n" as *u8)
219 return 0
220}