gba-x3dtest

view src/x3d.c @ 17:0a7f402892b3

texture mapping
author John Tsiombikas <nuclear@member.fsf.org>
date Thu, 26 Jun 2014 06:57:51 +0300
parents b755fb002f17
children 62390f9cc93e
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"
11 #include "x3d_impl.h"
13 int dbg_fill_dump;
15 #define MAT_STACK_SIZE 4
17 struct matrix {
18 int32_t m[12];
19 };
21 static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin,
22 pvec3 *vout, pvec3 *cout, pvec2 *tout);
23 static int dump_frame(struct pixel_buffer *frame);
26 static int32_t proj_fov = M_PI_X16;
27 static int32_t proj_aspect = 65536;
28 static int32_t inv_proj_aspect = 65536;
29 static int32_t proj_near = ftox16(0.5);
30 static int32_t proj_far = 500 << 16;
31 static int32_t inv_tan_half_xfov, inv_tan_half_yfov;
33 #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0}
35 static struct matrix identity = { ID_INIT };
37 static short mtop;
38 static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} };
40 static const int32_t *vertex_array;
41 static unsigned short vertex_count;
42 static const int32_t *color_array;
43 static unsigned short color_count;
44 static const int32_t *texcoord_array;
45 static unsigned short texcoord_count;
47 static int32_t im_color[3];
48 static int32_t im_texcoord[2];
49 static uint8_t im_color_index;
51 #define MAX_TEXTURES 64
52 static struct texture textures[MAX_TEXTURES];
53 static short cur_tex = -1;
56 void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz)
57 {
58 proj_fov = (M_PI_X16 * fov) / 180;
59 proj_aspect = aspect;
60 inv_proj_aspect = x16div(65536, proj_aspect);
61 proj_near = nearz;
62 proj_far = farz;
64 inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0));
65 inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect);
66 }
68 int x3d_push_matrix(void)
69 {
70 short newtop = mtop + 1;
71 if(newtop >= MAT_STACK_SIZE) {
72 return -1;
73 }
74 memcpy(mstack + newtop, mstack + mtop, sizeof *mstack);
75 mtop = newtop;
76 return 0;
77 }
79 int x3d_pop_matrix(void)
80 {
81 if(mtop <= 0) {
82 return -1;
83 }
84 --mtop;
85 return 0;
86 }
88 void x3d_load_matrix(int32_t *m)
89 {
90 memcpy(mstack[mtop].m, m, sizeof *mstack);
91 }
94 #define M(i,j) (((i) << 2) + (j))
95 void x3d_mult_matrix(int32_t *m)
96 {
97 int i, j;
98 struct matrix tmp;
100 memcpy(tmp.m, mstack[mtop].m, sizeof tmp);
102 for(i=0; i<3; i++) {
103 for(j=0; j<4; j++) {
104 mstack[mtop].m[M(i, j)] =
105 x16mul(m[M(0, j)], tmp.m[M(i, 0)]) +
106 x16mul(m[M(1, j)], tmp.m[M(i, 1)]) +
107 x16mul(m[M(2, j)], tmp.m[M(i, 2)]);
108 }
109 mstack[mtop].m[M(i, 3)] += tmp.m[M(i, 3)];
110 }
111 }
113 void x3d_load_identity(void)
114 {
115 memcpy(mstack[mtop].m, identity.m, sizeof identity);
116 }
118 void x3d_translate(int32_t x, int32_t y, int32_t z)
119 {
120 int32_t m[] = ID_INIT;
121 m[3] = x;
122 m[7] = y;
123 m[11] = z;
125 x3d_mult_matrix(m);
126 }
128 void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z)
129 {
130 int32_t xform[] = ID_INIT;
132 int32_t angle = x16mul(M_PI_X16, deg) / 180;
133 int32_t sina = sin_x16(angle);
134 int32_t cosa = cos_x16(angle);
135 int32_t one_minus_cosa = 65536 - cosa;
136 int32_t nxsq = x16sq(x);
137 int32_t nysq = x16sq(y);
138 int32_t nzsq = x16sq(z);
140 xform[0] = nxsq + x16mul(65536 - nxsq, cosa);
141 xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina);
142 xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina);
143 xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina);
144 xform[5] = nysq + x16mul(65536 - nysq, cosa);
145 xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina);
146 xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina);
147 xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina);
148 xform[10] = nzsq + x16mul(65536 - nzsq, cosa);
150 x3d_mult_matrix(xform);
151 }
153 void x3d_scale(int32_t x, int32_t y, int32_t z)
154 {
155 int32_t m[] = ID_INIT;
157 m[0] = x;
158 m[5] = y;
159 m[10] = z;
161 x3d_mult_matrix(m);
162 }
164 void x3d_vertex_array(int count, const int32_t *ptr)
165 {
166 vertex_array = ptr;
167 vertex_count = count;
168 }
170 void x3d_color_array(int count, const int32_t *ptr)
171 {
172 color_array = ptr;
173 color_count = count;
174 }
176 void x3d_texcoord_array(int count, const int32_t *ptr)
177 {
178 texcoord_array = ptr;
179 texcoord_count = count;
180 }
182 int x3d_draw(int prim, int vnum)
183 {
184 int i, j, pverts = prim;
185 const int32_t *vptr = vertex_array;
186 const int32_t *cptr = color_array;
187 const int32_t *tptr = texcoord_array;
188 #ifndef PALMODE
189 short cr, cg, cb;
190 #endif
191 uint16_t color;
193 if(!vertex_array) return -1;
195 if(vnum > vertex_count) {
196 logmsg(LOG_DBG, "%s called with vnum=%d, but current vertex array has %d vertices\n",
197 __FUNCTION__, vnum, vertex_count);
198 vnum = vertex_count;
199 }
200 if(color_array && vnum > color_count) {
201 logmsg(LOG_DBG, "%s called with vnum=%d, but current color array has %d elements\n",
202 __FUNCTION__, vnum, color_count);
203 vnum = color_count;
204 }
205 if(texcoord_array && vnum > texcoord_count) {
206 logmsg(LOG_DBG, "%s called with vnum=%d, but current texcoord array has %d elements\n",
207 __FUNCTION__, vnum, texcoord_count);
208 vnum = texcoord_count;
209 }
211 for(i=0; i<vnum; i+=pverts) {
212 /* process vertices */
213 pvec3 vpos[4];
214 pvec3 col[4];
215 pvec2 tex[4];
217 for(j=0; j<pverts; j++) {
218 proc_vertex(vptr, cptr, tptr, vpos + j, col + j, tex + j);
220 if(vpos[j].z <= proj_near) {
221 goto skip_prim;
222 }
224 vptr += 3;
225 if(cptr) cptr += 3;
226 if(tptr) tptr += 2;
227 }
229 #ifdef PALMODE
230 color = im_color_index;
231 #else
232 cr = col[0].x >> 8;
233 cg = col[0].y >> 8;
234 cb = col[0].z >> 8;
236 if(cr > 255) cr = 255;
237 if(cg > 255) cg = 255;
238 if(cb > 255) cb = 255;
240 color = RGB(cr, cg, cb);
241 #endif
243 /* project & viewport */
244 for(j=0; j<pverts; j++) {
245 int32_t x, y;
247 x = x16mul(vpos[j].x, inv_tan_half_xfov);
248 x = x16div(x, vpos[j].z);
249 vpos[j].x = (x16mul(x, inv_proj_aspect) + 65536) * (WIDTH / 2);
251 y = x16mul(vpos[j].y, inv_tan_half_yfov);
252 y = x16div(y, vpos[j].z);
253 vpos[j].y = (65536 - y) * (HEIGHT / 2);
254 }
256 switch(pverts) {
257 case X3D_POINTS:
258 draw_point(vpos, color);
259 break;
261 case X3D_LINES:
262 break;
264 case X3D_TRIANGLES:
265 case X3D_QUADS:
266 draw_poly(pverts, vpos, tex, color, cur_tex >= 0 ? textures + cur_tex : 0);
267 if(dbg_fill_dump) {
268 dump_frame(back_buffer);
269 }
270 break;
271 }
272 skip_prim: ;
273 }
275 dbg_fill_dump = 0;
276 return 0;
277 }
279 static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin,
280 pvec3 *vout, pvec3 *cout, pvec2 *tout)
281 {
282 int i;
283 int32_t tvert[3];
284 int32_t *mvmat = mstack[mtop].m;
286 /* transform vertex with current matrix */
287 for(i=0; i<3; i++) {
288 tvert[i] = x16mul(mvmat[0], vin[0]) +
289 x16mul(mvmat[1], vin[1]) +
290 x16mul(mvmat[2], vin[2]) +
291 mvmat[3];
292 mvmat += 4;
293 }
295 vout->x = tvert[0];
296 vout->y = tvert[1];
297 vout->z = tvert[2];
298 /*logmsg(LOG_DBG, "%s: (%g %g %g) -> (%g %g %g)\n", __FUNCTION__,
299 x16tof(vin[0]), x16tof(vin[1]), x16tof(vin[2]),
300 x16tof(vout->x), x16tof(vout->y), x16tof(vout->z));*/
302 if(color_array) {
303 cout->x = cin[0];
304 cout->y = cin[1];
305 cout->z = cin[2];
306 } else {
307 cout->x = im_color[0];
308 cout->y = im_color[1];
309 cout->z = im_color[2];
310 }
312 if(texcoord_array) {
313 tout->x = tin[0];
314 tout->y = tin[1];
315 } else {
316 tout->x = im_texcoord[0];
317 tout->y = im_texcoord[1];
318 }
319 }
321 void x3d_color_index(int cidx)
322 {
323 im_color_index = cidx;
324 }
326 void x3d_color(int32_t r, int32_t g, int32_t b)
327 {
328 im_color[0] = r;
329 im_color[1] = g;
330 im_color[2] = b;
331 }
333 static int count_bits(int x)
334 {
335 int i, count = 0;
336 for(i=0; i<32; i++) {
337 if(x & 1) count++;
338 x >>= 1;
339 }
340 return count;
341 }
343 int x3d_create_texture_rgb(int xsz, int ysz, const uint16_t *pixels)
344 {
345 int i, j;
347 if(xsz == 0 || count_bits(xsz) > 1 || ysz == 0 || count_bits(ysz) > 1) {
348 logmsg(LOG_DBG, "%s: texture size (%dx%d) not power of two!\n", __func__, xsz, ysz);
349 return -1;
350 }
352 for(i=0; i<MAX_TEXTURES; i++) {
353 if(!textures[i].pixels) {
354 textures[i].pixels = pixels;
355 textures[i].xsz = xsz;
356 textures[i].ysz = ysz;
357 textures[i].umask = xsz - 1;
358 textures[i].vmask = ysz - 1;
360 for(j=0; j<32; j++) {
361 if((1 << j) == xsz) {
362 textures[i].ushift = j;
363 }
364 if((1 << j) == ysz) {
365 textures[i].vshift = j;
366 }
367 }
369 return i;
370 }
371 }
372 return -1;
373 }
375 void x3d_enable_texture(int texid)
376 {
377 cur_tex = texid;
378 }
380 void x3d_disable_texture(void)
381 {
382 cur_tex = 0;
383 }
385 int x3d_get_active_texture(void)
386 {
387 return cur_tex;
388 }
390 static int dump_frame(struct pixel_buffer *frame)
391 {
392 static int frameno;
393 char buf[128];
394 FILE *fp;
395 int i, npix;
396 uint16_t *ptr = frame->pixels;
398 sprintf(buf, "dump%03d.ppm", ++frameno);
400 if(!(fp = fopen(buf, "wb"))) {
401 fprintf(stderr, "failed to dump file: %s\n", buf);
402 return -1;
403 }
405 fprintf(fp, "P6\n%d %d\n255\n", frame->x, frame->y);
407 npix = frame->x * frame->y;
408 for(i=0; i<npix; i++) {
409 uint16_t pixel = *ptr++;
410 fputc(GET_R(pixel), fp);
411 fputc(GET_G(pixel), fp);
412 fputc(GET_B(pixel), fp);
413 }
414 fclose(fp);
415 return 0;
416 }