X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?p=dosdemo;a=blobdiff_plain;f=src%2F3dgfx.c;h=a642c1e42da16918510da9dcdf6c1770021a167b;hp=41b395991a82a7cf096612e148db973e8a0eefdf;hb=5029eb9f7a538dd58e1c66c0945784acac8cc58b;hpb=0945eeeef21fe85f9a592bfc2e41069a7894b08b diff --git a/src/3dgfx.c b/src/3dgfx.c index 41b3959..a642c1e 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -3,14 +3,36 @@ #include #include #include +#if defined(__WATCOMC__) || defined(_MSC_VER) || defined(__DJGPP__) +#include +#else +#include +#endif #include "3dgfx.h" +#include "gfxutil.h" #include "polyfill.h" +#include "polyclip.h" #include "inttypes.h" +#include "demo.h" +#include "util.h" #define STACK_SIZE 8 typedef float g3d_matrix[16]; -#define MAX_VBUF_SIZE 256 +#define MAX_LIGHTS 4 + +#define IMM_VBUF_SIZE 256 + +struct light { + float x, y, z; + float r, g, b; +}; + +struct material { + float kd[3]; + float ks[3]; + float shin; +}; struct g3d_state { unsigned int opt; @@ -23,10 +45,23 @@ struct g3d_state { g3d_matrix norm_mat; + float ambient[3]; + struct light lt[MAX_LIGHTS]; + struct material mtl; + int width, height; - void *pixels; + uint16_t *pixels; + + int vport[4]; + + /* immediate mode */ + int imm_prim; + int imm_numv, imm_pcount; + struct g3d_vertex imm_curv; + struct g3d_vertex imm_vbuf[IMM_VBUF_SIZE]; }; +static void imm_flush(void); static void xform4_vec3(const float *mat, float *vec); static void xform3_vec3(const float *mat, float *vec); static void shade(struct g3d_vertex *v); @@ -47,12 +82,20 @@ int g3d_init(void) fprintf(stderr, "failed to allocate G3D context\n"); return -1; } + st->opt = G3D_CLIP_FRUSTUM; st->fill_mode = POLYFILL_FLAT; for(i=0; iheight = height; st->pixels = pixels; - pimg_fb.pixels = pixels; - pimg_fb.width = width; - pimg_fb.height = height; + pfill_fb.pixels = pixels; + pfill_fb.width = width; + pfill_fb.height = height; + + g3d_viewport(0, 0, width, height); +} + +/* set the framebuffer pointer, without resetting the size */ +void g3d_framebuffer_addr(void *pixels) +{ + st->pixels = pixels; + pfill_fb.pixels = pixels; +} + +void g3d_viewport(int x, int y, int w, int h) +{ + st->vport[0] = x; + st->vport[1] = y; + st->vport[2] = w; + st->vport[3] = h; } void g3d_enable(unsigned int opt) @@ -272,28 +332,102 @@ const float *g3d_get_matrix(int which, float *m) return st->mat[which][top]; } +void g3d_light_pos(int idx, float x, float y, float z) +{ + int mvtop = st->mtop[G3D_MODELVIEW]; + + st->lt[idx].x = x; + st->lt[idx].y = y; + st->lt[idx].z = z; + + xform4_vec3(st->mat[G3D_MODELVIEW][mvtop], &st->lt[idx].x); +} + +void g3d_light_color(int idx, float r, float g, float b) +{ + st->lt[idx].r = r; + st->lt[idx].g = g; + st->lt[idx].b = b; +} + +void g3d_light_ambient(float r, float g, float b) +{ + st->ambient[0] = r; + st->ambient[1] = g; + st->ambient[2] = b; +} + +void g3d_mtl_diffuse(float r, float g, float b) +{ + st->mtl.kd[0] = r; + st->mtl.kd[1] = g; + st->mtl.kd[2] = b; +} + +void g3d_mtl_specular(float r, float g, float b) +{ + st->mtl.ks[0] = r; + st->mtl.ks[1] = g; + st->mtl.ks[2] = b; +} + +void g3d_mtl_shininess(float shin) +{ + st->mtl.shin = shin; +} + +static INLINE int calc_shift(unsigned int x) +{ + int res = -1; + while(x) { + x >>= 1; + ++res; + } + return res; +} + +static INLINE int calc_mask(unsigned int x) +{ + return x - 1; +} + +void g3d_set_texture(int xsz, int ysz, void *pixels) +{ + pfill_tex.pixels = pixels; + pfill_tex.width = xsz; + pfill_tex.height = ysz; + + pfill_tex.xshift = calc_shift(xsz); + pfill_tex.yshift = calc_shift(ysz); + pfill_tex.xmask = calc_mask(xsz); + pfill_tex.ymask = calc_mask(ysz); +} + void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) { g3d_draw_indexed(prim, varr, varr_size, 0, 0); } void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, - const int16_t *iarr, int iarr_size) + const uint16_t *iarr, int iarr_size) { - int i, j, nfaces; - struct pvertex pv[4]; - struct g3d_vertex v[4]; - int vnum = prim; /* primitive vertex counts correspond to enum values */ + int i, j, vnum, nfaces; + struct pvertex pv[16]; + struct g3d_vertex v[16]; int mvtop = st->mtop[G3D_MODELVIEW]; int ptop = st->mtop[G3D_PROJECTION]; + struct g3d_vertex *tmpv; + + tmpv = alloca(prim * 6 * sizeof *tmpv); /* calc the normal matrix */ memcpy(st->norm_mat, st->mat[G3D_MODELVIEW][mvtop], 16 * sizeof(float)); st->norm_mat[12] = st->norm_mat[13] = st->norm_mat[14] = 0.0f; - nfaces = (iarr ? iarr_size : varr_size) / vnum; + nfaces = (iarr ? iarr_size : varr_size) / prim; for(j=0; jopt & G3D_LIGHTING) { shade(v + i); } + if(st->opt & G3D_TEXTURE_GEN) { + v[i].u = v[i].nx * 0.5 + 0.5; + v[i].v = v[i].ny * 0.5 + 0.5; + } xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x); } - /* TODO clipping */ + /* clipping */ + if(st->opt & G3D_CLIP_FRUSTUM) { + for(i=0; i<6; i++) { + memcpy(tmpv, v, vnum * sizeof *v); + + if(clip_frustum(v, &vnum, tmpv, vnum, i) < 0) { + /* polygon completely outside of view volume. discard */ + vnum = 0; + break; + } + } + + if(!vnum) continue; + } for(i=0; iwidth; - v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->height; + v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->vport[2] + st->vport[0]; + v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->vport[3] + st->vport[1]; /* convert pos to 24.8 fixed point */ - pv[i].x = (int32_t)(v[i].x * 256.0f); - pv[i].y = (int32_t)(v[i].y * 256.0f); + pv[i].x = cround64(v[i].x * 256.0f); + pv[i].y = cround64(v[i].y * 256.0f); /* convert tex coords to 16.16 fixed point */ - pv[i].u = (int32_t)(v[i].u * 65536.0f); - pv[i].v = (int32_t)(v[i].v * 65536.0f); + pv[i].u = cround64(v[i].u * 65536.0f); + pv[i].v = cround64(v[i].v * 65536.0f); /* pass the color through as is */ pv[i].r = v[i].r; pv[i].g = v[i].g; pv[i].b = v[i].b; + pv[i].a = v[i].a; } /* backface culling */ @@ -338,7 +490,7 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, int32_t ay = pv[1].y - pv[0].y; int32_t bx = pv[2].x - pv[0].x; int32_t by = pv[2].y - pv[0].y; - int32_t cross_z = ax * (by >> 8) - ay * (bx >> 8); + int32_t cross_z = (ax >> 4) * (by >> 4) - (ay >> 4) * (bx >> 4); int sign = (cross_z >> 31) & 1; if(!(sign ^ st->frontface)) { @@ -346,10 +498,120 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, } } - polyfill(st->fill_mode, pv, vnum); + switch(vnum) { + case 1: + if(st->opt & G3D_BLEND) { + int r, g, b; + int inv_alpha = 255 - pv[0].a; + uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8); + r = ((int)pv[0].r * pv[0].a + UNPACK_R16(*dest) * inv_alpha) >> 8; + g = ((int)pv[0].g * pv[0].a + UNPACK_G16(*dest) * inv_alpha) >> 8; + b = ((int)pv[0].b * pv[0].a + UNPACK_B16(*dest) * inv_alpha) >> 8; + *dest++ = PACK_RGB16(r, g, b); + } else { + uint16_t *dest = st->pixels + (pv[0].y >> 8) * st->width + (pv[0].x >> 8); + *dest = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b); + } + break; + + case 2: + /* TODO: draw line */ + break; + + default: + polyfill(st->fill_mode, pv, vnum); + } + } +} + +void g3d_begin(int prim) +{ + st->imm_prim = prim; + st->imm_pcount = prim; + st->imm_numv = 0; +} + +void g3d_end(void) +{ + imm_flush(); +} + +static void imm_flush(void) +{ + int numv = st->imm_numv; + st->imm_numv = 0; + g3d_draw_indexed(st->imm_prim, st->imm_vbuf, numv, 0, 0); +} + +void g3d_vertex(float x, float y, float z) +{ + struct g3d_vertex *vptr = st->imm_vbuf + st->imm_numv++; + *vptr = st->imm_curv; + vptr->x = x; + vptr->y = y; + vptr->z = z; + vptr->w = 1.0f; + + if(!--st->imm_pcount) { + if(st->imm_numv >= IMM_VBUF_SIZE - st->imm_prim) { + imm_flush(); + } + st->imm_pcount = st->imm_prim; } } +void g3d_normal(float x, float y, float z) +{ + st->imm_curv.nx = x; + st->imm_curv.ny = y; + st->imm_curv.nz = z; +} + +void g3d_color3b(unsigned char r, unsigned char g, unsigned char b) +{ + st->imm_curv.r = r; + st->imm_curv.g = g; + st->imm_curv.b = b; + st->imm_curv.a = 255; +} + +void g3d_color4b(unsigned char r, unsigned char g, unsigned char b, unsigned char a) +{ + st->imm_curv.r = r; + st->imm_curv.g = g; + st->imm_curv.b = b; + st->imm_curv.a = a; +} + +void g3d_color3f(float r, float g, float b) +{ + int ir = r * 255.0f; + int ig = g * 255.0f; + int ib = b * 255.0f; + st->imm_curv.r = ir > 255 ? 255 : ir; + st->imm_curv.g = ig > 255 ? 255 : ig; + st->imm_curv.b = ib > 255 ? 255 : ib; + st->imm_curv.a = 255; +} + +void g3d_color4f(float r, float g, float b, float a) +{ + int ir = r * 255.0f; + int ig = g * 255.0f; + int ib = b * 255.0f; + int ia = a * 255.0f; + st->imm_curv.r = ir > 255 ? 255 : ir; + st->imm_curv.g = ig > 255 ? 255 : ig; + st->imm_curv.b = ib > 255 ? 255 : ib; + st->imm_curv.a = ia > 255 ? 255 : ia; +} + +void g3d_texcoord(float u, float v) +{ + st->imm_curv.u = u; + st->imm_curv.v = v; +} + static void xform4_vec3(const float *mat, float *vec) { float x = mat[0] * vec[0] + mat[4] * vec[1] + mat[8] * vec[2] + mat[12]; @@ -374,7 +636,53 @@ static void xform3_vec3(const float *mat, float *vec) vec[2] = z; } +#define NORMALIZE(v) \ + do { \ + float len = sqrt(v[0] * v[0] + v[1] * v[1] + v[2] * v[2]); \ + if(len != 0.0) { \ + float s = 1.0 / len; \ + v[0] *= s; \ + v[1] *= s; \ + v[2] *= s; \ + } \ + } while(0) + static void shade(struct g3d_vertex *v) { - v->r = v->g = v->b = 255; + int i, r, g, b; + float color[3]; + + color[0] = st->ambient[0] * st->mtl.kd[0]; + color[1] = st->ambient[1] * st->mtl.kd[1]; + color[2] = st->ambient[2] * st->mtl.kd[2]; + + for(i=0; iopt & (G3D_LIGHT0 << i))) { + continue; + } + + ldir[0] = st->lt[i].x - v->x; + ldir[1] = st->lt[i].y - v->y; + ldir[2] = st->lt[i].z - v->z; + NORMALIZE(ldir); + + if((ndotl = v->nx * ldir[0] + v->ny * ldir[1] + v->nz * ldir[2]) < 0.0f) { + ndotl = 0.0f; + } + + color[0] += st->mtl.kd[0] * st->lt[i].r * ndotl; + color[1] += st->mtl.kd[1] * st->lt[i].g * ndotl; + color[2] += st->mtl.kd[2] * st->lt[i].b * ndotl; + } + + r = cround64(color[0] * 255.0); + g = cround64(color[1] * 255.0); + b = cround64(color[2] * 255.0); + + v->r = r > 255 ? 255 : r; + v->g = g > 255 ? 255 : g; + v->b = b > 255 ? 255 : b; }