split the polyfiller to a preprocessor-based template file, included
authorJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 3 Oct 2016 07:24:08 +0000 (10:24 +0300)
committerJohn Tsiombikas <nuclear@mutantstargoat.com>
Mon, 3 Oct 2016 07:24:08 +0000 (10:24 +0300)
multiple times in polyfill.c to instanciate all the variants. currently
fully implemented are: flat and gouraud.

src/3dgfx.h
src/polyfill.c
src/polyfill.h
src/polytest.c
src/polytmpl.h [new file with mode: 0644]

index ee9de63..ecc3f3c 100644 (file)
@@ -37,7 +37,8 @@ enum { G3D_CCW, G3D_CW };
 /* arg to g3d_polygon_mode */
 enum {
        G3D_WIRE,
-       G3D_FLAT
+       G3D_FLAT,
+       G3D_GOURAUD,
 };
 
 /* matrix stacks */
index 80bfee5..634d525 100644 (file)
@@ -14,7 +14,9 @@
 void (*fillfunc[])(struct pvertex*, int) = {
        polyfill_wire,
        polyfill_flat,
-       0, 0, 0
+       polyfill_gouraud,
+       polyfill_tex,
+       polyfill_tex_gouraud
 };
 
 struct pimage pimg_fb, pimg_texture;
@@ -55,92 +57,37 @@ void polyfill_wire(struct pvertex *verts, int nverts)
        }
 }
 
-static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge);
-
 #define NEXTIDX(x) (((x) - 1 + nverts) % nverts)
 #define PREVIDX(x) (((x) + 1) % nverts)
 
-void polyfill_flat(struct pvertex *pv, int nverts)
-{
-       int i;
-       int topidx = 0, botidx = 0, sltop = pimg_fb.height, slbot = 0;
-       struct pvertex *left, *right;
-       uint16_t color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
-
-       for(i=1; i<nverts; i++) {
-               if(pv[i].y < pv[topidx].y) topidx = i;
-               if(pv[i].y > pv[botidx].y) botidx = i;
-       }
-
-       left = (struct pvertex*)alloca(pimg_fb.height * sizeof *left);
-       right = (struct pvertex*)alloca(pimg_fb.height * sizeof *right);
-       memset(left, 0, pimg_fb.height * sizeof *left);
-       memset(right, 0, pimg_fb.height * sizeof *right);
-
-       for(i=0; i<nverts; i++) {
-               int next = NEXTIDX(i);
-               int32_t y0 = pv[i].y;
-               int32_t y1 = pv[next].y;
-
-               if((y0 >> 8) == (y1 >> 8)) {
-                       if(y0 > y1) {
-                               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;
-                       }
-               } else {
-                       struct pvertex *edge = y0 > y1 ? left : right;
-                       uint32_t res = scan_edge(pv + i, pv + next, edge);
-                       uint32_t tmp = (res >> 16) & 0xffff;
-                       if(tmp > slbot) slbot = tmp;
-                       if((tmp = res & 0xffff) < sltop) {
-                               sltop = tmp;
-                       }
-               }
-       }
-
-       for(i=sltop; i<=slbot; i++) {
-               int32_t x;
-               uint16_t *pixptr;
-
-               x = left[i].x;
-               pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 8);
-
-               while(x <= right[i].x) {
-#ifdef DEBUG_POLYFILL
-                       *pixptr++ += 15;
-#else
-                       *pixptr++ = color;
-#endif
-                       x += 256;
-               }
-       }
-}
-
-static uint32_t scan_edge(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
-{
-       int i;
-       int32_t x, dx, dy, slope;
-       int32_t start_idx, end_idx;
-
-       if(v0->y > v1->y) {
-               struct pvertex *tmp = v0;
-               v0 = v1;
-               v1 = tmp;
-       }
-
-       dy = v1->y - v0->y;
-       dx = v1->x - v0->x;
-       slope = (dx << 8) / dy;
-
-       start_idx = v0->y >> 8;
-       end_idx = v1->y >> 8;
-
-       x = v0->x;
-       for(i=start_idx; i<end_idx; i++) {
-               edge[i].x = x;
-               x += slope;
-       }
-
-       return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
-}
+#define POLYFILL polyfill_flat
+#define SCANEDGE scanedge_flat
+#undef GOURAUD
+#undef TEXMAP
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_gouraud
+#define SCANEDGE scanedge_gouraud
+#define GOURAUD
+#undef TEXMAP
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex
+#define SCANEDGE scanedge_tex
+#undef GOURAUD
+#define TEXMAP
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
+
+#define POLYFILL polyfill_tex_gouraud
+#define SCANEDGE scanedge_tex_gouraud
+#define GOURAUD
+#define TEXMAP
+#include "polytmpl.h"
+#undef POLYFILL
+#undef SCANEDGE
index b39574a..a01130c 100644 (file)
@@ -15,7 +15,7 @@ enum {
 struct pvertex {
        int32_t x, y; /* 24.8 fixed point */
        int32_t u, v; /* 16.16 fixed point */
-       unsigned char r, g, b;
+       int32_t r, g, b;  /* int 0-255 */
 };
 
 struct pimage {
@@ -29,5 +29,8 @@ extern struct pimage pimg_texture;
 void polyfill(int mode, struct pvertex *verts, int nverts);
 void polyfill_wire(struct pvertex *verts, int nverts);
 void polyfill_flat(struct pvertex *verts, int nverts);
+void polyfill_gouraud(struct pvertex *verts, int nverts);
+void polyfill_tex(struct pvertex *verts, int nverts);
+void polyfill_tex_gouraud(struct pvertex *verts, int nverts);
 
 #endif /* POLYFILL_H_ */
index 58fdb41..e7c3cdf 100644 (file)
@@ -76,6 +76,8 @@ static void start(long trans_time)
        g3d_enable(G3D_CULL_FACE);
        g3d_enable(G3D_LIGHTING);
        g3d_enable(G3D_LIGHT0);
+
+       g3d_polygon_mode(G3D_GOURAUD);
 }
 
 static void update(void)
diff --git a/src/polytmpl.h b/src/polytmpl.h
new file mode 100644 (file)
index 0000000..2021b3b
--- /dev/null
@@ -0,0 +1,210 @@
+static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
+{
+       int i;
+       int32_t x, dx, dy, slope;
+#ifdef GOURAUD
+       int r, g, b, dr, dg, db;
+       int32_t rslope, gslope, bslope;
+#endif
+#ifdef TEXMAP
+       int32_t u, v, du, dv, uslope, vslope;
+#endif
+       int32_t start_idx, end_idx;
+
+       if(v0->y > v1->y) {
+               struct pvertex *tmp = v0;
+               v0 = v1;
+               v1 = tmp;
+       }
+
+       x = v0->x;
+       dy = v1->y - v0->y;
+       dx = v1->x - v0->x;
+       slope = (dx << 8) / dy;
+#ifdef GOURAUD
+       r = (v0->r << 8);
+       g = (v0->g << 8);
+       b = (v0->b << 8);
+       dr = (v1->r << 8) - r;
+       dg = (v1->g << 8) - g;
+       db = (v1->b << 8) - b;
+       rslope = (dr << 8) / dy;
+       gslope = (dg << 8) / dy;
+       bslope = (db << 8) / dy;
+#endif
+#ifdef TEXMAP
+       u = v0->u;
+       v = v0->v;
+       du = v1->u - v0->u;
+       dv = v1->v - v0->v;
+       uslope = (du << 8) / dy;
+       vslope = (dv << 8) / dy;
+#endif
+
+       start_idx = v0->y >> 8;
+       end_idx = v1->y >> 8;
+
+       for(i=start_idx; i<end_idx; i++) {
+               edge[i].x = x;
+               x += slope;
+#ifdef GOURAUD
+               /* we'll store the color in the edge tables with 8 extra bits of precision */
+               edge[i].r = r;
+               edge[i].g = g;
+               edge[i].b = b;
+               r += rslope;
+               g += gslope;
+               b += bslope;
+#endif
+#ifdef TEXMAP
+               edge[i].u = u;
+               edge[i].v = v;
+               u += uslope;
+               v += vslope;
+#endif
+       }
+
+       return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
+}
+
+void POLYFILL(struct pvertex *pv, int nverts)
+{
+       int i;
+       int topidx = 0, botidx = 0, sltop = pimg_fb.height, slbot = 0;
+       struct pvertex *left, *right;
+       uint16_t color;
+       /* the following variables are used for interpolating horizontally accros scanlines */
+#if defined(GOURAUD) || defined(TEXMAP)
+       int mid;
+       int32_t dx, tmp;
+#else
+       /* flat version, just pack the color now */
+       color = PACK_RGB16(pv[0].r, pv[0].g, pv[0].b);
+#endif
+#ifdef GOURAUD
+       int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
+#endif
+#ifdef TEXMAP
+       int32_t u, v, du, dv, uslope, vslope;
+#endif
+
+       for(i=1; i<nverts; i++) {
+               if(pv[i].y < pv[topidx].y) topidx = i;
+               if(pv[i].y > pv[botidx].y) botidx = i;
+       }
+
+       left = alloca(pimg_fb.height * sizeof *left);
+       right = alloca(pimg_fb.height * sizeof *right);
+
+       for(i=0; i<nverts; i++) {
+               int next = NEXTIDX(i);
+               int32_t y0 = pv[i].y;
+               int32_t y1 = pv[next].y;
+
+               if((y0 >> 8) == (y1 >> 8)) {
+                       if(y0 > y1) {
+                               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;
+                       }
+               } else {
+                       struct pvertex *edge = y0 > y1 ? left : right;
+                       uint32_t res = SCANEDGE(pv + i, pv + next, edge);
+                       uint32_t tmp = (res >> 16) & 0xffff;
+                       if(tmp > slbot) slbot = tmp;
+                       if((tmp = res & 0xffff) < sltop) {
+                               sltop = tmp;
+                       }
+               }
+       }
+
+       /* find the mid-point and calculate slopes for all attributes */
+#if 0
+#if defined(GOURAUD) || defined(TEXMAP)
+       mid = (sltop + slbot) >> 1;
+       dx = right[mid].x - left[mid].x;
+       if((tmp = right[sltop].x - left[sltop].x) > dx) {
+               dx = tmp;
+               mid = sltop;
+       }
+       if((tmp = right[slbot].x - left[slbot].x) > dx) {
+               dx = tmp;
+               mid = slbot;
+       }
+       if(!dx) {
+               dx = 256;       /* 1 */
+       }
+#endif
+#ifdef GOURAUD
+       dr = right[mid].r - left[mid].r;
+       dg = right[mid].g - left[mid].g;
+       db = right[mid].b - left[mid].b;
+       rslope = (dr << 8) / dx;
+       gslope = (dg << 8) / dx;
+       bslope = (db << 8) / dx;
+#endif
+#ifdef TEXMAP
+       du = right[mid].u - left[mid].u;
+       dv = right[mid].v - left[mid].v;
+       uslope = (du << 8) / dx;
+       vslope = (dv << 8) / dx;
+#endif
+#endif /* 0 */
+
+       for(i=sltop; i<=slbot; i++) {
+               uint16_t *pixptr;
+               int32_t x;
+
+               x = left[i].x;
+               pixptr = pimg_fb.pixels + i * pimg_fb.width + (x >> 8);
+
+#if defined(GOURAUD) || defined(TEXMAP)
+               if(!(dx = right[i].x - left[i].x)) dx = 256;    /* 1 */
+#endif
+#ifdef GOURAUD
+               r = left[i].r;
+               g = left[i].g;
+               b = left[i].b;
+               dr = right[i].r - left[i].r;
+               dg = right[i].g - left[i].g;
+               db = right[i].b - left[i].b;
+               rslope = (dr << 8) / dx;
+               gslope = (dg << 8) / dx;
+               bslope = (db << 8) / dx;
+#endif
+#ifdef TEXMAP
+               u = left[i].u;
+               v = left[i].v;
+               du = right[i].u - left[i].u;
+               dv = right[i].v - left[i].v;
+               uslope = (du << 8) / dx;
+               vslope = (dv << 8) / dx;
+#endif
+
+               while(x <= right[i].x) {
+#ifdef GOURAUD
+                       /* drop the extra 8 bits when packing */
+                       int cr = r >> 8;
+                       int cg = g >> 8;
+                       int cb = b >> 8;
+                       color = PACK_RGB16(cr, cg, cb);
+                       r += rslope;
+                       g += gslope;
+                       b += bslope;
+#endif
+#ifdef TEXMAP
+                       /* TODO */
+                       u += uslope;
+                       v += vslope;
+#endif
+
+#ifdef DEBUG_OVERDRAW
+                       *pixptr++ += DEBUG_OVERDRAW;
+#else
+                       *pixptr++ = color;
+#endif
+                       x += 256;
+               }
+       }
+}
+