code wiki / (root) / nx_morph.nx

nx_morph.nx source

↩ module page · 137 lines · 4992 B

1// nx_morph.nx -- MORPH TARGETS AS DATA (Elara bar E3; VAMX R4): a morph = a bank of vertex DELTAS over an 2// nx_mesh3 base mesh + a weight slider 0..256; morphs COMPOSE additively (v' = v + sum w_m*delta_m/256). 3// Applied to the BIND-POSE mesh BEFORE skinning (industry standard). THE POINT: a body/face slider is PURE 4// DATA -- serializable to a pack blob (NXM1 format) that ships through the CID mod economy exactly like 5// mineworld block packs. ALL INTEGER, base-relative, non-destructive apply (base mesh -> out mesh). 6// license_tier: ORIGINAL 7import "nx_syscalls.nx" 8import "nx_mesh3.nx" 9const MO_MAGIC_2147483648: i64 = 2147483648 10const MO_MAGIC_4294967296: i64 = 4294967296 11 12// bank header: [0]=nmorphs [1]=ndeltas_total ; morph dir at 64: 4 slots each {id, ndeltas, delta_off, spare} 13// delta pool after dir: 4 slots each {vi, dx, dy, dz} 14const MO_MAXM: i64 = 32 15const MO_MAXD: i64 = 16384 16 17func mo_hdr(base: i64) -> *i64 { return base as *i64 } 18func mo_dir(base: i64, m: i64) -> *i64 { return (base + 64 + m * 32) as *i64 } 19func mo_delta(base: i64, d: i64) -> *i64 { return (base + 64 + MO_MAXM * 32 + d * 32) as *i64 } 20func mo_bytes() -> i64 { return 64 + MO_MAXM * 32 + MO_MAXD * 32 + 64 } 21 22func mo_init(base: i64) -> i64 { 23 let h: *i64 = mo_hdr(base) 24 h[0] = 0 25 h[1] = 0 26 return 0 27} 28func mo_begin(base: i64, id: i64) -> i64 { 29 let h: *i64 = mo_hdr(base) 30 if h[0] >= MO_MAXM { return 0 - 1 } 31 let d: *i64 = mo_dir(base, h[0]) 32 d[0] = id 33 d[1] = 0 34 d[2] = h[1] 35 h[0] = h[0] + 1 36 return h[0] - 1 37} 38func mo_add_delta(base: i64, m: i64, vi: i64, dx: i64, dy: i64, dz: i64) -> i64 { 39 let h: *i64 = mo_hdr(base) 40 if h[1] >= MO_MAXD { return 0 - 1 } 41 let dd: *i64 = mo_delta(base, h[1]) 42 dd[0] = vi; dd[1] = dx; dd[2] = dy; dd[3] = dz 43 let d: *i64 = mo_dir(base, m) 44 d[1] = d[1] + 1 45 h[1] = h[1] + 1 46 return 0 47} 48 49// non-destructive apply: copy base mesh verts+tris into out mesh, then add weighted deltas. 50// weights: one 0..256 slider per morph (array of h[0] entries). 51func mo_apply(base: i64, meshIn: i64, meshOut: i64, weights: *i64) -> i64 { 52 let hin: *i64 = m3_hdr(meshIn) 53 m3_init(meshOut) 54 var i: i64 = 0 55 while i < hin[0] { 56 let v: *i64 = m3_vert(meshIn, i) 57 m3_add_vert(meshOut, v[0], v[1], v[2]) 58 i = i + 1 59 } 60 i = 0 61 while i < hin[1] { 62 let t: *i64 = m3_tri(meshIn, i) 63 m3_add_tri(meshOut, t[0], t[1], t[2]) 64 i = i + 1 65 } 66 let h: *i64 = mo_hdr(base) 67 var m: i64 = 0 68 while m < h[0] { 69 let w: i64 = weights[m] 70 if w != 0 { 71 let d: *i64 = mo_dir(base, m) 72 var k: i64 = 0 73 while k < d[1] { 74 let dd: *i64 = mo_delta(base, d[2] + k) 75 let ov: *i64 = m3_vert(meshOut, dd[0]) 76 ov[0] = ov[0] + dd[1] * w / 256 77 ov[1] = ov[1] + dd[2] * w / 256 78 ov[2] = ov[2] + dd[3] * w / 256 79 k = k + 1 80 } 81 } 82 m = m + 1 83 } 84 return 0 85} 86 87// ---- THE PACK FORMAT (the mod-economy artifact): "NXM1" + id + ndeltas + records {vi,dx,dy,dz} as i32 LE ---- 88func mo_w32(buf: *u8, off: i64, v: i64) -> i64 { 89 buf[off] = (v & 255) as u8 90 buf[off + 1] = ((v >> 8) & 255) as u8 91 buf[off + 2] = ((v >> 16) & 255) as u8 92 buf[off + 3] = ((v >> 24) & 255) as u8 93 return 0 94} 95func mo_r32(buf: *u8, off: i64) -> i64 { 96 var v: i64 = (buf[off] as i64) | ((buf[off + 1] as i64) << 8) | ((buf[off + 2] as i64) << 16) | ((buf[off + 3] as i64) << 24) 97 if v >= MO_MAGIC_2147483648 { v = v - MO_MAGIC_4294967296 } // sign-extend i32 98 return v 99} 100// serialize morph m -> buf; returns byte length 101func mo_save(base: i64, m: i64, buf: *u8) -> i64 { 102 let d: *i64 = mo_dir(base, m) 103 buf[0] = 78 as u8; buf[1] = 88 as u8; buf[2] = 77 as u8; buf[3] = 49 as u8 // "NXM1" 104 mo_w32(buf, 4, d[0]) 105 mo_w32(buf, 8, d[1]) 106 var k: i64 = 0 107 while k < d[1] { 108 let dd: *i64 = mo_delta(base, d[2] + k) 109 let rec: i64 = 12 + k * 16 110 mo_w32(buf, rec, dd[0]) 111 mo_w32(buf, rec + 4, dd[1]) 112 mo_w32(buf, rec + 8, dd[2]) 113 mo_w32(buf, rec + 12, dd[3]) 114 k = k + 1 115 } 116 return 12 + d[1] * 16 117} 118// load a pack blob into the bank as a NEW morph; returns the morph index (-1 = bad blob) 119func mo_load(base: i64, buf: *u8, len: i64) -> i64 { 120 if len < 12 { return 0 - 1 } 121 if buf[0] as i64 != 78 { return 0 - 1 } 122 if buf[1] as i64 != 88 { return 0 - 1 } 123 if buf[2] as i64 != 77 { return 0 - 1 } 124 if buf[3] as i64 != 49 { return 0 - 1 } 125 let id: i64 = mo_r32(buf, 4) 126 let nd: i64 = mo_r32(buf, 8) 127 if len < 12 + nd * 16 { return 0 - 1 } 128 let m: i64 = mo_begin(base, id) 129 if m < 0 { return 0 - 1 } 130 var k: i64 = 0 131 while k < nd { 132 let rec: i64 = 12 + k * 16 133 mo_add_delta(base, m, mo_r32(buf, rec), mo_r32(buf, rec + 4), mo_r32(buf, rec + 8), mo_r32(buf, rec + 12)) 134 k = k + 1 135 } 136 return m 137}