gba-x3dtest

view src/polyfill.c @ 15:b755fb002f17

foo
author John Tsiombikas <nuclear@member.fsf.org>
date Wed, 25 Jun 2014 17:02:48 +0300
parents c398d834d64a
children 0a7f402892b3
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"
8 /* TODO: constant interpolant optimization */
10 #define VNEXT(x, n) (((x) + 1) % (n))
11 #define VPREV(x, n) ((x) > 0 ? (x) - 1 : (n) - 1)
13 static void fill_scanline_pal(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
14 int32_t v0, int32_t v1, uint8_t color);
15 static void fill_scanline_rgb(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
16 int32_t v0, int32_t v1, uint16_t color);
17 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1);
19 void draw_poly(int num, const pvec3 *verts, const pvec2 *tex, uint16_t color)
20 {
21 int i, topidx = 0, botidx = 0;
22 int lidx[2] = {-1, -1}, ridx[2] = {-1, -1};
23 int32_t y, topy, boty;
24 int32_t ldy = 0, rdy = 0, ldxdy, rdxdy;
25 int32_t lx, rx;
26 int start, end;
27 pvec3 v0, v1;
29 int32_t lu, lv, ru, rv, ldudy, ldvdy, rdudy, rdvdy; /* texture interpolants */
31 v0.x = verts[1].x - verts[0].x;
32 v0.y = verts[1].y - verts[0].y;
34 v1.x = verts[2].x - verts[0].x;
35 v1.y = verts[2].y - verts[0].y;
37 if(winding(v0.x, v0.y, v1.x, v1.y) < 0) {
38 return; /* backface */
39 }
41 topy = boty = verts[0].y;
42 for(i=1; i<num; i++) {
43 int32_t y = verts[i].y;
44 if(y < topy) {
45 topy = y;
46 topidx = i;
47 }
48 if(y > boty) {
49 boty = y;
50 botidx = i;
51 }
52 }
54 lidx[0] = ridx[0] = topidx;
56 /* find starting left edge */
57 lidx[1] = VPREV(lidx[0], num);
58 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
60 while(ldy == 0) {
61 lidx[0] = lidx[1];
62 lidx[1] = VPREV(lidx[1], num);
64 if(lidx[1] == topidx) {
65 return; /* degenerate */
66 }
68 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
69 }
70 lx = verts[lidx[0]].x;
71 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
72 lu = tex[lidx[0]].x;
73 ldudy = x16div(tex[lidx[1]].x - lu, ldy);
74 lv = tex[lidx[0]].y;
75 ldvdy = x16div(tex[lidx[1]].y - lv, ldy);
77 /* find starting right edge */
78 ridx[1] = VNEXT(ridx[0], num);
79 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
81 while(rdy == 0) {
82 ridx[0] = ridx[1];
83 ridx[1] = VNEXT(ridx[1], num);
85 if(ridx[1] == topidx) {
86 return; /* degenerate */
87 }
89 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
90 }
91 rx = verts[ridx[0]].x;
92 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
93 ru = tex[ridx[0]].x;
94 rdudy = x16div(tex[ridx[1]].x - ru, rdy);
95 rv = tex[ridx[0]].y;
96 rdvdy = x16div(tex[ridx[1]].y - rv, rdy);
98 start = topy >> 16;
99 end = boty >> 16;
101 if(end >= HEIGHT) end = HEIGHT - 1;
103 y = topy;
104 for(i=start; i<=end; i++) {
106 if(y >= verts[lidx[1]].y) {
107 lx = verts[lidx[1]].x;
108 lidx[0] = lidx[1];
109 lidx[1] = VPREV(lidx[1], num);
110 ldy = verts[lidx[1]].y - verts[lidx[0]].y;
111 if(ldy < 0) {
112 break;
113 }
115 lu = tex[lidx[0]].x;
116 lv = tex[lidx[0]].y;
118 if(ldy) {
119 ldxdy = x16div(verts[lidx[1]].x - lx, ldy);
120 ldudy = x16div(tex[lidx[1]].x - lu, ldy);
121 ldvdy = x16div(tex[lidx[1]].y - lv, ldy);
122 } else {
123 ldxdy = verts[lidx[1]].x - lx;
124 ldudy = tex[lidx[1]].x - lu;
125 ldvdy = tex[lidx[1]].y - lv;
126 }
127 }
128 if(y >= verts[ridx[1]].y) {
129 rx = verts[ridx[1]].x;
130 ridx[0] = ridx[1];
131 ridx[1] = VNEXT(ridx[1], num);
132 rdy = verts[ridx[1]].y - verts[ridx[0]].y;
133 if(rdy < 0) {
134 break;
135 }
137 ru = tex[ridx[0]].x;
138 rv = tex[ridx[0]].y;
140 if(rdy) {
141 rdxdy = x16div(verts[ridx[1]].x - rx, rdy);
142 rdudy = x16div(tex[ridx[1]].x - ru, rdy);
143 rdvdy = x16div(tex[ridx[1]].y - rv, rdy);
144 } else {
145 rdxdy = verts[ridx[1]].x - rx;
146 rdudy = tex[ridx[1]].x - ru;
147 rdvdy = tex[ridx[1]].y - rv;
148 }
149 }
151 if(i >= 0) {
152 #ifdef PALMODE
153 fill_scanline_pal(i, lx, rx, lu, ru, lv, rv, (uint8_t)color);
154 #else
155 fill_scanline_rgb(i, lx, rx, lu, ru, lv, rv, color);
156 #endif
157 }
159 lx += ldxdy;
160 rx += rdxdy;
161 y += 65536;
163 lu += ldudy;
164 lv += ldvdy;
165 ru += rdudy;
166 rv += rdvdy;
167 }
168 }
171 static void fill_scanline_pal(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
172 int32_t v0, int32_t v1, uint8_t color)
173 {
174 int ix0, ix1;
175 int32_t dx;
176 int32_t u, v, dudx, dvdx;
178 int i, num_pairs, num_pix;
179 uint16_t *pixels;
180 uint16_t colpair = (uint16_t)color | ((uint16_t)color << 8);
182 if(x0 > x1) {
183 int32_t tmp = x0;
184 x0 = x1;
185 x1 = tmp;
186 }
188 dx = x1 - x0;
190 u = u0;
191 v = v0;
192 if(dx) {
193 dudx = x16div(u1 - u0, dx);
194 dvdx = x16div(v1 - v0, dx);
195 } else {
196 dudx = u1 - u0;
197 dvdx = v1 - v0;
198 }
200 ix0 = (x0 + 32768) >> 16;
201 ix1 = (x1 + 32768) >> 16;
203 if(ix0 < 0) ix0 = 0;
204 if(ix1 >= WIDTH - 1) ix1 = WIDTH - 1;
206 num_pix = ix1 - ix0;
207 pixels = (uint16_t*)back_buffer->pixels + (y * WIDTH + ix0) / 2;
209 if(ix0 & 1) {
210 uint16_t pix = *pixels & 0xff;
211 *pixels++ = pix | ((uint16_t)color << 8);
212 --num_pix;
213 u += dudx;
214 v += dvdx;
215 }
217 num_pairs = (num_pix & 0xfffe) / 2;
219 for(i=0; i<num_pairs; i++) {
220 *pixels++ = colpair;
221 u += dudx * 2;
222 v += dvdx * 2;
223 }
225 if(num_pix & 1) {
226 uint16_t pix = *pixels & 0xff00;
227 *pixels = pix | color;
228 }
229 }
231 static void fill_scanline_rgb(int y, int32_t x0, int32_t x1, int32_t u0, int32_t u1,
232 int32_t v0, int32_t v1, uint16_t color)
233 {
234 int i, ix0, ix1;
235 uint16_t *pixels;
236 int32_t dx;
237 int32_t u, v, dudx, dvdx;
239 if(x0 > x1) {
240 int32_t tmp = x0;
241 x0 = x1;
242 x1 = tmp;
243 }
245 dx = x1 - x0;
247 u = u0;
248 v = v0;
249 if(dx) {
250 dudx = x16div(u1 - u0, dx);
251 dvdx = x16div(v1 - v0, dx);
252 } else {
253 dudx = u1 - u0;
254 dvdx = v1 - v0;
255 }
257 ix0 = (x0 + 32768) >> 16;
258 ix1 = (x1 + 32768) >> 16;
260 if(ix0 < 0) ix0 = 0;
261 if(ix1 >= WIDTH - 1) ix1 = WIDTH - 1;
263 pixels = (uint16_t*)back_buffer->pixels + y * WIDTH + ix0;
264 for(i=ix0; i<ix1; i++) {
265 /**pixels++ = color;*/
266 int cr = u >> 8;
267 int cg = v >> 8;
268 if(cr > 255) cr = 255;
269 if(cg > 255) cg = 255;
271 *pixels++ = RGB(cr, cg, 0);
273 u += dudx;
274 v += dvdx;
275 }
276 }
279 void draw_point(const pvec3 *v, uint16_t color)
280 {
281 int x = v->x >> 16;
282 int y = v->y >> 16;
283 uint16_t *pixels = (uint16_t*)back_buffer->pixels;
285 if(x < 0 || x >= WIDTH || y < 0 || y >= HEIGHT) {
286 return;
287 }
289 #ifdef PALMODE
290 pixels += (y * WIDTH + x) / 2;
291 if(x & 1) {
292 *pixels = (*pixels & 0xff) | (color << 8);
293 } else {
294 *pixels = (*pixels & 0xff00) | color;
295 }
296 #else
297 pixels[y * WIDTH + x] = color;
298 #endif
299 }
301 static int winding(int32_t x0, int32_t y0, int32_t x1, int32_t y1)
302 {
303 return x16mul(x0, y1) - x16mul(y0, x1);
304 }