code wiki / (root) / nx_uvunwrap_lib.nx

nx_uvunwrap_lib.nx

buildroot/runtime/nx_uvunwrap_lib.nx

75241 B1642 linesdepth 3pulls 5 transitivereach 33 importersview sourcekind library
docsdependenciesstructsconstsfunctions

about

nx_uvunwrap_lib.nx -- A GENERAL UV UNWRAP FOR AN ARBITRARY MESH, WITH A DISTORTION REFEREE (/compare/dcc DC5). WHAT WAS ABSENT, MEASURED NOT ASSERTED. nx_capsearch over 6,892 organs (1,375 tools + 5,517 libs, corpus_complete=1) returned NO general parameterisation: the estate's only unwrap is ntx_apply in nx_nxa_texc_lib, a bone-anchored CYLINDRICAL map that reads SKEL parents and SKIN weights and refuses outright without them ("no SKIN section -- refusing to fabricate bone ownership"). That is the right design for a humanoid NXA and it is unreachable for everything else: a sculpt, a boolean result, a terrain patch, a retopologised prop has no skeleton to anchor to, so it could not be unwrapped AT ALL, and texture painting was blocked for every non-humanoid asset in the estate. OUTPUT IS WIRE-COMPATIBLE WITH THE INCUMBENT BAKE PATH ON PURPOSE. uv_emit_texc writes exactly the TEXC payload nx_nxa_texbake_lib already consumes -- header [nv][stride 3][atlas grid g][reserved 0] then per vertex [u Q16][v Q16][chart], charts owning disjoint tiles of a g x g grid with a one-unit gutter, the same shape and the same fixed-point scale ntx_apply emits. So a mesh unwrapped here bakes through the existing sampler with nothing else changed. BUT THE BRIDGE IS LOSSY AND IT SAYS SO. TEXC is PER VERTEX and a seam is exactly the place where one mesh vertex needs TWO texture coordinates, so the incumbent wire format cannot represent a seam at all. This library solves per CORNER (a mesh vertex split by seams into several UV vertices, which is what makes a cut actually cut), and uv_emit_texc COUNTS the vertices whose extra coordinates the per-vertex form drops, into UV_H_TEXCLOSS. A lossy conversion that reports zero loss would be the defect; one that names its loss is a bridge. THE HONEST ALGORITHM. A least-squares conformal map (Levy et al., LSCM) needs a linear solve, and there is no linear solver in this estate and no float type to build one on. So this is an ITERATIVE relaxation toward the same stationary condition, and every part of that choice is declared rather than hidden: * The energy is the LSCM energy in its Dirichlet-minus-area form, E = sum_edges W|dU|^2 - 2 sum_t A_t. THAT SECOND TERM IS THE WHOLE REASON THIS DOES NOT COLLAPSE. A pure harmonic (Dirichlet-only) relaxation with a free boundary and two pinned vertices has its minimum at the degenerate map that puts every vertex on the segment between the pins -- a fold, scoring zero by every naive measure. The -2*area term rewards area and makes the non-degenerate map the minimiser instead. * Setting dE/dU_p = 0 gives a closed-form per-vertex update, so this is a damped Jacobi sweep over the exact stationary condition rather than an invented heuristic. Interior vertices see a pure cotangent-Laplacian average (their one-ring area terms telescope to zero); the area term acts only on the boundary, pushing it outward. That is LSCM, iterated. * TWO PINNED VERTICES PER CHART, the standard LSCM constraint: the conformal energy is invariant to translation, rotation and scale, so two pins remove exactly the null space and no more. * The iteration bound is DERIVED FROM THE CHART, the convergence criterion is DECLARED, and a chart that reaches neither is REFUSED BY NAME (UV_E_NOCONVERGE) rather than emitted folded. THE REFEREE IS THE POINT. uv_distortion reports angle (quasi-conformal dilatation) and area distortion

dependencies 3 imports · 2 importers

nx_syscalls.nx nx_vecmath.nx nx_meshvalid_lib.nx nx_uvunwrap_lib.nx nx_nxa_corner_prepare_candidate_t2 nx_uvunwrap_gate.nx

imports: nx_syscalls.nxnx_vecmath.nxnx_meshvalid_lib.nx

imported by: nx_nxa_corner_prepare_candidate_t280.nxnx_uvunwrap_gate.nx

structs

none

consts

58const UV_H_NV: i64 = 0
59const UV_H_NT: i64 = 1
60const UV_H_ECAP: i64 = 2
61const UV_H_SCAP: i64 = 3
62const UV_H_NC: i64 = 4
63const UV_H_NUV: i64 = 5
64const UV_H_ERR: i64 = 6
65const UV_H_STAGE: i64 = 7
66const UV_H_GRID: i64 = 8
67const UV_H_NSEAM: i64 = 9
68const UV_H_ITERS: i64 = 10
69const UV_H_MAXMOVE: i64 = 11
70const UV_H_FLIP: i64 = 12
71const UV_H_SING: i64 = 13
72const UV_H_UVDEGEN: i64 = 14
73const UV_H_NOCONV: i64 = 15
74const UV_H_ANGMEAN: i64 = 16
75const UV_H_ANGMAX: i64 = 17
76const UV_H_AREAMEAN: i64 = 18
77const UV_H_AREAMAX: i64 = 19
78const UV_H_OVERLAP: i64 = 20
79const UV_H_TEXCLOSS: i64 = 21
80const UV_H_MVERR: i64 = 22
81const UV_H_MVCLOSED: i64 = 23
82const UV_H_NCORN: i64 = 24
84const UV_O_VERT: i64 = 25
85const UV_O_TRI: i64 = 26
86const UV_O_ETAB: i64 = 27
87const UV_O_STAB: i64 = 28
88const UV_O_TCHART: i64 = 29
89const UV_O_STACK: i64 = 30
90const UV_O_CSTART: i64 = 31
91const UV_O_CORDER: i64 = 32
92const UV_O_UVF: i64 = 33
93const UV_O_UVSRC: i64 = 34
94const UV_O_UVCH: i64 = 35
95const UV_O_WU: i64 = 36
96const UV_O_WV: i64 = 37
97const UV_O_ACCU: i64 = 38
98const UV_O_ACCV: i64 = 39
99const UV_O_ACCW: i64 = 40
100const UV_O_ACCAU: i64 = 41
101const UV_O_ACCAV: i64 = 42
102const UV_O_CUV: i64 = 43
103const UV_O_TANG: i64 = 44
104const UV_O_TRAT: i64 = 45
105const UV_O_TSAR: i64 = 46
106const UV_O_CBOX: i64 = 47
107const UV_O_CCNT: i64 = 48
108const UV_O_CDIST: i64 = 49
109const UV_O_LIST: i64 = 50
110const UV_O_STAMP: i64 = 51
111const UV_O_TSEEN: i64 = 52
112const UV_O_PLACED: i64 = 53
113const UV_O_ROOT: i64 = 54
118const UV_HDR: i64 = 64
119const UV_I64: i64 = 8
120const UV_TRI: i64 = 3
121const UV_EREC: i64 = 4 // edge record: [lo, hi, tri0+1, tri1+1]
122const UV_SREC: i64 = 3 // seam record: [lo, hi, used]
126const UV_ED_LO: i64 = 0
127const UV_ED_HI: i64 = 1
128const UV_ED_T0: i64 = 2 // first triangle, stored +1 so that 0 reads as EMPTY
129const UV_ED_T1: i64 = 3 // second triangle, same +1 bias
130const UV_SM_LO: i64 = 0
131const UV_SM_HI: i64 = 1
132const UV_SM_USED: i64 = 2
133const UV_ACCN: i64 = 5 // accU accV accW accAU accAV
141const UV_CUVREC: i64 = 2 // per-corner uv pair: [u, v]
142const UV_BOXREC: i64 = 4 // per-chart uv bounds: [u0, v0, u1, v1]
143const UV_DISTREC: i64 = 4 // per-chart distortion: [amean, amax, dmean, dmax]
144const UV_P_U: i64 = 0
145const UV_P_V: i64 = 1
146const UV_B_U0: i64 = 0
147const UV_B_V0: i64 = 1
148const UV_B_U1: i64 = 2
149const UV_B_V1: i64 = 3
150const UV_D_AMEAN: i64 = 0
151const UV_D_AMAX: i64 = 1
152const UV_D_DMEAN: i64 = 2
153const UV_D_DMAX: i64 = 3
159const UV_X_HDR: i64 = 4
160const UV_X_NV: i64 = 0
161const UV_X_STRIDE: i64 = 1
162const UV_X_GRID: i64 = 2
163const UV_X_RSVD: i64 = 3
164const UV_X_U: i64 = 0 // per-vertex payload slots, relative to that vertex's record base
165const UV_X_V: i64 = 1
166const UV_X_CH: i64 = 2
169const UV_ST_NEW: i64 = 0
170const UV_ST_CHARTS: i64 = 1
171const UV_ST_SOLVED: i64 = 2
172const UV_ST_MEASURED: i64 = 3
176const UV_OK: i64 = 0
177const UV_E_ARGS: i64 = 0 - 1
178const UV_E_TOPOLOGY: i64 = 0 - 2
179const UV_E_NOPIN: i64 = 0 - 3
180const UV_E_NOCONVERGE: i64 = 0 - 4
181const UV_E_FOLD: i64 = 0 - 5
182const UV_E_UVDEGEN: i64 = 0 - 6
183const UV_E_OVERLAP: i64 = 0 - 7
184const UV_E_STAGE: i64 = 0 - 8
185const UV_E_SPAN: i64 = 0 - 9
186const UV_E_NOTRUN: i64 = 0 - 10
191const UV_E_UNPLACED: i64 = 0 - 11
197const UV_Q16: i64 = 65536
198const UV_Q16M: i64 = 65535
202const UV_GUTTER: i64 = 1
206const UV_W_Q: i64 = 4096
212const UV_PIN_SPAN: i64 = 1048576
215const UV_GUESS_SPAN: i64 = 65536
220const UV_COT_CLAMP: i64 = 64
227const UV_CONV_EPS: i64 = 32
233const UV_ITER_PER_UVV: i64 = 32
235const UV_ITER_MIN: i64 = 64
241const UV_OMEGA_DEN: i64 = 2
246const UV_ABC_MAX: i64 = 1048576
251const UV_SS_MAX: i64 = 1000000000
256const UV_SDEN_MAX: i64 = 100000000000
257const UV_PERMIL: i64 = 1000
258const UV_MIN_PINS: i64 = 2
816const UV_UNF_Q: i64 = 4096

functions

260func uv_err_name(e: i64) -> *u8
called by 1: main
281func uv_layout(h: *i64) -> i64
called by 2: ncp_model_newuv_new
327func uv_new(nv: i64, nt: i64) -> *i64
354func uv_words_used(m: *i64) -> i64 { return m[UV_O_CDIST] + m[UV_H_NT] * UV_DISTREC }
356func uv_set_vert(m: *i64, i: i64, x: i64, y: i64, z: i64) -> i64
366func uv_set_tri(m: *i64, i: i64, a: i64, b: i64, c: i64) -> i64
376func uv_vx(m: *i64, v: i64) -> i64 { return m[m[UV_O_VERT] + v * UV_TRI + 0] }
377func uv_vy(m: *i64, v: i64) -> i64 { return m[m[UV_O_VERT] + v * UV_TRI + 1] }
378func uv_vz(m: *i64, v: i64) -> i64 { return m[m[UV_O_VERT] + v * UV_TRI + 2] }
379func uv_ti(m: *i64, t: i64, k: i64) -> i64 { return m[m[UV_O_TRI] + t * UV_TRI + k] }
388func uv_seam_set(m: *i64, a: i64, b: i64) -> i64
419func uv_is_seam(m: *i64, a: i64, b: i64) -> i64
440func uvi_edge_slot(m: *i64, a: i64, b: i64, t: i64) -> i64
called by 1: uv_chart_build calls 1: mv_mix
467func uvi_edge_find(m: *i64, a: i64, b: i64) -> i64
486func uvi_find(f: *i64, base: i64, x: i64) -> i64
492func uvi_union(f: *i64, base: i64, a: i64, b: i64) -> i64
called by 2: uct_measureuv_chart_build calls 1: uvi_find
501func uvi_corner_of(m: *i64, t: i64, v: i64) -> i64
517func uvi_validate(m: *i64) -> i64
542func uv_chart_build(m: *i64) -> i64
706func uv_chart_count(m: *i64) -> i64 { return m[UV_H_NC] }
707func uv_uvvert_count(m: *i64) -> i64 { return m[UV_H_NUV] }
called by 1: main
708func uv_seam_count(m: *i64) -> i64 { return m[UV_H_NSEAM] }
709func uv_chart_of_tri(m: *i64, t: i64) -> i64
715func uv_chart_tris(m: *i64, c: i64) -> i64
called by 3: ua_reusemainmain
723func uvi_chart_classes(m: *i64, c: i64) -> i64
751func uvi_d2(m: *i64, va: i64, vb: i64) -> i64
763func uv_pins_for(m: *i64, c: i64, out: *i64) -> i64
793func uvi_cotq(m: *i64, vi: i64, vj: i64, vk: i64) -> i64
819func uvi_len_q(m: *i64, va: i64, vb: i64) -> i64
832func uvi_place_third(m: *i64, tp: i64, tn: i64, va: i64, vb: i64) -> i64
875func uvi_unfold(m: *i64, c: i64, n: i64) -> i64
974func uvi_initial(m: *i64, c: i64, n: i64, pa: i64, pb: i64) -> i64
1028func uvi_solve_chart(m: *i64, c: i64) -> i64
1136func uv_grid_for(nc: i64) -> i64
called by 1: uvi_atlas
1145func uvi_atlas(m: *i64) -> i64
1217func uv_conformal(m: *i64) -> i64
1237func uv_iters(m: *i64) -> i64 { return m[UV_H_ITERS] }
called by 1: main
1238func uv_maxmove(m: *i64) -> i64 { return m[UV_H_MAXMOVE] }
called by 1: main
1242func uv_singular_sweeps(m: *i64) -> i64 { return m[UV_H_SING] }
called by 1: main
1243func uv_grid(m: *i64) -> i64 { return m[UV_H_GRID] }
1244func uv_corner_u(m: *i64, t: i64, k: i64) -> i64 { return m[m[UV_O_CUV] + (t * UV_TRI + k) * UV_CUVREC + UV_P_U] }
1245func uv_corner_v(m: *i64, t: i64, k: i64) -> i64 { return m[m[UV_O_CUV] + (t * UV_TRI + k) * UV_CUVREC + UV_P_V] }
1246func uv_corner_class(m: *i64, t: i64, k: i64) -> i64 { return m[m[UV_O_UVF] + t * UV_TRI + k] }
1263func uvi_tri_metrics(m: *i64, t: i64) -> i64
1362func uv_distortion(m: *i64) -> i64
1467func uv_angle_mean(m: *i64) -> i64 { return m[UV_H_ANGMEAN] }
1468func uv_angle_max(m: *i64) -> i64 { return m[UV_H_ANGMAX] }
1469func uv_area_mean(m: *i64) -> i64 { return m[UV_H_AREAMEAN] }
called by 2: ncp_emitmain
1470func uv_area_max(m: *i64) -> i64 { return m[UV_H_AREAMAX] }
called by 2: ncp_emitmain
1471func uv_flipped(m: *i64) -> i64 { return m[UV_H_FLIP] }
1472func uv_uvdegen(m: *i64) -> i64 { return m[UV_H_UVDEGEN] }
1473func uv_chart_angle_mean(m: *i64, c: i64) -> i64
called by 1: ua_worst
1478func uv_chart_angle_max(m: *i64, c: i64) -> i64
called by 1: ua_worst
1483func uv_chart_area_mean(m: *i64, c: i64) -> i64
called by 1: ua_worst
1488func uv_chart_area_max(m: *i64, c: i64) -> i64
called by 1: ua_worst
1497func uv_chart_uv_area(m: *i64, c: i64) -> i64
called by 1: main calls 1: vm_abs
1522func uv_overlap_check(m: *i64) -> i64
1547func uv_overlaps(m: *i64) -> i64 { return m[UV_H_OVERLAP] }
called by 2: ncp_emitmain
1548func uv_chart_box(m: *i64, c: i64, k: i64) -> i64
called by 1: main
1559func uv_force_box(m: *i64, c: i64, u0: i64, v0: i64, u1: i64, v1: i64) -> i64
called by 1: main
1574func uv_force_corner(m: *i64, t: i64, k: i64, u: i64, v: i64) -> i64
called by 1: main
1585func uv_unwrap(m: *i64) -> i64
1595func uv_verdict(m: *i64) -> i64 { return m[UV_H_ERR] }
called by 1: main
1596func uv_stage(m: *i64) -> i64 { return m[UV_H_STAGE] }
1597func uv_mv_verdict(m: *i64) -> i64 { return m[UV_H_MVERR] }
called by 2: ncp_emitmain
1598func uv_mv_closed(m: *i64) -> i64 { return m[UV_H_MVCLOSED] }
called by 2: ncp_emitmain
1608func uv_texc_words(m: *i64) -> i64 { return UV_X_HDR + m[UV_H_NV] * UV_TRI }
called by 1: main
1610func uv_emit_texc(m: *i64, out: *i64) -> i64
1642func uv_texc_loss(m: *i64) -> i64 { return m[UV_H_TEXCLOSS] }
called by 1: main