3d cube and dirty drawing
[dos_low3d] / src / polyfill.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "3dgfx.h"
4 #include "util.h"
5
6 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2);
7 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2);
8
9 void g3d_polyfill(struct g3d_vertex *verts)
10 {
11         int i, topidx, botidx, mididx;
12         int32_t dx, dy, dym;
13         int32_t v01x, v01y, v02x, v02y;
14         struct g3d_vertex vtmp;
15
16         /* calculate winding */
17         v01x = verts[1].x - verts[0].x;
18         v01y = verts[1].y - verts[0].y;
19         v02x = verts[2].x - verts[0].x;
20         v02y = verts[2].y - verts[0].y;
21         if(!((v01x * v02y - v02x * v01y) & 0x80000000)) {
22                 return;
23         }
24
25         topidx = botidx = 0;
26         for(i=1; i<3; i++) {
27                 if(verts[i].y < verts[topidx].y) {
28                         topidx = i;
29                 }
30                 if(verts[i].y > verts[botidx].y) {
31                         botidx = i;
32                 }
33         }
34         mididx = topidx + 1; if(mididx > 2) mididx = 0;
35         if(mididx == botidx) {
36                 if(++mididx > 2) mididx = 0;
37         }
38
39         dy = verts[botidx].y - verts[topidx].y;
40         if(dy == 0) return;
41
42         dx = verts[botidx].x - verts[topidx].x;
43         dym = verts[mididx].y - verts[topidx].y;
44         vtmp.x = muldiv(dx, dym, dy) + verts[topidx].x; /* dx * dym / dy + vtop.x */
45         vtmp.y = verts[mididx].y;
46
47         if(verts[topidx].y != verts[mididx].y) {
48                 filltop(verts + topidx, verts + mididx, &vtmp);
49         }
50         if(verts[mididx].y != verts[botidx].y) {
51                 fillbot(verts + mididx, &vtmp, verts + botidx);
52         }
53 }
54
55 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
56 {
57         struct g3d_vertex *vtmp;
58         int x, xn, line, lasty, len;
59         int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
60         int32_t y0, y1, yoffs;
61         unsigned char *fbptr;
62
63         if(v1->x > v2->x) {
64                 vtmp = v1;
65                 v1 = v2;
66                 v2 = vtmp;
67         }
68
69         dy = v1->y - v0->y;
70         dxl = v1->x - v0->x;
71         dxr = v2->x - v0->x;
72         slopel = (dxl << 8) / dy;
73         sloper = (dxr << 8) / dy;
74
75         y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
76         yoffs = y0 - v0->y;                                     /* offset of the next scanline */
77         xl = v0->x + ((yoffs * slopel) >> 8);
78         xr = v0->x + ((yoffs * sloper) >> 8);
79
80         line = y0 >> 8;
81         lasty = v1->y >> 8;
82         if(lasty >= YRES) lasty = YRES - 1;
83         x = xl >> 8;
84
85         fbptr = g3d_fbpixels + line * XRES + x;
86
87         while(line <= lasty) {
88                 if(line >= 0) {
89                         len = ((xr + 0x100) >> 8) - (xl >> 8);
90                         if(len > 0) memset(fbptr, g3d_curcidx, len);
91                 }
92
93                 xl += slopel;
94                 xr += sloper;
95                 xn = xl >> 8;
96                 fbptr += XRES + (xn - x);
97                 x = xn;
98                 line++;
99         }
100 }
101
102 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
103 {
104         struct g3d_vertex *vtmp;
105         int x, xn, line, lasty, len;
106         int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
107         int32_t y0, y1, yoffs;
108         unsigned char *fbptr;
109
110         if(v0->x > v1->x) {
111                 vtmp = v0;
112                 v0 = v1;
113                 v1 = vtmp;
114         }
115
116         dy = v2->y - v0->y;
117         dxl = v2->x - v0->x;
118         dxr = v2->x - v1->x;
119         slopel = (dxl << 8) / dy;
120         sloper = (dxr << 8) / dy;
121
122         y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
123         yoffs = y0 - v0->y;                                     /* offset of the next scanline */
124         xl = v0->x + ((yoffs * slopel) >> 8);
125         xr = v1->x + ((yoffs * sloper) >> 8);
126
127         line = y0 >> 8;
128         lasty = v2->y >> 8;
129         if(lasty >= YRES) lasty = YRES - 1;
130         x = xl >> 8;
131
132         fbptr = g3d_fbpixels + line * XRES + x;
133
134         while(line <= lasty) {
135                 if(line >= 0) {
136                         len = ((xr + 0x100) >> 8) - (xl >> 8);
137                         if(len > 0) memset(fbptr, g3d_curcidx, len);
138                 }
139
140                 xl += slopel;
141                 xr += sloper;
142                 xn = xl >> 8;
143                 fbptr += XRES + (xn - x);
144                 x = xn;
145                 line++;
146         }
147 }