From 1bd8af3c3c9ec41903590d6ad24ff6313a5cc19b Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Fri, 2 Feb 2018 14:00:35 +0200 Subject: [PATCH] - clipper debugging - fixed branches based on uninitialized variables in polyfiller - added g3d_viewport function --- src/3dgfx.c | 34 ++++++++++++--- src/3dgfx.h | 1 + src/metaball.c | 11 ++++- src/polyclip.c | 130 +++++++++++++++++++++++++++++++++++++++++++++++++++++++- src/polyclip.h | 12 +++++- src/polytmpl.h | 32 ++++++++++++-- 6 files changed, 208 insertions(+), 12 deletions(-) diff --git a/src/3dgfx.c b/src/3dgfx.c index 47b3830..46cc9ab 100644 --- a/src/3dgfx.c +++ b/src/3dgfx.c @@ -5,6 +5,7 @@ #include #include "3dgfx.h" #include "polyfill.h" +#include "polyclip.h" #include "inttypes.h" #include "util.h" @@ -42,6 +43,8 @@ struct g3d_state { int width, height; void *pixels; + + int vport[4]; }; static void xform4_vec3(const float *mat, float *vec); @@ -94,6 +97,18 @@ void g3d_framebuffer(int width, int height, void *pixels) pfill_fb.pixels = pixels; pfill_fb.width = width; pfill_fb.height = height; + + st->vport[0] = st->vport[1] = 0; + st->vport[2] = width; + st->vport[3] = height; +} + +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) @@ -376,8 +391,8 @@ 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]; + struct pvertex pv[16]; + struct g3d_vertex v[16]; int vnum = prim; /* primitive vertex counts correspond to enum values */ int mvtop = st->mtop[G3D_MODELVIEW]; int ptop = st->mtop[G3D_PROJECTION]; @@ -402,7 +417,16 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size, xform4_vec3(st->mat[G3D_PROJECTION][ptop], &v[i].x); } - /* TODO clipping */ + /* clipping */ + for(i=0; i<6; i++) { + struct g3d_vertex orig[16]; + memcpy(orig, v, vnum * sizeof *v); + + if(clip_frustum(v, &vnum, orig, vnum, i) < 0) { + /* polygon completely outside of view volume. discard */ + return; + } + } 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 = cround64(v[i].x * 256.0f); diff --git a/src/3dgfx.h b/src/3dgfx.h index fbbccf6..8708e21 100644 --- a/src/3dgfx.h +++ b/src/3dgfx.h @@ -55,6 +55,7 @@ int g3d_init(void); void g3d_destroy(void); void g3d_framebuffer(int width, int height, void *pixels); +void g3d_viewport(int x, int y, int w, int h); void g3d_enable(unsigned int opt); void g3d_disable(unsigned int opt); diff --git a/src/metaball.c b/src/metaball.c index ac0563c..af7ea93 100644 --- a/src/metaball.c +++ b/src/metaball.c @@ -134,7 +134,7 @@ static void update(void) { int i, j; - float tsec = time_msec / 1000.0f; + float tsec = 0;//time_msec / 1000.0f; static float phase[] = {0.0, M_PI / 3.0, M_PI * 0.8}; static float speed[] = {0.8, 1.4, 1.0}; static float scale[][3] = {{1, 2, 0.8}, {0.5, 1.6, 0.6}, {1.5, 0.7, 0.5}}; @@ -159,10 +159,19 @@ static void update(void) static void draw(void) { + int i, j; + update(); memset(fb_pixels, 0, fb_width * fb_height * 2); + for(i=0; i<120; i++) { + for(j=0; j<160; j++) { + fb_pixels[(i + 60) * 320 + (j + 80)] = 0x1e7; + } + } + g3d_viewport(80, 60, 160, 120); + g3d_matrix_mode(G3D_MODELVIEW); g3d_load_identity(); g3d_translate(0, 0, -cam_dist); diff --git a/src/polyclip.c b/src/polyclip.c index 9ef8e95..f5ef9c7 100644 --- a/src/polyclip.c +++ b/src/polyclip.c @@ -10,6 +10,8 @@ struct ray { static int clip_edge(struct g3d_vertex *poly, int *vnumptr, const struct g3d_vertex *v0, const struct g3d_vertex *v1, const struct cplane *plane); +static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr, + const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane); static float distance_signed(float *pos, const struct cplane *plane); static int intersect(const struct ray *ray, const struct cplane *plane, float *t); @@ -24,7 +26,31 @@ int clip_poly(struct g3d_vertex *vout, int *voutnum, for(i=0; i 0 ? 0 : 1; +} + + +int clip_frustum(struct g3d_vertex *vout, int *voutnum, + const struct g3d_vertex *vin, int vnum, int fplane) +{ + int i; + int edges_clipped = 0; + int out_vnum = 0; + + for(i=0; inx * orig_pt_dir[0] + plane->ny * orig_pt_dir[1] + plane->nz * orig_pt_dir[2]) / ndotdir; return 1; } + +/* homogeneous frustum clipper helpers */ + +static int inside_frustum_plane(const struct g3d_vertex *v, int fplane) +{ + switch(fplane) { + case CLIP_LEFT: + return v->x >= -v->w; + case CLIP_RIGHT: + return v->x <= v->w; + case CLIP_BOTTOM: + return v->y >= -v->w; + case CLIP_TOP: + return v->y <= v->w; + case CLIP_NEAR: + return v->z >= -v->w; + case CLIP_FAR: + return v->z <= v->w; + } + assert(0); + return 0; +} + +static float intersect_frustum(const struct g3d_vertex *a, const struct g3d_vertex *b, int fplane) +{ + switch(fplane) { + case CLIP_LEFT: + return (-a->w - a->x) / (b->x - a->x + b->w - a->w); + case CLIP_RIGHT: + return (a->w - a->x) / (b->x - a->x - b->w + a->w); + case CLIP_BOTTOM: + return (-a->w - a->y) / (b->y - a->y + b->w - a->w); + case CLIP_TOP: + return (a->w - a->y) / (b->y - a->y - b->w + a->w); + case CLIP_NEAR: + return (-a->w - a->z) / (b->z - a->z + b->w - a->w); + case CLIP_FAR: + return (a->w - a->z) / (b->z - a->z - b->w + a->w); + } + + assert(0); + return 0; +} + +static int clip_edge_frustum(struct g3d_vertex *poly, int *vnumptr, + const struct g3d_vertex *v0, const struct g3d_vertex *v1, int fplane) +{ + int vnum = *vnumptr; + int in0, in1; + float t; + + in0 = inside_frustum_plane(v0, fplane); + in1 = inside_frustum_plane(v1, fplane); + + if(in0) { + /* start inside */ + if(in1) { + /* all inside */ + poly[vnum++] = *v1; /* append v1 */ + *vnumptr = vnum; + return 1; + } else { + /* going out */ + struct g3d_vertex *vptr = poly + vnum; + + t = intersect_frustum(v0, v1, fplane); + + vptr->x = v0->x + (v1->x - v0->x) * t; + vptr->y = v0->y + (v1->y - v0->y) * t; + vptr->z = v0->z + (v1->z - v0->z) * t; + vptr->w = v0->w + (v1->w - v0->w) * t; + + LERP_VATTR(vptr, v0, v1, t); + ++vnum; /* append new vertex on the intersection point */ + } + } else { + /* start outside */ + if(in1) { + /* going in */ + struct g3d_vertex *vptr = poly + vnum; + + t = intersect_frustum(v0, v1, fplane); + + vptr->x = v0->x + (v1->x - v0->x) * t; + vptr->y = v0->y + (v1->y - v0->y) * t; + vptr->z = v0->z + (v1->z - v0->z) * t; + vptr->w = v0->w + (v1->w - v0->w) * t; + + LERP_VATTR(vptr, v0, v1, t); + ++vnum; /* append new vertex on the intersection point */ + + /* then append v1 ... */ + poly[vnum++] = *v1; + } else { + /* all outside */ + return -1; + } + } + + *vnumptr = vnum; + return 0; +} diff --git a/src/polyclip.h b/src/polyclip.h index c6745e3..0b460cf 100644 --- a/src/polyclip.h +++ b/src/polyclip.h @@ -8,7 +8,13 @@ struct cplane { float nx, ny, nz; }; -/* Polygon clipper +enum { + CLIP_LEFT, CLIP_RIGHT, + CLIP_BOTTOM, CLIP_TOP, + CLIP_NEAR, CLIP_FAR +}; + +/* Generic polygon clipper * returns: * 1 -> fully inside, not clipped * 0 -> straddling the plane and clipped @@ -19,4 +25,8 @@ struct cplane { int clip_poly(struct g3d_vertex *vout, int *voutnum, const struct g3d_vertex *vin, int vnum, struct cplane *plane); +/* Special-case frustum clipper (might be slightly faster) */ +int clip_frustum(struct g3d_vertex *vout, int *voutnum, + const struct g3d_vertex *vin, int vnum, int fplane); + #endif /* POLYCLIP_H_ */ diff --git a/src/polytmpl.h b/src/polytmpl.h index 3b3917e..db5997a 100644 --- a/src/polytmpl.h +++ b/src/polytmpl.h @@ -102,11 +102,35 @@ void POLYFILL(struct pvertex *pv, int nverts) int32_t y1 = pv[next].y; if((y0 >> 8) == (y1 >> 8)) { - if(y0 > y1) { + /*if(y0 > y1) {*/ + int i0, i1; int idx = y0 >> 8; - left[idx].x = pv[i].x < pv[next].x ? pv[i].x : pv[next].x; - right[idx].x = pv[i].x < pv[next].x ? pv[next].x : pv[i].x; - } + if(pv[i].x < pv[next].x) { + i0 = i; + i1 = next; + } else { + i0 = next; + i1 = i; + } + left[idx].x = pv[i0].x; + right[idx].x = pv[i1].x; +#ifdef GOURAUD + left[idx].r = pv[i0].r << COLOR_SHIFT; + left[idx].g = pv[i0].g << COLOR_SHIFT; + left[idx].b = pv[i0].b << COLOR_SHIFT; + right[idx].r = pv[i1].r << COLOR_SHIFT; + right[idx].g = pv[i1].g << COLOR_SHIFT; + right[idx].b = pv[i1].b << COLOR_SHIFT; +#endif +#ifdef TEXMAP + left[idx].u = pv[i0].u; + left[idx].v = pv[i0].v; + right[idx].u = pv[i1].u; + right[idx].v = pv[i1].v; +#endif + if(idx > slbot) slbot = idx; + if(idx < sltop) sltop = idx; + /*}*/ } else { struct pvertex *edge = y0 > y1 ? left : right; uint32_t res = SCANEDGE(pv + i, pv + next, edge); -- 1.7.10.4