code wiki / (root) / nx_morf_eval_core.nx

nx_morf_eval_core.nx source

↩ module page · 144 lines · 6135 B

1// ORIGINAL. Pure MORF arithmetic extracted from the admitted mf_eval path. 2// No file parser, allocations, globals, hardware access or rendering policy. 3// The owner admits NXA through nxa_section_entry/nxa_counted_section and the 4// existing MORF shape/membership checks, then lends immutable arrays here. 5const MVC_I64_MAX: i64 = 9223372036854775807 6const MVC_WORD: i64 = 8 7const MVC_AXES: i64 = 3 8const MVC_E_SHAPE: i64 = 0 - 1 9const MVC_E_ALIAS: i64 = 0 - 2 10const MVC_E_PRODUCT: i64 = 0 - 3 11const MVC_E_SUM: i64 = 0 - 4 12 13struct MvcView { 14 bind: *i64 15 bind_words: i64 16 face: *i64 17 face_words: i64 18 delta: *i64 19 delta_words: i64 20 vertices: i64 21 faces: i64 22 channels: i64 23 unit: i64 24} 25 26// Representation checks precede address arithmetic. Empty borrowed slices may be null. 27func mvc_span(p: *i64, words: i64) -> i64 { 28 if words < 0 { return 0 } 29 if words == 0 { return 1 } 30 if words > MVC_I64_MAX/MVC_WORD { return 0 } 31 let address: i64 = p as i64 32 if address <= 0 { return 0 } 33 if address > MVC_I64_MAX-words*MVC_WORD { return 0 } 34 return 1 35} 36func mvc_overlap(a: *i64, an: i64, b: *i64, bn: i64) -> i64 { 37 if an == 0 { return 0 }; if bn == 0 { return 0 } 38 let ap: i64 = a as i64; let bp: i64 = b as i64 39 if ap < bp+bn*MVC_WORD { if bp < ap+an*MVC_WORD { return 1 } } 40 return 0 41} 42// These signed product branches preserve the current producer's exact admission. 43func mvc_product_ok(dv: i64, weight: i64) -> i64 { 44 let imax: i64 = MVC_I64_MAX; let imin: i64 = 0-imax-1 45 if dv > 0 { 46 if weight > 0 { if dv > imax/weight { return 0 } } 47 if weight < 0 { if weight < imin/dv { return 0 } } 48 } 49 if dv < 0 { 50 if weight > 0 { if dv < imin/weight { return 0 } } 51 if weight < 0 { if dv < imax/weight { return 0 } } 52 } 53 return 1 54} 55func mvc_sum_ok(old: i64, add: i64) -> i64 { 56 let imax: i64 = MVC_I64_MAX; let imin: i64 = 0-imax-1 57 if add > 0 { if old > imax-add { return 0 } } 58 if add < 0 { if old < imin-add { return 0 } } 59 return 1 60} 61 62// Caller retains ownership and must not mutate borrowed inputs during the call. 63// FACE uniqueness is established at asset admission, not re-scanned every frame. 64// Channels accumulate in declared order, truncating each contribution separately. 65// Return changed FACE vertex count, or a named negative error; errors never alter output. 66func mvc_apply(v: *MvcView, weights: *i64, weight_words: i64, out: *i64, out_words: i64) -> i64 { 67 if (v as i64) <= 0 { return MVC_E_SHAPE } 68 if v.vertices < 1 { return MVC_E_SHAPE } 69 if v.vertices > MVC_I64_MAX/MVC_AXES { return MVC_E_SHAPE } 70 let coords: i64 = v.vertices*MVC_AXES 71 if v.bind_words != coords { return MVC_E_SHAPE } 72 if out_words != coords { return MVC_E_SHAPE } 73 if v.faces < 0 { return MVC_E_SHAPE }; if v.faces > v.vertices { return MVC_E_SHAPE } 74 if v.face_words != v.faces { return MVC_E_SHAPE } 75 if v.channels < 0 { return MVC_E_SHAPE } 76 if weight_words != v.channels { return MVC_E_SHAPE } 77 if v.delta_words < 0 { return MVC_E_SHAPE } 78 if v.channels == 0 { 79 if v.faces != 0 { return MVC_E_SHAPE } 80 if v.delta_words != 0 { return MVC_E_SHAPE } 81 } else { 82 if v.faces == 0 { return MVC_E_SHAPE } 83 if v.unit <= 0 { return MVC_E_SHAPE } 84 if v.delta_words % v.channels != 0 { return MVC_E_SHAPE } 85 let per: i64 = v.delta_words/v.channels 86 if per % MVC_AXES != 0 { return MVC_E_SHAPE } 87 if per/MVC_AXES != v.faces { return MVC_E_SHAPE } 88 } 89 if mvc_span(v.bind,v.bind_words) == 0 { return MVC_E_SHAPE } 90 if mvc_span(v.face,v.face_words) == 0 { return MVC_E_SHAPE } 91 if mvc_span(v.delta,v.delta_words) == 0 { return MVC_E_SHAPE } 92 if mvc_span(weights,weight_words) == 0 { return MVC_E_SHAPE } 93 if mvc_span(out,out_words) == 0 { return MVC_E_SHAPE } 94 if mvc_overlap(out,out_words,v.bind,v.bind_words) == 1 { return MVC_E_ALIAS } 95 if mvc_overlap(out,out_words,v.face,v.face_words) == 1 { return MVC_E_ALIAS } 96 if mvc_overlap(out,out_words,v.delta,v.delta_words) == 1 { return MVC_E_ALIAS } 97 if mvc_overlap(out,out_words,weights,weight_words) == 1 { return MVC_E_ALIAS } 98 // The view itself is caller-owned too; output may not overwrite its pointer fields. 99 if mvc_overlap(out,out_words,v as *i64,__size_of(MvcView)/MVC_WORD) == 1 { return MVC_E_ALIAS } 100 var row: i64 = 0; var moved: i64 = 0 101 while row < v.faces { 102 let vi: i64 = v.face[row] 103 if vi < 0 { return MVC_E_SHAPE }; if vi >= v.vertices { return MVC_E_SHAPE } 104 var axis: i64 = 0; var changed: i64 = 0 105 while axis < MVC_AXES { 106 let original: i64 = v.bind[vi*MVC_AXES+axis] 107 var value: i64 = original; var ch: i64 = 0 108 while ch < v.channels { 109 let weight: i64 = weights[ch] 110 if weight != 0 { 111 let dv: i64 = v.delta[(ch*v.faces+row)*MVC_AXES+axis] 112 if mvc_product_ok(dv,weight) == 0 { return MVC_E_PRODUCT } 113 let add: i64 = dv*weight/v.unit 114 if mvc_sum_ok(value,add) == 0 { return MVC_E_SUM } 115 value = value+add 116 } 117 ch = ch+1 118 } 119 if value != original { changed = 1 }; axis = axis+1 120 } 121 if changed == 1 { moved = moved+1 }; row = row+1 122 } 123 // Commit only after all vertex/channel arithmetic has passed. 124 var at: i64 = 0 125 while at < coords { out[at] = v.bind[at]; at = at+1 } 126 row = 0 127 while row < v.faces { 128 let vi: i64 = v.face[row]; var axis: i64 = 0 129 while axis < MVC_AXES { 130 var value: i64 = v.bind[vi*MVC_AXES+axis]; var ch: i64 = 0 131 while ch < v.channels { 132 let weight: i64 = weights[ch] 133 if weight != 0 { 134 let dv: i64 = v.delta[(ch*v.faces+row)*MVC_AXES+axis] 135 value = value+dv*weight/v.unit 136 } 137 ch = ch+1 138 } 139 out[vi*MVC_AXES+axis] = value; axis = axis+1 140 } 141 row = row+1 142 } 143 return moved 144}