gba-x3dtest

annotate src/polyfill.c @ 14:c398d834d64a

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