2072e2b5f19e01b4279084b83f2278e847f3f7b5
[dosdemo] / src / 3dgfx / polytmpl.h
1 static uint32_t SCANEDGE(struct pvertex *v0, struct pvertex *v1, struct pvertex *edge)
2 {
3         int i;
4         int32_t x, dx, dy, slope;
5 #ifdef GOURAUD
6         int r, g, b, dr, dg, db;
7         int32_t rslope, gslope, bslope;
8 #ifdef BLEND_ALPHA
9         int32_t a, da, aslope;
10 #endif
11 #endif  /* GOURAUD */
12 #ifdef TEXMAP
13         int32_t u, v, du, dv, uslope, vslope;
14 #endif
15         int32_t start_idx, end_idx;
16
17         if(v0->y > v1->y) {
18                 struct pvertex *tmp = v0;
19                 v0 = v1;
20                 v1 = tmp;
21         }
22
23         x = v0->x;
24         dy = v1->y - v0->y;
25         dx = v1->x - v0->x;
26         slope = (dx << 8) / dy;
27 #ifdef GOURAUD
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;
37 #ifdef BLEND_ALPHA
38         a = (v0->a << COLOR_SHIFT);
39         da = (v1->a << COLOR_SHIFT) - a;
40         aslope = (da << 8) / dy;
41 #endif  /* BLEND_ALPHA */
42 #endif  /* GOURAUD */
43 #ifdef TEXMAP
44         u = v0->u;
45         v = v0->v;
46         du = v1->u - v0->u;
47         dv = v1->v - v0->v;
48         uslope = (du << 8) / dy;
49         vslope = (dv << 8) / dy;
50 #endif
51
52         start_idx = v0->y >> 8;
53         end_idx = v1->y >> 8;
54
55         for(i=start_idx; i<end_idx; i++) {
56                 CHECKEDGE(i);
57                 edge[i].x = x;
58                 x += slope;
59 #ifdef GOURAUD
60                 /* we'll store the color in the edge tables with COLOR_SHIFT extra bits of precision */
61                 CHECKEDGE(i);
62                 edge[i].r = r;
63                 edge[i].g = g;
64                 edge[i].b = b;
65                 r += rslope;
66                 g += gslope;
67                 b += bslope;
68 #ifdef BLEND_ALPHA
69                 CHECKEDGE(i);
70                 edge[i].a = a;
71                 a += aslope;
72 #endif
73 #endif  /* GOURAUD */
74 #ifdef TEXMAP
75                 CHECKEDGE(i);
76                 edge[i].u = u;
77                 edge[i].v = v;
78                 u += uslope;
79                 v += vslope;
80 #endif
81         }
82
83         return (uint32_t)start_idx | ((uint32_t)(end_idx - 1) << 16);
84 }
85
86 void POLYFILL(struct pvertex *pv, int nverts)
87 {
88         int i, winding;
89         int topidx = 0, botidx = 0, sltop = pfill_fb.height, slbot = 0;
90         g3d_pixel color;
91         /* the following variables are used for interpolating horizontally accros scanlines */
92 #if defined(GOURAUD) || defined(TEXMAP)
93         int mid;
94         int32_t dx, tmp;
95 #else
96         /* flat version, just pack the color now */
97         color = G3D_PACK_RGB(pv[0].r, pv[0].g, pv[0].b);
98 #endif
99 #ifdef GOURAUD
100         int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
101 #ifdef BLEND_ALPHA
102         int32_t a, da, aslope;
103 #endif
104 #endif
105 #ifdef TEXMAP
106         int32_t u, v, du, dv, uslope, vslope;
107 #endif
108
109         for(i=1; i<nverts; i++) {
110                 if(pv[i].y < pv[topidx].y) topidx = i;
111                 if(pv[i].y > pv[botidx].y) botidx = i;
112         }
113
114         winding = 0;
115         for(i=0; i<nverts; i++) {
116                 int next = NEXTIDX(i);
117                 winding += ((pv[next].x - pv[i].x) >> 4) * ((pv[next].y + pv[i].y) >> 4);
118         }
119
120         for(i=0; i<nverts; i++) {
121                 int next = NEXTIDX(i);
122                 int32_t y0 = pv[i].y;
123                 int32_t y1 = pv[next].y;
124
125                 if((y0 >> 8) == (y1 >> 8)) {
126                         /*if(y0 > y1) {*/
127                                 int i0, i1;
128                                 int idx = y0 >> 8;
129                                 if(pv[i].x < pv[next].x) {
130                                         i0 = i;
131                                         i1 = next;
132                                 } else {
133                                         i0 = next;
134                                         i1 = i;
135                                 }
136                                 CHECKEDGE(idx);
137                                 left[idx].x = pv[i0].x;
138                                 right[idx].x = pv[i1].x;
139 #ifdef GOURAUD
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;
146 #ifdef BLEND_ALPHA
147                                 left[idx].a = pv[i0].a << COLOR_SHIFT;
148                                 right[idx].a = pv[i1].a << COLOR_SHIFT;
149 #endif  /* BLEND_ALPHA */
150 #endif
151 #ifdef TEXMAP
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;
156 #endif
157                                 CHECKEDGE(idx);
158                                 if(idx > slbot) slbot = idx;
159                                 if(idx < sltop) sltop = idx;
160                         /*}*/
161                 } else {
162                         struct pvertex *edge;
163                         uint32_t res, tmp;
164
165                         if(winding < 0) {
166                                 /* clockwise */
167                                 edge = y0 > y1 ? left : right;
168                         } else {
169                                 /* counter-clockwise */
170                                 edge = y0 > y1 ? right : left;
171                         }
172                         res = SCANEDGE(pv + i, pv + next, edge);
173                         tmp = (res >> 16) & 0xffff;
174                         if(tmp > slbot) slbot = tmp;
175                         if((tmp = res & 0xffff) < sltop) {
176                                 sltop = tmp;
177                         }
178                 }
179         }
180
181         /* calculate the slopes of all attributes across the largest span out
182          * of the three: middle, top, or bottom.
183          */
184 #ifndef HIGH_QUALITY
185 #if defined(GOURAUD) || defined(TEXMAP)
186         mid = (sltop + slbot) >> 1;
187         CHECKEDGE(sltop);
188         CHECKEDGE(slbot);
189         CHECKEDGE(mid);
190         dx = right[mid].x - left[mid].x;
191         if((tmp = right[sltop].x - left[sltop].x) > dx) {
192                 dx = tmp;
193                 mid = sltop;
194         }
195         if((tmp = right[slbot].x - left[slbot].x) > dx) {
196                 dx = tmp;
197                 mid = slbot;
198         }
199         if(!dx) dx = 256;       /* avoid division by zero */
200 #endif
201         CHECKEDGE(idx);
202 #ifdef GOURAUD
203         dr = right[mid].r - left[mid].r;
204         dg = right[mid].g - left[mid].g;
205         db = right[mid].b - left[mid].b;
206         rslope = (dr << 8) / dx;
207         gslope = (dg << 8) / dx;
208         bslope = (db << 8) / dx;
209 #ifdef BLEND_ALPHA
210         da = right[mid].a - left[mid].a;
211         aslope = (da << 8) / dx;
212 #endif  /* BLEND_ALPHA */
213 #endif
214 #ifdef TEXMAP
215         du = right[mid].u - left[mid].u;
216         dv = right[mid].v - left[mid].v;
217         uslope = (du << 8) / dx;
218         vslope = (dv << 8) / dx;
219 #endif
220 #endif  /* !defined(HIGH_QUALITY) */
221
222         /* for each scanline ... */
223         for(i=sltop; i<=slbot; i++) {
224                 g3d_pixel *pixptr;
225                 int32_t x;
226
227                 CHECKEDGE(i);
228                 x = left[i].x;
229                 pixptr = pfill_fb.pixels + i * pfill_fb.width + (x >> 8);
230
231 #ifdef GOURAUD
232                 r = left[i].r;
233                 g = left[i].g;
234                 b = left[i].b;
235 #ifdef BLEND_ALPHA
236                 a = left[i].a;
237 #endif  /* BLEND_ALPHA */
238 #endif
239 #ifdef TEXMAP
240                 u = left[i].u;
241                 v = left[i].v;
242 #endif
243                 CHECKEDGE(i);
244
245 #if defined(HIGH_QUALITY) && (defined(GOURAUD) || defined(TEXMAP))
246                 if(!(dx = right[i].x - left[i].x)) dx = 256;
247
248                 CHECKEDGE(i);
249 #ifdef GOURAUD
250                 dr = right[i].r - left[i].r;
251                 dg = right[i].g - left[i].g;
252                 db = right[i].b - left[i].b;
253                 rslope = (dr << 8) / dx;
254                 gslope = (dg << 8) / dx;
255                 bslope = (db << 8) / dx;
256 #ifdef BLEND_ALPHA
257                 da = right[i].a - left[i].a;
258                 aslope = (da << 8) / dx;
259 #endif  /* BLEND_ALPHA */
260 #endif  /* GOURAUD */
261 #ifdef TEXMAP
262                 du = right[i].u - left[i].u;
263                 dv = right[i].v - left[i].v;
264                 uslope = (du << 8) / dx;
265                 vslope = (dv << 8) / dx;
266 #endif
267 #endif  /* HIGH_QUALITY */
268                 CHECKEDGE(i);
269
270                 /* go across the scanline interpolating if necessary */
271                 while(x <= right[i].x) {
272 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
273                         int cr, cg, cb;
274 #endif
275 #if defined(BLEND_ALPHA) || defined(BLEND_ADD)
276                         g3d_pixel fbcol;
277 #endif
278 #ifdef BLEND_ALPHA
279                         int alpha, inv_alpha;
280 #endif
281 #ifdef GOURAUD
282                         /* we upped the color precision to while interpolating the
283                          * edges, now drop the extra bits before packing
284                          */
285                         cr = r < 0 ? 0 : (r >> COLOR_SHIFT);
286                         cg = g < 0 ? 0 : (g >> COLOR_SHIFT);
287                         cb = b < 0 ? 0 : (b >> COLOR_SHIFT);
288                         r += rslope;
289                         g += gslope;
290                         b += bslope;
291 #ifdef BLEND_ALPHA
292                         a += aslope;
293 #else
294                         if(cr > 255) cr = 255;
295                         if(cg > 255) cg = 255;
296                         if(cb > 255) cb = 255;
297 #endif  /* BLEND_ALPHA */
298 #endif  /* GOURAUD */
299 #ifdef TEXMAP
300                         {
301                                 int tx = (u >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
302                                 int ty = (v >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
303                                 g3d_pixel texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
304 #ifdef GOURAUD
305                                 /* This is not correct, should be /255, but it's much faster
306                                  * to shift by 8 (/256), and won't make a huge difference
307                                  */
308                                 cr = (cr * G3D_UNPACK_R(texel)) >> 8;
309                                 cg = (cg * G3D_UNPACK_G(texel)) >> 8;
310                                 cb = (cb * G3D_UNPACK_B(texel)) >> 8;
311 #else
312                                 cr = G3D_UNPACK_R(texel);
313                                 cg = G3D_UNPACK_G(texel);
314                                 cb = G3D_UNPACK_B(texel);
315 #endif
316                         }
317                         u += uslope;
318                         v += vslope;
319 #endif
320
321 #if defined(BLEND_ALPHA) || defined(BLEND_ADD)
322 #if !defined(GOURAUD) && !defined(TEXMAP)
323                         /* flat version: cr,cg,cb are uninitialized so far */
324                         cr = pv[0].r;
325                         cg = pv[0].g;
326                         cb = pv[0].b;
327 #endif
328                         fbcol = *pixptr;
329
330 #ifdef BLEND_ALPHA
331 #ifdef GOURAUD
332                         alpha = a >> COLOR_SHIFT;
333 #else
334                         alpha = pv[0].a;
335 #endif
336                         inv_alpha = 255 - alpha;
337                         cr = (cr * alpha + G3D_UNPACK_R(fbcol) * inv_alpha) >> 8;
338                         cg = (cg * alpha + G3D_UNPACK_G(fbcol) * inv_alpha) >> 8;
339                         cb = (cb * alpha + G3D_UNPACK_B(fbcol) * inv_alpha) >> 8;
340 #else   /* !BLEND_ALPHA (so BLEND_ADD) */
341                         cr += G3D_UNPACK_R(fbcol);
342                         cg += G3D_UNPACK_R(fbcol);
343                         cb += G3D_UNPACK_R(fbcol);
344 #endif
345                         if(cr > 255) cr = 255;
346                         if(cg > 255) cg = 255;
347                         if(cb > 255) cb = 255;
348 #endif  /* BLEND(ALPHA|ADD) */
349
350 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
351                         color = G3D_PACK_RGB(cr, cg, cb);
352 #endif
353
354 #ifdef DEBUG_OVERDRAW
355                         *pixptr++ += DEBUG_OVERDRAW;
356 #else
357                         *pixptr++ = color;
358 #endif
359                         x += 256;
360                 }
361         }
362 }
363