From 9e546fcbdc870e396abeb6eaacaa7bc4054a61f0 Mon Sep 17 00:00:00 2001 From: John Tsiombikas Date: Tue, 4 Oct 2016 07:47:51 +0300 Subject: [PATCH] optional high-quality but slower calculation of attribute slopes across each scanline, and extra color bits during interpolation. --- src/polyfill.c | 15 +++++++++++++ src/polytest.c | 6 ++++-- src/polytmpl.h | 65 ++++++++++++++++++++++++++++++++++---------------------- 3 files changed, 59 insertions(+), 27 deletions(-) diff --git a/src/polyfill.c b/src/polyfill.c index 0d1351e..e94de2f 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -60,6 +60,21 @@ void polyfill_wire(struct pvertex *verts, int nverts) #define NEXTIDX(x) (((x) - 1 + nverts) % nverts) #define PREVIDX(x) (((x) + 1) % nverts) +/* XXX + * When HIGH_QUALITY is defined, the rasterizer calculates slopes for attribute + * interpolation on each scanline separately; otherwise the slope for each + * attribute would be calculated once for the whole polygon, which is faster, + * but produces some slight quantization artifacts, due to the limited precision + * of fixed-point calculations. + */ +#undef HIGH_QUALITY + +/* extra bits of precision to use when interpolating colors. + * try tweaking this if you notice strange quantization artifacts. + */ +#define COLOR_SHIFT 12 + + #define POLYFILL polyfill_flat #define SCANEDGE scanedge_flat #undef GOURAUD diff --git a/src/polytest.c b/src/polytest.c index 800dd46..0d5187d 100644 --- a/src/polytest.c +++ b/src/polytest.c @@ -104,8 +104,8 @@ static void update(void) int dy = mouse_y - prev_my; if(dx || dy) { - theta += dx * 2.0; - phi += dy * 2.0; + theta += dx * 1.0; + phi += dy * 1.0; if(phi < -90) phi = -90; if(phi > 90) phi = 90; @@ -283,6 +283,8 @@ static int gen_torus(struct mesh *mesh, float rad, float ringrad, int usub, int nfaces = usub * vsub; mesh->icount = nfaces * 4; + printf("generating torus with %d faces (%d vertices)\n", nfaces, mesh->vcount); + if(!(mesh->varr = malloc(mesh->vcount * sizeof *mesh->varr))) { return -1; } diff --git a/src/polytmpl.h b/src/polytmpl.h index 79660ef..3b3917e 100644 --- a/src/polytmpl.h +++ b/src/polytmpl.h @@ -22,12 +22,12 @@ static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex 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; + r = (v0->r << COLOR_SHIFT); + g = (v0->g << COLOR_SHIFT); + b = (v0->b << COLOR_SHIFT); + dr = (v1->r << COLOR_SHIFT) - r; + dg = (v1->g << COLOR_SHIFT) - g; + db = (v1->b << COLOR_SHIFT) - b; rslope = (dr << 8) / dy; gslope = (dg << 8) / dy; bslope = (db << 8) / dy; @@ -48,7 +48,7 @@ static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex edge[i].x = x; x += slope; #ifdef GOURAUD - /* we'll store the color in the edge tables with 8 extra bits of precision */ + /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */ edge[i].r = r; edge[i].g = g; edge[i].b = b; @@ -75,8 +75,8 @@ void POLYFILL(struct pvertex *pv, int nverts) uint16_t color; /* the following variables are used for interpolating horizontally accros scanlines */ #if defined(GOURAUD) || defined(TEXMAP) - /*int mid;*/ - int32_t dx/*, tmp*/; + 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); @@ -118,8 +118,10 @@ void POLYFILL(struct pvertex *pv, int nverts) } } - /* find the mid-point and calculate slopes for all attributes */ -#if 0 + /* calculate the slopes of all attributes across the largest span out + * of the three: middle, top, or bottom. + */ +#ifndef HIGH_QUALITY #if defined(GOURAUD) || defined(TEXMAP) mid = (sltop + slbot) >> 1; dx = right[mid].x - left[mid].x; @@ -131,9 +133,7 @@ void POLYFILL(struct pvertex *pv, int nverts) dx = tmp; mid = slbot; } - if(!dx) { - dx = 256; /* 1 */ - } + if(!dx) dx = 256; /* avoid division by zero */ #endif #ifdef GOURAUD dr = right[mid].r - left[mid].r; @@ -149,8 +149,9 @@ void POLYFILL(struct pvertex *pv, int nverts) uslope = (du << 8) / dx; vslope = (dv << 8) / dx; #endif -#endif /* 0 */ +#endif /* !defined(HIGH_QUALITY) */ + /* for each scanline ... */ for(i=sltop; i<=slbot; i++) { uint16_t *pixptr; int32_t x; @@ -158,13 +159,20 @@ void POLYFILL(struct pvertex *pv, int nverts) x = left[i].x; pixptr = pfill_fb.pixels + i * pfill_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; +#endif +#ifdef TEXMAP + u = left[i].u; + v = left[i].v; +#endif + +#if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP)) + if(!(dx = right[i].x - left[i].x)) dx = 256; + +#ifdef GOURAUD dr = right[i].r - left[i].r; dg = right[i].g - left[i].g; db = right[i].b - left[i].b; @@ -173,23 +181,28 @@ void POLYFILL(struct pvertex *pv, int nverts) 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 +#endif /* HIGH_QUALITY */ + /* go across the scanline interpolating if necessary */ while(x <= right[i].x) { #if defined(GOURAUD) || defined(TEXMAP) int cr, cg, cb; #endif #ifdef GOURAUD - /* drop the extra 8 bits when packing */ - cr = r >> 8; - cg = g >> 8; - cb = b >> 8; + /* we upped the color precision to while interpolating the + * edges, now drop the extra bits before packing + */ + cr = r < 0 ? 0 : (r >> COLOR_SHIFT); + cg = g < 0 ? 0 : (g >> COLOR_SHIFT); + cb = b < 0 ? 0 : (b >> COLOR_SHIFT); + if(cr > 255) cr = 255; + if(cg > 255) cg = 255; + if(cb > 255) cb = 255; r += rslope; g += gslope; b += bslope; @@ -200,7 +213,9 @@ void POLYFILL(struct pvertex *pv, int nverts) int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask; uint16_t texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx]; #ifdef GOURAUD - /* XXX this is not correct, should be /255, but it might not make a huge difference */ + /* This is not correct, should be /255, but it's much faster + * to shift by 8 (/256), and won't make a huge difference + */ cr = (cr * UNPACK_R16(texel)) >> 8; cg = (cg * UNPACK_G16(texel)) >> 8; cb = (cb * UNPACK_B16(texel)) >> 8; -- 1.7.10.4