Merge branch 'master' of mutantstargoat.com:/home/nuclear/git/dosdemo
[dosdemo] / src / polyfill.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include "polyfill.h"
4 #include "gfxutil.h"
5 #include "demo.h"
6
7 void (*fillfunc[])(struct pvertex*, int) = {
8         polyfill_wire,
9         polyfill_flat,
10         0, 0, 0
11 };
12
13 void polyfill(int mode, struct pvertex *verts, int nverts)
14 {
15 #ifndef NDEBUG
16         if(!fillfunc[mode]) {
17                 fprintf(stderr, "polyfill mode %d not implemented\n", mode);
18                 abort();
19         }
20 #endif
21
22         fillfunc[mode](verts, nverts);
23 }
24
25 void polyfill_wire(struct pvertex *verts, int nverts)
26 {
27         int i, x0, y0, x1, y1;
28         struct pvertex *v = verts;
29         unsigned short color = ((v->r << 8) & 0xf800) |
30                 ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
31
32         for(i=0; i<nverts - 1; i++) {
33                 x0 = v->x >> 8;
34                 y0 = v->y >> 8;
35                 ++v;
36                 x1 = v->x >> 8;
37                 y1 = v->y >> 8;
38                 if(clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width, fb_height)) {
39                         draw_line(x0, y0, x1, y1, color);
40                 }
41         }
42         x0 = verts[0].x >> 8;
43         y0 = verts[0].y >> 8;
44         if(clip_line(&x1, &y1, &x0, &y0, 0, 0, fb_width, fb_height)) {
45                 draw_line(x1, y1, x0, y0, color);
46         }
47 }
48
49 #define NEXTIDX(x) ((x) ? (x) - 1 : nverts - 1)
50 #define PREVIDX(x) (((x) + 1) % nverts)
51
52 #define CALC_EDGE(which) \
53         do { \
54                 which##_x = pv[which##_beg].x; \
55                 which##_dx = pv[which##_end].x - pv[which##_beg].x; \
56                 which##_slope = (which##_dx << 8) / which##_dy; \
57         } while(0)
58
59 void polyfill_flat(struct pvertex *pv, int nverts)
60 {
61         int i, sline, x, slen, top = 0;
62         int left_beg, left_end, right_beg, right_end;
63         int32_t left_dy, left_dx, right_dy, right_dx;
64         int32_t left_slope, right_slope;
65         int32_t left_x, right_x, y;
66         uint16_t color = ((pv->r << 8) & 0xf800) | ((pv->g << 3) & 0x7e0) |
67                 ((pv->b >> 3) & 0x1f);
68         uint16_t *pixptr;
69
70         /* find topmost */
71         for(i=1; i<nverts; i++) {
72                 if(pv[i].y < pv[top].y) {
73                         top = i;
74                 }
75         }
76         left_beg = right_beg = top;
77         left_end = PREVIDX(left_beg);
78         right_end = NEXTIDX(right_beg);
79
80         if((left_dy = pv[left_end].y - pv[left_beg].y)) {
81                 CALC_EDGE(left);
82         }
83
84         if((right_dy = pv[right_end].y - pv[right_beg].y)) {
85                 CALC_EDGE(right);
86         }
87
88         y = pv[top].y;
89         sline = pv[top].y >> 8;
90
91         for(;;) {
92                 if(y >= pv[left_end].y) {
93                         while(y >= pv[left_end].y) {
94                                 left_beg = left_end;
95                                 if(left_beg == right_beg) return;
96                                 left_end = PREVIDX(left_end);
97                         }
98
99                         left_dy = pv[left_end].y - pv[left_beg].y;
100                         CALC_EDGE(left);
101                 }
102
103                 if(y >= pv[right_end].y) {
104                         while(y >= pv[right_end].y) {
105                                 right_beg = right_end;
106                                 if(left_beg == right_beg) return;
107                                 right_end = NEXTIDX(right_end);
108                         }
109
110                         right_dy = pv[right_end].y - pv[right_beg].y;
111                         CALC_EDGE(right);
112                 }
113
114                 x = left_x >> 8;
115                 slen = (right_x >> 8) - (left_x >> 8);
116
117                 pixptr = (uint16_t*)fb_pixels + sline * fb_width + x;
118                 for(i=0; i<slen; i++) {
119                         *pixptr++ = color;
120                 }
121
122                 ++sline;
123                 y += 256;
124                 left_x += left_slope;
125                 right_x += right_slope;
126         }
127 }