gba-x3dtest

view src/x3d.c @ 15:b755fb002f17

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 25 Jun 2014 17:02:48 +0300
parents c398d834d64a
children 0a7f402892b3
line source
1 #include "config.h"
2 #include <stdio.h>
3 #include <string.h>
4 #include <math.h>
5 #include "x3d.h"
6 #include "fixed.h"
7 #include "sincos.h"
8 #include "logger.h"
9 #include "polyfill.h"
10 #include "gbasys.h"
12 int dbg_fill_dump;
14 #define MAT_STACK_SIZE 4
16 struct matrix {
17 int32_t m[12];
18 };
20 static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin,
21 pvec3 *vout, pvec3 *cout, pvec2 *tout);
22 static int dump_frame(struct pixel_buffer *frame);
25 static int32_t proj_fov = M_PI_X16;
26 static int32_t proj_aspect = 65536;
27 static int32_t inv_proj_aspect = 65536;
28 static int32_t proj_near = ftox16(0.5);
29 static int32_t proj_far = 500 << 16;
30 static int32_t inv_tan_half_xfov, inv_tan_half_yfov;
32 #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
34 static struct matrix identity = { ID_INIT };
36 static short mtop;
37 static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
39 static const int32_t *vertex_array;
40 static unsigned short vertex_count;
41 static const int32_t *color_array;
42 static unsigned short color_count;
43 static const int32_t *texcoord_array;
44 static unsigned short texcoord_count;
46 static int32_t im_color[3];
47 static int32_t im_texcoord[2];
48 static uint8_t im_color_index;
50 void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
51 {
52 proj_fov = (M_PI_X16 * fov) / 180;
53 proj_aspect = aspect;
54 inv_proj_aspect = x16div(65536, proj_aspect);
55 proj_near = nearz;
56 proj_far = farz;
58 inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0));
59 inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect);
60 }
62 int x3d_push_matrix(void)
63 {
64 short newtop = mtop + 1;
65 if(newtop >= MAT_STACK_SIZE) {
66 return -1;
67 }
68 memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
69 mtop = newtop;
70 return 0;
71 }
73 int x3d_pop_matrix(void)
74 {
75 if(mtop <= 0) {
76 return -1;
77 }
78 --mtop;
79 return 0;
80 }
82 void x3d_load_matrix(int32_t *m)
83 {
84 memcpy(mstack[mtop].m, m, sizeof *mstack);
85 }
88 #define M(i,j) (((i) << 2) + (j))
89 void x3d_mult_matrix(int32_t *m)
90 {
91 int i, j;
92 struct matrix tmp;
94 memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
96 for(i=0; i<3; i++) {
97 for(j=0; j<4; j++) {
98 mstack[mtop].m[M(i, j)] =
99 x16mul(m[M(0, j)], tmp.m[M(i, 0)]) +
100 x16mul(m[M(1, j)], tmp.m[M(i, 1)]) +
101 x16mul(m[M(2, j)], tmp.m[M(i, 2)]);
102 }
103 mstack[mtop].m[M(i, 3)] += tmp.m[M(i, 3)];
104 }
105 }
107 void x3d_load_identity(void)
108 {
109 memcpy(mstack[mtop].m, identity.m, sizeof identity);
110 }
112 void x3d_translate(int32_t x, int32_t y, int32_t z)
113 {
114 int32_t m[] = ID_INIT;
115 m[3] = x;
116 m[7] = y;
117 m[11] = z;
119 x3d_mult_matrix(m);
120 }
122 void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
123 {
124 int32_t xform[] = ID_INIT;
126 int32_t angle = x16mul(M_PI_X16, deg) / 180;
127 int32_t sina = sin_x16(angle);
128 int32_t cosa = cos_x16(angle);
129 int32_t one_minus_cosa = 65536 - cosa;
130 int32_t nxsq = x16sq(x);
131 int32_t nysq = x16sq(y);
132 int32_t nzsq = x16sq(z);
134 xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
135 xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
136 xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
137 xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
138 xform[5] = nysq + x16mul(65536 - nysq, cosa);
139 xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
140 xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
141 xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
142 xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
144 x3d_mult_matrix(xform);
145 }
147 void x3d_scale(int32_t x, int32_t y, int32_t z)
148 {
149 int32_t m[] = ID_INIT;
151 m[0] = x;
152 m[5] = y;
153 m[10] = z;
155 x3d_mult_matrix(m);
156 }
158 void x3d_vertex_array(int count, const int32_t *ptr)
159 {
160 vertex_array = ptr;
161 vertex_count = count;
162 }
164 void x3d_color_array(int count, const int32_t *ptr)
165 {
166 color_array = ptr;
167 color_count = count;
168 }
170 void x3d_texcoord_array(int count, const int32_t *ptr)
171 {
172 texcoord_array = ptr;
173 texcoord_count = count;
174 }
176 int x3d_draw(int prim, int vnum)
177 {
178 int i, j, pverts = prim;
179 const int32_t *vptr = vertex_array;
180 const int32_t *cptr = color_array;
181 const int32_t *tptr = texcoord_array;
182 #ifndef PALMODE
183 short cr, cg, cb;
184 #endif
185 uint16_t color;
187 if(!vertex_array) return -1;
189 if(vnum > vertex_count) {
190 logmsg(LOG_DBG, "%s called with vnum=%d, but current vertex array has %d vertices\n",
191 __FUNCTION__, vnum, vertex_count);
192 vnum = vertex_count;
193 }
194 if(color_array && vnum > color_count) {
195 logmsg(LOG_DBG, "%s called with vnum=%d, but current color array has %d elements\n",
196 __FUNCTION__, vnum, color_count);
197 vnum = color_count;
198 }
199 if(texcoord_array && vnum > texcoord_count) {
200 logmsg(LOG_DBG, "%s called with vnum=%d, but current texcoord array has %d elements\n",
201 __FUNCTION__, vnum, texcoord_count);
202 vnum = texcoord_count;
203 }
205 for(i=0; i<vnum; i+=pverts) {
206 /* process vertices */
207 pvec3 vpos[4];
208 pvec3 col[4];
209 pvec2 tex[4];
211 for(j=0; j<pverts; j++) {
212 proc_vertex(vptr, cptr, tptr, vpos + j, col + j, tex + j);
214 if(vpos[j].z <= proj_near) {
215 goto skip_prim;
216 }
218 vptr += 3;
219 if(cptr) cptr += 3;
220 if(tptr) tptr += 2;
221 }
223 #ifdef PALMODE
224 color = im_color_index;
225 #else
226 cr = col[0].x >> 8;
227 cg = col[0].y >> 8;
228 cb = col[0].z >> 8;
230 if(cr > 255) cr = 255;
231 if(cg > 255) cg = 255;
232 if(cb > 255) cb = 255;
234 color = RGB(cr, cg, cb);
235 #endif
237 /* project & viewport */
238 for(j=0; j<pverts; j++) {
239 int32_t x, y;
241 x = x16mul(vpos[j].x, inv_tan_half_xfov);
242 x = x16div(x, vpos[j].z);
243 vpos[j].x = (x16mul(x, inv_proj_aspect) + 65536) * (WIDTH / 2);
245 y = x16mul(vpos[j].y, inv_tan_half_yfov);
246 y = x16div(y, vpos[j].z);
247 vpos[j].y = (65536 - y) * (HEIGHT / 2);
248 }
250 switch(pverts) {
251 case X3D_POINTS:
252 draw_point(vpos, color);
253 break;
255 case X3D_LINES:
256 break;
258 case X3D_TRIANGLES:
259 case X3D_QUADS:
260 draw_poly(pverts, vpos, tex, color);
261 if(dbg_fill_dump) {
262 dump_frame(back_buffer);
263 }
264 break;
265 }
266 skip_prim: ;
267 }
269 dbg_fill_dump = 0;
270 return 0;
271 }
273 static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin,
274 pvec3 *vout, pvec3 *cout, pvec2 *tout)
275 {
276 int i;
277 int32_t tvert[3];
278 int32_t *mvmat = mstack[mtop].m;
280 /* transform vertex with current matrix */
281 for(i=0; i<3; i++) {
282 tvert[i] = x16mul(mvmat[0], vin[0]) +
283 x16mul(mvmat[1], vin[1]) +
284 x16mul(mvmat[2], vin[2]) +
285 mvmat[3];
286 mvmat += 4;
287 }
289 vout->x = tvert[0];
290 vout->y = tvert[1];
291 vout->z = tvert[2];
292 /*logmsg(LOG_DBG, "%s: (%g %g %g) -> (%g %g %g)\n", __FUNCTION__,
293 x16tof(vin[0]), x16tof(vin[1]), x16tof(vin[2]),
294 x16tof(vout->x), x16tof(vout->y), x16tof(vout->z));*/
296 if(color_array) {
297 cout->x = cin[0];
298 cout->y = cin[1];
299 cout->z = cin[2];
300 } else {
301 cout->x = im_color[0];
302 cout->y = im_color[1];
303 cout->z = im_color[2];
304 }
306 if(texcoord_array) {
307 tout->x = tin[0];
308 tout->y = tin[1];
309 } else {
310 tout->x = im_texcoord[0];
311 tout->y = im_texcoord[1];
312 }
313 }
315 void x3d_color_index(int cidx)
316 {
317 im_color_index = cidx;
318 }
320 void x3d_color(int32_t r, int32_t g, int32_t b)
321 {
322 im_color[0] = r;
323 im_color[1] = g;
324 im_color[2] = b;
325 }
327 static int dump_frame(struct pixel_buffer *frame)
328 {
329 static int frameno;
330 char buf[128];
331 FILE *fp;
332 int i, npix;
333 uint16_t *ptr = frame->pixels;
335 sprintf(buf, "dump%03d.ppm", ++frameno);
337 if(!(fp = fopen(buf, "wb"))) {
338 fprintf(stderr, "failed to dump file: %s\n", buf);
339 return -1;
340 }
342 fprintf(fp, "P6\n%d %d\n255\n", frame->x, frame->y);
344 npix = frame->x * frame->y;
345 for(i=0; i<npix; i++) {
346 uint16_t pixel = *ptr++;
347 fputc(GET_R(pixel), fp);
348 fputc(GET_G(pixel), fp);
349 fputc(GET_B(pixel), fp);
350 }
351 fclose(fp);
352 return 0;
353 }