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