gba-x3dtest

annotate src/polyfill.c @ 20:2e903e27e35a

fixed x3d_disable_texture added runtime teture checks in the rasterizer
author John Tsiombikas <nuclear@member.fsf.org>
date Tue, 01 Jul 2014 23:23:37 +0300
parents 62390f9cc93e
children
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@19 7 #include "logger.h"
nuclear@19 8
nuclear@19 9 #define USE_TEX
nuclear@5 10
nuclear@15 11 /* TODO: constant interpolant optimization */
nuclear@15 12
nuclear@9 13 #define VNEXT(x, n) (((x) + 1) % (n))
nuclear@9 14 #define VPREV(x, n) ((x) > 0 ? (x) - 1 : (n) - 1)
nuclear@9 15
nuclear@15 16 static void fill_scanline_pal(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
nuclear@15 17 int32_t v0, int32_t v1, uint8_t color);
nuclear@15 18 static void fill_scanline_rgb(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
nuclear@17 19 int32_t v0, int32_t v1, uint16_t color, struct texture *tex);
nuclear@14 20 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
nuclear@5 21
nuclear@17 22 void draw_poly(int num, const pvec3 *verts, const pvec2 *texcoords, uint16_t color,
nuclear@17 23 struct texture *tex)
nuclear@5 24 {
nuclear@5 25 int i, topidx = 0, botidx = 0;
nuclear@9 26 int lidx[2] = {-1, -1}, ridx[2] = {-1, -1};
nuclear@5 27 int32_t y, topy, boty;
nuclear@9 28 int32_t ldy = 0, rdy = 0, ldxdy, rdxdy;
nuclear@5 29 int32_t lx, rx;
nuclear@5 30 int start, end;
nuclear@14 31 pvec3 v0, v1;
nuclear@14 32
nuclear@19 33 #ifdef USE_TEX
nuclear@19 34 int32_t ldudy, ldvdy, rdudy, rdvdy; /* texture interpolants */
nuclear@19 35 #else
nuclear@19 36 static /* to avoid lu,lv,ru,rv uninitialized warnings */
nuclear@19 37 #endif
nuclear@19 38 int32_t lu, lv, ru, rv;
nuclear@15 39
nuclear@14 40 v0.x = verts[1].x - verts[0].x;
nuclear@14 41 v0.y = verts[1].y - verts[0].y;
nuclear@14 42
nuclear@14 43 v1.x = verts[2].x - verts[0].x;
nuclear@14 44 v1.y = verts[2].y - verts[0].y;
nuclear@14 45
nuclear@14 46 if(winding(v0.x, v0.y, v1.x, v1.y) < 0) {
nuclear@14 47 return; /* backface */
nuclear@14 48 }
nuclear@5 49
nuclear@5 50 topy = boty = verts[0].y;
nuclear@5 51 for(i=1; i<num; i++) {
nuclear@5 52 int32_t y = verts[i].y;
nuclear@5 53 if(y < topy) {
nuclear@5 54 topy = y;
nuclear@5 55 topidx = i;
nuclear@5 56 }
nuclear@5 57 if(y > boty) {
nuclear@5 58 boty = y;
nuclear@5 59 botidx = i;
nuclear@5 60 }
nuclear@5 61 }
nuclear@5 62
nuclear@5 63 lidx[0] = ridx[0] = topidx;
nuclear@9 64
nuclear@9 65 /* find starting left edge */
nuclear@9 66 lidx[1] = VPREV(lidx[0], num);
nuclear@9 67 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@9 68
nuclear@9 69 while(ldy == 0) {
nuclear@9 70 lidx[0] = lidx[1];
nuclear@9 71 lidx[1] = VPREV(lidx[1], num);
nuclear@9 72
nuclear@9 73 if(lidx[1] == topidx) {
nuclear@9 74 return; /* degenerate */
nuclear@9 75 }
nuclear@9 76
nuclear@9 77 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@9 78 }
nuclear@9 79 lx = verts[lidx[0]].x;
nuclear@9 80 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
nuclear@19 81 #ifdef USE_TEX
nuclear@20 82 if(tex) {
nuclear@20 83 lu = texcoords[lidx[0]].x;
nuclear@20 84 ldudy = x16div(texcoords[lidx[1]].x - lu, ldy);
nuclear@20 85 lv = texcoords[lidx[0]].y;
nuclear@20 86 ldvdy = x16div(texcoords[lidx[1]].y - lv, ldy);
nuclear@20 87 }
nuclear@19 88 #endif
nuclear@9 89
nuclear@9 90 /* find starting right edge */
nuclear@9 91 ridx[1] = VNEXT(ridx[0], num);
nuclear@9 92 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@9 93
nuclear@9 94 while(rdy == 0) {
nuclear@9 95 ridx[0] = ridx[1];
nuclear@9 96 ridx[1] = VNEXT(ridx[1], num);
nuclear@9 97
nuclear@9 98 if(ridx[1] == topidx) {
nuclear@9 99 return; /* degenerate */
nuclear@9 100 }
nuclear@9 101
nuclear@9 102 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@9 103 }
nuclear@9 104 rx = verts[ridx[0]].x;
nuclear@9 105 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
nuclear@19 106 #ifdef USE_TEX
nuclear@20 107 if(tex) {
nuclear@20 108 ru = texcoords[ridx[0]].x;
nuclear@20 109 rdudy = x16div(texcoords[ridx[1]].x - ru, rdy);
nuclear@20 110 rv = texcoords[ridx[0]].y;
nuclear@20 111 rdvdy = x16div(texcoords[ridx[1]].y - rv, rdy);
nuclear@20 112 }
nuclear@19 113 #endif
nuclear@9 114
nuclear@20 115 start = (topy + 32768) >> 16;
nuclear@20 116 end = (boty + 32768) >> 16;
nuclear@5 117
nuclear@6 118 if(end >= HEIGHT) end = HEIGHT - 1;
nuclear@6 119
nuclear@5 120 y = topy;
nuclear@14 121 for(i=start; i<=end; i++) {
nuclear@5 122
nuclear@5 123 if(y >= verts[lidx[1]].y) {
nuclear@9 124 lx = verts[lidx[1]].x;
nuclear@5 125 lidx[0] = lidx[1];
nuclear@9 126 lidx[1] = VPREV(lidx[1], num);
nuclear@5 127 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
nuclear@5 128 if(ldy < 0) {
nuclear@5 129 break;
nuclear@5 130 }
nuclear@15 131
nuclear@19 132 if(ldy) {
nuclear@19 133 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
nuclear@19 134 } else {
nuclear@19 135 ldxdy = verts[lidx[1]].x - lx;
nuclear@19 136 }
nuclear@19 137
nuclear@19 138 #ifdef USE_TEX
nuclear@20 139 if(tex) {
nuclear@20 140 lu = texcoords[lidx[0]].x;
nuclear@20 141 lv = texcoords[lidx[0]].y;
nuclear@20 142 if(ldy) {
nuclear@20 143 ldudy = x16div(texcoords[lidx[1]].x - lu, ldy);
nuclear@20 144 ldvdy = x16div(texcoords[lidx[1]].y - lv, ldy);
nuclear@20 145 } else {
nuclear@20 146 ldudy = texcoords[lidx[1]].x - lu;
nuclear@20 147 ldvdy = texcoords[lidx[1]].y - lv;
nuclear@20 148 }
nuclear@14 149 }
nuclear@19 150 #endif /* USE_TEX */
nuclear@5 151 }
nuclear@5 152 if(y >= verts[ridx[1]].y) {
nuclear@9 153 rx = verts[ridx[1]].x;
nuclear@5 154 ridx[0] = ridx[1];
nuclear@9 155 ridx[1] = VNEXT(ridx[1], num);
nuclear@5 156 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
nuclear@5 157 if(rdy < 0) {
nuclear@5 158 break;
nuclear@5 159 }
nuclear@15 160
nuclear@19 161 if(rdy) {
nuclear@19 162 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
nuclear@19 163 } else {
nuclear@19 164 rdxdy = verts[ridx[1]].x - rx;
nuclear@19 165 }
nuclear@19 166
nuclear@19 167 #ifdef USE_TEX
nuclear@20 168 if(tex) {
nuclear@20 169 ru = texcoords[ridx[0]].x;
nuclear@20 170 rv = texcoords[ridx[0]].y;
nuclear@20 171 if(rdy) {
nuclear@20 172 rdudy = x16div(texcoords[ridx[1]].x - ru, rdy);
nuclear@20 173 rdvdy = x16div(texcoords[ridx[1]].y - rv, rdy);
nuclear@20 174 } else {
nuclear@20 175 rdudy = texcoords[ridx[1]].x - ru;
nuclear@20 176 rdvdy = texcoords[ridx[1]].y - rv;
nuclear@20 177 }
nuclear@14 178 }
nuclear@19 179 #endif /* USE_TEX */
nuclear@5 180 }
nuclear@5 181
nuclear@15 182 if(i >= 0) {
nuclear@9 183 #ifdef PALMODE
nuclear@15 184 fill_scanline_pal(i, lx, rx, lu, ru, lv, rv, (uint8_t)color);
nuclear@9 185 #else
nuclear@17 186 fill_scanline_rgb(i, lx, rx, lu, ru, lv, rv, color, tex);
nuclear@9 187 #endif
nuclear@9 188 }
nuclear@9 189
nuclear@5 190 lx += ldxdy;
nuclear@5 191 rx += rdxdy;
nuclear@6 192 y += 65536;
nuclear@15 193
nuclear@19 194 #ifdef USE_TEX
nuclear@20 195 if(tex) {
nuclear@20 196 lu += ldudy;
nuclear@20 197 lv += ldvdy;
nuclear@20 198 ru += rdudy;
nuclear@20 199 rv += rdvdy;
nuclear@20 200 }
nuclear@19 201 #endif
nuclear@5 202 }
nuclear@5 203 }
nuclear@5 204
nuclear@9 205
nuclear@15 206 static void fill_scanline_pal(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
nuclear@15 207 int32_t v0, int32_t v1, uint8_t color)
nuclear@9 208 {
nuclear@15 209 int ix0, ix1;
nuclear@19 210 #ifdef USE_TEX
nuclear@15 211 int32_t dx;
nuclear@15 212 int32_t u, v, dudx, dvdx;
nuclear@19 213 #endif
nuclear@15 214
nuclear@15 215 int i, num_pairs, num_pix;
nuclear@15 216 uint16_t *pixels;
nuclear@9 217 uint16_t colpair = (uint16_t)color | ((uint16_t)color << 8);
nuclear@9 218
nuclear@15 219 if(x0 > x1) {
nuclear@15 220 int32_t tmp = x0;
nuclear@15 221 x0 = x1;
nuclear@15 222 x1 = tmp;
nuclear@15 223 }
nuclear@15 224
nuclear@19 225 #ifdef USE_TEX
nuclear@15 226 dx = x1 - x0;
nuclear@15 227
nuclear@15 228 u = u0;
nuclear@15 229 v = v0;
nuclear@15 230 if(dx) {
nuclear@15 231 dudx = x16div(u1 - u0, dx);
nuclear@15 232 dvdx = x16div(v1 - v0, dx);
nuclear@15 233 } else {
nuclear@15 234 dudx = u1 - u0;
nuclear@15 235 dvdx = v1 - v0;
nuclear@15 236 }
nuclear@19 237 #endif
nuclear@15 238
nuclear@15 239 ix0 = (x0 + 32768) >> 16;
nuclear@15 240 ix1 = (x1 + 32768) >> 16;
nuclear@15 241
nuclear@15 242 if(ix0 < 0) ix0 = 0;
nuclear@15 243 if(ix1 >= WIDTH - 1) ix1 = WIDTH - 1;
nuclear@15 244
nuclear@15 245 num_pix = ix1 - ix0;
nuclear@15 246 pixels = (uint16_t*)back_buffer->pixels + (y * WIDTH + ix0) / 2;
nuclear@15 247
nuclear@15 248 if(ix0 & 1) {
nuclear@9 249 uint16_t pix = *pixels & 0xff;
nuclear@9 250 *pixels++ = pix | ((uint16_t)color << 8);
nuclear@9 251 --num_pix;
nuclear@19 252 #ifdef USE_TEX
nuclear@15 253 u += dudx;
nuclear@15 254 v += dvdx;
nuclear@19 255 #endif
nuclear@9 256 }
nuclear@9 257
nuclear@9 258 num_pairs = (num_pix & 0xfffe) / 2;
nuclear@9 259
nuclear@9 260 for(i=0; i<num_pairs; i++) {
nuclear@9 261 *pixels++ = colpair;
nuclear@19 262 #ifdef USE_TEX
nuclear@15 263 u += dudx * 2;
nuclear@15 264 v += dvdx * 2;
nuclear@19 265 #endif
nuclear@9 266 }
nuclear@9 267
nuclear@9 268 if(num_pix & 1) {
nuclear@9 269 uint16_t pix = *pixels & 0xff00;
nuclear@9 270 *pixels = pix | color;
nuclear@9 271 }
nuclear@9 272 }
nuclear@9 273
nuclear@15 274 static void fill_scanline_rgb(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
nuclear@17 275 int32_t v0, int32_t v1, uint16_t color, struct texture *tex)
nuclear@5 276 {
nuclear@15 277 int i, ix0, ix1;
nuclear@14 278 uint16_t *pixels;
nuclear@19 279 #ifdef USE_TEX
nuclear@15 280 int32_t dx;
nuclear@15 281 int32_t u, v, dudx, dvdx;
nuclear@19 282 #endif
nuclear@5 283
nuclear@14 284 if(x0 > x1) {
nuclear@15 285 int32_t tmp = x0;
nuclear@14 286 x0 = x1;
nuclear@15 287 x1 = tmp;
nuclear@14 288 }
nuclear@14 289
nuclear@19 290 #ifdef USE_TEX
nuclear@20 291 if(tex) {
nuclear@20 292 dx = x1 - x0;
nuclear@14 293
nuclear@20 294 u = u0;
nuclear@20 295 v = v0;
nuclear@20 296 if(dx) {
nuclear@20 297 dudx = x16div(u1 - u0, dx);
nuclear@20 298 dvdx = x16div(v1 - v0, dx);
nuclear@20 299 } else {
nuclear@20 300 dudx = u1 - u0;
nuclear@20 301 dvdx = v1 - v0;
nuclear@20 302 }
nuclear@15 303 }
nuclear@19 304 #endif
nuclear@15 305
nuclear@15 306 ix0 = (x0 + 32768) >> 16;
nuclear@15 307 ix1 = (x1 + 32768) >> 16;
nuclear@15 308
nuclear@15 309 if(ix0 < 0) ix0 = 0;
nuclear@15 310 if(ix1 >= WIDTH - 1) ix1 = WIDTH - 1;
nuclear@15 311
nuclear@15 312 pixels = (uint16_t*)back_buffer->pixels + y * WIDTH + ix0;
nuclear@19 313 #ifdef USE_TEX
nuclear@19 314 if(tex) {
nuclear@19 315 for(i=ix0; i<ix1; i++) {
nuclear@17 316 int tx = (u >> (16 - tex->ushift)) & tex->umask;
nuclear@17 317 int ty = (v >> (16 - tex->vshift)) & tex->vmask;
nuclear@20 318 *pixels++ = ((uint16_t*)tex->pixels)[ty * tex->xsz + tx];
nuclear@19 319
nuclear@19 320 u += dudx;
nuclear@19 321 v += dvdx;
nuclear@19 322 }
nuclear@19 323 } else
nuclear@19 324 #endif
nuclear@19 325 {
nuclear@19 326 for(i=ix0; i<ix1; i++) {
nuclear@17 327 *pixels++ = color;
nuclear@17 328 }
nuclear@5 329 }
nuclear@5 330 }
nuclear@8 331
nuclear@8 332
nuclear@8 333 void draw_point(const pvec3 *v, uint16_t color)
nuclear@8 334 {
nuclear@20 335 int x = (v->x + 32768) >> 16;
nuclear@20 336 int y = (v->y + 32768) >> 16;
nuclear@8 337 uint16_t *pixels = (uint16_t*)back_buffer->pixels;
nuclear@8 338
nuclear@8 339 if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
nuclear@8 340 return;
nuclear@8 341 }
nuclear@8 342
nuclear@9 343 #ifdef PALMODE
nuclear@9 344 pixels += (y * WIDTH + x) / 2;
nuclear@9 345 if(x & 1) {
nuclear@9 346 *pixels = (*pixels & 0xff) | (color << 8);
nuclear@9 347 } else {
nuclear@9 348 *pixels = (*pixels & 0xff00) | color;
nuclear@9 349 }
nuclear@9 350 #else
nuclear@8 351 pixels[y * WIDTH + x] = color;
nuclear@9 352 #endif
nuclear@8 353 }
nuclear@14 354
nuclear@14 355 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
nuclear@14 356 {
nuclear@14 357 return x16mul(x0, y1) - x16mul(y0, x1);
nuclear@14 358 }