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