gba-x3dtest

annotate src/x3d.c @ 20:2e903e27e35a

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