added crappy polygon filler
[dosdemo] / src / polyfill.c
index d8facb5..215cd78 100644 (file)
@@ -6,7 +6,8 @@
 
 void (*fillfunc[])(struct pvertex*, int) = {
        polyfill_wire,
-       0, 0, 0, 0
+       polyfill_flat,
+       0, 0, 0
 };
 
 void polyfill(int mode, struct pvertex *verts, int nverts)
@@ -23,19 +24,104 @@ void polyfill(int mode, struct pvertex *verts, int nverts)
 
 void polyfill_wire(struct pvertex *verts, int nverts)
 {
-       int i;
+       int i, x0, y0, x1, y1;
        struct pvertex *v = verts;
        unsigned short color = ((v->r << 8) & 0xf800) |
                ((v->g << 3) & 0x7e0) | ((v->b >> 3) & 0x1f);
 
-       for(i=0; i<nverts; i++) {
-               int x0, y0, x1, y1;
+       for(i=0; i<nverts - 1; i++) {
                x0 = v->x >> 8;
                y0 = v->y >> 8;
                ++v;
                x1 = v->x >> 8;
                y1 = v->y >> 8;
-               clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width, fb_height);
-               draw_line(x0, y0, x1, y1, color);
+               if(clip_line(&x0, &y0, &x1, &y1, 0, 0, fb_width, fb_height)) {
+                       draw_line(x0, y0, x1, y1, color);
+               }
+       }
+       x0 = verts[0].x >> 8;
+       y0 = verts[0].y >> 8;
+       if(clip_line(&x1, &y1, &x0, &y0, 0, 0, fb_width, fb_height)) {
+               draw_line(x1, y1, x0, y0, color);
+       }
+}
+
+#define NEXTIDX(x) ((x) ? (x) - 1 : nverts - 1)
+#define PREVIDX(x) (((x) + 1) % nverts)
+
+#define CALC_EDGE(which) \
+       do { \
+               which##_x = pv[which##_beg].x; \
+               which##_dx = pv[which##_end].x - pv[which##_beg].x; \
+               which##_slope = (which##_dx << 8) / which##_dy; \
+       } while(0)
+
+void polyfill_flat(struct pvertex *pv, int nverts)
+{
+       int i, sline, x, slen, top = 0;
+       int left_beg, left_end, right_beg, right_end;
+       int32_t left_dy, left_dx, right_dy, right_dx;
+       int32_t left_slope, right_slope;
+       int32_t left_x, right_x, y;
+       uint16_t color = ((pv->r << 8) & 0xf800) | ((pv->g << 3) & 0x7e0) |
+               ((pv->b >> 3) & 0x1f);
+       uint16_t *pixptr;
+
+       /* find topmost */
+       for(i=1; i<nverts; i++) {
+               if(pv[i].y < pv[top].y) {
+                       top = i;
+               }
+       }
+       left_beg = right_beg = top;
+       left_end = PREVIDX(left_beg);
+       right_end = NEXTIDX(right_beg);
+
+       if((left_dy = pv[left_end].y - pv[left_beg].y)) {
+               CALC_EDGE(left);
+       }
+
+       if((right_dy = pv[right_end].y - pv[right_beg].y)) {
+               CALC_EDGE(right);
+       }
+
+       y = pv[top].y;
+       sline = pv[top].y >> 8;
+
+       for(;;) {
+               if(y >= pv[left_end].y) {
+                       while(y >= pv[left_end].y) {
+                               left_beg = left_end;
+                               if(left_beg == right_beg) return;
+                               left_end = PREVIDX(left_end);
+                       }
+
+                       left_dy = pv[left_end].y - pv[left_beg].y;
+                       CALC_EDGE(left);
+               }
+
+               if(y >= pv[right_end].y) {
+                       while(y >= pv[right_end].y) {
+                               right_beg = right_end;
+                               if(left_beg == right_beg) return;
+                               right_end = NEXTIDX(right_end);
+                       }
+
+                       right_dy = pv[right_end].y - pv[right_beg].y;
+                       CALC_EDGE(right);
+               }
+
+               x = left_x >> 8;
+               slen = (right_x >> 8) - (left_x >> 8);
+
+               pixptr = (uint16_t*)fb_pixels + sline * fb_width + x;
+               for(i=0; i<slen; i++) {
+                       *pixptr++ = color;
+               }
+
+               ++sline;
+               y += 256;
+               left_x += left_slope;
+               right_x += right_slope;
        }
 }