X-Git-Url: http://git.mutantstargoat.com/user/nuclear/?a=blobdiff_plain;f=src%2Fpolyfill.c;h=856ea5f2204c5f045174cfbd3763a10fb84b9092;hb=3eebc6b38f3ad1fd082ae9d4d3263c42c384951c;hp=a068295f6b6974528fa5e602d55b4b9283db8ac2;hpb=9123da2ff9583baa8a221deceb23436fcbfea7d9;p=gba_blender diff --git a/src/polyfill.c b/src/polyfill.c index a068295..856ea5f 100644 --- a/src/polyfill.c +++ b/src/polyfill.c @@ -41,6 +41,7 @@ void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col) int32_t x, y0, y1, dx, dy, slope, fx, fy; short *tab, start, len; unsigned char *fbptr; + uint16_t *pptr, pcol = ((uint16_t)col << 8) | (uint16_t)col; vlast = varr + vnum - 1; top = fbheight; @@ -92,8 +93,176 @@ void polyfill_flat(struct pvertex *varr, int vnum, unsigned char col) len = scantab[1][i] - start; if(len > 0) { - memset(fbptr + start, col, len); + if(start & 1) { + pptr = (uint16_t*)(fbptr + (start & 0xfffe)); + *pptr = (*pptr & 0xff) | ((uint16_t)col << 8); + len--; + start++; + } + pptr = (uint16_t*)(fbptr + start); + while(len > 1) { + *pptr++ = pcol; + len -= 2; + } + if(len) { + *pptr = (*pptr & 0xff00) | col; + } } fbptr += fbwidth; } } + + +/* ----- line drawing and clipping ------ */ +enum { + IN = 0, + LEFT = 1, + RIGHT = 2, + TOP = 4, + BOTTOM = 8 +}; + +static int outcode(int x, int y, int xmin, int ymin, int xmax, int ymax) +{ + int code = 0; + + if(x < xmin) { + code |= LEFT; + } else if(x > xmax) { + code |= RIGHT; + } + if(y < ymin) { + code |= TOP; + } else if(y > ymax) { + code |= BOTTOM; + } + return code; +} + +#define FIXMUL(a, b) (((a) * (b)) >> 8) +#define FIXDIV(a, b) (((a) << 8) / (b)) + +#define LERP(a, b, t) ((a) + FIXMUL((b) - (a), (t))) + +int clip_line(int *x0, int *y0, int *x1, int *y1, int xmin, int ymin, int xmax, int ymax) +{ + int oc_out; + + int oc0 = outcode(*x0, *y0, xmin, ymin, xmax, ymax); + int oc1 = outcode(*x1, *y1, xmin, ymin, xmax, ymax); + + long fx0, fy0, fx1, fy1, fxmin, fymin, fxmax, fymax; + + if(!(oc0 | oc1)) return 1; /* both points are inside */ + + fx0 = *x0 << 8; + fy0 = *y0 << 8; + fx1 = *x1 << 8; + fy1 = *y1 << 8; + fxmin = xmin << 8; + fymin = ymin << 8; + fxmax = xmax << 8; + fymax = ymax << 8; + + for(;;) { + long x, y, t; + + if(oc0 & oc1) return 0; /* both have points with the same outbit, not visible */ + if(!(oc0 | oc1)) break; /* both points are inside */ + + oc_out = oc0 ? oc0 : oc1; + + if(oc_out & TOP) { + t = FIXDIV(fymin - fy0, fy1 - fy0); + x = LERP(fx0, fx1, t); + y = fymin; + } else if(oc_out & BOTTOM) { + t = FIXDIV(fymax - fy0, fy1 - fy0); + x = LERP(fx0, fx1, t); + y = fymax; + } else if(oc_out & LEFT) { + t = FIXDIV(fxmin - fx0, fx1 - fx0); + x = fxmin; + y = LERP(fy0, fy1, t); + } else {/*if(oc_out & RIGHT) {*/ + t = FIXDIV(fxmax - fx0, fx1 - fx0); + x = fxmax; + y = LERP(fy0, fy1, t); + } + + if(oc_out == oc0) { + fx0 = x; + fy0 = y; + oc0 = outcode(fx0 >> 8, fy0 >> 8, xmin, ymin, xmax, ymax); + } else { + fx1 = x; + fy1 = y; + oc1 = outcode(fx1 >> 8, fy1 >> 8, xmin, ymin, xmax, ymax); + } + } + + *x0 = fx0 >> 8; + *y0 = fy0 >> 8; + *x1 = fx1 >> 8; + *y1 = fy1 >> 8; + return 1; +} + +#define PUTPIXEL(ptr) \ + do { \ + uint16_t *pptr = (uint16_t*)((uint32_t)ptr & 0xfffffffe); \ + if((uint32_t)ptr & 1) { \ + *pptr = (*pptr & 0xff) | (color << 8); \ + } else { \ + *pptr = (*pptr & 0xff00) | color; \ + } \ + } while(0) + +void draw_line(int x0, int y0, int x1, int y1, unsigned short color) +{ + int i, dx, dy, x_inc, y_inc, error; + unsigned char *fbptr = fb; + + fbptr += y0 * fbwidth + x0; + + dx = x1 - x0; + dy = y1 - y0; + + if(dx >= 0) { + x_inc = 1; + } else { + x_inc = -1; + dx = -dx; + } + if(dy >= 0) { + y_inc = fbwidth; + } else { + y_inc = -fbwidth; + dy = -dy; + } + + if(dx > dy) { + error = dy * 2 - dx; + for(i=0; i<=dx; i++) { + PUTPIXEL(fbptr); + if(error >= 0) { + error -= dx * 2; + fbptr += y_inc; + } + error += dy * 2; + fbptr += x_inc; + } + } else { + error = dx * 2 - dy; + for(i=0; i<=dy; i++) { + PUTPIXEL(fbptr); + if(error >= 0) { + error -= dy * 2; + fbptr += x_inc; + } + error += dx * 2; + fbptr += y_inc; + } + } +} +