code wiki / _hdl_build / nx_shade.nx
nx_shade.nx source
↩ module page · 88 lines · 4072 B
1// nx_shade.nx -- P1 VISUALIZATION: RGB GOURAUD shading + TEXTURE mapping (barycentric), writing to a
2// packed-RGB framebuffer (fb[y*w+x] = R | G<<8 | B<<16) ready for nx_png.write_png. Extends the existing
3// single-channel shaded raster to full per-vertex RGB interpolation + per-vertex UV texture sampling.
4// Pure integer (Pineda edge functions). 100% sovereign. license_tier: ORIGINAL
5import "nx_syscalls.nx"
6
7func sh_rgb(r: i64, g: i64, b: i64) -> i64 { return (r & 0xff) | ((g & 0xff) << 8) | ((b & 0xff) << 16) }
8func sh_r(c: i64) -> i64 { return c & 0xff }
9func sh_g(c: i64) -> i64 { return (c >> 8) & 0xff }
10func sh_b(c: i64) -> i64 { return (c >> 16) & 0xff }
11
12// Pineda edge function: >0 left of edge AB through C (signed area*2).
13func sh_edge(ax: i64, ay: i64, bx: i64, by: i64, cx: i64, cy: i64) -> i64 {
14 return (bx - ax) * (cy - ay) - (by - ay) * (cx - ax)
15}
16
17func sh_clear(fb: *i64, w: i64, h: i64, c: i64) -> i64 { var i: i64=0; while i < w*h { fb[i]=c; i=i+1 } return 0 }
18
19// GOURAUD: fill triangle, interpolate per-vertex RGB (ca/cb/cc packed) smoothly across pixels.
20func sh_tri_gouraud(fb: *i64, w: i64, h: i64,
21 x0: i64, y0: i64, ca: i64, x1: i64, y1: i64, cb: i64, x2: i64, y2: i64, cc: i64) -> i64 {
22 let area: i64 = sh_edge(x0, y0, x1, y1, x2, y2)
23 if area == 0 { return 0 - 1 }
24 var xmin: i64=x0; if x1<xmin {xmin=x1} if x2<xmin {xmin=x2}
25 var xmax: i64=x0; if x1>xmax {xmax=x1} if x2>xmax {xmax=x2}
26 var ymin: i64=y0; if y1<ymin {ymin=y1} if y2<ymin {ymin=y2}
27 var ymax: i64=y0; if y1>ymax {ymax=y1} if y2>ymax {ymax=y2}
28 if xmin<0 {xmin=0} if ymin<0 {ymin=0}
29 if xmax>=w {xmax=w-1} if ymax>=h {ymax=h-1}
30 var py: i64=ymin
31 while py<=ymax {
32 var px: i64=xmin
33 while px<=xmax {
34 let e0: i64 = sh_edge(x1,y1,x2,y2,px,py)
35 let e1: i64 = sh_edge(x2,y2,x0,y0,px,py)
36 let e2: i64 = sh_edge(x0,y0,x1,y1,px,py)
37 var inside: i64=0
38 if area>0 { if e0>=0 { if e1>=0 { if e2>=0 { inside=1 } } } }
39 if area<0 { if e0<=0 { if e1<=0 { if e2<=0 { inside=1 } } } }
40 if inside==1 {
41 let r: i64 = (e0*sh_r(ca) + e1*sh_r(cb) + e2*sh_r(cc)) / area
42 let g: i64 = (e0*sh_g(ca) + e1*sh_g(cb) + e2*sh_g(cc)) / area
43 let b: i64 = (e0*sh_b(ca) + e1*sh_b(cb) + e2*sh_b(cc)) / area
44 fb[py*w+px] = sh_rgb(r,g,b)
45 }
46 px=px+1
47 }
48 py=py+1
49 }
50 return 0
51}
52
53// TEXTURED: fill triangle, interpolate per-vertex UV (texel coords) + sample tex[v*ts+u] (packed RGB).
54func sh_tri_textured(fb: *i64, w: i64, h: i64, tex: *i64, ts: i64,
55 x0: i64, y0: i64, u0: i64, v0: i64,
56 x1: i64, y1: i64, u1: i64, v1: i64,
57 x2: i64, y2: i64, u2: i64, v2: i64) -> i64 {
58 let area: i64 = sh_edge(x0, y0, x1, y1, x2, y2)
59 if area == 0 { return 0 - 1 }
60 var xmin: i64=x0; if x1<xmin {xmin=x1} if x2<xmin {xmin=x2}
61 var xmax: i64=x0; if x1>xmax {xmax=x1} if x2>xmax {xmax=x2}
62 var ymin: i64=y0; if y1<ymin {ymin=y1} if y2<ymin {ymin=y2}
63 var ymax: i64=y0; if y1>ymax {ymax=y1} if y2>ymax {ymax=y2}
64 if xmin<0 {xmin=0} if ymin<0 {ymin=0}
65 if xmax>=w {xmax=w-1} if ymax>=h {ymax=h-1}
66 var py: i64=ymin
67 while py<=ymax {
68 var px: i64=xmin
69 while px<=xmax {
70 let e0: i64 = sh_edge(x1,y1,x2,y2,px,py)
71 let e1: i64 = sh_edge(x2,y2,x0,y0,px,py)
72 let e2: i64 = sh_edge(x0,y0,x1,y1,px,py)
73 var inside: i64=0
74 if area>0 { if e0>=0 { if e1>=0 { if e2>=0 { inside=1 } } } }
75 if area<0 { if e0<=0 { if e1<=0 { if e2<=0 { inside=1 } } } }
76 if inside==1 {
77 var u: i64 = (e0*u0 + e1*u1 + e2*u2) / area
78 var v: i64 = (e0*v0 + e1*v1 + e2*v2) / area
79 if u<0 {u=0} if u>=ts {u=ts-1}
80 if v<0 {v=0} if v>=ts {v=ts-1}
81 fb[py*w+px] = tex[v*ts+u]
82 }
83 px=px+1
84 }
85 py=py+1
86 }
87 return 0
88}