initial commit
[retroray] / src / gaw / polytmpl.h
1 #ifdef _MSC_VER
2 #pragma warning (disable: 4101)
3 #endif
4
5 #if !defined(GOURAUD) && !defined(TEXMAP) && !defined(ZBUF)
6 #define NOLERP
7 #endif
8
9 void POLYFILL(struct pvertex *varr, int vnum)
10 {
11         int i, line, top, bot;
12         struct pvertex *vlast, *v, *vn, *tab;
13         int32_t x, y0, y1, dx, dy, slope, fx, fy;
14         int start, len;
15         gaw_pixel *fbptr, *pptr, color;
16 #ifdef GOURAUD
17         int32_t r, g, b, dr, dg, db, rslope, gslope, bslope;
18 #ifdef BLEND_ALPHA
19         int32_t a, da, aslope;
20 #endif
21 #endif  /* GOURAUD */
22 #ifdef TEXMAP
23         int32_t tu, tv, du, dv, uslope, vslope;
24         int tx, ty;
25         gaw_pixel texel;
26 #endif
27 #ifdef ZBUF
28         int32_t z, dz, zslope;
29         uint32_t *zptr;
30 #endif
31
32 #if !defined(GOURAUD)
33         /* for flat shading we already know the color, so pack it once */
34         color = PACK_RGB(varr[0].r, varr[0].g, varr[0].b);
35 #endif
36
37         vlast = varr + vnum - 1;
38         top = pfill_fb.height;
39         bot = 0;
40
41         for(i=0; i<vnum; i++) {
42                 /* scan the edge between the current and next vertex */
43                 v = varr + i;
44                 vn = VNEXT(v);
45
46                 if(vn->y == v->y) continue;     // XXX ???
47
48                 if(vn->y >= v->y) {
49                         /* inrementing Y: left side */
50                         tab = left;
51                 } else {
52                         /* decrementing Y: right side, flip vertices to trace bottom->up */
53                         tab = right;
54                         v = vn;
55                         vn = varr + i;
56                 }
57
58                 /* calculate edge slope */
59                 dx = vn->x - v->x;
60                 dy = vn->y - v->y;
61                 slope = (dx << 8) / dy;
62
63 #ifdef GOURAUD
64                 r = v->r << COLOR_SHIFT;
65                 g = v->g << COLOR_SHIFT;
66                 b = v->b << COLOR_SHIFT;
67                 dr = (vn->r << COLOR_SHIFT) - r;
68                 dg = (vn->g << COLOR_SHIFT) - g;
69                 db = (vn->b << COLOR_SHIFT) - b;
70                 rslope = (dr << 8) / dy;
71                 gslope = (dg << 8) / dy;
72                 bslope = (db << 8) / dy;
73 #ifdef BLEND_ALPHA
74                 a = v->a << COLOR_SHIFT;
75                 da = (vn->a << COLOR_SHIFT) - a;
76                 aslope = (da << 8) / dy;
77 #endif  /* BLEND_ALPHA */
78 #endif  /* GOURAUD */
79 #ifdef TEXMAP
80                 tu = v->u;
81                 tv = v->v;
82                 du = vn->u - tu;
83                 dv = vn->v - tv;
84                 uslope = (du << 8) / dy;
85                 vslope = (dv << 8) / dy;
86 #endif  /* TEXMAP */
87 #ifdef ZBUF
88                 z = v->z;
89                 dz = vn->z - z;
90                 zslope = (dz << 8) / dy;
91 #endif  /* ZBUF */
92
93                 y0 = (v->y + 0x100) & 0xffffff00;       /* start from the next scanline */
94                 fy = y0 - v->y;                                         /* fractional part before the next scanline */
95                 fx = (fy * slope) >> 8;                         /* X adjust for the step to the next scanline */
96                 x = v->x + fx;                                          /* adjust X */
97                 y1 = vn->y & 0xffffff00;                        /* last scanline of the edge <= vn->y */
98
99                 /* also adjust other interpolated attributes */
100 #ifdef GOURAUD
101                 r += (fy * rslope) >> 8;
102                 g += (fy * gslope) >> 8;
103                 b += (fy * bslope) >> 8;
104 #ifdef BLEND_ALPHA
105                 a += (fy * aslope) >> 8;
106 #endif  /* BLEND_ALPHA */
107 #endif  /* GOURAUD */
108 #ifdef TEXMAP
109                 tu += (fy * uslope) >> 8;
110                 tv += (fy * vslope) >> 8;
111 #endif
112 #ifdef ZBUF
113                 z += (fy * zslope) >> 8;
114 #endif
115
116                 line = y0 >> 8;
117                 if(line < top) top = line;
118                 if((y1 >> 8) > bot) bot = y1 >> 8;
119
120                 if(line > 0) tab += line;
121
122                 while(line <= (y1 >> 8) && line < pfill_fb.height) {
123                         if(line >= 0) {
124                                 int val = x < 0 ? 0 : x >> 8;
125                                 tab->x = val < pfill_fb.width ? val : pfill_fb.width - 1;
126 #ifdef GOURAUD
127                                 tab->r = r;
128                                 tab->g = g;
129                                 tab->b = b;
130 #ifdef BLEND_ALPHA
131                                 tab->a = a;
132 #endif  /* BLEND_ALPHA */
133 #endif  /* GOURAUD */
134 #ifdef TEXMAP
135                                 tab->u = tu;
136                                 tab->v = tv;
137 #endif
138 #ifdef ZBUF
139                                 tab->z = z;
140 #endif
141                                 tab++;
142                         }
143                         x += slope;
144 #ifdef GOURAUD
145                         r += rslope;
146                         g += gslope;
147                         b += bslope;
148 #ifdef BLEND_ALPHA
149                         a += aslope;
150 #endif  /* BLEND_ALPHA */
151 #endif  /* GOURAUD */
152 #ifdef TEXMAP
153                         tu += uslope;
154                         tv += vslope;
155 #endif  /* TEXMAP */
156 #ifdef ZBUF
157                         z += zslope;
158 #endif  /* ZBUF */
159                         line++;
160                 }
161         }
162
163         if(top < 0) top = 0;
164         if(bot >= pfill_fb.height) bot = pfill_fb.height - 1;
165
166         fbptr = pfill_fb.pixels + top * pfill_fb.width;
167         for(i=top; i<=bot; i++) {
168                 start = left[i].x;
169                 len = right[i].x - start;
170                 /* XXX we probably need more precision in left/right.x */
171
172 #ifndef NOLERP
173                 dx = len == 0 ? 256 : (len << 8);
174 #endif
175
176 #ifdef GOURAUD
177                 r = left[i].r;
178                 g = left[i].g;
179                 b = left[i].b;
180                 dr = right[i].r - r;
181                 dg = right[i].g - g;
182                 db = right[i].b - b;
183                 rslope = (dr << 8) / dx;
184                 gslope = (dg << 8) / dx;
185                 bslope = (db << 8) / dx;
186 #ifdef BLEND_ALPHA
187                 a = left[i].a;
188                 da = right[i].a - a;
189                 aslope = (da << 8) / dx;
190 #endif  /* BLEND_ALPHA */
191 #endif  /* GOURAUD */
192 #ifdef TEXMAP
193                 tu = left[i].u;
194                 tv = left[i].v;
195                 du = right[i].u - tu;
196                 dv = right[i].v - tv;
197                 uslope = (du << 8) / dx;
198                 vslope = (dv << 8) / dx;
199 #endif  /* TEXMAP */
200 #ifdef ZBUF
201                 z = left[i].z;
202                 dz = right[i].z - z;
203                 zslope = (dz << 8) / dx;
204                 zptr = pfill_zbuf + i * pfill_fb.width + start;
205 #endif  /* ZBUF */
206
207                 pptr = fbptr + start;
208                 while(len-- > 0) {
209 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
210                         int cr, cg, cb;
211 #ifdef BLEND_ALPHA
212                         int ca;
213 #endif
214 #endif
215 #if defined(BLEND_ALPHA) || defined(BLEND_ADD)
216                         gaw_pixel fbcol;
217 #endif
218 #ifdef BLEND_ALPHA
219                         int inv_alpha;
220 #endif
221 #ifdef ZBUF
222                         uint32_t cz = z;
223                         z += zslope;
224
225                         if(cz <= *zptr) {
226                                 *zptr++ = cz;
227                         } else {
228                                 /* ZFAIL: advance all attributes and continue */
229 #ifdef GOURAUD
230                                 r += rslope;
231                                 g += gslope;
232                                 b += bslope;
233 #ifdef BLEND_ALPHA
234                                 a += aslope;
235 #endif
236 #endif  /* GOURAUD */
237 #ifdef TEXMAP
238                                 tu += uslope;
239                                 tv += vslope;
240 #endif  /* TEXMAP */
241                                 /* skip pixel */
242                                 pptr++;
243                                 zptr++;
244                                 continue;
245                         }
246 #endif  /* ZBUF */
247
248 #ifdef GOURAUD
249                         /* we upped the color precision to while interpolating the
250                          * edges, now drop the extra bits before packing
251                          */
252                         cr = r < 0 ? 0 : (r >> COLOR_SHIFT);
253                         cg = g < 0 ? 0 : (g >> COLOR_SHIFT);
254                         cb = b < 0 ? 0 : (b >> COLOR_SHIFT);
255                         r += rslope;
256                         g += gslope;
257                         b += bslope;
258 #ifdef BLEND_ALPHA
259                         ca = a < 0 ? 0 : (a >> COLOR_SHIFT);
260                         a += aslope;
261 #endif  /* BLEND_ALPHA */
262 #endif  /* GOURAUD */
263 #ifdef TEXMAP
264                         tx = (tu >> (16 - pfill_tex.xshift)) & pfill_tex.xmask;
265                         ty = (tv >> (16 - pfill_tex.yshift)) & pfill_tex.ymask;
266                         texel = pfill_tex.pixels[(ty << pfill_tex.xshift) + tx];
267
268                         tu += uslope;
269                         tv += vslope;
270
271 #ifndef GOURAUD
272                         /* for flat textured, cr,cg,cb would not be initialized */
273                         cr = varr[0].r;
274                         cg = varr[0].g;
275                         cb = varr[0].b;
276 #ifdef BLEND_ALPHA
277                         ca = varr[0].a;
278 #endif
279 #endif  /* !GOURAUD */
280                         /* This is not correct, should be /255, but it's much faster
281                          * to shift by 8 (/256), and won't make a huge difference
282                          */
283                         cr = (cr * UNPACK_R(texel)) >> 8;
284                         cg = (cg * UNPACK_G(texel)) >> 8;
285                         cb = (cb * UNPACK_B(texel)) >> 8;
286 #ifdef BLEND_ALPHA
287                         ca = (ca * UNPACK_A(texel)) >> 8;
288 #endif
289 #endif  /* TEXMAP */
290
291 #ifdef BLEND_ALPHA
292                         inv_alpha = 255 - ca;
293                         fbcol = *pptr;
294                         cr = (cr * ca + UNPACK_R(fbcol) * inv_alpha) >> 8;
295                         cg = (cg * ca + UNPACK_G(fbcol) * inv_alpha) >> 8;
296                         cb = (cb * ca + UNPACK_B(fbcol) * inv_alpha) >> 8;
297 #endif  /* BLEND_ALPHA */
298 #ifdef BLEND_ADD
299                         fbcol = *pptr;
300                         cr += UNPACK_R(fbcol);
301                         cg += UNPACK_G(fbcol);
302                         cb += UNPACK_B(fbcol);
303 #endif  /* BLEND_ADD */
304
305 #ifdef DEBUG_OVERDRAW
306                         *pptr++ += DEBUG_OVERDRAW;
307 #else
308 #if defined(GOURAUD) || defined(TEXMAP) || defined(BLEND_ALPHA) || defined(BLEND_ADD)
309                         if(cr >= 255) cr = 255;
310                         if(cg >= 255) cg = 255;
311                         if(cb >= 255) cb = 255;
312                         color = PACK_RGB(cr, cg, cb);
313 #endif
314                         *pptr++ = color;
315 #endif
316                 }
317                 fbptr += pfill_fb.width;
318         }
319 }
320
321 #undef NOLERP