nx_scene3d.nx source
↩ module page · 132 lines · 5004 B
1// nx_scene3d.nx -- reusable 3D scene primitives: integer trig (Bhaskara Q10) + rotate + perspective project +
2// per-face Lambert-shaded, depth-sorted cube. Extracted from the proven cube gates so the native game window and
3// the gates share ONE implementation of the 3D math (no duplicate sprawl). Composes nx_depth_tri. Pure integer,
4// deterministic, no gcc/GL. license_tier: ORIGINAL
5import "nx_syscalls.nx"
6import "nx_image.nx"
7import "nx_depth_tri.nx"
8
9const SC_AMB: i64 = 105 // ambient floor (~41%)
10
11func sc_isin(deg: i64) -> i64 {
12 var d: i64 = deg % 360
13 if d < 0 { d = d + 360 }
14 var sign: i64 = 1
15 if d >= 180 { sign = 0 - 1; d = d - 180 }
16 let hh: i64 = d * (180 - d)
17 return sign * (4 * hh * 1024 / (40500 - hh))
18}
19func sc_icos(deg: i64) -> i64 { return sc_isin(deg + 90) }
20
21struct Cube3D {
22 cvx: *i64, cvy: *i64, cvz: *i64,
23 rx: *i64, ry: *i64, rz: *i64,
24 px: *i64, py: *i64, pz: *i64,
25 o: *i64,
26 S: i64, focal: i64, dist: i64
27}
28const CUBE3D_BYTES: i64 = 128
29
30func sc_cube_new(S: i64, focal: i64, dist: i64) -> *Cube3D {
31 let c: *Cube3D = sys_mmap(CUBE3D_BYTES) as *Cube3D
32 c.cvx = sys_mmap(64) as *i64
33 c.cvy = sys_mmap(64) as *i64
34 c.cvz = sys_mmap(64) as *i64
35 c.rx = sys_mmap(64) as *i64
36 c.ry = sys_mmap(64) as *i64
37 c.rz = sys_mmap(64) as *i64
38 c.px = sys_mmap(64) as *i64
39 c.py = sys_mmap(64) as *i64
40 c.pz = sys_mmap(64) as *i64
41 c.o = sys_mmap(32) as *i64
42 c.S = S; c.focal = focal; c.dist = dist
43 let cvx: *i64 = c.cvx
44 let cvy: *i64 = c.cvy
45 let cvz: *i64 = c.cvz
46 cvx[0]=0-S; cvy[0]=0-S; cvz[0]=0-S
47 cvx[1]=S; cvy[1]=0-S; cvz[1]=0-S
48 cvx[2]=S; cvy[2]=S; cvz[2]=0-S
49 cvx[3]=0-S; cvy[3]=S; cvz[3]=0-S
50 cvx[4]=0-S; cvy[4]=0-S; cvz[4]=S
51 cvx[5]=S; cvy[5]=0-S; cvz[5]=S
52 cvx[6]=S; cvy[6]=S; cvz[6]=S
53 cvx[7]=0-S; cvy[7]=S; cvz[7]=S
54 return c
55}
56
57// n.L for a face (normal forced OUTWARD via centroid sign), light L=(3,4,12)
58func sc_ndotl(rx: *i64, ry: *i64, rz: *i64, ia: i64, ib: i64, ic: i64, id: i64) -> i64 {
59 let ux: i64 = rx[ib]-rx[ia]; let uy: i64 = ry[ib]-ry[ia]; let uz: i64 = rz[ib]-rz[ia]
60 let vx: i64 = rx[id]-rx[ia]; let vy: i64 = ry[id]-ry[ia]; let vz: i64 = rz[id]-rz[ia]
61 var nx: i64 = uy*vz - uz*vy
62 var ny: i64 = uz*vx - ux*vz
63 var nz: i64 = ux*vy - uy*vx
64 let sx: i64 = rx[ia]+rx[ib]+rx[ic]+rx[id]
65 let sy: i64 = ry[ia]+ry[ib]+ry[ic]+ry[id]
66 let sz: i64 = rz[ia]+rz[ib]+rz[ic]+rz[id]
67 if nx*sx + ny*sy + nz*sz < 0 { nx = 0-nx; ny = 0-ny; nz = 0-nz }
68 return nx*3 + ny*4 + nz*12
69}
70func sc_shade(ndl: i64, nlmax: i64) -> i64 {
71 var d: i64 = ndl
72 if d < 0 { d = 0 }
73 if d > nlmax { d = nlmax }
74 return SC_AMB + ((255 - SC_AMB) * d) / nlmax
75}
76func sc_face(c: *Cube3D, fb: *Image, zb: *i64, ia: i64, ib: i64, ic: i64, id: i64, r: i64, g: i64, b: i64, nlmax: i64) -> i64 {
77 let rx: *i64 = c.rx
78 let ry: *i64 = c.ry
79 let rz: *i64 = c.rz
80 let px: *i64 = c.px
81 let py: *i64 = c.py
82 let pz: *i64 = c.pz
83 let sh: i64 = sc_shade(sc_ndotl(rx, ry, rz, ia, ib, ic, id), nlmax)
84 let rr: i64 = r * sh / 255
85 let gg: i64 = g * sh / 255
86 let bb: i64 = b * sh / 255
87 depth_tri_render(fb, zb, px[ia], py[ia], pz[ia], px[ib], py[ib], pz[ib], px[ic], py[ic], pz[ic], rr, gg, bb, 1)
88 depth_tri_render(fb, zb, px[ia], py[ia], pz[ia], px[ic], py[ic], pz[ic], px[id], py[id], pz[id], rr, gg, bb, 1)
89 return 0
90}
91
92// draw a lit, depth-sorted cube at screen (cx,cy), Y-angle ay, X-angle ax. Caller clears fb + depth-clears zb.
93func sc_cube_draw(c: *Cube3D, fb: *Image, zb: *i64, cx: i64, cy: i64, ay: i64, ax: i64) -> i64 {
94 let SA: i64 = sc_isin(ay)
95 let CA: i64 = sc_icos(ay)
96 let SB: i64 = sc_isin(ax)
97 let CB: i64 = sc_icos(ax)
98 let cvx: *i64 = c.cvx
99 let cvy: *i64 = c.cvy
100 let cvz: *i64 = c.cvz
101 let rx: *i64 = c.rx
102 let ry: *i64 = c.ry
103 let rz: *i64 = c.rz
104 let px: *i64 = c.px
105 let py: *i64 = c.py
106 let pz: *i64 = c.pz
107 let dist: i64 = c.dist
108 let focal: i64 = c.focal
109 var i: i64 = 0
110 while i < 8 {
111 let x1: i64 = (cvx[i] * CA + cvz[i] * SA) / 1024
112 let z1: i64 = (0 - (cvx[i] * SA) + cvz[i] * CA) / 1024
113 let ry2: i64 = (cvy[i] * CB - z1 * SB) / 1024
114 let rz2: i64 = (cvy[i] * SB + z1 * CB) / 1024
115 rx[i] = x1
116 ry[i] = ry2
117 rz[i] = rz2
118 let zc: i64 = rz2 + dist
119 px[i] = cx + (x1 * focal) / zc
120 py[i] = cy - (ry2 * focal) / zc
121 pz[i] = zc
122 i = i + 1
123 }
124 let nlmax: i64 = 4 * c.S * c.S * 13
125 sc_face(c, fb, zb, 4, 5, 6, 7, 80, 120, 255, nlmax) // +Z blue
126 sc_face(c, fb, zb, 0, 1, 2, 3, 235, 220, 90, nlmax) // -Z amber
127 sc_face(c, fb, zb, 1, 5, 6, 2, 255, 90, 90, nlmax) // +X red
128 sc_face(c, fb, zb, 0, 4, 7, 3, 90, 220, 220, nlmax) // -X cyan
129 sc_face(c, fb, zb, 3, 2, 6, 7, 110, 230, 130, nlmax) // +Y green
130 sc_face(c, fb, zb, 0, 1, 5, 4, 230, 120, 230, nlmax) // -Y magenta
131 return 0
132}