rev |
line source |
nuclear@9
|
1 #include "config.h"
|
nuclear@7
|
2 #include <string.h>
|
nuclear@12
|
3 #include <math.h>
|
nuclear@7
|
4 #include "x3d.h"
|
nuclear@7
|
5 #include "fixed.h"
|
nuclear@7
|
6 #include "sincos.h"
|
nuclear@8
|
7 #include "logger.h"
|
nuclear@8
|
8 #include "polyfill.h"
|
nuclear@8
|
9 #include "gbasys.h"
|
nuclear@7
|
10
|
nuclear@7
|
11 #define MAT_STACK_SIZE 4
|
nuclear@7
|
12
|
nuclear@7
|
13 struct matrix {
|
nuclear@8
|
14 int32_t m[12];
|
nuclear@7
|
15 };
|
nuclear@7
|
16
|
nuclear@8
|
17 static void proc_vertex(const int32_t *vin, const int32_t *cin, pvec3 *vout, pvec3 *cout);
|
nuclear@8
|
18
|
nuclear@8
|
19
|
nuclear@7
|
20 static int32_t proj_fov = M_PI_X16;
|
nuclear@7
|
21 static int32_t proj_aspect = 65536;
|
nuclear@7
|
22 static int32_t proj_near = ftox16(0.5);
|
nuclear@7
|
23 static int32_t proj_far = 500 << 16;
|
nuclear@12
|
24 static int32_t tan_half_xfov, tan_half_yfov;
|
nuclear@7
|
25
|
nuclear@8
|
26 #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
|
nuclear@8
|
27
|
nuclear@8
|
28 static struct matrix identity = { ID_INIT };
|
nuclear@7
|
29
|
nuclear@7
|
30 static short mtop;
|
nuclear@8
|
31 static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
|
nuclear@8
|
32
|
nuclear@8
|
33 static const int32_t *vertex_array;
|
nuclear@8
|
34 static unsigned short vertex_count;
|
nuclear@8
|
35 static const int32_t *color_array;
|
nuclear@8
|
36 static unsigned short color_count;
|
nuclear@8
|
37
|
nuclear@8
|
38 static int32_t im_color[3];
|
nuclear@9
|
39 static uint8_t im_color_index;
|
nuclear@7
|
40
|
nuclear@12
|
41 void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
|
nuclear@7
|
42 {
|
nuclear@12
|
43 proj_fov = (M_PI_X16 * fov) / 180;
|
nuclear@7
|
44 proj_aspect = aspect;
|
nuclear@7
|
45 proj_near = nearz;
|
nuclear@7
|
46 proj_far = farz;
|
nuclear@12
|
47
|
nuclear@12
|
48 tan_half_yfov = (int32_t)(tan(0.5 * proj_fov / 65536.0) * 65536.0);
|
nuclear@12
|
49 tan_half_xfov = x16mul(tan_half_yfov, aspect);
|
nuclear@7
|
50 }
|
nuclear@7
|
51
|
nuclear@7
|
52 int x3d_push_matrix(void)
|
nuclear@7
|
53 {
|
nuclear@7
|
54 short newtop = mtop + 1;
|
nuclear@7
|
55 if(newtop >= MAT_STACK_SIZE) {
|
nuclear@7
|
56 return -1;
|
nuclear@7
|
57 }
|
nuclear@7
|
58 memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
|
nuclear@7
|
59 mtop = newtop;
|
nuclear@7
|
60 return 0;
|
nuclear@7
|
61 }
|
nuclear@7
|
62
|
nuclear@7
|
63 int x3d_pop_matrix(void)
|
nuclear@7
|
64 {
|
nuclear@7
|
65 if(mtop <= 0) {
|
nuclear@7
|
66 return -1;
|
nuclear@7
|
67 }
|
nuclear@7
|
68 --mtop;
|
nuclear@7
|
69 return 0;
|
nuclear@7
|
70 }
|
nuclear@7
|
71
|
nuclear@7
|
72 void x3d_load_matrix(int32_t *m)
|
nuclear@7
|
73 {
|
nuclear@8
|
74 memcpy(mstack[mtop].m, m, sizeof *mstack);
|
nuclear@7
|
75 }
|
nuclear@7
|
76
|
nuclear@7
|
77
|
nuclear@7
|
78 #define M(i,j) (((i) << 2) + (j))
|
nuclear@7
|
79 void x3d_mult_matrix(int32_t *m)
|
nuclear@7
|
80 {
|
nuclear@7
|
81 int i, j;
|
nuclear@7
|
82 struct matrix tmp;
|
nuclear@7
|
83
|
nuclear@8
|
84 memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
|
nuclear@7
|
85
|
nuclear@7
|
86 for(i=0; i<3; i++) {
|
nuclear@7
|
87 for(j=0; j<4; j++) {
|
nuclear@8
|
88 mstack[mtop].m[M(i, j)] =
|
nuclear@8
|
89 x16mul(tmp.m[M(0, j)], m[M(i, 0)]) +
|
nuclear@8
|
90 x16mul(tmp.m[M(1, j)], m[M(i, 1)]) +
|
nuclear@8
|
91 x16mul(tmp.m[M(2, j)], m[M(i, 2)]);
|
nuclear@7
|
92 }
|
nuclear@8
|
93 mstack[mtop].m[M(i, 3)] += m[M(i, 3)];
|
nuclear@7
|
94 }
|
nuclear@7
|
95 }
|
nuclear@7
|
96
|
nuclear@7
|
97 void x3d_load_identity(void)
|
nuclear@7
|
98 {
|
nuclear@8
|
99 memcpy(mstack[mtop].m, identity.m, sizeof identity);
|
nuclear@7
|
100 }
|
nuclear@7
|
101
|
nuclear@8
|
102 void x3d_translate(int32_t x, int32_t y, int32_t z)
|
nuclear@8
|
103 {
|
nuclear@8
|
104 int32_t m[] = ID_INIT;
|
nuclear@8
|
105 m[3] = x;
|
nuclear@8
|
106 m[7] = y;
|
nuclear@8
|
107 m[11] = z;
|
nuclear@8
|
108
|
nuclear@8
|
109 x3d_mult_matrix(m);
|
nuclear@8
|
110 }
|
nuclear@8
|
111
|
nuclear@8
|
112 void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
|
nuclear@8
|
113 {
|
nuclear@8
|
114 int32_t xform[] = ID_INIT;
|
nuclear@8
|
115
|
nuclear@8
|
116 int32_t angle = x16mul(M_PI_X16, deg) / 180;
|
nuclear@8
|
117 int32_t sina = sin_x16(angle);
|
nuclear@8
|
118 int32_t cosa = cos_x16(angle);
|
nuclear@8
|
119 int32_t one_minus_cosa = 65536 - cosa;
|
nuclear@8
|
120 int32_t nxsq = x16sq(x);
|
nuclear@8
|
121 int32_t nysq = x16sq(y);
|
nuclear@8
|
122 int32_t nzsq = x16sq(z);
|
nuclear@8
|
123
|
nuclear@8
|
124 xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
|
nuclear@8
|
125 xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
|
nuclear@8
|
126 xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
|
nuclear@8
|
127 xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
|
nuclear@8
|
128 xform[5] = nysq + x16mul(65536 - nysq, cosa);
|
nuclear@8
|
129 xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
|
nuclear@8
|
130 xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
|
nuclear@8
|
131 xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
|
nuclear@8
|
132 xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
|
nuclear@8
|
133
|
nuclear@8
|
134 x3d_mult_matrix(xform);
|
nuclear@8
|
135 }
|
nuclear@8
|
136
|
nuclear@8
|
137 void x3d_scale(int32_t x, int32_t y, int32_t z)
|
nuclear@8
|
138 {
|
nuclear@8
|
139 int32_t m[] = ID_INIT;
|
nuclear@8
|
140
|
nuclear@8
|
141 m[0] = x;
|
nuclear@8
|
142 m[5] = y;
|
nuclear@8
|
143 m[10] = z;
|
nuclear@8
|
144
|
nuclear@8
|
145 x3d_mult_matrix(m);
|
nuclear@8
|
146 }
|
nuclear@8
|
147
|
nuclear@8
|
148 void x3d_vertex_array(int count, const int32_t *ptr)
|
nuclear@8
|
149 {
|
nuclear@8
|
150 vertex_array = ptr;
|
nuclear@8
|
151 vertex_count = count;
|
nuclear@8
|
152 }
|
nuclear@8
|
153
|
nuclear@8
|
154 void x3d_color_array(int count, const int32_t *ptr)
|
nuclear@8
|
155 {
|
nuclear@8
|
156 color_array = ptr;
|
nuclear@8
|
157 color_count = count;
|
nuclear@8
|
158 }
|
nuclear@8
|
159
|
nuclear@12
|
160 int x3d_draw(int prim, int vnum)
|
nuclear@8
|
161 {
|
nuclear@8
|
162 int i, j, pverts = prim;
|
nuclear@8
|
163 const int32_t *vptr = vertex_array;
|
nuclear@8
|
164 const int32_t *cptr = color_array;
|
nuclear@9
|
165 #ifndef PALMODE
|
nuclear@8
|
166 short cr, cg, cb;
|
nuclear@9
|
167 #endif
|
nuclear@9
|
168 uint16_t color;
|
nuclear@8
|
169
|
nuclear@8
|
170 if(!vertex_array) return -1;
|
nuclear@8
|
171
|
nuclear@8
|
172 if(vnum > vertex_count) {
|
nuclear@8
|
173 logmsg(LOG_DBG, "%s called with vnum=%d, but current vertex array has %d vertices\n",
|
nuclear@8
|
174 __FUNCTION__, vnum, vertex_count);
|
nuclear@8
|
175 vnum = vertex_count;
|
nuclear@8
|
176 }
|
nuclear@8
|
177 if(color_array && vnum > color_count) {
|
nuclear@8
|
178 logmsg(LOG_DBG, "%s called with vnum=%d, but current color array has %d elements\n",
|
nuclear@8
|
179 __FUNCTION__, vnum, color_count);
|
nuclear@8
|
180 vnum = color_count;
|
nuclear@8
|
181 }
|
nuclear@8
|
182
|
nuclear@8
|
183 for(i=0; i<vnum; i+=pverts) {
|
nuclear@8
|
184 /* process vertices */
|
nuclear@8
|
185 pvec3 vpos[4];
|
nuclear@8
|
186 pvec3 col[4];
|
nuclear@8
|
187
|
nuclear@8
|
188 for(j=0; j<pverts; j++) {
|
nuclear@8
|
189 proc_vertex(vptr, cptr, vpos + j, col + j);
|
nuclear@12
|
190
|
nuclear@12
|
191 if(vpos[j].z <= proj_near) {
|
nuclear@12
|
192 goto skip_prim;
|
nuclear@12
|
193 }
|
nuclear@12
|
194
|
nuclear@8
|
195 vptr += 3;
|
nuclear@8
|
196 if(cptr) cptr += 3;
|
nuclear@8
|
197 }
|
nuclear@8
|
198
|
nuclear@9
|
199 #ifdef PALMODE
|
nuclear@9
|
200 color = im_color_index;
|
nuclear@9
|
201 #else
|
nuclear@8
|
202 cr = col[0].x >> 8;
|
nuclear@8
|
203 cg = col[0].y >> 8;
|
nuclear@8
|
204 cb = col[0].z >> 8;
|
nuclear@8
|
205
|
nuclear@8
|
206 if(cr > 255) cr = 255;
|
nuclear@8
|
207 if(cg > 255) cg = 255;
|
nuclear@8
|
208 if(cb > 255) cb = 255;
|
nuclear@8
|
209
|
nuclear@9
|
210 color = RGB(cr, cg, cb);
|
nuclear@9
|
211 #endif
|
nuclear@9
|
212
|
nuclear@12
|
213 /* project & viewport */
|
nuclear@12
|
214 for(j=0; j<pverts; j++) {
|
nuclear@12
|
215 int32_t x, y;
|
nuclear@12
|
216
|
nuclear@12
|
217 x = x16mul(vpos[j].x, tan_half_xfov);
|
nuclear@12
|
218 x = x16div(x, vpos[j].z);
|
nuclear@12
|
219 vpos[j].x = (x + 65536) * (WIDTH / 2);
|
nuclear@12
|
220
|
nuclear@12
|
221 y = x16mul(vpos[j].y, tan_half_yfov);
|
nuclear@12
|
222 y = x16div(y, vpos[j].z);
|
nuclear@12
|
223 vpos[j].y = (65536 - y) * (HEIGHT / 2);
|
nuclear@12
|
224 }
|
nuclear@12
|
225
|
nuclear@8
|
226 switch(pverts) {
|
nuclear@8
|
227 case X3D_POINTS:
|
nuclear@9
|
228 draw_point(vpos, color);
|
nuclear@8
|
229 break;
|
nuclear@8
|
230
|
nuclear@8
|
231 case X3D_LINES:
|
nuclear@8
|
232 break;
|
nuclear@8
|
233
|
nuclear@8
|
234 case X3D_TRIANGLES:
|
nuclear@8
|
235 case X3D_QUADS:
|
nuclear@9
|
236 draw_poly(pverts, vpos, color);
|
nuclear@8
|
237 break;
|
nuclear@8
|
238 }
|
nuclear@12
|
239 skip_prim: ;
|
nuclear@8
|
240 }
|
nuclear@8
|
241 return 0;
|
nuclear@8
|
242 }
|
nuclear@8
|
243
|
nuclear@8
|
244 static void proc_vertex(const int32_t *vin, const int32_t *cin, pvec3 *vout, pvec3 *cout)
|
nuclear@8
|
245 {
|
nuclear@8
|
246 int i;
|
nuclear@8
|
247 int32_t tvert[3];
|
nuclear@8
|
248 int32_t *mvmat = mstack[mtop].m;
|
nuclear@8
|
249
|
nuclear@8
|
250 /* transform vertex with current matrix */
|
nuclear@8
|
251 for(i=0; i<3; i++) {
|
nuclear@8
|
252 tvert[i] = x16mul(mvmat[0], vin[0]) +
|
nuclear@8
|
253 x16mul(mvmat[1], vin[1]) +
|
nuclear@8
|
254 x16mul(mvmat[2], vin[2]) +
|
nuclear@8
|
255 mvmat[3];
|
nuclear@8
|
256 mvmat += 4;
|
nuclear@8
|
257 }
|
nuclear@8
|
258
|
nuclear@8
|
259 vout->x = tvert[0];
|
nuclear@8
|
260 vout->y = tvert[1];
|
nuclear@8
|
261 vout->z = tvert[2];
|
nuclear@8
|
262 /*logmsg(LOG_DBG, "%s: (%g %g %g) -> (%g %g %g)\n", __FUNCTION__,
|
nuclear@8
|
263 x16tof(vin[0]), x16tof(vin[1]), x16tof(vin[2]),
|
nuclear@8
|
264 x16tof(vout->x), x16tof(vout->y), x16tof(vout->z));*/
|
nuclear@8
|
265
|
nuclear@8
|
266 if(color_array) {
|
nuclear@8
|
267 cout->x = cin[0];
|
nuclear@8
|
268 cout->y = cin[1];
|
nuclear@8
|
269 cout->z = cin[2];
|
nuclear@8
|
270 } else {
|
nuclear@8
|
271 cout->x = im_color[0];
|
nuclear@8
|
272 cout->y = im_color[1];
|
nuclear@8
|
273 cout->z = im_color[2];
|
nuclear@8
|
274 }
|
nuclear@8
|
275 }
|
nuclear@8
|
276
|
nuclear@9
|
277 void x3d_color_index(int cidx)
|
nuclear@9
|
278 {
|
nuclear@9
|
279 im_color_index = cidx;
|
nuclear@9
|
280 }
|
nuclear@9
|
281
|
nuclear@8
|
282 void x3d_color(int32_t r, int32_t g, int32_t b)
|
nuclear@8
|
283 {
|
nuclear@8
|
284 im_color[0] = r;
|
nuclear@8
|
285 im_color[1] = g;
|
nuclear@8
|
286 im_color[2] = b;
|
nuclear@8
|
287 }
|