13e12c5d1SDavid du Colombier /*
23e12c5d1SDavid du Colombier * fill -- polygon tiler
33e12c5d1SDavid du Colombier * Updating the edgelist from scanline to scanline could be quicker if no
43e12c5d1SDavid du Colombier * edges cross: we can just merge the incoming edges. If the scan-line
53e12c5d1SDavid du Colombier * filling routine were a parameter, we could do textured
63e12c5d1SDavid du Colombier * polygons, polyblt, and other such stuff.
73e12c5d1SDavid du Colombier */
83e12c5d1SDavid du Colombier #include "mplot.h"
93e12c5d1SDavid du Colombier typedef enum{
103e12c5d1SDavid du Colombier Odd=1,
113e12c5d1SDavid du Colombier Nonzero=~0
123e12c5d1SDavid du Colombier }Windrule;
133e12c5d1SDavid du Colombier typedef struct edge Edge;
143e12c5d1SDavid du Colombier struct edge{
153e12c5d1SDavid du Colombier Point p; /* point of crossing current scan-line */
163e12c5d1SDavid du Colombier int maxy; /* scan line at which to discard edge */
173e12c5d1SDavid du Colombier int dx; /* x increment if x fraction<1 */
183e12c5d1SDavid du Colombier int dx1; /* x increment if x fraction>=1 */
193e12c5d1SDavid du Colombier int x; /* x fraction, scaled by den */
203e12c5d1SDavid du Colombier int num; /* x fraction increment for unit y change, scaled by den */
213e12c5d1SDavid du Colombier int den; /* x fraction increment for unit x change, scaled by num */
223e12c5d1SDavid du Colombier int dwind; /* increment of winding number on passing this edge */
233e12c5d1SDavid du Colombier Edge *next; /* next edge on current scanline */
243e12c5d1SDavid du Colombier Edge *prev; /* previous edge on current scanline */
253e12c5d1SDavid du Colombier };
insert(Edge * ep,Edge ** yp)263e12c5d1SDavid du Colombier static void insert(Edge *ep, Edge **yp){
273e12c5d1SDavid du Colombier while(*yp && (*yp)->p.x<ep->p.x) yp=&(*yp)->next;
283e12c5d1SDavid du Colombier ep->next=*yp;
293e12c5d1SDavid du Colombier *yp=ep;
303e12c5d1SDavid du Colombier if(ep->next){
313e12c5d1SDavid du Colombier ep->prev=ep->next->prev;
323e12c5d1SDavid du Colombier ep->next->prev=ep;
333e12c5d1SDavid du Colombier if(ep->prev)
343e12c5d1SDavid du Colombier ep->prev->next=ep;
353e12c5d1SDavid du Colombier }
363e12c5d1SDavid du Colombier else
373e12c5d1SDavid du Colombier ep->prev=0;
383e12c5d1SDavid du Colombier }
polygon(int cnt[],double * pts[],Windrule w,int v)39*7dd7cddfSDavid du Colombier static void polygon(int cnt[], double *pts[], Windrule w, int v){
403e12c5d1SDavid du Colombier Edge *edges, *ep, *nextep, **ylist, **eylist, **yp;
413e12c5d1SDavid du Colombier Point p, q, p0, p1, p10;
423e12c5d1SDavid du Colombier int i, dy, nbig, y, left, right, wind, nwind, nvert;
433e12c5d1SDavid du Colombier int *cntp;
443e12c5d1SDavid du Colombier double **ptsp, *xp;
453e12c5d1SDavid du Colombier nvert=0;
463e12c5d1SDavid du Colombier for(cntp=cnt;*cntp;cntp++) nvert+=*cntp;
473e12c5d1SDavid du Colombier edges=(Edge *)malloc(nvert*sizeof(Edge));
483e12c5d1SDavid du Colombier if(edges==0){
493e12c5d1SDavid du Colombier NoSpace:
503e12c5d1SDavid du Colombier fprintf(stderr, "polygon: no space\n");
513e12c5d1SDavid du Colombier exits("malloc failed");
523e12c5d1SDavid du Colombier }
53*7dd7cddfSDavid du Colombier ylist=(Edge **)malloc(Dy(screen->r)*sizeof(Edge *));
543e12c5d1SDavid du Colombier if(ylist==0) goto NoSpace;
55*7dd7cddfSDavid du Colombier eylist=ylist+Dy(screen->r);
563e12c5d1SDavid du Colombier for(yp=ylist;yp!=eylist;yp++) *yp=0;
573e12c5d1SDavid du Colombier ep=edges;
583e12c5d1SDavid du Colombier for(cntp=cnt,ptsp=pts;*cntp;cntp++,ptsp++){
593e12c5d1SDavid du Colombier p.x=SCX((*ptsp)[*cntp*2-2]);
603e12c5d1SDavid du Colombier p.y=SCY((*ptsp)[*cntp*2-1]);
613e12c5d1SDavid du Colombier nvert=*cntp;
623e12c5d1SDavid du Colombier for(xp=*ptsp,i=0;i!=nvert;xp+=2,i++){
633e12c5d1SDavid du Colombier q=p;
643e12c5d1SDavid du Colombier p.x=SCX(xp[0]);
653e12c5d1SDavid du Colombier p.y=SCY(xp[1]);
663e12c5d1SDavid du Colombier if(p.y==q.y) continue;
673e12c5d1SDavid du Colombier if(p.y<q.y){
683e12c5d1SDavid du Colombier p0=p;
693e12c5d1SDavid du Colombier p1=q;
703e12c5d1SDavid du Colombier ep->dwind=1;
713e12c5d1SDavid du Colombier }
723e12c5d1SDavid du Colombier else{
733e12c5d1SDavid du Colombier p0=q;
743e12c5d1SDavid du Colombier p1=p;
753e12c5d1SDavid du Colombier ep->dwind=-1;
763e12c5d1SDavid du Colombier }
77*7dd7cddfSDavid du Colombier if(p1.y<=screen->r.min.y) continue;
78*7dd7cddfSDavid du Colombier if(p0.y>=screen->r.max.y) continue;
793e12c5d1SDavid du Colombier ep->p=p0;
80*7dd7cddfSDavid du Colombier if(p1.y>screen->r.max.y)
81*7dd7cddfSDavid du Colombier ep->maxy=screen->r.max.y;
823e12c5d1SDavid du Colombier else
833e12c5d1SDavid du Colombier ep->maxy=p1.y;
84*7dd7cddfSDavid du Colombier p10=subpt(p1, p0);
853e12c5d1SDavid du Colombier if(p10.x>=0){
863e12c5d1SDavid du Colombier ep->dx=p10.x/p10.y;
873e12c5d1SDavid du Colombier ep->dx1=ep->dx+1;
883e12c5d1SDavid du Colombier }
893e12c5d1SDavid du Colombier else{
903e12c5d1SDavid du Colombier p10.x=-p10.x;
913e12c5d1SDavid du Colombier ep->dx=-(p10.x/p10.y); /* this nonsense rounds toward zero */
923e12c5d1SDavid du Colombier ep->dx1=ep->dx-1;
933e12c5d1SDavid du Colombier }
943e12c5d1SDavid du Colombier ep->x=0;
953e12c5d1SDavid du Colombier ep->num=p10.x%p10.y;
963e12c5d1SDavid du Colombier ep->den=p10.y;
97*7dd7cddfSDavid du Colombier if(ep->p.y<screen->r.min.y){
98*7dd7cddfSDavid du Colombier dy=screen->r.min.y-ep->p.y;
993e12c5d1SDavid du Colombier ep->x+=dy*ep->num;
1003e12c5d1SDavid du Colombier nbig=ep->x/ep->den;
1013e12c5d1SDavid du Colombier ep->p.x+=ep->dx1*nbig+ep->dx*(dy-nbig);
1023e12c5d1SDavid du Colombier ep->x%=ep->den;
103*7dd7cddfSDavid du Colombier ep->p.y=screen->r.min.y;
1043e12c5d1SDavid du Colombier }
105*7dd7cddfSDavid du Colombier insert(ep, ylist+(ep->p.y-screen->r.min.y));
1063e12c5d1SDavid du Colombier ep++;
1073e12c5d1SDavid du Colombier }
1083e12c5d1SDavid du Colombier }
1093e12c5d1SDavid du Colombier left = 0;
110*7dd7cddfSDavid du Colombier for(yp=ylist,y=screen->r.min.y;yp!=eylist;yp++,y++){
1113e12c5d1SDavid du Colombier wind=0;
1123e12c5d1SDavid du Colombier for(ep=*yp;ep;ep=nextep){
1133e12c5d1SDavid du Colombier nwind=wind+ep->dwind;
1143e12c5d1SDavid du Colombier if(nwind&w){ /* inside */
1153e12c5d1SDavid du Colombier if(!(wind&w)){
1163e12c5d1SDavid du Colombier left=ep->p.x;
117*7dd7cddfSDavid du Colombier if(left<screen->r.min.x) left=screen->r.min.x;
1183e12c5d1SDavid du Colombier }
1193e12c5d1SDavid du Colombier }
1203e12c5d1SDavid du Colombier else if(wind&w){
1213e12c5d1SDavid du Colombier right=ep->p.x;
122*7dd7cddfSDavid du Colombier if(right>=screen->r.max.x) right=screen->r.max.x;
123*7dd7cddfSDavid du Colombier #define BART_BUG_FIXED /* what goes on here?? -rob */
1243e12c5d1SDavid du Colombier #ifdef BART_BUG_FIXED
1253e12c5d1SDavid du Colombier if(right>left)
126*7dd7cddfSDavid du Colombier line(screen, Pt(left, y), Pt(right, y), Endsquare, Endsquare, 0, getcolor(v), ZP);
1273e12c5d1SDavid du Colombier #else
1283e12c5d1SDavid du Colombier if(right>left){
1293e12c5d1SDavid du Colombier switch(v){
1303e12c5d1SDavid du Colombier default:
1313e12c5d1SDavid du Colombier segment(&screen, Pt(left, y), Pt(right, y),
1323e12c5d1SDavid du Colombier ~0, D&~S);
1333e12c5d1SDavid du Colombier segment(&screen, Pt(left, y), Pt(right, y),
1343e12c5d1SDavid du Colombier v, f);
1353e12c5d1SDavid du Colombier break;
1363e12c5d1SDavid du Colombier case 0:
1373e12c5d1SDavid du Colombier segment(&screen, Pt(left, y), Pt(right, y),
1383e12c5d1SDavid du Colombier ~0, D&~S);
1393e12c5d1SDavid du Colombier break;
1403e12c5d1SDavid du Colombier case 3:
1413e12c5d1SDavid du Colombier segment(&screen, Pt(left, y), Pt(right, y),
1423e12c5d1SDavid du Colombier v, f);
1433e12c5d1SDavid du Colombier break;
1443e12c5d1SDavid du Colombier }
1453e12c5d1SDavid du Colombier }
1463e12c5d1SDavid du Colombier #endif
1473e12c5d1SDavid du Colombier }
1483e12c5d1SDavid du Colombier wind=nwind;
1493e12c5d1SDavid du Colombier nextep=ep->next;
1503e12c5d1SDavid du Colombier if(++ep->p.y!=ep->maxy){
1513e12c5d1SDavid du Colombier ep->x+=ep->num;
1523e12c5d1SDavid du Colombier if(ep->x>=ep->den){
1533e12c5d1SDavid du Colombier ep->x-=ep->den;
1543e12c5d1SDavid du Colombier ep->p.x+=ep->dx1;
1553e12c5d1SDavid du Colombier }
1563e12c5d1SDavid du Colombier else
1573e12c5d1SDavid du Colombier ep->p.x+=ep->dx;
1583e12c5d1SDavid du Colombier insert(ep, yp+1);
1593e12c5d1SDavid du Colombier }
1603e12c5d1SDavid du Colombier }
1613e12c5d1SDavid du Colombier }
1623e12c5d1SDavid du Colombier free((char *)edges);
1633e12c5d1SDavid du Colombier free((char *)ylist);
1643e12c5d1SDavid du Colombier }
fill(int num[],double * ff[])1653e12c5d1SDavid du Colombier void fill(int num[], double *ff[]){
166*7dd7cddfSDavid du Colombier polygon(num, ff, Odd, e1->foregr);
1673e12c5d1SDavid du Colombier }
168