c7fc500d92a0c15b932cb74cf53e301b8bac6d6c
[dos_low3d] / src / polyfill.c
1 #include <stdio.h>
2 #include <string.h>
3 #include "3dgfx.h"
4 #include "video.h"
5 #include "util.h"
6
7 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2);
8 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2);
9 static void fillspan(unsigned char *dest, int x, int len);
10
11 void g3d_polyfill(struct g3d_vertex *verts)
12 {
13         int i, topidx, botidx, mididx;
14         int32_t dx, dy, dym;
15         int32_t v01x, v01y, v02x, v02y;
16         struct g3d_vertex vtmp;
17
18         /* calculate winding */
19         v01x = verts[1].x - verts[0].x;
20         v01y = verts[1].y - verts[0].y;
21         v02x = verts[2].x - verts[0].x;
22         v02y = verts[2].y - verts[0].y;
23         if(!((v01x * v02y - v02x * v01y) & 0x80000000)) {
24                 return;
25         }
26
27         topidx = botidx = 0;
28         for(i=1; i<3; i++) {
29                 if(verts[i].y < verts[topidx].y) {
30                         topidx = i;
31                 }
32                 if(verts[i].y > verts[botidx].y) {
33                         botidx = i;
34                 }
35         }
36         mididx = topidx + 1; if(mididx > 2) mididx = 0;
37         if(mididx == botidx) {
38                 if(++mididx > 2) mididx = 0;
39         }
40
41         dy = verts[botidx].y - verts[topidx].y;
42         if(dy == 0) return;
43
44         dx = verts[botidx].x - verts[topidx].x;
45         dym = verts[mididx].y - verts[topidx].y;
46         vtmp.x = muldiv(dx, dym, dy) + verts[topidx].x; /* dx * dym / dy + vtop.x */
47         vtmp.y = verts[mididx].y;
48
49         if(verts[topidx].y != verts[mididx].y) {
50                 filltop(verts + topidx, verts + mididx, &vtmp);
51         }
52         if(verts[mididx].y != verts[botidx].y) {
53                 fillbot(verts + mididx, &vtmp, verts + botidx);
54         }
55 }
56
57 static void filltop(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
58 {
59         struct g3d_vertex *vtmp;
60         int x, line, lasty, len;
61         int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
62         int32_t y0, y1, yoffs;
63         unsigned char *fbptr;
64
65         if(v1->x > v2->x) {
66                 vtmp = v1;
67                 v1 = v2;
68                 v2 = vtmp;
69         }
70
71         dy = v1->y - v0->y;
72         dxl = v1->x - v0->x;
73         dxr = v2->x - v0->x;
74         slopel = (dxl << 8) / dy;
75         sloper = (dxr << 8) / dy;
76
77         y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
78         yoffs = y0 - v0->y;                                     /* offset of the next scanline */
79         xl = v0->x + ((yoffs * slopel) >> 8);
80         xr = v0->x + ((yoffs * sloper) >> 8);
81
82         line = y0 >> 8;
83         lasty = v1->y >> 8;
84         if(lasty >= YRES) lasty = YRES - 1;
85         x = xl >> 8;
86
87         fbptr = g3d_fbpixels + line * (XRES >> 2);
88
89         while(line <= lasty) {
90                 if(line >= 0) {
91                         len = ((xr + 0x100) >> 8) - (xl >> 8);
92                         if(len > 0) fillspan(fbptr, x, len);
93                 }
94
95                 xl += slopel;
96                 xr += sloper;
97                 x = xl >> 8;
98                 fbptr += XRES >> 2;
99                 line++;
100         }
101 }
102
103 static void fillbot(struct g3d_vertex *v0, struct g3d_vertex *v1, struct g3d_vertex *v2)
104 {
105         struct g3d_vertex *vtmp;
106         int x, line, lasty, len;
107         int32_t xl, xr, dxl, dxr, slopel, sloper, dy;
108         int32_t y0, y1, yoffs;
109         unsigned char *fbptr;
110
111         if(v0->x > v1->x) {
112                 vtmp = v0;
113                 v0 = v1;
114                 v1 = vtmp;
115         }
116
117         dy = v2->y - v0->y;
118         dxl = v2->x - v0->x;
119         dxr = v2->x - v1->x;
120         slopel = (dxl << 8) / dy;
121         sloper = (dxr << 8) / dy;
122
123         y0 = (v0->y + 0x100) & 0xffffff00;      /* start from the next scanline */
124         yoffs = y0 - v0->y;                                     /* offset of the next scanline */
125         xl = v0->x + ((yoffs * slopel) >> 8);
126         xr = v1->x + ((yoffs * sloper) >> 8);
127
128         line = y0 >> 8;
129         lasty = v2->y >> 8;
130         if(lasty >= YRES) lasty = YRES - 1;
131         x = xl >> 8;
132
133         fbptr = g3d_fbpixels + line * (XRES >> 2);
134
135         while(line <= lasty) {
136                 if(line >= 0) {
137                         len = ((xr + 0x100) >> 8) - (xl >> 8);
138                         if(len > 0) fillspan(fbptr, x, len);
139                 }
140
141                 xl += slopel;
142                 xr += sloper;
143                 x = xl >> 8;
144                 fbptr += XRES >> 2;
145                 line++;
146         }
147 }
148
149 static void fillspan(unsigned char *dest, int x, int len)
150 {
151         unsigned int mask = 0xf;
152         int align;
153
154         dest += x >> 2;
155
156         if(len < 4) mask >>= 4 - len;
157
158         /* handle the start of the span. The x offset alignment affects:
159          * 1. which bitplane to start from, adjust the plane mask accordingly.
160          * 2. how many pixels we write, adjust remaining length accordingly.
161          */
162         align = x & 3;
163         vid_setmask(mask << align);
164         *dest++ = g3d_curcidx;
165         len -= 4 - align;
166
167         /* the middle part of the span is all written 4 pixels at a time by
168          * enabling all 4 bit planes.
169          */
170         if(len >= 4) {
171                 vid_setmask(0xf);
172                 while(len >= 4) {
173                         *dest++ = g3d_curcidx;
174                         len -= 4;
175                 }
176         }
177
178         /* handle any leftovers at the end */
179         if(len) {
180                 mask = 0xf >> (4 - len);
181                 vid_setmask(mask);
182                 *dest = g3d_curcidx;
183         }
184 }