gba-x3dtest

annotate src/x3d.c @ 14:c398d834d64a

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