gba-x3dtest

annotate src/polyfill.c @ 9:b0ed38f13261

working on the rasterizer
author John Tsiombikas <nuclear@member.fsf.org>
date Sun, 22 Jun 2014 05:16:10 +0300
parents fb0a0d6a8b52
children c398d834d64a
rev   line source
nuclear@5 1 #include "config.h"
nuclear@5 2 #include <string.h>
nuclear@6 3 #include <assert.h>
nuclear@5 4 #include "polyfill.h"
nuclear@5 5 #include "fixed.h"
nuclear@5 6 #include "gbasys.h"
nuclear@5 7
nuclear@9 8 #define VNEXT(x, n) (((x) + 1) % (n))
nuclear@9 9 #define VPREV(x, n) ((x) > 0 ? (x) - 1 : (n) - 1)
nuclear@9 10
nuclear@9 11 static void fill_scanline_pal(int y, int x0, int x1, uint8_t color);
nuclear@9 12 static void fill_scanline_rgb(int y, int x0, int x1, uint16_t color);
nuclear@5 13
nuclear@5 14 void draw_poly(int num, const pvec3 *verts, uint16_t color)
nuclear@5 15 {
nuclear@5 16 int i, topidx = 0, botidx = 0;
nuclear@9 17 int lidx[2] = {-1, -1}, ridx[2] = {-1, -1};
nuclear@5 18 int32_t y, topy, boty;
nuclear@9 19 int32_t ldy = 0, rdy = 0, ldxdy, rdxdy;
nuclear@5 20 int32_t lx, rx;
nuclear@5 21 int start, end;
nuclear@5 22
nuclear@5 23 topy = boty = verts[0].y;
nuclear@5 24 for(i=1; i<num; i++) {
nuclear@5 25 int32_t y = verts[i].y;
nuclear@5 26 if(y < topy) {
nuclear@5 27 topy = y;
nuclear@5 28 topidx = i;
nuclear@5 29 }
nuclear@5 30 if(y > boty) {
nuclear@5 31 boty = y;
nuclear@5 32 botidx = i;
nuclear@5 33 }
nuclear@5 34 }
nuclear@5 35
nuclear@5 36 lidx[0] = ridx[0] = topidx;
nuclear@9 37
nuclear@9 38 /* find starting left edge */
nuclear@9 39 lidx[1] = VPREV(lidx[0], num);
nuclear@9 40 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@9 41
nuclear@9 42 while(ldy == 0) {
nuclear@9 43 lidx[0] = lidx[1];
nuclear@9 44 lidx[1] = VPREV(lidx[1], num);
nuclear@9 45
nuclear@9 46 if(lidx[1] == topidx) {
nuclear@9 47 return; /* degenerate */
nuclear@9 48 }
nuclear@9 49
nuclear@9 50 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@9 51 }
nuclear@9 52 lx = verts[lidx[0]].x;
nuclear@9 53 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
nuclear@9 54
nuclear@9 55 /* find starting right edge */
nuclear@9 56 ridx[1] = VNEXT(ridx[0], num);
nuclear@9 57 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@9 58
nuclear@9 59 while(rdy == 0) {
nuclear@9 60 ridx[0] = ridx[1];
nuclear@9 61 ridx[1] = VNEXT(ridx[1], num);
nuclear@9 62
nuclear@9 63 if(ridx[1] == topidx) {
nuclear@9 64 return; /* degenerate */
nuclear@9 65 }
nuclear@9 66
nuclear@9 67 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@9 68 }
nuclear@9 69 rx = verts[ridx[0]].x;
nuclear@9 70 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
nuclear@9 71
nuclear@5 72
nuclear@6 73 if(verts[ridx[1]].x < verts[lidx[1]].x) {
nuclear@9 74 return; /* backface (CCW) */
nuclear@5 75 }
nuclear@5 76
nuclear@5 77 start = topy >> 16;
nuclear@5 78 end = boty >> 16;
nuclear@5 79
nuclear@6 80 if(end >= HEIGHT) end = HEIGHT - 1;
nuclear@6 81
nuclear@5 82 y = topy;
nuclear@5 83 for(i=start; i<end; i++) {
nuclear@9 84 short x0, x1;
nuclear@5 85
nuclear@5 86 if(y >= verts[lidx[1]].y) {
nuclear@9 87 lx = verts[lidx[1]].x;
nuclear@5 88 lidx[0] = lidx[1];
nuclear@9 89 lidx[1] = VPREV(lidx[1], num);
nuclear@5 90 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@5 91 if(ldy < 0) {
nuclear@5 92 break;
nuclear@5 93 }
nuclear@5 94 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
nuclear@5 95 }
nuclear@5 96 if(y >= verts[ridx[1]].y) {
nuclear@9 97 rx = verts[ridx[1]].x;
nuclear@5 98 ridx[0] = ridx[1];
nuclear@9 99 ridx[1] = VNEXT(ridx[1], num);
nuclear@5 100 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@5 101 if(rdy < 0) {
nuclear@5 102 break;
nuclear@5 103 }
nuclear@5 104 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
nuclear@5 105 }
nuclear@5 106
nuclear@9 107 x0 = lx < 0 ? 0 : (lx >> 16);
nuclear@9 108 x1 = (rx >> 16) >= WIDTH ? WIDTH - 1 : (rx >> 16);
nuclear@9 109
nuclear@9 110 if(i >= 0 && x1 > x0) {
nuclear@9 111 #ifdef PALMODE
nuclear@9 112 fill_scanline_pal(i, x0, x1, (uint8_t)color);
nuclear@9 113 #else
nuclear@9 114 fill_scanline_rgb(i, x0, x1, color);
nuclear@9 115 #endif
nuclear@9 116 }
nuclear@9 117
nuclear@5 118 lx += ldxdy;
nuclear@5 119 rx += rdxdy;
nuclear@6 120 y += 65536;
nuclear@5 121 }
nuclear@5 122 }
nuclear@5 123
nuclear@9 124
nuclear@9 125 static void fill_scanline_pal(int y, int x0, int x1, uint8_t color)
nuclear@9 126 {
nuclear@9 127 #if 1
nuclear@9 128 int i, num_pairs, num_pix = x1 - x0;
nuclear@9 129 uint16_t *pixels = (uint16_t*)back_buffer->pixels + (y * WIDTH + x0) / 2;
nuclear@9 130 uint16_t colpair = (uint16_t)color | ((uint16_t)color << 8);
nuclear@9 131
nuclear@9 132 if(x0 & 1) {
nuclear@9 133 uint16_t pix = *pixels & 0xff;
nuclear@9 134 *pixels++ = pix | ((uint16_t)color << 8);
nuclear@9 135 --num_pix;
nuclear@9 136 }
nuclear@9 137
nuclear@9 138 num_pairs = (num_pix & 0xfffe) / 2;
nuclear@9 139
nuclear@9 140 for(i=0; i<num_pairs; i++) {
nuclear@9 141 *pixels++ = colpair;
nuclear@9 142 }
nuclear@9 143
nuclear@9 144 if(num_pix & 1) {
nuclear@9 145 uint16_t pix = *pixels & 0xff00;
nuclear@9 146 *pixels = pix | color;
nuclear@9 147 }
nuclear@9 148 #else
nuclear@9 149 int i;
nuclear@9 150 uint8_t *pixels = (uint8_t*)back_buffer->pixels + y * WIDTH + x0;
nuclear@9 151
nuclear@9 152 for(i=x0; i<x1; i++) {
nuclear@9 153 *pixels++ = color;
nuclear@9 154 }
nuclear@9 155 #endif
nuclear@9 156 }
nuclear@9 157
nuclear@9 158 static void fill_scanline_rgb(int y, int x0, int x1, uint16_t color)
nuclear@5 159 {
nuclear@5 160 int i;
nuclear@5 161 uint16_t *pixels = (uint16_t*)back_buffer->pixels + y * WIDTH + x0;
nuclear@5 162
nuclear@5 163 for(i=x0; i<x1; i++) {
nuclear@5 164 *pixels++ = color;
nuclear@5 165 }
nuclear@5 166 }
nuclear@8 167
nuclear@8 168
nuclear@8 169 void draw_point(const pvec3 *v, uint16_t color)
nuclear@8 170 {
nuclear@8 171 int x = v->x >> 16;
nuclear@8 172 int y = v->y >> 16;
nuclear@8 173 uint16_t *pixels = (uint16_t*)back_buffer->pixels;
nuclear@8 174
nuclear@8 175 if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
nuclear@8 176 return;
nuclear@8 177 }
nuclear@8 178
nuclear@9 179 #ifdef PALMODE
nuclear@9 180 pixels += (y * WIDTH + x) / 2;
nuclear@9 181 if(x & 1) {
nuclear@9 182 *pixels = (*pixels & 0xff) | (color << 8);
nuclear@9 183 } else {
nuclear@9 184 *pixels = (*pixels & 0xff00) | color;
nuclear@9 185 }
nuclear@9 186 #else
nuclear@8 187 pixels[y * WIDTH + x] = color;
nuclear@9 188 #endif
nuclear@8 189 }