nuclear@1: #include nuclear@5: #include nuclear@5: #include nuclear@1: #include "min3d.h" nuclear@1: #include "m3dimpl.h" nuclear@6: #include "logger.h" nuclear@1: nuclear@1: #ifndef M_PI nuclear@1: #define M_PI 3.141592653 nuclear@1: #endif nuclear@1: nuclear@3: struct min3d_context *m3dctx; nuclear@3: nuclear@1: int m3d_init(void) nuclear@1: { nuclear@1: if(!(m3dctx = malloc(sizeof *m3dctx))) { nuclear@1: return -1; nuclear@1: } nuclear@1: memset(m3dctx, 0, sizeof *m3dctx); nuclear@1: nuclear@1: m3d_matrix_mode(M3D_PROJECTION); nuclear@1: m3d_load_identity(); nuclear@1: m3d_matrix_mode(M3D_MODELVIEW); nuclear@1: m3d_load_identity(); nuclear@6: nuclear@6: m3d_color(1, 1, 1); nuclear@1: return 0; nuclear@1: } nuclear@1: nuclear@1: void m3d_shutdown(void) nuclear@1: { nuclear@1: free(m3dctx); nuclear@1: } nuclear@1: nuclear@1: void m3d_set_buffers(struct m3d_image *cbuf, uint16_t *zbuf) nuclear@1: { nuclear@1: m3dctx->cbuf = cbuf; nuclear@1: m3dctx->zbuf = zbuf; nuclear@6: nuclear@9: m3d_viewport(0, 0, cbuf->xsz, cbuf->ysz); nuclear@6: } nuclear@6: nuclear@6: void m3d_clear_color(float r, float g, float b) nuclear@6: { nuclear@6: m3dctx->clear_color[0] = (int)((r > 1.0 ? 1.0 : r) * 255.0); nuclear@6: m3dctx->clear_color[1] = (int)((g > 1.0 ? 1.0 : g) * 255.0); nuclear@6: m3dctx->clear_color[2] = (int)((b > 1.0 ? 1.0 : b) * 255.0); nuclear@1: } nuclear@1: nuclear@1: void m3d_clear(unsigned int bmask) nuclear@1: { nuclear@9: int num_pixels = m3dctx->cbuf->xsz * m3dctx->cbuf->ysz; nuclear@1: if(bmask & M3D_COLOR_BUFFER_BIT) { nuclear@9: memset(m3dctx->cbuf->pixels, 0, num_pixels * 4); nuclear@9: /* nuclear@9: int i; nuclear@6: unsigned char *ptr = m3dctx->cbuf->pixels; nuclear@6: unsigned char r = m3dctx->clear_color[0]; nuclear@6: unsigned char g = m3dctx->clear_color[1]; nuclear@6: unsigned char b = m3dctx->clear_color[2]; nuclear@6: for(i=0; izbuf, 0xff, num_pixels * sizeof *m3dctx->zbuf); nuclear@1: } nuclear@1: } nuclear@1: nuclear@1: nuclear@1: void m3d_enable(int bit) nuclear@1: { nuclear@1: m3dctx->state |= (1 << bit); nuclear@1: } nuclear@1: nuclear@1: void m3d_disable(int bit) nuclear@1: { nuclear@1: m3dctx->state &= ~(1 << bit); nuclear@1: } nuclear@1: nuclear@9: void m3d_viewport(int x, int y, int xsz, int ysz) nuclear@9: { nuclear@9: m3dctx->vport[0] = x; nuclear@9: m3dctx->vport[1] = y; nuclear@9: m3dctx->vport[2] = xsz; nuclear@9: m3dctx->vport[3] = ysz; nuclear@9: } nuclear@9: nuclear@1: nuclear@1: /* matrix stack */ nuclear@1: void m3d_matrix_mode(int mode) nuclear@1: { nuclear@1: m3dctx->mmode = mode; nuclear@1: } nuclear@1: nuclear@6: void m3d_push_matrix(void) nuclear@6: { nuclear@6: int mm = m3dctx->mmode; nuclear@6: int top = m3dctx->mstack[mm].top; nuclear@6: if(top < MSTACK_SIZE) { nuclear@6: float *cur = m3dctx->mstack[mm].m[top++]; nuclear@6: memcpy(m3dctx->mstack[mm].m[top], cur, 16 * sizeof *cur); nuclear@6: m3dctx->mstack[mm].top = top; nuclear@6: } nuclear@6: } nuclear@6: nuclear@6: void m3d_pop_matrix(void) nuclear@6: { nuclear@6: int mm = m3dctx->mmode; nuclear@6: if(m3dctx->mstack[mm].top > 0) { nuclear@6: --m3dctx->mstack[mm].top; nuclear@6: } nuclear@6: } nuclear@6: nuclear@1: void m3d_load_identity(void) nuclear@1: { nuclear@1: static const float mid[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@1: m3d_load_matrix(mid); nuclear@1: } nuclear@1: nuclear@1: void m3d_load_matrix(const float *m) nuclear@1: { nuclear@1: int top = m3dctx->mstack[m3dctx->mmode].top; nuclear@1: memcpy(m3dctx->mstack[m3dctx->mmode].m[top], m, 16 * sizeof *m); nuclear@1: } nuclear@1: nuclear@17: void m3d_load_transpose_matrix(const float *m) nuclear@17: { nuclear@17: int i, j, lin = 0; nuclear@17: int top = m3dctx->mstack[m3dctx->mmode].top; nuclear@17: float *dest = m3dctx->mstack[m3dctx->mmode].m[top]; nuclear@17: nuclear@17: for(i=0; i<4; i++) { nuclear@17: for(j=0; j<4; j++) { nuclear@17: *dest++ = m[j * 4 + i]; nuclear@17: } nuclear@17: } nuclear@17: } nuclear@17: nuclear@1: #define M(i,j) (((i) << 2) + (j)) nuclear@1: void m3d_mult_matrix(const float *m2) nuclear@1: { nuclear@1: int i, j, top = m3dctx->mstack[m3dctx->mmode].top; nuclear@1: float m1[16]; nuclear@1: float *dest = m3dctx->mstack[m3dctx->mmode].m[top]; nuclear@1: nuclear@1: memcpy(m1, dest, sizeof m1); nuclear@1: nuclear@1: for(i=0; i<4; i++) { nuclear@1: for(j=0; j<4; j++) { nuclear@17: *dest++ = m1[M(0,j)] * m2[M(i,0)] + nuclear@1: m1[M(1,j)] * m2[M(i,1)] + nuclear@1: m1[M(2,j)] * m2[M(i,2)] + nuclear@1: m1[M(3,j)] * m2[M(i,3)]; nuclear@1: } nuclear@1: } nuclear@1: } nuclear@1: nuclear@17: void m3d_mult_transpose_matrix(const float *m2) nuclear@17: { nuclear@17: int i, j, top = m3dctx->mstack[m3dctx->mmode].top; nuclear@17: float m1[16]; nuclear@17: float *dest = m3dctx->mstack[m3dctx->mmode].m[top]; nuclear@17: nuclear@17: memcpy(m1, dest, sizeof m1); nuclear@17: nuclear@17: for(i=0; i<4; i++) { nuclear@17: for(j=0; j<4; j++) { nuclear@17: *dest++ = m1[M(0,j)] * m2[M(0,i)] + nuclear@17: m1[M(1,j)] * m2[M(1,i)] + nuclear@17: m1[M(2,j)] * m2[M(2,i)] + nuclear@17: m1[M(3,j)] * m2[M(3,i)]; nuclear@17: } nuclear@17: } nuclear@17: } nuclear@17: nuclear@1: void m3d_translate(float x, float y, float z) nuclear@1: { nuclear@1: float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@1: m[12] = x; nuclear@1: m[13] = y; nuclear@1: m[14] = z; nuclear@1: m3d_mult_matrix(m); nuclear@1: } nuclear@1: nuclear@1: void m3d_rotate(float deg, float x, float y, float z) nuclear@1: { nuclear@1: float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@1: nuclear@1: float angle = M_PI * deg / 180.0f; nuclear@1: float sina = sin(angle); nuclear@1: float cosa = cos(angle); nuclear@1: float one_minus_cosa = 1.0f - cosa; nuclear@1: float nxsq = x * x; nuclear@1: float nysq = y * y; nuclear@1: float nzsq = z * z; nuclear@1: nuclear@1: xform[0] = nxsq + (1.0f - nxsq) * cosa; nuclear@1: xform[4] = x * y * one_minus_cosa - z * sina; nuclear@1: xform[8] = x * z * one_minus_cosa + y * sina; nuclear@1: xform[1] = x * y * one_minus_cosa + z * sina; nuclear@1: xform[5] = nysq + (1.0 - nysq) * cosa; nuclear@1: xform[9] = y * z * one_minus_cosa - x * sina; nuclear@1: xform[2] = x * z * one_minus_cosa - y * sina; nuclear@1: xform[6] = y * z * one_minus_cosa + x * sina; nuclear@1: xform[10] = nzsq + (1.0 - nzsq) * cosa; nuclear@1: nuclear@1: m3d_mult_matrix(xform); nuclear@1: } nuclear@1: nuclear@1: void m3d_scale(float x, float y, float z) nuclear@1: { nuclear@1: static float m[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@1: m[0] = x; nuclear@1: m[5] = y; nuclear@1: m[10] = z; nuclear@1: m3d_mult_matrix(m); nuclear@1: } nuclear@1: nuclear@1: void m3d_frustum(float left, float right, float bottom, float top, float nr, float fr) nuclear@1: { nuclear@1: float xform[] = {1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1}; nuclear@1: nuclear@1: float dx = right - left; nuclear@1: float dy = top - bottom; nuclear@1: float dz = fr - nr; nuclear@1: nuclear@1: float a = (right + left) / dx; nuclear@1: float b = (top + bottom) / dy; nuclear@1: float c = -(fr + nr) / dz; nuclear@1: float d = -2.0 * fr * nr / dz; nuclear@1: nuclear@1: xform[0] = 2.0 * nr / dx; nuclear@1: xform[5] = 2.0 * nr / dy; nuclear@1: xform[8] = a; nuclear@1: xform[9] = b; nuclear@1: xform[10] = c; nuclear@1: xform[11] = -1.0f; nuclear@1: xform[14] = d; nuclear@1: nuclear@1: m3d_mult_matrix(xform); nuclear@1: } nuclear@1: nuclear@1: void m3d_perspective(float vfov, float aspect, float nr, float fr) nuclear@1: { nuclear@1: float vfov_rad = M_PI * vfov / 180.0; nuclear@1: float x = nr * tan(vfov_rad / 2.0); nuclear@1: m3d_frustum(-aspect * x, aspect * x, -x, x, nr, fr); nuclear@1: } nuclear@1: nuclear@2: static void xform4(float *mat, float *vec) nuclear@2: { nuclear@6: float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12]; nuclear@6: float y = mat[1] * vec[0] + mat[5] * vec[1] + mat[9] * vec[2] + mat[13]; nuclear@6: float z = mat[2] * vec[0] + mat[6] * vec[1] + mat[10] * vec[2] + mat[14]; nuclear@6: float w = mat[3] * vec[0] + mat[7] * vec[1] + mat[11] * vec[2] + mat[15]; nuclear@2: nuclear@2: vec[0] = x; nuclear@2: vec[1] = y; nuclear@2: vec[2] = z; nuclear@2: vec[3] = w; nuclear@2: } nuclear@2: nuclear@3: static int proc_prim(int prim, struct min3d_vertex *res, struct min3d_vertex *v) nuclear@2: { nuclear@3: int i; nuclear@3: int vcount = prim; nuclear@3: int mvtop, ptop; nuclear@3: float *mvmat, *pmat; nuclear@6: int *vport = m3dctx->vport; nuclear@3: nuclear@3: mvtop = m3dctx->mstack[M3D_MODELVIEW].top; nuclear@3: mvmat = m3dctx->mstack[M3D_MODELVIEW].m[mvtop]; nuclear@3: ptop = m3dctx->mstack[M3D_PROJECTION].top; nuclear@3: pmat = m3dctx->mstack[M3D_PROJECTION].m[ptop]; nuclear@3: nuclear@3: /* transform to view space */ nuclear@3: for(i=0; i= w || nuclear@3: res[0].pos[0] / w < -1 || res[0].pos[0] / w >= 1 || nuclear@3: res[0].pos[1] / w < -1 || res[0].pos[1] / w >= 1) { nuclear@3: vcount = 0; nuclear@3: } nuclear@3: } nuclear@3: break; nuclear@3: nuclear@3: default: nuclear@3: break; /* TODO */ nuclear@3: } nuclear@3: nuclear@6: /* perspective division & viewport */ nuclear@3: for(i=0; ivert_array = (float*)varr; nuclear@5: } nuclear@5: nuclear@5: void m3d_normal_array(const float *narr) nuclear@5: { nuclear@6: m3dctx->norm_array = (float*)narr; nuclear@5: } nuclear@5: nuclear@5: void m3d_color_array(const float *carr) nuclear@5: { nuclear@6: m3dctx->col_array = (float*)carr; nuclear@5: } nuclear@5: nuclear@5: void m3d_texcoord_array(const float *tcarr) nuclear@5: { nuclear@6: m3dctx->tc_array = (float*)tcarr; nuclear@5: } nuclear@5: nuclear@5: nuclear@5: void m3d_draw(int prim, int vcount) nuclear@1: { nuclear@3: int i; nuclear@3: struct min3d_vertex v[4]; nuclear@3: struct min3d_vertex resv[16]; nuclear@5: const float *varr = m3dctx->vert_array; nuclear@5: const float *carr = m3dctx->col_array; nuclear@5: nuclear@5: if(!varr) return; nuclear@3: nuclear@3: for(i=0; iim_color[0]) * 255.0; nuclear@9: g = (carr ? *carr++ : m3dctx->im_color[1]) * 255.0; nuclear@9: b = (carr ? *carr++ : m3dctx->im_color[2]) * 255.0; nuclear@9: v[idx].color = (r << 16) | (g << 8) | b; nuclear@3: nuclear@3: if(idx == prim - 1) { nuclear@3: int resnum = proc_prim(prim, resv, v); nuclear@3: switch(resnum) { nuclear@3: case 1: nuclear@9: m3d_draw_point(resv); nuclear@3: break; nuclear@3: nuclear@9: case 2: nuclear@9: m3d_draw_line(resv); nuclear@3: break; nuclear@3: nuclear@3: default: nuclear@9: m3d_draw_poly(resv, resnum); nuclear@3: } nuclear@3: } nuclear@3: } nuclear@1: } nuclear@1: nuclear@9: void m3d_draw_indexed(int prim, const unsigned int *idxarr, int icount) nuclear@1: { nuclear@9: int i, vcount = prim; nuclear@9: struct min3d_vertex v[4]; nuclear@9: struct min3d_vertex resv[16]; nuclear@9: const float *varr = m3dctx->vert_array; nuclear@9: const float *carr = m3dctx->col_array; nuclear@9: nuclear@9: if(!varr) return; nuclear@9: nuclear@9: for(i=0; iim_color[0]) * 255.0; nuclear@9: g = (carr ? carr[index * 3 + 1] : m3dctx->im_color[1]) * 255.0; nuclear@9: b = (carr ? carr[index * 3 + 2] : m3dctx->im_color[2]) * 255.0; nuclear@9: v[vnum].color = (r << 16) | (g << 8) | b; nuclear@9: nuclear@9: if(vnum == vcount - 1) { nuclear@9: int resnum = proc_prim(prim, resv, v); nuclear@9: switch(resnum) { nuclear@9: case 1: nuclear@9: m3d_draw_point(resv); nuclear@9: break; nuclear@9: nuclear@9: case 2: nuclear@9: m3d_draw_line(resv); nuclear@9: break; nuclear@9: nuclear@9: default: nuclear@9: m3d_draw_poly(resv, resnum); nuclear@9: } nuclear@9: } nuclear@9: } nuclear@1: } nuclear@1: nuclear@6: void m3d_begin(int prim) nuclear@6: { nuclear@6: m3dctx->im_prim = prim; nuclear@6: m3dctx->im_idx = 0; nuclear@6: nuclear@6: m3dctx->vert_array = m3dctx->im_varr; nuclear@6: m3dctx->norm_array = 0; nuclear@6: m3dctx->col_array = 0; nuclear@6: m3dctx->tc_array = 0; nuclear@6: } nuclear@6: nuclear@6: void m3d_end(void) nuclear@6: { nuclear@6: } nuclear@6: nuclear@6: void m3d_vertex(float x, float y, float z) nuclear@6: { nuclear@6: int nverts = m3dctx->im_prim; nuclear@6: int idx = m3dctx->im_idx; nuclear@6: float *v = m3dctx->vert_array + idx * 3; nuclear@6: nuclear@6: v[0] = x; nuclear@6: v[1] = y; nuclear@6: v[2] = z; nuclear@6: nuclear@6: if(m3dctx->norm_array) { nuclear@6: float *ptr = m3dctx->im_narr + idx * 3; nuclear@6: ptr[0] = m3dctx->im_normal[0]; nuclear@6: ptr[1] = m3dctx->im_normal[1]; nuclear@6: ptr[2] = m3dctx->im_normal[2]; nuclear@6: } nuclear@6: if(m3dctx->col_array) { nuclear@6: float *ptr = m3dctx->im_carr + idx * 3; nuclear@6: ptr[0] = m3dctx->im_color[0]; nuclear@6: ptr[1] = m3dctx->im_color[1]; nuclear@6: ptr[2] = m3dctx->im_color[2]; nuclear@6: } nuclear@6: if(m3dctx->tc_array) { nuclear@6: float *ptr = m3dctx->im_texcoord + idx * 2; nuclear@6: ptr[0] = m3dctx->im_texcoord[0]; nuclear@6: ptr[1] = m3dctx->im_texcoord[1]; nuclear@6: } nuclear@6: nuclear@6: if(++idx == nverts) { nuclear@6: m3d_draw(m3dctx->im_prim, nverts); nuclear@6: idx = 0; nuclear@6: } nuclear@6: nuclear@6: m3dctx->im_idx = idx; nuclear@6: } nuclear@6: nuclear@6: void m3d_normal(float x, float y, float z) nuclear@6: { nuclear@6: m3dctx->im_normal[0] = x; nuclear@6: m3dctx->im_normal[1] = y; nuclear@6: m3dctx->im_normal[2] = z; nuclear@6: } nuclear@6: nuclear@6: void m3d_color(float x, float y, float z) nuclear@6: { nuclear@6: m3dctx->im_color[0] = x; nuclear@6: m3dctx->im_color[1] = y; nuclear@6: m3dctx->im_color[2] = z; nuclear@6: } nuclear@6: nuclear@6: void m3d_texcoord(float x, float y) nuclear@6: { nuclear@6: m3dctx->im_texcoord[0] = x; nuclear@6: m3dctx->im_texcoord[1] = y; nuclear@6: }