- clipper debugging
authorJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 2 Feb 2018 12:00:35 +0000 (14:00 +0200)
committerJohn Tsiombikas <nuclear@member.fsf.org>
Fri, 2 Feb 2018 12:00:35 +0000 (14:00 +0200)
- fixed branches based on uninitialized variables in polyfiller
- added g3d_viewport function

src/3dgfx.c
src/3dgfx.h
src/metaball.c
src/polyclip.c
src/polyclip.h
src/polytmpl.h

index 47b3830..46cc9ab 100644 (file)
@@ -5,6 +5,7 @@
 #include <assert.h>
 #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; i<vnum; i++) {
                        if(v[i].w != 0.0f) {
@@ -412,8 +436,8 @@ void g3d_draw_indexed(int prim, const struct g3d_vertex *varr, int varr_size,
                        }
 
                        /* viewport transformation */
-                       v[i].x = (v[i].x * 0.5f + 0.5f) * (float)st->width;
-                       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);
index fbbccf6..8708e21 100644 (file)
@@ -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);
index ac0563c..af7ea93 100644 (file)
@@ -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);
index 9ef8e95..f5ef9c7 100644 (file)
@@ -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<vnum; i++) {
                int res = clip_edge(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, plane);
                if(res == 0) {
-                       edges_clipped++;
+                       ++edges_clipped;
+               }
+       }
+
+       if(out_vnum <= 0) {
+               assert(edges_clipped == 0);
+               return -1;
+       }
+
+       *voutnum = out_vnum;
+       return edges_clipped > 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; i<vnum; i++) {
+               int res = clip_edge_frustum(vout, &out_vnum, vin + i, vin + (i + 1) % vnum, fplane);
+               if(res == 0) {
+                       ++edges_clipped;
                }
        }
 
@@ -152,3 +178,105 @@ static int intersect(const struct ray *ray, const struct cplane *plane, float *t
        *t = (plane->nx * 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;
+}
index c6745e3..0b460cf 100644 (file)
@@ -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_ */
index 3b3917e..db5997a 100644 (file)
@@ -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);