code wiki / (root) / nx_explode3d.nx

nx_explode3d.nx source

↩ module page · 288 lines · 10988 B

1// nx_explode3d.nx -- R2 of the CAD car-twin ladder: the 3D EXPLODED-VIEW ENGINE (LIB, no main; gated by 2// nx_explode3d_gate). Lifts the gated nx_assembly explode law (pos = home + explode_vec * t) to 3D parts in 3// nx_meshrender's vertex format (Q14 x,y,z,color stride-4). Parts carry: home centroid, UNIT explode 4// direction (radial from their parent's centroid -- the Li/Agrawala-spirit local separation), and assembly 5// DEPTH (deeper parts travel further = staged explosion, the explodeview signature look). ex3_pose writes the 6// world-space vertex array for any t in 0..1024 -- deterministic integer, so the same t is the same bytes. 7// Geometry here = box/octagon-prism STAND-INS (real STEP face tessellation = R1b, its own rung). 8// ctx e: *i64 slots: 0=lverts 1=nlverts 2=idx 3=ntris 4=nparts 5=home[] 6=dir[] 7=depth[] 8=vstart[] 9// 9=vcount[] 10=maxv 11=maxt 12=maxp. license_tier: ORIGINAL 10import "nx_syscalls.nx" 11const EX3_MAGIC_3400: i64 = 3400 12const EX3_MAGIC_1500: i64 = 1500 13const EX3_MAGIC_1400: i64 = 1400 14const EX3_MAGIC_16384: i64 = 16384 15const EX3_MAGIC_11585: i64 = 11585 16const EX3_MAGIC_1024: i64 = 1024 17 18// Q14 world units (16384 = 1.0). EXPLODE_STEP = travel per assembly-depth level at full t (t=1024). 19const EX3_ONE: i64 = 16384 20const EX3_STEP: i64 = 3600 21 22func ex3_init(e: *i64, lverts: *i64, idx: *i64, home: *i64, dir: *i64, depth: *i64, vstart: *i64, vcount: *i64, maxv: i64, maxt: i64, maxp: i64, scratch: *i64) -> i64 { 23 e[0] = lverts as i64 24 e[1] = 0 25 e[2] = idx as i64 26 e[3] = 0 27 e[4] = 0 28 e[5] = home as i64 29 e[6] = dir as i64 30 e[7] = depth as i64 31 e[8] = vstart as i64 32 e[9] = vcount as i64 33 e[10] = maxv 34 e[11] = maxt 35 e[12] = maxp 36 e[13] = scratch as i64 // 2-slot scratch (wasm-safe: no mmap inside lib calls) 37 return 0 38} 39 40// assembled-layout ring radius + vertical drop per assembly depth (Q14; compact when assembled). 41// Shared by the native gate AND the explodelab tree generator (one layout law). 42func ex3_rad(d: i64) -> i64 { if d == 1 { return EX3_MAGIC_3400 } if d == 2 { return EX3_MAGIC_1500 } return 800 } 43func ex3_dyv(d: i64) -> i64 { if d == 1 { return 0 - EX3_MAGIC_1400 } if d == 2 { return 0 - 1000 } return 0 - 700 } 44 45func ex3_isqrt(n: i64) -> i64 { 46 if n <= 0 { return 0 } 47 var x: i64 = n 48 var y: i64 = (x + 1) / 2 49 while y < x { x = y; y = (x + n / x) / 2 } 50 return x 51} 52 53// octagon ring direction k (0..7), Q14 unit; out2[0]=cos out2[1]=sin 54func ex3_oct(k: i64, out2: *i64) -> i64 { 55 let m: i64 = k % 8 56 if m == 0 { out2[0] = EX3_MAGIC_16384; out2[1] = 0; return 0 } 57 if m == 1 { out2[0] = EX3_MAGIC_11585; out2[1] = EX3_MAGIC_11585; return 0 } 58 if m == 2 { out2[0] = 0; out2[1] = EX3_MAGIC_16384; return 0 } 59 if m == 3 { out2[0] = 0 - EX3_MAGIC_11585; out2[1] = EX3_MAGIC_11585; return 0 } 60 if m == 4 { out2[0] = 0 - EX3_MAGIC_16384; out2[1] = 0; return 0 } 61 if m == 5 { out2[0] = 0 - EX3_MAGIC_11585; out2[1] = 0 - EX3_MAGIC_11585; return 0 } 62 if m == 6 { out2[0] = 0; out2[1] = 0 - EX3_MAGIC_16384; return 0 } 63 out2[0] = EX3_MAGIC_11585; out2[1] = 0 - EX3_MAGIC_11585 64 return 0 65} 66 67// begin a part at home (hx,hy,hz) with RAW explode direction (dx,dy,dz) (normalized here; zero -> +y) + depth 68func ex3_part_begin(e: *i64, hx: i64, hy: i64, hz: i64, dx: i64, dy: i64, dz: i64, dep: i64) -> i64 { 69 if e[4] >= e[12] { return 0 - 1 } 70 let p: i64 = e[4] 71 let home: *i64 = e[5] as *i64 72 let dir: *i64 = e[6] as *i64 73 let depth: *i64 = e[7] as *i64 74 let vstart: *i64 = e[8] as *i64 75 let vcount: *i64 = e[9] as *i64 76 home[p * 3 + 0] = hx 77 home[p * 3 + 1] = hy 78 home[p * 3 + 2] = hz 79 let len2: i64 = dx * dx + dy * dy + dz * dz 80 let len: i64 = ex3_isqrt(len2) 81 if len == 0 { 82 dir[p * 3 + 0] = 0 83 dir[p * 3 + 1] = EX3_ONE 84 dir[p * 3 + 2] = 0 85 } else { 86 dir[p * 3 + 0] = (dx * EX3_ONE) / len 87 dir[p * 3 + 1] = (dy * EX3_ONE) / len 88 dir[p * 3 + 2] = (dz * EX3_ONE) / len 89 } 90 depth[p] = dep 91 vstart[p] = e[1] 92 vcount[p] = 0 93 e[4] = p + 1 94 return p 95} 96 97func ex3_vert(e: *i64, x: i64, y: i64, z: i64, color: i64) -> i64 { 98 if e[1] >= e[10] { return 0 - 1 } 99 let lv: *i64 = e[0] as *i64 100 let i: i64 = e[1] 101 lv[i * 4 + 0] = x 102 lv[i * 4 + 1] = y 103 lv[i * 4 + 2] = z 104 lv[i * 4 + 3] = color 105 e[1] = i + 1 106 let vcount: *i64 = e[9] as *i64 107 let p: i64 = e[4] - 1 108 if p >= 0 { vcount[p] = vcount[p] + 1 } 109 return i 110} 111 112func ex3_tri(e: *i64, a: i64, b: i64, c: i64) -> i64 { 113 if e[3] >= e[11] { return 0 - 1 } 114 let ix: *i64 = e[2] as *i64 115 let t: i64 = e[3] 116 ix[t * 3 + 0] = a 117 ix[t * 3 + 1] = b 118 ix[t * 3 + 2] = c 119 e[3] = t + 1 120 return t 121} 122 123// axis-aligned box at absolute assembled center (cx,cy,cz), half-extents (hx,hy,hz) 124func ex3_add_box(e: *i64, cx: i64, cy: i64, cz: i64, hx: i64, hy: i64, hz: i64, color: i64) -> i64 { 125 let v0: i64 = ex3_vert(e, cx - hx, cy - hy, cz - hz, color) 126 let v1: i64 = ex3_vert(e, cx + hx, cy - hy, cz - hz, color) 127 let v2: i64 = ex3_vert(e, cx + hx, cy + hy, cz - hz, color) 128 let v3: i64 = ex3_vert(e, cx - hx, cy + hy, cz - hz, color) 129 let v4: i64 = ex3_vert(e, cx - hx, cy - hy, cz + hz, color) 130 let v5: i64 = ex3_vert(e, cx + hx, cy - hy, cz + hz, color) 131 let v6: i64 = ex3_vert(e, cx + hx, cy + hy, cz + hz, color) 132 let v7: i64 = ex3_vert(e, cx - hx, cy + hy, cz + hz, color) 133 if v7 < 0 { return 0 - 1 } 134 let t1: i64 = ex3_tri(e, v0, v1, v2) 135 let t2: i64 = ex3_tri(e, v0, v2, v3) 136 let t3: i64 = ex3_tri(e, v4, v6, v5) 137 let t4: i64 = ex3_tri(e, v4, v7, v6) 138 let t5: i64 = ex3_tri(e, v0, v4, v5) 139 let t6: i64 = ex3_tri(e, v0, v5, v1) 140 let t7: i64 = ex3_tri(e, v3, v2, v6) 141 let t8: i64 = ex3_tri(e, v3, v6, v7) 142 let t9: i64 = ex3_tri(e, v0, v3, v7) 143 let ta: i64 = ex3_tri(e, v0, v7, v4) 144 let tb: i64 = ex3_tri(e, v1, v5, v6) 145 let tc: i64 = ex3_tri(e, v1, v6, v2) 146 if tc < 0 { return 0 - 1 } 147 return 0 148} 149 150// octagonal prism at absolute center; r = ring radius, hh = half height; axis 0 = y (upright), 1 = x (lying) 151func ex3_add_prism(e: *i64, cx: i64, cy: i64, cz: i64, r: i64, hh: i64, axis: i64, color: i64) -> i64 { 152 let out2: *i64 = e[13] as *i64 153 var first: i64 = 0 - 1 154 var k: i64 = 0 155 while k < 8 { 156 let ig: i64 = ex3_oct(k, out2) 157 let rx: i64 = (out2[0] * r) / EX3_ONE 158 let rz: i64 = (out2[1] * r) / EX3_ONE 159 var b: i64 = 0 160 var t: i64 = 0 161 if axis == 0 { 162 b = ex3_vert(e, cx + rx, cy - hh, cz + rz, color) 163 t = ex3_vert(e, cx + rx, cy + hh, cz + rz, color) 164 } else { 165 b = ex3_vert(e, cx - hh, cy + rx, cz + rz, color) 166 t = ex3_vert(e, cx + hh, cy + rx, cz + rz, color) 167 } 168 if k == 0 { first = b } 169 k = k + 1 170 } 171 var bc: i64 = 0 172 var tc: i64 = 0 173 if axis == 0 { 174 bc = ex3_vert(e, cx, cy - hh, cz, color) 175 tc = ex3_vert(e, cx, cy + hh, cz, color) 176 } else { 177 bc = ex3_vert(e, cx - hh, cy, cz, color) 178 tc = ex3_vert(e, cx + hh, cy, cz, color) 179 } 180 if tc < 0 { return 0 - 1 } 181 // rim vert k: bottom = first + 2k, top = first + 2k + 1 182 k = 0 183 while k < 8 { 184 let k1: i64 = (k + 1) % 8 185 let bk: i64 = first + 2 * k 186 let tk: i64 = first + 2 * k + 1 187 let bk1: i64 = first + 2 * k1 188 let tk1: i64 = first + 2 * k1 + 1 189 let s1: i64 = ex3_tri(e, bk, bk1, tk) 190 let s2: i64 = ex3_tri(e, tk, bk1, tk1) 191 let c1: i64 = ex3_tri(e, bc, bk1, bk) 192 let c2: i64 = ex3_tri(e, tc, tk, tk1) 193 if c2 < 0 { return 0 - 1 } 194 k = k + 1 195 } 196 return 0 197} 198 199// displacement magnitude (Q14) of a depth-d part at explode factor t (0..1024) 200func ex3_disp_mag(t: i64, d: i64) -> i64 { return (t * (EX3_STEP * d)) / EX3_MAGIC_1024 } 201 202// write world verts for explode factor t into wverts (same layout/order as lverts) 203func ex3_pose(e: *i64, t: i64, wverts: *i64) -> i64 { 204 let lv: *i64 = e[0] as *i64 205 let dir: *i64 = e[6] as *i64 206 let depth: *i64 = e[7] as *i64 207 let vstart: *i64 = e[8] as *i64 208 let vcount: *i64 = e[9] as *i64 209 var p: i64 = 0 210 while p < e[4] { 211 let mag: i64 = ex3_disp_mag(t, depth[p]) 212 let dx: i64 = (dir[p * 3 + 0] * mag) / EX3_ONE 213 let dy: i64 = (dir[p * 3 + 1] * mag) / EX3_ONE 214 let dz: i64 = (dir[p * 3 + 2] * mag) / EX3_ONE 215 var i: i64 = vstart[p] 216 let iend: i64 = vstart[p] + vcount[p] 217 while i < iend { 218 wverts[i * 4 + 0] = lv[i * 4 + 0] + dx 219 wverts[i * 4 + 1] = lv[i * 4 + 1] + dy 220 wverts[i * 4 + 2] = lv[i * 4 + 2] + dz 221 wverts[i * 4 + 3] = lv[i * 4 + 3] 222 i = i + 1 223 } 224 p = p + 1 225 } 226 return 0 227} 228 229// mean pairwise L1 distance between part centroids at explode factor t (integer, deterministic) 230func ex3_mean_pairdist(e: *i64, t: i64) -> i64 { 231 let home: *i64 = e[5] as *i64 232 let dir: *i64 = e[6] as *i64 233 let depth: *i64 = e[7] as *i64 234 let n: i64 = e[4] 235 if n < 2 { return 0 } 236 var total: i64 = 0 237 var pairs: i64 = 0 238 var i: i64 = 0 239 while i < n { 240 let mi: i64 = ex3_disp_mag(t, depth[i]) 241 let xi: i64 = home[i * 3 + 0] + (dir[i * 3 + 0] * mi) / EX3_ONE 242 let yi: i64 = home[i * 3 + 1] + (dir[i * 3 + 1] * mi) / EX3_ONE 243 let zi: i64 = home[i * 3 + 2] + (dir[i * 3 + 2] * mi) / EX3_ONE 244 var j: i64 = i + 1 245 while j < n { 246 let mj: i64 = ex3_disp_mag(t, depth[j]) 247 let xj: i64 = home[j * 3 + 0] + (dir[j * 3 + 0] * mj) / EX3_ONE 248 let yj: i64 = home[j * 3 + 1] + (dir[j * 3 + 1] * mj) / EX3_ONE 249 let zj: i64 = home[j * 3 + 2] + (dir[j * 3 + 2] * mj) / EX3_ONE 250 var ax: i64 = xi - xj 251 if ax < 0 { ax = 0 - ax } 252 var ay: i64 = yi - yj 253 if ay < 0 { ay = 0 - ay } 254 var az: i64 = zi - zj 255 if az < 0 { az = 0 - az } 256 total = total + ax + ay + az 257 pairs = pairs + 1 258 j = j + 1 259 } 260 i = i + 1 261 } 262 return total / pairs 263} 264 265// mean displacement magnitude (Q14 L1 of the applied offset) over parts of exactly depth d at factor t 266func ex3_mean_disp_at_depth(e: *i64, t: i64, d: i64) -> i64 { 267 let dir: *i64 = e[6] as *i64 268 let depth: *i64 = e[7] as *i64 269 var total: i64 = 0 270 var cnt: i64 = 0 271 var p: i64 = 0 272 while p < e[4] { 273 if depth[p] == d { 274 let mag: i64 = ex3_disp_mag(t, depth[p]) 275 var dx: i64 = (dir[p * 3 + 0] * mag) / EX3_ONE 276 if dx < 0 { dx = 0 - dx } 277 var dy: i64 = (dir[p * 3 + 1] * mag) / EX3_ONE 278 if dy < 0 { dy = 0 - dy } 279 var dz: i64 = (dir[p * 3 + 2] * mag) / EX3_ONE 280 if dz < 0 { dz = 0 - dz } 281 total = total + dx + dy + dz 282 cnt = cnt + 1 283 } 284 p = p + 1 285 } 286 if cnt == 0 { return 0 } 287 return total / cnt 288}