nx_texr_chart_candidate_t279.nx source
↩ module page · 144 lines · 7362 B
1// nx_texr_chart_candidate_t279.nx -- Validates and initializes chart data structures for regional texture mapping in a 3D model.
2import "nx_nxa_texbake_region_lib.nx"
3
4// Candidate addition to the regional owner. Coordinates are Q16; micro UV is unwrapped
5// so interpolation precedes repeat addressing. Scale is the asset's declared model.
6struct NtrChartPoint { region:i64,joint:i64,u:i64,v:i64,micro_u:i64,micro_v:i64,micro_valid:i64 }
7struct NtrChartContext { w:*i64,x:i64,r:i64,t:i64,nv:i64,nt:i64,nj:i64,g:i64,res:i64,repeat_um:i64,sets:[4]i64 }
8const NTR_CHART_BAD:i64=0-3
9const NTR_CHART_LAYOUT:i64=0-4
10const NTR_CHART_STRADDLE:i64=0-5
11const NTR_CHART_SEAM:i64=0-6
12const NTR_CHART_OVERFLOW:i64=0-7
13const NTR_CHART_MAX:i64=9223372036854775807
14
15func ntr_chart_ranks(w:*i64,r:i64,c:*NtrChartContext,nj:i64)->i64{
16 var total:i64=0;var region:i64=0
17 while region<NTR_REGIONS{let m:i64=c.sets[region];if m>=0{let n:i64=w[m+NTR_S_NJR];if n>nj-total{return NTR_CHART_BAD};total=total+n};region=region+1}
18 if total!=nj{return NTR_CHART_BAD}
19 let seen:*u8=sys_mmap_try(nj);if (seen as i64)<=0{return NTR_CHART_BAD}
20 var rc:i64=0;var j:i64=0
21 while j<nj{
22 let jo:i64=r+NTR_HDR_WORDS+j*NTR_JOINT_WORDS
23 let reg:i64=w[jo];var base:i64=0;region=0
24 while region<reg{let m:i64=c.sets[region];if m>=0{base=base+w[m+NTR_S_NJR]};region=region+1}
25 let index:i64=base+w[jo+1]
26 if seen[index]!=(0 as u8){rc=NTR_CHART_BAD;break};seen[index]=1 as u8;j=j+1
27 }
28 sys_munmap_direct(seen,nj);return rc
29}
30func ntr_chart_init(b:*u8,flen:i64,c:*NtrChartContext)->i64{
31 if c==(0 as *NtrChartContext){return NTR_CHART_BAD}
32 c.w=0 as *i64
33 if b==(0 as *u8){return NTR_CHART_BAD}
34 let r:i64=ntr_texr_find(b,flen);if r<0{return r}
35 let xe:i64=nxa_section_entry(b,flen,nxa_tag4("TEXC"))
36 let te:i64=nxa_section_entry(b,flen,nxa_tag4("TRIS"))
37 let ve:i64=nxa_section_entry(b,flen,nxa_tag4("VERT"))
38 let se:i64=nxa_section_entry(b,flen,nxa_tag4("SKEL"))
39 if xe<0{return xe};if te<0{return te};if ve<0{return ve};if se<0{return se}
40 let w:*i64=b as *i64
41 if w[xe+2]<NT_PHDR{return NTR_CHART_BAD}
42 if w[te+2]<1{return NTR_CHART_BAD};if w[ve+2]<1{return NTR_CHART_BAD};if w[se+2]<1{return NTR_CHART_BAD}
43 let x:i64=w[xe+1]/NTR_WORD;let t:i64=w[te+1]/NTR_WORD
44 let nv:i64=w[x];let nt:i64=w[t];let nj:i64=w[r+NTR_W_NJ]
45 if nv<=0{return NTR_CHART_BAD};if nt<0{return NTR_CHART_BAD};if nj<=0{return NTR_CHART_BAD}
46 if w[x+1]!=NT_STRIDE{return NTR_CHART_LAYOUT}
47 if w[x+3]!=0{return NTR_CHART_LAYOUT}
48 if nv>(w[xe+2]-NT_PHDR)/NT_STRIDE{return NTR_CHART_BAD}
49 if nt>(w[te+2]-1)/3{return NTR_CHART_BAD}
50 if w[w[ve+1]/NTR_WORD]!=nv{return NTR_CHART_BAD}
51 if w[w[se+1]/NTR_WORD]!=nj{return NTR_CHART_BAD}
52 let g:i64=w[x+2];if g<1{return NTR_CHART_BAD};if g>NTR_Q16{return NTR_CHART_BAD}
53 if nj/g>g{return NTR_CHART_BAD};if nj>g*g{return NTR_CHART_BAD}
54 let res:i64=w[r+NTR_W_RES]
55 if res>NTR_CHART_MAX/NTR_Q16/NTR_SUB{return NTR_CHART_OVERFLOW}
56 var k:i64=0;while k<NTR_REGIONS{c.sets[k]=NTR_MISS;k=k+1}
57 let ns:i64=w[r+NTR_W_NSETS]
58 k=0;while k<ns{
59 let m:i64=r+NTR_HDR_WORDS+nj*NTR_JOINT_WORDS+k*w[r+NTR_W_SETW]
60 let region:i64=w[m+NTR_S_REGION];let gr:i64=w[m+NTR_S_GR];let tp:i64=w[m+NTR_S_TPX]
61 let count:i64=w[m+NTR_S_NJR]
62 if gr<1{return NTR_CHART_BAD};if gr>res{return NTR_CHART_BAD}
63 if tp<1{return NTR_CHART_BAD};if tp!=res/gr{return NTR_CHART_BAD}
64 if count<1{return NTR_CHART_BAD};if count>nj{return NTR_CHART_BAD}
65 if gr> NTR_CHART_MAX/gr{return NTR_CHART_OVERFLOW}
66 if count>gr*gr{return NTR_CHART_BAD}
67 c.sets[region]=m;k=k+1
68 }
69 k=0;while k<nj{
70 let j:i64=r+NTR_HDR_WORDS+k*NTR_JOINT_WORDS
71 let region:i64=w[j];let rank:i64=w[j+1]
72 if region<0{return NTR_CHART_BAD};if region>=NTR_REGIONS{return NTR_CHART_BAD}
73 let m:i64=c.sets[region];if m<0{return NTR_CHART_LAYOUT}
74 if rank<0{return NTR_CHART_BAD};if rank>=w[m+NTR_S_NJR]{return NTR_CHART_BAD}
75 if w[j+2]<0{return NTR_CHART_BAD};if w[j+3]<0{return NTR_CHART_BAD}
76 k=k+1
77 }
78 let ranks:i64=ntr_chart_ranks(w,r,c,nj);if ranks!=0{return ranks}
79 c.x=x;c.r=r;c.t=t;c.nv=nv;c.nt=nt;c.nj=nj;c.g=g;c.res=res;c.repeat_um=w[r+NTR_W_MREP]
80 c.w=w
81 return 0
82}
83func ntr_chart_ratio_q16(n:i64,d:i64)->i64{
84 if n<0{return NTR_CHART_BAD};if d<=0{return NTR_CHART_BAD}
85 let q:i64=n/d;let rem:i64=n%d
86 if q>NTR_CHART_MAX/NTR_Q16{return NTR_CHART_OVERFLOW}
87 if rem>NTR_CHART_MAX/NTR_Q16{return NTR_CHART_OVERFLOW}
88 let whole:i64=q*NTR_Q16;let frac:i64=rem*NTR_Q16/d
89 if frac>NTR_CHART_MAX-whole{return NTR_CHART_OVERFLOW}
90 return whole+frac
91}
92func ntr_chart_point(c:*NtrChartContext,i:i64,p:*NtrChartPoint)->i64{
93 if p==(0 as *NtrChartPoint){return NTR_CHART_BAD}
94 p.region=NTR_MISS;p.joint=NTR_MISS;p.u=0;p.v=0;p.micro_u=0;p.micro_v=0;p.micro_valid=0
95 if c==(0 as *NtrChartContext){return NTR_CHART_BAD}
96 if c.w==(0 as *i64){return NTR_CHART_BAD}
97 if i<0{return NTR_CHART_BAD};if i>=c.nv{return NTR_CHART_BAD}
98 let w:*i64=c.w;let at:i64=c.x+NT_PHDR+i*NT_STRIDE
99 let j:i64=w[at+2];if j<0{return NTR_CHART_BAD};if j>=c.nj{return NTR_CHART_BAD}
100 let jo:i64=c.r+NTR_HDR_WORDS+j*NTR_JOINT_WORDS
101 let region:i64=w[jo];let rank:i64=w[jo+1];let m:i64=c.sets[region]
102 if w[at]<0{return NTR_CHART_LAYOUT};if w[at]>NTR_Q16{return NTR_CHART_LAYOUT}
103 if w[at+1]<0{return NTR_CHART_LAYOUT};if w[at+1]>NTR_Q16{return NTR_CHART_LAYOUT}
104 let tw:i64=NTR_Q16/c.g
105 let lu:i64=w[at]-(j%c.g)*tw;let lv:i64=w[at+1]-(j/c.g)*tw
106 if lu<0{return NTR_CHART_LAYOUT};if lu>tw{return NTR_CHART_LAYOUT}
107 if lv<0{return NTR_CHART_LAYOUT};if lv>tw{return NTR_CHART_LAYOUT}
108 let us:i64=ntr_px_sub(w[at],j,0,1,c.g,w[m+NTR_S_GR],w[m+NTR_S_TPX],rank,c.res)
109 let vs:i64=ntr_px_sub(w[at+1],j,1,1,c.g,w[m+NTR_S_GR],w[m+NTR_S_TPX],rank,c.res)
110 let u:i64=ntr_chart_ratio_q16(us,c.res*NTR_SUB);let v:i64=ntr_chart_ratio_q16(vs,c.res*NTR_SUB)
111 if u<0{return u};if v<0{return v}
112 var mu:i64=0;var mv:i64=0;var valid:i64=0
113 if w[jo+2]>0{if w[jo+3]>0{
114 if w[jo+2]>NTR_CHART_MAX/tw{return NTR_CHART_OVERFLOW}
115 if w[jo+3]>NTR_CHART_MAX/tw{return NTR_CHART_OVERFLOW}
116 if c.repeat_um>NTR_CHART_MAX/tw{return NTR_CHART_OVERFLOW}
117 mu=ntr_chart_ratio_q16(lu*w[jo+2],tw*c.repeat_um);mv=ntr_chart_ratio_q16(lv*w[jo+3],tw*c.repeat_um)
118 if mu<0{return mu};if mv<0{return mv};valid=1
119 }}
120 p.region=region;p.joint=j;p.u=u;p.v=v;p.micro_u=mu;p.micro_v=mv;p.micro_valid=valid
121 return 0
122}
123// A triangle must remain in one chart. A cylindrical wrap seam is not a straight
124// interpolation of its endpoints; reject it until explicit seam topology exists.
125func ntr_chart_triangle(c:*NtrChartContext,t:i64,p:*NtrChartPoint)->i64{
126 if c==(0 as *NtrChartContext){return NTR_CHART_BAD}
127 if c.w==(0 as *i64){return NTR_CHART_BAD}
128 if t<0{return NTR_CHART_BAD};if t>=c.nt{return NTR_CHART_BAD}
129 let w:*i64=c.w;let at:i64=c.t+1+t*3
130 var k:i64=0
131 while k<3{
132 let rc:i64=ntr_chart_point(c,w[at+k],((p as i64)+k*__size_of(NtrChartPoint)) as *NtrChartPoint)
133 if rc!=0{return rc};k=k+1
134 }
135 let a:*NtrChartPoint=p
136 let b:*NtrChartPoint=((p as i64)+__size_of(NtrChartPoint)) as *NtrChartPoint
137 let d:*NtrChartPoint=((p as i64)+2*__size_of(NtrChartPoint)) as *NtrChartPoint
138 if a.joint!=b.joint{return NTR_CHART_STRADDLE};if a.joint!=d.joint{return NTR_CHART_STRADDLE}
139 let u0:i64=w[c.x+NT_PHDR+w[at]*NT_STRIDE]
140 let u1:i64=w[c.x+NT_PHDR+w[at+1]*NT_STRIDE]
141 let u2:i64=w[c.x+NT_PHDR+w[at+2]*NT_STRIDE]
142 if ntr_max(ntr_max(u0,u1),u2)-ntr_min(ntr_min(u0,u1),u2)>NTR_Q16/c.g/2{return NTR_CHART_SEAM}
143 return 0
144}