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