1 static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
4 int32_t x, dx, dy, slope;
6 int r, g, b, dr, dg, db;
7 int32_t rslope, gslope, bslope;
13 int32_t u, v, du, dv, uslope, vslope;
15 int32_t start_idx, end_idx;
18 struct pvertex *tmp = v0;
26 slope = (dx << 8) / dy;
28 r = (v0->r << COLOR_SHIFT);
29 g = (v0->g << COLOR_SHIFT);
30 b = (v0->b << COLOR_SHIFT);
31 dr = (v1->r << COLOR_SHIFT) - r;
32 dg = (v1->g << COLOR_SHIFT) - g;
33 db = (v1->b << COLOR_SHIFT) - b;
34 rslope = (dr << 8) / dy;
35 gslope = (dg << 8) / dy;
36 bslope = (db << 8) / dy;
38 a = (v0->a << COLOR_SHIFT);
39 da = (v1->a << COLOR_SHIFT) - a;
40 aslope = (da << 8) / dy;
48 uslope = (du << 8) / dy;
49 vslope = (dv << 8) / dy;
52 start_idx = v0->y >> 8;
55 for(i=start_idx; i<end_idx; i++) {
59 /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */
79 return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
82 void POLYFILL(struct pvertex *pv, int nverts)
85 int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
86 struct pvertex *left, *right;
88 /* the following variables are used for interpolating horizontally accros scanlines */
89 #if defined(GOURAUD) || defined(TEXMAP)
93 /* flat version, just pack the color now */
94 color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
97 int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
99 int32_t a, da, aslope;
103 int32_t u, v, du, dv, uslope, vslope;
106 for(i=1; i<nverts; i++) {
107 if(pv[i].y < pv[topidx].y) topidx = i;
108 if(pv[i].y > pv[botidx].y) botidx = i;
112 for(i=0; i<nverts; i++) {
113 int next = NEXTIDX(i);
114 winding += ((pv[next].x - pv[i].x) >> 4) * ((pv[next].y + pv[i].y) >> 4);
117 /* +1 to avoid crashing due to off-by-one rounding errors in the rasterization */
118 left = alloca((pfill_fb.height + 1) * sizeof *left);
119 right = alloca((pfill_fb.height + 1) * sizeof *right);
121 for(i=0; i<nverts; i++) {
122 int next = NEXTIDX(i);
123 int32_t y0 = pv[i].y;
124 int32_t y1 = pv[next].y;
126 if((y0 >> 8) == (y1 >> 8)) {
130 if(pv[i].x < pv[next].x) {
137 left[idx].x = pv[i0].x;
138 right[idx].x = pv[i1].x;
140 left[idx].r = pv[i0].r << COLOR_SHIFT;
141 left[idx].g = pv[i0].g << COLOR_SHIFT;
142 left[idx].b = pv[i0].b << COLOR_SHIFT;
143 right[idx].r = pv[i1].r << COLOR_SHIFT;
144 right[idx].g = pv[i1].g << COLOR_SHIFT;
145 right[idx].b = pv[i1].b << COLOR_SHIFT;
147 left[idx].a = pv[i0].a << COLOR_SHIFT;
148 right[idx].a = pv[i1].a << COLOR_SHIFT;
152 left[idx].u = pv[i0].u;
153 left[idx].v = pv[i0].v;
154 right[idx].u = pv[i1].u;
155 right[idx].v = pv[i1].v;
157 if(idx > slbot) slbot = idx;
158 if(idx < sltop) sltop = idx;
161 struct pvertex *edge;
166 edge = y0 > y1 ? left : right;
168 /* counter-clockwise */
169 edge = y0 > y1 ? right : left;
171 res = SCANEDGE(pv + i, pv + next, edge);
172 tmp = (res >> 16) & 0xffff;
173 if(tmp > slbot) slbot = tmp;
174 if((tmp = res & 0xffff) < sltop) {
180 /* calculate the slopes of all attributes across the largest span out
181 * of the three: middle, top, or bottom.
184 #if defined(GOURAUD) || defined(TEXMAP)
185 mid = (sltop + slbot) >> 1;
186 dx = right[mid].x - left[mid].x;
187 if((tmp = right[sltop].x - left[sltop].x) > dx) {
191 if((tmp = right[slbot].x - left[slbot].x) > dx) {
195 if(!dx) dx = 256; /* avoid division by zero */
198 dr = right[mid].r - left[mid].r;
199 dg = right[mid].g - left[mid].g;
200 db = right[mid].b - left[mid].b;
201 rslope = (dr << 8) / dx;
202 gslope = (dg << 8) / dx;
203 bslope = (db << 8) / dx;
205 da = right[mid].a - left[mid].a;
206 aslope = (da << 8) / dx;
210 du = right[mid].u - left[mid].u;
211 dv = right[mid].v - left[mid].v;
212 uslope = (du << 8) / dx;
213 vslope = (dv << 8) / dx;
215 #endif /* !defined(HIGH_QUALITY) */
217 /* for each scanline ... */
218 for(i=sltop; i<=slbot; i++) {
223 pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8);
238 #if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP))
239 if(!(dx = right[i].x - left[i].x)) dx = 256;
242 dr = right[i].r - left[i].r;
243 dg = right[i].g - left[i].g;
244 db = right[i].b - left[i].b;
245 rslope = (dr << 8) / dx;
246 gslope = (dg << 8) / dx;
247 bslope = (db << 8) / dx;
249 da = right[i].a - left[i].a;
250 aslope = (da << 8) / dx;
254 du = right[i].u - left[i].u;
255 dv = right[i].v - left[i].v;
256 uslope = (du << 8) / dx;
257 vslope = (dv << 8) / dx;
259 #endif /* HIGH_QUALITY */
261 /* go across the scanline interpolating if necessary */
262 while(x <= right[i].x) {
263 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
268 int alpha, inv_alpha;
271 /* we upped the color precision to while interpolating the
272 * edges, now drop the extra bits before packing
274 cr = r < 0 ? 0 : (r >> COLOR_SHIFT);
275 cg = g < 0 ? 0 : (g >> COLOR_SHIFT);
276 cb = b < 0 ? 0 : (b >> COLOR_SHIFT);
283 if(cr > 255) cr = 255;
284 if(cg > 255) cg = 255;
285 if(cb > 255) cb = 255;
290 int tx = (u >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
291 int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
292 g3d_pixel texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
294 /* This is not correct, should be /255, but it's much faster
295 * to shift by 8 (/256), and won't make a huge difference
297 cr = (cr * G3D_UNPACK_R(texel)) >> 8;
298 cg = (cg * G3D_UNPACK_G(texel)) >> 8;
299 cb = (cb * G3D_UNPACK_B(texel)) >> 8;
301 cr = G3D_UNPACK_R(texel);
302 cg = G3D_UNPACK_G(texel);
303 cb = G3D_UNPACK_B(texel);
311 #if !defined(GOURAUD) && !defined(TEXMAP)
312 /* flat version: cr,cg,cb are uninitialized so far */
318 alpha = a >> COLOR_SHIFT;
323 inv_alpha = 255 - alpha;
324 cr = (cr * alpha + G3D_UNPACK_R(fbcol) * inv_alpha) >> 8;
325 cg = (cg * alpha + G3D_UNPACK_G(fbcol) * inv_alpha) >> 8;
326 cb = (cb * alpha + G3D_UNPACK_B(fbcol) * inv_alpha) >> 8;
327 if(cr > 255) cr = 255;
328 if(cg > 255) cg = 255;
329 if(cb > 255) cb = 255;
332 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND)
333 color = G3D_PACK_RGB(cr, cg, cb);
336 #ifdef DEBUG_OVERDRAW
337 *pixptr++ += DEBUG_OVERDRAW;