f0355c1baf4c4ac646dc8171c92e23599401e7cf
[retroray] / src / gaw / polyfill.c
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 #include <stdio.h>
19 #include <stdlib.h>
20 #include <string.h>
21 #include <assert.h>
22 #include "polyfill.h"
23
24 /*#define DEBUG_OVERDRAW        PACK_RGB(10, 10, 10)*/
25
26 #define FILL_POLY_BITS  0x03
27
28
29 /* mode bits: 00-wire 01-flat 10-gouraud 11-reserved
30  *     bit 2: texture
31  *     bit 3-4: blend mode: 00-none 01-alpha 10-additive 11-reserved
32  *     bit 5: zbuffering
33  */
34 void (*fillfunc[])(struct pvertex*, int) = {
35         polyfill_wire,
36         polyfill_flat,
37         polyfill_gouraud,
38         0,
39         polyfill_tex_wire,
40         polyfill_tex_flat,
41         polyfill_tex_gouraud,
42         0,
43         polyfill_alpha_wire,
44         polyfill_alpha_flat,
45         polyfill_alpha_gouraud,
46         0,
47         polyfill_alpha_tex_wire,
48         polyfill_alpha_tex_flat,
49         polyfill_alpha_tex_gouraud,
50         0,
51         polyfill_add_wire,
52         polyfill_add_flat,
53         polyfill_add_gouraud,
54         0,
55         polyfill_add_tex_wire,
56         polyfill_add_tex_flat,
57         polyfill_add_tex_gouraud,
58         0, 0, 0, 0, 0, 0, 0, 0, 0,
59         polyfill_wire_zbuf,
60         polyfill_flat_zbuf,
61         polyfill_gouraud_zbuf,
62         0,
63         polyfill_tex_wire_zbuf,
64         polyfill_tex_flat_zbuf,
65         polyfill_tex_gouraud_zbuf,
66         0,
67         polyfill_alpha_wire_zbuf,
68         polyfill_alpha_flat_zbuf,
69         polyfill_alpha_gouraud_zbuf,
70         0,
71         polyfill_alpha_tex_wire_zbuf,
72         polyfill_alpha_tex_flat_zbuf,
73         polyfill_alpha_tex_gouraud_zbuf,
74         0,
75         polyfill_add_wire_zbuf,
76         polyfill_add_flat_zbuf,
77         polyfill_add_gouraud_zbuf,
78         0,
79         polyfill_add_tex_wire_zbuf,
80         polyfill_add_tex_flat_zbuf,
81         polyfill_add_tex_gouraud_zbuf,
82         0, 0, 0, 0, 0, 0, 0, 0, 0
83 };
84
85 struct pimage pfill_fb, pfill_tex;
86 uint32_t *pfill_zbuf;
87
88 #define EDGEPAD 8
89 static struct pvertex *edgebuf, *left, *right;
90 static int edgebuf_size;
91 static int fbheight;
92
93 /*
94 #define CHECKEDGE(x) \
95         do { \
96                 assert(x >= 0); \
97                 assert(x < fbheight); \
98         } while(0)
99 */
100 #define CHECKEDGE(x)
101
102
103 void polyfill_fbheight(int height)
104 {
105         int newsz = (height * 2 + EDGEPAD * 3) * sizeof *edgebuf;
106
107         if(newsz > edgebuf_size) {
108                 free(edgebuf);
109                 if(!(edgebuf = malloc(newsz))) {
110                         fprintf(stderr, "failed to allocate edge table buffer (%d bytes)\n", newsz);
111                         abort();
112                 }
113                 edgebuf_size = newsz;
114
115                 left = edgebuf + EDGEPAD;
116                 right = edgebuf + height + EDGEPAD * 2;
117
118 #ifndef NDEBUG
119                 memset(edgebuf, 0xaa, EDGEPAD * sizeof *edgebuf);
120                 memset(edgebuf + height + EDGEPAD, 0xaa, EDGEPAD * sizeof *edgebuf);
121                 memset(edgebuf + height * 2 + EDGEPAD * 2, 0xaa, EDGEPAD * sizeof *edgebuf);
122 #endif
123         }
124
125         fbheight = height;
126 }
127
128 void polyfill(int mode, struct pvertex *verts, int nverts)
129 {
130 #ifndef NDEBUG
131         if(!fillfunc[mode]) {
132                 fprintf(stderr, "polyfill mode %d not implemented\n", mode);
133                 abort();
134         }
135 #endif
136
137         fillfunc[mode](verts, nverts);
138 }
139
140 void polyfill_wire(struct pvertex *verts, int nverts)
141 {
142         draw_line(verts);
143 }
144
145 void polyfill_tex_wire(struct pvertex *verts, int nverts)
146 {
147         polyfill_wire(verts, nverts);   /* TODO */
148 }
149
150 void polyfill_alpha_wire(struct pvertex *verts, int nverts)
151 {
152         polyfill_wire(verts, nverts);   /* TODO */
153 }
154
155 void polyfill_alpha_tex_wire(struct pvertex *verts, int nverts)
156 {
157         polyfill_wire(verts, nverts);   /* TODO */
158 }
159
160 void polyfill_add_wire(struct pvertex *verts, int nverts)
161 {
162         polyfill_wire(verts, nverts);   /* TODO */
163 }
164
165 void polyfill_add_tex_wire(struct pvertex *verts, int nverts)
166 {
167         polyfill_wire(verts, nverts);   /* TODO */
168 }
169
170 void polyfill_wire_zbuf(struct pvertex *verts, int nverts)
171 {
172         draw_line_zbuf(verts);
173 }
174
175 void polyfill_tex_wire_zbuf(struct pvertex *verts, int nverts)
176 {
177         polyfill_wire_zbuf(verts, nverts);      /* TODO */
178 }
179
180 void polyfill_alpha_wire_zbuf(struct pvertex *verts, int nverts)
181 {
182         polyfill_wire_zbuf(verts, nverts);      /* TODO */
183 }
184
185 void polyfill_alpha_tex_wire_zbuf(struct pvertex *verts, int nverts)
186 {
187         polyfill_wire_zbuf(verts, nverts);      /* TODO */
188 }
189
190 void polyfill_add_wire_zbuf(struct pvertex *verts, int nverts)
191 {
192         polyfill_wire_zbuf(verts, nverts);      /* TODO */
193 }
194
195 void polyfill_add_tex_wire_zbuf(struct pvertex *verts, int nverts)
196 {
197         polyfill_wire_zbuf(verts, nverts);      /* TODO */
198 }
199
200
201 #define VNEXT(p)        (((p) == vlast) ? varr : (p) + 1)
202 #define VPREV(p)        ((p) == varr ? vlast : (p) - 1)
203 #define VSUCC(p, side)  ((side) == 0 ? VNEXT(p) : VPREV(p))
204
205 /* extra bits of precision to use when interpolating colors.
206  * try tweaking this if you notice strange quantization artifacts.
207  */
208 #define COLOR_SHIFT     12
209
210
211 #define POLYFILL polyfill_flat
212 #undef GOURAUD
213 #undef TEXMAP
214 #undef BLEND_ALPHA
215 #undef BLEND_ADD
216 #undef ZBUF
217 #include "polytmpl.h"
218 #undef POLYFILL
219
220 #define POLYFILL polyfill_gouraud
221 #define GOURAUD
222 #undef TEXMAP
223 #undef BLEND_ALPHA
224 #undef BLEND_ADD
225 #undef ZBUF
226 #include "polytmpl.h"
227 #undef POLYFILL
228
229 #define POLYFILL polyfill_tex_flat
230 #undef GOURAUD
231 #define TEXMAP
232 #undef BLEND_ALPHA
233 #undef BLEND_ADD
234 #undef ZBUF
235 #include "polytmpl.h"
236 #undef POLYFILL
237
238 #define POLYFILL polyfill_tex_gouraud
239 #define GOURAUD
240 #define TEXMAP
241 #undef BLEND_ALPHA
242 #undef BLEND_ADD
243 #undef ZBUF
244 #include "polytmpl.h"
245 #undef POLYFILL
246
247 #define POLYFILL polyfill_alpha_flat
248 #undef GOURAUD
249 #undef TEXMAP
250 #define BLEND_ALPHA
251 #undef BLEND_ADD
252 #undef ZBUF
253 #include "polytmpl.h"
254 #undef POLYFILL
255
256 #define POLYFILL polyfill_alpha_gouraud
257 #define GOURAUD
258 #undef TEXMAP
259 #define BLEND_ALPHA
260 #undef BLEND_ADD
261 #undef ZBUF
262 #include "polytmpl.h"
263 #undef POLYFILL
264
265 #define POLYFILL polyfill_alpha_tex_flat
266 #undef GOURAUD
267 #define TEXMAP
268 #define BLEND_ALPHA
269 #undef BLEND_ADD
270 #undef ZBUF
271 #include "polytmpl.h"
272 #undef POLYFILL
273
274 #define POLYFILL polyfill_alpha_tex_gouraud
275 #define GOURAUD
276 #define TEXMAP
277 #define BLEND_ALPHA
278 #undef BLEND_ADD
279 #undef ZBUF
280 #include "polytmpl.h"
281 #undef POLYFILL
282
283 #define POLYFILL polyfill_add_flat
284 #undef GOURAUD
285 #undef TEXMAP
286 #undef BLEND_ALPHA
287 #define BLEND_ADD
288 #undef ZBUF
289 #include "polytmpl.h"
290 #undef POLYFILL
291
292 #define POLYFILL polyfill_add_gouraud
293 #define GOURAUD
294 #undef TEXMAP
295 #undef BLEND_ALPHA
296 #define BLEND_ADD
297 #undef ZBUF
298 #include "polytmpl.h"
299 #undef POLYFILL
300
301 #define POLYFILL polyfill_add_tex_flat
302 #undef GOURAUD
303 #define TEXMAP
304 #undef BLEND_ALPHA
305 #define BLEND_ADD
306 #undef ZBUF
307 #include "polytmpl.h"
308 #undef POLYFILL
309
310 #define POLYFILL polyfill_add_tex_gouraud
311 #define GOURAUD
312 #define TEXMAP
313 #undef BLEND_ALPHA
314 #define BLEND_ADD
315 #undef ZBUF
316 #include "polytmpl.h"
317 #undef POLYFILL
318
319 /* ---- zbuffer variants ----- */
320
321 #define POLYFILL polyfill_flat_zbuf
322 #undef GOURAUD
323 #undef TEXMAP
324 #undef BLEND_ALPHA
325 #undef BLEND_ADD
326 #define ZBUF
327 #include "polytmpl.h"
328 #undef POLYFILL
329
330 #define POLYFILL polyfill_gouraud_zbuf
331 #define GOURAUD
332 #undef TEXMAP
333 #undef BLEND_ALPHA
334 #undef BLEND_ADD
335 #define ZBUF
336 #include "polytmpl.h"
337 #undef POLYFILL
338
339 #define POLYFILL polyfill_tex_flat_zbuf
340 #undef GOURAUD
341 #define TEXMAP
342 #undef BLEND_ALPHA
343 #undef BLEND_ADD
344 #define ZBUF
345 #include "polytmpl.h"
346 #undef POLYFILL
347
348 #define POLYFILL polyfill_tex_gouraud_zbuf
349 #define GOURAUD
350 #define TEXMAP
351 #undef BLEND_ALPHA
352 #undef BLEND_ADD
353 #define ZBUF
354 #include "polytmpl.h"
355 #undef POLYFILL
356
357 #define POLYFILL polyfill_alpha_flat_zbuf
358 #undef GOURAUD
359 #undef TEXMAP
360 #define BLEND_ALPHA
361 #undef BLEND_ADD
362 #define ZBUF
363 #include "polytmpl.h"
364 #undef POLYFILL
365
366 #define POLYFILL polyfill_alpha_gouraud_zbuf
367 #define GOURAUD
368 #undef TEXMAP
369 #define BLEND_ALPHA
370 #undef BLEND_ADD
371 #define ZBUF
372 #include "polytmpl.h"
373 #undef POLYFILL
374
375 #define POLYFILL polyfill_alpha_tex_flat_zbuf
376 #undef GOURAUD
377 #define TEXMAP
378 #define BLEND_ALPHA
379 #undef BLEND_ADD
380 #define ZBUF
381 #include "polytmpl.h"
382 #undef POLYFILL
383
384 #define POLYFILL polyfill_alpha_tex_gouraud_zbuf
385 #define GOURAUD
386 #define TEXMAP
387 #define BLEND_ALPHA
388 #undef BLEND_ADD
389 #define ZBUF
390 #include "polytmpl.h"
391 #undef POLYFILL
392
393 #define POLYFILL polyfill_add_flat_zbuf
394 #undef GOURAUD
395 #undef TEXMAP
396 #undef BLEND_ALPHA
397 #define BLEND_ADD
398 #define ZBUF
399 #include "polytmpl.h"
400 #undef POLYFILL
401
402 #define POLYFILL polyfill_add_gouraud_zbuf
403 #define GOURAUD
404 #undef TEXMAP
405 #undef BLEND_ALPHA
406 #define BLEND_ADD
407 #define ZBUF
408 #include "polytmpl.h"
409 #undef POLYFILL
410
411 #define POLYFILL polyfill_add_tex_flat_zbuf
412 #undef GOURAUD
413 #define TEXMAP
414 #undef BLEND_ALPHA
415 #define BLEND_ADD
416 #define ZBUF
417 #include "polytmpl.h"
418 #undef POLYFILL
419
420 #define POLYFILL polyfill_add_tex_gouraud_zbuf
421 #define GOURAUD
422 #define TEXMAP
423 #undef BLEND_ALPHA
424 #define BLEND_ADD
425 #define ZBUF
426 #include "polytmpl.h"
427 #undef POLYFILL
428
429
430 void draw_line(struct pvertex *verts)
431 {
432         int32_t x0, y0, x1, y1;
433         int i, dx, dy, x_inc, y_inc, error;
434         uint32_t *fb = pfill_fb.pixels;
435         uint32_t color = PACK_RGB(verts[0].r, verts[0].g, verts[0].b);
436
437         x0 = verts[0].x >> 8;
438         y0 = verts[0].y >> 8;
439         x1 = verts[1].x >> 8;
440         y1 = verts[1].y >> 8;
441
442         fb += y0 * pfill_fb.width + x0;
443
444         dx = x1 - x0;
445         dy = y1 - y0;
446
447         if(dx >= 0) {
448                 x_inc = 1;
449         } else {
450                 x_inc = -1;
451                 dx = -dx;
452         }
453         if(dy >= 0) {
454                 y_inc = pfill_fb.width;
455         } else {
456                 y_inc = -pfill_fb.width;
457                 dy = -dy;
458         }
459
460         if(dx > dy) {
461                 error = dy * 2 - dx;
462                 for(i=0; i<=dx; i++) {
463                         *fb = color;
464                         if(error >= 0) {
465                                 error -= dx * 2;
466                                 fb += y_inc;
467                         }
468                         error += dy * 2;
469                         fb += x_inc;
470                 }
471         } else {
472                 error = dx * 2 - dy;
473                 for(i=0; i<=dy; i++) {
474                         *fb = color;
475                         if(error >= 0) {
476                                 error -= dy * 2;
477                                 fb += x_inc;
478                         }
479                         error += dx * 2;
480                         fb += y_inc;
481                 }
482         }
483 }
484
485 void draw_line_zbuf(struct pvertex *verts)
486 {
487         int32_t x0, y0, x1, y1, z0, z1, z, dz, zslope;
488         int i, dx, dy, x_inc, y_inc, error;
489         uint32_t *fb = pfill_fb.pixels;
490         uint32_t *zptr;
491         uint32_t color = PACK_RGB(verts[0].r, verts[0].g, verts[0].b);
492
493         x0 = verts[0].x >> 8;
494         y0 = verts[0].y >> 8;
495         x1 = verts[1].x >> 8;
496         y1 = verts[1].y >> 8;
497         z0 = verts[0].z;
498         z1 = verts[1].z;
499
500         fb += y0 * pfill_fb.width + x0;
501         zptr = pfill_zbuf + y0 * pfill_fb.width + x0;
502
503         dx = x1 - x0;
504         dy = y1 - y0;
505         dz = z1 - z0;
506
507         if(dx >= 0) {
508                 x_inc = 1;
509         } else {
510                 x_inc = -1;
511                 dx = -dx;
512         }
513         if(dy >= 0) {
514                 y_inc = pfill_fb.width;
515         } else {
516                 y_inc = -pfill_fb.width;
517                 dy = -dy;
518         }
519
520         if(dx > dy) {
521                 zslope = dx ? (dz << 8) / dx : 0;
522                 error = dy * 2 - dx;
523                 for(i=0; i<=dx; i++) {
524                         if(z <= *zptr) {
525                                 *fb = color;
526                                 *zptr = z;
527                         }
528                         if(error >= 0) {
529                                 error -= dx * 2;
530                                 fb += y_inc;
531                                 zptr += y_inc;
532                         }
533                         error += dy * 2;
534                         fb += x_inc;
535
536                         zptr += x_inc;
537                         z += zslope;
538                 }
539         } else {
540                 zslope = dy ? (dz << 8) / dy : 0;
541                 error = dx * 2 - dy;
542                 for(i=0; i<=dy; i++) {
543                         if(z <= *zptr) {
544                                 *fb = color;
545                                 *zptr = z;
546                         }
547                         if(error >= 0) {
548                                 error -= dy * 2;
549                                 fb += x_inc;
550                                 zptr += x_inc;
551                         }
552                         error += dx * 2;
553                         fb += y_inc;
554
555                         zptr += y_inc;
556                         z += zslope;
557                 }
558         }
559 }