nuclear@9: #include "config.h" nuclear@7: #include nuclear@12: #include nuclear@7: #include "x3d.h" nuclear@7: #include "fixed.h" nuclear@7: #include "sincos.h" nuclear@8: #include "logger.h" nuclear@8: #include "polyfill.h" nuclear@8: #include "gbasys.h" nuclear@7: nuclear@7: #define MAT_STACK_SIZE 4 nuclear@7: nuclear@7: struct matrix { nuclear@8: int32_t m[12]; nuclear@7: }; nuclear@7: nuclear@8: static void proc_vertex(const int32_t *vin, const int32_t *cin, pvec3 *vout, pvec3 *cout); nuclear@8: nuclear@8: nuclear@7: static int32_t proj_fov = M_PI_X16; nuclear@7: static int32_t proj_aspect = 65536; nuclear@13: static int32_t inv_proj_aspect = 65536; nuclear@7: static int32_t proj_near = ftox16(0.5); nuclear@7: static int32_t proj_far = 500 << 16; nuclear@13: static int32_t inv_tan_half_xfov, inv_tan_half_yfov; nuclear@7: nuclear@8: #define ID_INIT {65536, 0, 0, 0, 0, 65536, 0, 0, 0, 0, 65536, 0} nuclear@8: nuclear@8: static struct matrix identity = { ID_INIT }; nuclear@7: nuclear@7: static short mtop; nuclear@8: static struct matrix mstack[MAT_STACK_SIZE] = { {ID_INIT}, {ID_INIT} }; nuclear@8: nuclear@8: static const int32_t *vertex_array; nuclear@8: static unsigned short vertex_count; nuclear@8: static const int32_t *color_array; nuclear@8: static unsigned short color_count; nuclear@8: nuclear@8: static int32_t im_color[3]; nuclear@9: static uint8_t im_color_index; nuclear@7: nuclear@12: void x3d_projection(int fov, int32_t aspect, int32_t nearz, int32_t farz) nuclear@7: { nuclear@12: proj_fov = (M_PI_X16 * fov) / 180; nuclear@7: proj_aspect = aspect; nuclear@13: inv_proj_aspect = x16div(65536, proj_aspect); nuclear@7: proj_near = nearz; nuclear@7: proj_far = farz; nuclear@12: nuclear@13: inv_tan_half_yfov = (int32_t)(65536.0 / tan(0.5 * proj_fov / 65536.0)); nuclear@13: inv_tan_half_xfov = x16mul(inv_tan_half_yfov, aspect); nuclear@7: } nuclear@7: nuclear@7: int x3d_push_matrix(void) nuclear@7: { nuclear@7: short newtop = mtop + 1; nuclear@7: if(newtop >= MAT_STACK_SIZE) { nuclear@7: return -1; nuclear@7: } nuclear@7: memcpy(mstack + newtop, mstack + mtop, sizeof *mstack); nuclear@7: mtop = newtop; nuclear@7: return 0; nuclear@7: } nuclear@7: nuclear@7: int x3d_pop_matrix(void) nuclear@7: { nuclear@7: if(mtop <= 0) { nuclear@7: return -1; nuclear@7: } nuclear@7: --mtop; nuclear@7: return 0; nuclear@7: } nuclear@7: nuclear@7: void x3d_load_matrix(int32_t *m) nuclear@7: { nuclear@8: memcpy(mstack[mtop].m, m, sizeof *mstack); nuclear@7: } nuclear@7: nuclear@7: nuclear@7: #define M(i,j) (((i) << 2) + (j)) nuclear@7: void x3d_mult_matrix(int32_t *m) nuclear@7: { nuclear@7: int i, j; nuclear@7: struct matrix tmp; nuclear@7: nuclear@8: memcpy(tmp.m, mstack[mtop].m, sizeof tmp); nuclear@7: nuclear@7: for(i=0; i<3; i++) { nuclear@7: for(j=0; j<4; j++) { nuclear@8: mstack[mtop].m[M(i, j)] = nuclear@8: x16mul(tmp.m[M(0, j)], m[M(i, 0)]) + nuclear@8: x16mul(tmp.m[M(1, j)], m[M(i, 1)]) + nuclear@8: x16mul(tmp.m[M(2, j)], m[M(i, 2)]); nuclear@7: } nuclear@8: mstack[mtop].m[M(i, 3)] += m[M(i, 3)]; nuclear@7: } nuclear@7: } nuclear@7: nuclear@7: void x3d_load_identity(void) nuclear@7: { nuclear@8: memcpy(mstack[mtop].m, identity.m, sizeof identity); nuclear@7: } nuclear@7: nuclear@8: void x3d_translate(int32_t x, int32_t y, int32_t z) nuclear@8: { nuclear@8: int32_t m[] = ID_INIT; nuclear@8: m[3] = x; nuclear@8: m[7] = y; nuclear@8: m[11] = z; nuclear@8: nuclear@8: x3d_mult_matrix(m); nuclear@8: } nuclear@8: nuclear@8: void x3d_rotate(int32_t deg, int32_t x, int32_t y, int32_t z) nuclear@8: { nuclear@8: int32_t xform[] = ID_INIT; nuclear@8: nuclear@8: int32_t angle = x16mul(M_PI_X16, deg) / 180; nuclear@8: int32_t sina = sin_x16(angle); nuclear@8: int32_t cosa = cos_x16(angle); nuclear@8: int32_t one_minus_cosa = 65536 - cosa; nuclear@8: int32_t nxsq = x16sq(x); nuclear@8: int32_t nysq = x16sq(y); nuclear@8: int32_t nzsq = x16sq(z); nuclear@8: nuclear@8: xform[0] = nxsq + x16mul(65536 - nxsq, cosa); nuclear@8: xform[4] = x16mul(x16mul(x, y), one_minus_cosa) - x16mul(z, sina); nuclear@8: xform[8] = x16mul(x16mul(x, z), one_minus_cosa) + x16mul(y, sina); nuclear@8: xform[1] = x16mul(x16mul(x, y), one_minus_cosa) + x16mul(z, sina); nuclear@8: xform[5] = nysq + x16mul(65536 - nysq, cosa); nuclear@8: xform[9] = x16mul(x16mul(y, z), one_minus_cosa) - x16mul(x, sina); nuclear@8: xform[2] = x16mul(x16mul(x, z), one_minus_cosa) - x16mul(y, sina); nuclear@8: xform[6] = x16mul(x16mul(y, z), one_minus_cosa) + x16mul(x, sina); nuclear@8: xform[10] = nzsq + x16mul(65536 - nzsq, cosa); nuclear@8: nuclear@8: x3d_mult_matrix(xform); nuclear@8: } nuclear@8: nuclear@8: void x3d_scale(int32_t x, int32_t y, int32_t z) nuclear@8: { nuclear@8: int32_t m[] = ID_INIT; nuclear@8: nuclear@8: m[0] = x; nuclear@8: m[5] = y; nuclear@8: m[10] = z; nuclear@8: nuclear@8: x3d_mult_matrix(m); nuclear@8: } nuclear@8: nuclear@8: void x3d_vertex_array(int count, const int32_t *ptr) nuclear@8: { nuclear@8: vertex_array = ptr; nuclear@8: vertex_count = count; nuclear@8: } nuclear@8: nuclear@8: void x3d_color_array(int count, const int32_t *ptr) nuclear@8: { nuclear@8: color_array = ptr; nuclear@8: color_count = count; nuclear@8: } nuclear@8: nuclear@12: int x3d_draw(int prim, int vnum) nuclear@8: { nuclear@8: int i, j, pverts = prim; nuclear@8: const int32_t *vptr = vertex_array; nuclear@8: const int32_t *cptr = color_array; nuclear@9: #ifndef PALMODE nuclear@8: short cr, cg, cb; nuclear@9: #endif nuclear@9: uint16_t color; nuclear@8: nuclear@8: if(!vertex_array) return -1; nuclear@8: nuclear@8: if(vnum > vertex_count) { nuclear@8: logmsg(LOG_DBG, "%s called with vnum=%d, but current vertex array has %d vertices\n", nuclear@8: __FUNCTION__, vnum, vertex_count); nuclear@8: vnum = vertex_count; nuclear@8: } nuclear@8: if(color_array && vnum > color_count) { nuclear@8: logmsg(LOG_DBG, "%s called with vnum=%d, but current color array has %d elements\n", nuclear@8: __FUNCTION__, vnum, color_count); nuclear@8: vnum = color_count; nuclear@8: } nuclear@8: nuclear@8: for(i=0; i> 8; nuclear@8: cg = col[0].y >> 8; nuclear@8: cb = col[0].z >> 8; nuclear@8: nuclear@8: if(cr > 255) cr = 255; nuclear@8: if(cg > 255) cg = 255; nuclear@8: if(cb > 255) cb = 255; nuclear@8: nuclear@9: color = RGB(cr, cg, cb); nuclear@9: #endif nuclear@9: nuclear@12: /* project & viewport */ nuclear@12: for(j=0; jx = tvert[0]; nuclear@8: vout->y = tvert[1]; nuclear@8: vout->z = tvert[2]; nuclear@8: /*logmsg(LOG_DBG, "%s: (%g %g %g) -> (%g %g %g)\n", __FUNCTION__, nuclear@8: x16tof(vin[0]), x16tof(vin[1]), x16tof(vin[2]), nuclear@8: x16tof(vout->x), x16tof(vout->y), x16tof(vout->z));*/ nuclear@8: nuclear@8: if(color_array) { nuclear@8: cout->x = cin[0]; nuclear@8: cout->y = cin[1]; nuclear@8: cout->z = cin[2]; nuclear@8: } else { nuclear@8: cout->x = im_color[0]; nuclear@8: cout->y = im_color[1]; nuclear@8: cout->z = im_color[2]; nuclear@8: } nuclear@8: } nuclear@8: nuclear@9: void x3d_color_index(int cidx) nuclear@9: { nuclear@9: im_color_index = cidx; nuclear@9: } nuclear@9: nuclear@8: void x3d_color(int32_t r, int32_t g, int32_t b) nuclear@8: { nuclear@8: im_color[0] = r; nuclear@8: im_color[1] = g; nuclear@8: im_color[2] = b; nuclear@8: }