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