code wiki / (root) / nx_morf_draw_core.nx

nx_morf_draw_core.nx source

↩ module page · 115 lines · 5813 B

1// ORIGINAL. One caller-owned pre-skinning draw view; no asset parser or mood policy. 2// Inputs are admitted immutable arrays. Outputs are DISPOSABLE scratch, valid only 3// on nonnegative return; publish/upload their generation only after success. 4import "nx_morf_eval_core.nx" 5import "nx_vnormals_lib.nx" 6 7const MRD_E_SHAPE: i64 = 0-61 8const MRD_E_ALIAS: i64 = 0-62 9const MRD_E_TRIANGLE: i64 = 0-63 10const MRD_E_NORMAL_RANGE: i64 = 0-64 11 12struct MrdAsset { 13 morph: *MvcView 14 triangles: *i64 15 triangle_words: i64 16 bind_normals: *i64 17 normal_words: i64 18} 19 20// Nonnegative representable absolute difference, or named refusal. No abs(MIN). 21func mrd_abs_difference(a: i64, b: i64) -> i64 { 22 var high: i64 = a; var low: i64 = b 23 if a < b { high = b; low = a } 24 if low < 0 { if high > MVC_I64_MAX+low { return MRD_E_NORMAL_RANGE } } 25 return high-low 26} 27 28// Conservative proof for the unchanged shared normal owner: 29// each edge component <= E, face cross component <= 2 E^2, 30// accumulated component <= 2 E^2 D, where D counts incident triangle entries. 31// This bounds every intermediate, length-square and VN_SCALE multiplication. 32// A refusal means this representation is unproven; it is never a quality verdict. 33func mrd_normal_envelope(positions: *i64, tri: *i64, nt: i64, degree: i64) -> i64 { 34 var edge: i64 = 0; var t: i64 = 0 35 while t < nt { 36 let first: i64 = tri[t*VN_TRI_I] 37 var other: i64 = 1 38 while other < VN_TRI_I { 39 let vertex: i64 = tri[t*VN_TRI_I+other]; var axis: i64 = 0 40 while axis < VN_V3 { 41 let d: i64 = mrd_abs_difference(positions[vertex*VN_V3+axis],positions[first*VN_V3+axis]) 42 if d < 0 { return MRD_E_NORMAL_RANGE } 43 if d > edge { edge = d }; axis = axis+1 44 } 45 other = other+1 46 } 47 t = t+1 48 } 49 if edge == 0 { return 0 }; if degree == 0 { return 0 } 50 if mvc_product_ok(edge,edge) == 0 { return MRD_E_NORMAL_RANGE } 51 let square: i64 = edge*edge 52 if mvc_product_ok(square,2) == 0 { return MRD_E_NORMAL_RANGE } 53 let cross: i64 = square*2 54 if mvc_product_ok(cross,degree) == 0 { return MRD_E_NORMAL_RANGE } 55 let component: i64 = cross*degree 56 if component > (MVC_I64_MAX/VN_V3)/component { return MRD_E_NORMAL_RANGE } 57 if mvc_product_ok(component,VN_SCALE) == 0 { return MRD_E_NORMAL_RANGE } 58 return 0 59} 60 61func mrd_prepare(a: *MrdAsset, weights: *i64, weight_words: i64, positions: *i64, position_words: i64, normals: *i64, normal_words: i64) -> i64 { 62 if (a as i64) <= 0 { return MRD_E_SHAPE } 63 let v: *MvcView = a.morph 64 if (v as i64) <= 0 { return MRD_E_SHAPE } 65 if normal_words != position_words { return MRD_E_SHAPE } 66 if normal_words != a.normal_words { return MRD_E_SHAPE } 67 if position_words != v.bind_words { return MRD_E_SHAPE } 68 if a.triangle_words < 0 { return MRD_E_SHAPE } 69 if a.triangle_words % VN_TRI_I != 0 { return MRD_E_SHAPE } 70 if mvc_span(a.triangles,a.triangle_words) == 0 { return MRD_E_SHAPE } 71 if mvc_span(a.bind_normals,a.normal_words) == 0 { return MRD_E_SHAPE } 72 if mvc_span(normals,normal_words) == 0 { return MRD_E_SHAPE } 73 if mvc_span(positions,position_words) == 0 { return MRD_E_SHAPE } 74 if mvc_span(v.bind,v.bind_words) == 0 { return MRD_E_SHAPE } 75 if mvc_span(v.face,v.face_words) == 0 { return MRD_E_SHAPE } 76 if mvc_span(v.delta,v.delta_words) == 0 { return MRD_E_SHAPE } 77 if mvc_span(weights,weight_words) == 0 { return MRD_E_SHAPE } 78 if mvc_overlap(normals,normal_words,positions,position_words) == 1 { return MRD_E_ALIAS } 79 if mvc_overlap(normals,normal_words,v.bind,v.bind_words) == 1 { return MRD_E_ALIAS } 80 if mvc_overlap(normals,normal_words,v.face,v.face_words) == 1 { return MRD_E_ALIAS } 81 if mvc_overlap(normals,normal_words,v.delta,v.delta_words) == 1 { return MRD_E_ALIAS } 82 if mvc_overlap(normals,normal_words,weights,weight_words) == 1 { return MRD_E_ALIAS } 83 if mvc_overlap(normals,normal_words,a.triangles,a.triangle_words) == 1 { return MRD_E_ALIAS } 84 if mvc_overlap(normals,normal_words,a.bind_normals,a.normal_words) == 1 { return MRD_E_ALIAS } 85 if mvc_overlap(positions,position_words,a.triangles,a.triangle_words) == 1 { return MRD_E_ALIAS } 86 if mvc_overlap(positions,position_words,a.bind_normals,a.normal_words) == 1 { return MRD_E_ALIAS } 87 if mvc_overlap(normals,normal_words,v as *i64,__size_of(MvcView)/MVC_WORD) == 1 { return MRD_E_ALIAS } 88 if mvc_overlap(normals,normal_words,a as *i64,__size_of(MrdAsset)/MVC_WORD) == 1 { return MRD_E_ALIAS } 89 if mvc_overlap(positions,position_words,a as *i64,__size_of(MrdAsset)/MVC_WORD) == 1 { return MRD_E_ALIAS } 90 // Core admission and arithmetic must succeed before topology scratch is used. 91 let moved: i64 = mvc_apply(v,weights,weight_words,positions,position_words) 92 if moved < 0 { return moved } 93 if moved == 0 { 94 var copy: i64 = 0 95 while copy < normal_words { normals[copy] = a.bind_normals[copy]; copy = copy+1 } 96 return 0 97 } 98 // Reuse normal output as degree scratch; no hidden per-entity allocation. 99 var i: i64 = 0 100 while i < v.vertices { normals[i] = 0; i = i+1 } 101 var degree: i64 = 0; i = 0 102 while i < a.triangle_words { 103 let vertex: i64 = a.triangles[i] 104 if vertex < 0 { return MRD_E_TRIANGLE } 105 if vertex >= v.vertices { return MRD_E_TRIANGLE } 106 normals[vertex] = normals[vertex]+1 107 if normals[vertex] > degree { degree = normals[vertex] } 108 i = i+1 109 } 110 let nt: i64 = a.triangle_words/VN_TRI_I 111 if mrd_normal_envelope(positions,a.triangles,nt,degree) < 0 { return MRD_E_NORMAL_RANGE } 112 let rc: i64 = vn_smooth_area(positions,a.triangles,v.vertices,nt,normals) 113 if rc < 0 { return rc } 114 return moved 115}