nuclear@9: #include "config.h" nuclear@14: #include nuclear@19: #include 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@17: #include "x3d_impl.h" nuclear@7: nuclear@14: int dbg_fill_dump; nuclear@14: nuclear@7: #define MAT_STACK_SIZE 4 nuclear@7: nuclear@7: struct matrix { nuclear@8: int32_t m[12]; nuclear@7: }; nuclear@7: nuclear@15: static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin, nuclear@15: pvec3 *vout, pvec3 *cout, pvec2 *tout); nuclear@14: static int dump_frame(struct pixel_buffer *frame); 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@15: static const int32_t *texcoord_array; nuclear@15: static unsigned short texcoord_count; nuclear@8: nuclear@8: static int32_t im_color[3]; nuclear@15: static int32_t im_texcoord[2]; nuclear@9: static uint8_t im_color_index; nuclear@7: nuclear@17: #define MAX_TEXTURES 64 nuclear@17: static struct texture textures[MAX_TEXTURES]; nuclear@17: static short cur_tex = -1; nuclear@17: nuclear@17: 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@14: x16mul(m[M(0, j)], tmp.m[M(i, 0)]) + nuclear@14: x16mul(m[M(1, j)], tmp.m[M(i, 1)]) + nuclear@14: x16mul(m[M(2, j)], tmp.m[M(i, 2)]); nuclear@7: } nuclear@14: mstack[mtop].m[M(i, 3)] += tmp.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@15: void x3d_texcoord_array(int count, const int32_t *ptr) nuclear@15: { nuclear@15: texcoord_array = ptr; nuclear@15: texcoord_count = count; nuclear@15: } nuclear@15: 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@15: const int32_t *tptr = texcoord_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@15: if(texcoord_array && vnum > texcoord_count) { nuclear@15: logmsg(LOG_DBG, "%s called with vnum=%d, but current texcoord array has %d elements\n", nuclear@15: __FUNCTION__, vnum, texcoord_count); nuclear@15: vnum = texcoord_count; nuclear@15: } 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; j= 0 ? textures + cur_tex : 0); nuclear@14: if(dbg_fill_dump) { nuclear@14: dump_frame(back_buffer); nuclear@14: } nuclear@8: break; nuclear@8: } nuclear@12: skip_prim: ; nuclear@8: } nuclear@14: nuclear@14: dbg_fill_dump = 0; nuclear@8: return 0; nuclear@8: } nuclear@8: nuclear@15: static void proc_vertex(const int32_t *vin, const int32_t *cin, const int32_t *tin, nuclear@15: pvec3 *vout, pvec3 *cout, pvec2 *tout) nuclear@8: { nuclear@8: int i; nuclear@8: int32_t tvert[3]; nuclear@8: int32_t *mvmat = mstack[mtop].m; nuclear@8: nuclear@8: /* transform vertex with current matrix */ nuclear@8: for(i=0; i<3; i++) { nuclear@8: tvert[i] = x16mul(mvmat[0], vin[0]) + nuclear@8: x16mul(mvmat[1], vin[1]) + nuclear@8: x16mul(mvmat[2], vin[2]) + nuclear@8: mvmat[3]; nuclear@8: mvmat += 4; nuclear@8: } nuclear@8: nuclear@8: vout->x = 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@15: nuclear@15: if(texcoord_array) { nuclear@15: tout->x = tin[0]; nuclear@15: tout->y = tin[1]; nuclear@15: } else { nuclear@15: tout->x = im_texcoord[0]; nuclear@15: tout->y = im_texcoord[1]; nuclear@15: } 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: } nuclear@14: nuclear@17: static int count_bits(int x) nuclear@17: { nuclear@17: int i, count = 0; nuclear@17: for(i=0; i<32; i++) { nuclear@17: if(x & 1) count++; nuclear@17: x >>= 1; nuclear@17: } nuclear@17: return count; nuclear@17: } nuclear@17: nuclear@17: int x3d_create_texture_rgb(int xsz, int ysz, const uint16_t *pixels) nuclear@17: { nuclear@17: int i, j; nuclear@17: nuclear@17: if(xsz == 0 || count_bits(xsz) > 1 || ysz == 0 || count_bits(ysz) > 1) { nuclear@17: logmsg(LOG_DBG, "%s: texture size (%dx%d) not power of two!\n", __func__, xsz, ysz); nuclear@17: return -1; nuclear@17: } nuclear@17: nuclear@17: for(i=0; ipixels; nuclear@14: nuclear@14: sprintf(buf, "dump%03d.ppm", ++frameno); nuclear@14: nuclear@14: if(!(fp = fopen(buf, "wb"))) { nuclear@14: fprintf(stderr, "failed to dump file: %s\n", buf); nuclear@14: return -1; nuclear@14: } nuclear@14: nuclear@14: fprintf(fp, "P6\n%d %d\n255\n", frame->x, frame->y); nuclear@14: nuclear@14: npix = frame->x * frame->y; nuclear@14: for(i=0; i