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 }
|