nuclear@5: #include "config.h" nuclear@5: #include nuclear@6: #include nuclear@5: #include "polyfill.h" nuclear@5: #include "fixed.h" nuclear@5: #include "gbasys.h" nuclear@5: nuclear@9: #define VNEXT(x, n) (((x) + 1) % (n)) nuclear@9: #define VPREV(x, n) ((x) > 0 ? (x) - 1 : (n) - 1) nuclear@9: nuclear@9: static void fill_scanline_pal(int y, int x0, int x1, uint8_t color); nuclear@9: static void fill_scanline_rgb(int y, int x0, int x1, uint16_t color); nuclear@14: static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1); nuclear@5: nuclear@5: void draw_poly(int num, const pvec3 *verts, uint16_t color) nuclear@5: { nuclear@5: int i, topidx = 0, botidx = 0; nuclear@9: int lidx[2] = {-1, -1}, ridx[2] = {-1, -1}; nuclear@5: int32_t y, topy, boty; nuclear@9: int32_t ldy = 0, rdy = 0, ldxdy, rdxdy; nuclear@5: int32_t lx, rx; nuclear@5: int start, end; nuclear@14: pvec3 v0, v1; nuclear@14: nuclear@14: v0.x = verts[1].x - verts[0].x; nuclear@14: v0.y = verts[1].y - verts[0].y; nuclear@14: nuclear@14: v1.x = verts[2].x - verts[0].x; nuclear@14: v1.y = verts[2].y - verts[0].y; nuclear@14: nuclear@14: if(winding(v0.x, v0.y, v1.x, v1.y) < 0) { nuclear@14: return; /* backface */ nuclear@14: } nuclear@5: nuclear@5: topy = boty = verts[0].y; nuclear@5: for(i=1; i boty) { nuclear@5: boty = y; nuclear@5: botidx = i; nuclear@5: } nuclear@5: } nuclear@5: nuclear@5: lidx[0] = ridx[0] = topidx; nuclear@9: nuclear@9: /* find starting left edge */ nuclear@9: lidx[1] = VPREV(lidx[0], num); nuclear@9: ldy = verts[lidx[1]].y - verts[lidx[0]].y; nuclear@9: nuclear@9: while(ldy == 0) { nuclear@9: lidx[0] = lidx[1]; nuclear@9: lidx[1] = VPREV(lidx[1], num); nuclear@9: nuclear@9: if(lidx[1] == topidx) { nuclear@9: return; /* degenerate */ nuclear@9: } nuclear@9: nuclear@9: ldy = verts[lidx[1]].y - verts[lidx[0]].y; nuclear@9: } nuclear@9: lx = verts[lidx[0]].x; nuclear@9: ldxdy = x16div(verts[lidx[1]].x - lx, ldy); nuclear@9: nuclear@9: /* find starting right edge */ nuclear@9: ridx[1] = VNEXT(ridx[0], num); nuclear@9: rdy = verts[ridx[1]].y - verts[ridx[0]].y; nuclear@9: nuclear@9: while(rdy == 0) { nuclear@9: ridx[0] = ridx[1]; nuclear@9: ridx[1] = VNEXT(ridx[1], num); nuclear@9: nuclear@9: if(ridx[1] == topidx) { nuclear@9: return; /* degenerate */ nuclear@9: } nuclear@9: nuclear@9: rdy = verts[ridx[1]].y - verts[ridx[0]].y; nuclear@9: } nuclear@9: rx = verts[ridx[0]].x; nuclear@9: rdxdy = x16div(verts[ridx[1]].x - rx, rdy); nuclear@9: nuclear@5: start = topy >> 16; nuclear@5: end = boty >> 16; nuclear@5: nuclear@6: if(end >= HEIGHT) end = HEIGHT - 1; nuclear@6: nuclear@5: y = topy; nuclear@14: for(i=start; i<=end; i++) { nuclear@9: short x0, x1; nuclear@5: nuclear@5: if(y >= verts[lidx[1]].y) { nuclear@9: lx = verts[lidx[1]].x; nuclear@5: lidx[0] = lidx[1]; nuclear@9: lidx[1] = VPREV(lidx[1], num); nuclear@5: ldy = verts[lidx[1]].y - verts[lidx[0]].y; nuclear@5: if(ldy < 0) { nuclear@5: break; nuclear@5: } nuclear@14: if(ldy) { nuclear@14: ldxdy = x16div(verts[lidx[1]].x - lx, ldy); nuclear@14: } else { nuclear@14: ldxdy = verts[lidx[1]].x - lx; nuclear@14: } nuclear@5: } nuclear@5: if(y >= verts[ridx[1]].y) { nuclear@9: rx = verts[ridx[1]].x; nuclear@5: ridx[0] = ridx[1]; nuclear@9: ridx[1] = VNEXT(ridx[1], num); nuclear@5: rdy = verts[ridx[1]].y - verts[ridx[0]].y; nuclear@5: if(rdy < 0) { nuclear@5: break; nuclear@5: } nuclear@14: if(rdy) { nuclear@14: rdxdy = x16div(verts[ridx[1]].x - rx, rdy); nuclear@14: } else { nuclear@14: rdxdy = verts[ridx[1]].x - rx; nuclear@14: } nuclear@5: } nuclear@5: nuclear@14: x0 = lx >> 16; nuclear@14: x1 = rx >> 16; nuclear@9: nuclear@14: if(i >= 0) {// && x0 < x1) { nuclear@9: #ifdef PALMODE nuclear@9: fill_scanline_pal(i, x0, x1, (uint8_t)color); nuclear@9: #else nuclear@9: fill_scanline_rgb(i, x0, x1, color); nuclear@9: #endif nuclear@9: } nuclear@9: nuclear@5: lx += ldxdy; nuclear@5: rx += rdxdy; nuclear@6: y += 65536; nuclear@5: } nuclear@5: } nuclear@5: nuclear@9: nuclear@9: static void fill_scanline_pal(int y, int x0, int x1, uint8_t color) nuclear@9: { nuclear@9: #if 1 nuclear@9: int i, num_pairs, num_pix = x1 - x0; nuclear@9: uint16_t *pixels = (uint16_t*)back_buffer->pixels + (y * WIDTH + x0) / 2; nuclear@9: uint16_t colpair = (uint16_t)color | ((uint16_t)color << 8); nuclear@9: nuclear@9: if(x0 & 1) { nuclear@9: uint16_t pix = *pixels & 0xff; nuclear@9: *pixels++ = pix | ((uint16_t)color << 8); nuclear@9: --num_pix; nuclear@9: } nuclear@9: nuclear@9: num_pairs = (num_pix & 0xfffe) / 2; nuclear@9: nuclear@9: for(i=0; ipixels + y * WIDTH + x0; nuclear@9: nuclear@9: for(i=x0; i x1) { nuclear@14: i = x0; nuclear@14: x0 = x1; nuclear@14: x1 = i; nuclear@14: } nuclear@14: nuclear@14: if(x0 < 0) x0 = 0; nuclear@14: if(x1 >= WIDTH - 1) x1 = WIDTH - 1; nuclear@14: nuclear@14: pixels = (uint16_t*)back_buffer->pixels + y * WIDTH + x0; nuclear@5: for(i=x0; ix >> 16; nuclear@8: int y = v->y >> 16; nuclear@8: uint16_t *pixels = (uint16_t*)back_buffer->pixels; nuclear@8: nuclear@8: if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) { nuclear@8: return; nuclear@8: } nuclear@8: nuclear@9: #ifdef PALMODE nuclear@9: pixels += (y * WIDTH + x) / 2; nuclear@9: if(x & 1) { nuclear@9: *pixels = (*pixels & 0xff) | (color << 8); nuclear@9: } else { nuclear@9: *pixels = (*pixels & 0xff00) | color; nuclear@9: } nuclear@9: #else nuclear@8: pixels[y * WIDTH + x] = color; nuclear@9: #endif nuclear@8: } nuclear@14: nuclear@14: static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1) nuclear@14: { nuclear@14: return x16mul(x0, y1) - x16mul(y0, x1); nuclear@14: }