fixed overdlow when calculating winding of large polygons in the
[dosdemo] / src / polytmpl.h
index 3b3917e..2147666 100644 (file)
@@ -93,8 +93,15 @@ void POLYFILL(struct pvertex *pv, int nverts)
                if(pv[i].y > pv[botidx].y) botidx = i;
        }
 
-       left = alloca(pfill_fb.height * sizeof *left);
-       right = alloca(pfill_fb.height * sizeof *right);
+       int winding = 0;
+       for(i=0; i<nverts; i++) {
+               int next = NEXTIDX(i);
+               winding += ((pv[next].x - pv[i].x) >> 8) * ((pv[next].y + pv[i].y) >> 8);
+       }
+
+       /* +1 to avoid crashing due to off-by-one rounding errors in the rasterization */
+       left = alloca((pfill_fb.height + 1) * sizeof *left);
+       right = alloca((pfill_fb.height + 1) * sizeof *right);
 
        for(i=0; i<nverts; i++) {
                int next = NEXTIDX(i);
@@ -102,15 +109,46 @@ void POLYFILL(struct pvertex *pv, int nverts)
                int32_t y1 = pv[next].y;
 
                if((y0 >> 8) == (y1 >> 8)) {
-                       if(y0 > y1) {
+                       /*if(y0 > y1) {*/
+                               int i0, i1;
                                int idx = y0 >> 8;
-                               left[idx].x = pv[i].x < pv[next].x ? pv[i].x : pv[next].x;
-                               right[idx].x = pv[i].x < pv[next].x ? pv[next].x : pv[i].x;
-                       }
+                               if(pv[i].x < pv[next].x) {
+                                       i0 = i;
+                                       i1 = next;
+                               } else {
+                                       i0 = next;
+                                       i1 = i;
+                               }
+                               left[idx].x = pv[i0].x;
+                               right[idx].x = pv[i1].x;
+#ifdef GOURAUD
+                               left[idx].r = pv[i0].r << COLOR_SHIFT;
+                               left[idx].g = pv[i0].g << COLOR_SHIFT;
+                               left[idx].b = pv[i0].b << COLOR_SHIFT;
+                               right[idx].r = pv[i1].r << COLOR_SHIFT;
+                               right[idx].g = pv[i1].g << COLOR_SHIFT;
+                               right[idx].b = pv[i1].b << COLOR_SHIFT;
+#endif
+#ifdef TEXMAP
+                               left[idx].u = pv[i0].u;
+                               left[idx].v = pv[i0].v;
+                               right[idx].u = pv[i1].u;
+                               right[idx].v = pv[i1].v;
+#endif
+                               if(idx > slbot) slbot = idx;
+                               if(idx < sltop) sltop = idx;
+                       /*}*/
                } else {
-                       struct pvertex *edge = y0 > y1 ? left : right;
-                       uint32_t res = SCANEDGE(pv + i, pv + next, edge);
-                       uint32_t tmp = (res >> 16) & 0xffff;
+                       struct pvertex *edge;
+                       uint32_t res, tmp;
+
+                       if(winding < 0) {
+                               edge = y0 > y1 ? left : right;
+                       } else {
+                               edge = y0 > y1 ? right : left;
+                       }
+                       res = SCANEDGE(pv + i, pv + next, edge);
+                       tmp = (res >> 16) & 0xffff;
                        if(tmp > slbot) slbot = tmp;
                        if((tmp = res & 0xffff) < sltop) {
                                sltop = tmp;