X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2F3dgfx.c;h=47b3830ee38fcc190b04a67fbd6c1481e6123b93;hb=07ce18b114e1e01b2a85a04079128f3eb754de1d;hp=49b4c2c2c413b8ca34f91883681d5553a0983a40;hpb=633743214adddf6ec20f8b1bee1782e6966023af;p=dosdemo diff --git a/src/3dgfx.c b/src/3dgfx.c index 49b4c2c..47b3830 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -6,15 +6,29 @@ #include "3dgfx.h" #include "polyfill.h" #include "inttypes.h" +#include "util.h" #define STACK_SIZE 8 typedef float g3d_matrix[16]; #define MAX_VBUF_SIZE 256 +#define MAX_LIGHTS 4 + +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; int frontface; + int fill_mode; g3d_matrix mat[G3D_NUM_MATRICES][STACK_SIZE]; int mtop[G3D_NUM_MATRICES]; @@ -22,6 +36,10 @@ struct g3d_state { g3d_matrix norm_mat; + float ambient[3]; + struct light lt[MAX_LIGHTS]; + struct material mtl; + int width, height; void *pixels; }; @@ -46,11 +64,19 @@ int g3d_init(void) fprintf(stderr, "failed to allocate G3D context\n"); return -1; } + st->fill_mode = POLYFILL_FLAT; for(i=0; iwidth = width; st->height = height; st->pixels = pixels; + + pfill_fb.pixels = pixels; + pfill_fb.width = width; + pfill_fb.height = height; } void g3d_enable(unsigned int opt) @@ -91,6 +121,11 @@ void g3d_front_face(unsigned int order) st->frontface = order; } +void g3d_polygon_mode(int pmode) +{ + st->fill_mode = pmode; +} + void g3d_matrix_mode(int mmode) { st->mmode = mmode; @@ -251,16 +286,96 @@ void g3d_perspective(float vfov_deg, float aspect, float znear, float zfar) g3d_mult_matrix(m); } -#define CROSS(res, a, b) \ - do { \ - (res)[0] = (a)[1] * (b)[2] - (a)[2] * (b)[1]; \ - (res)[1] = (a)[2] * (b)[0] - (a)[0] * (b)[2]; \ - (res)[2] = (a)[0] * (b)[1] - (a)[1] * (b)[0]; \ - } while(0) +const float *g3d_get_matrix(int which, float *m) +{ + int top = st->mtop[which]; + + if(m) { + memcpy(m, st->mat[which][top], 16 * sizeof(float)); + } + 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) { - int i; + 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) +{ + int i, j, nfaces; struct pvertex pv[4]; struct g3d_vertex v[4]; int vnum = prim; /* primitive vertex counts correspond to enum values */ @@ -271,11 +386,12 @@ void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) 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; - while(varr_size >= vnum) { - varr_size -= vnum; + nfaces = (iarr ? iarr_size : varr_size) / vnum; + + for(j=0; jmat[G3D_MODELVIEW][mvtop], &v[i].x); xform3_vec3(st->norm_mat, &v[i].nx); @@ -300,11 +416,11 @@ void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) v[i].y = (0.5f - v[i].y * 0.5f) * (float)st->height; /* 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; @@ -325,7 +441,7 @@ void g3d_draw(int prim, const struct g3d_vertex *varr, int varr_size) } } - polyfill_flat(pv, vnum); + polyfill(st->fill_mode, pv, vnum); } } @@ -353,7 +469,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; }