8 i_mmarray_cr(i_mmarray *ar,int l) {
12 ar->data=mymalloc(sizeof(minmax)*l);
13 for(i=0;i<l;i++) { ar->data[i].max=-1; ar->data[i].min=MAXINT; }
17 i_mmarray_dst(i_mmarray *ar) {
19 if (ar->data != NULL) { myfree(ar->data); ar->data=NULL; }
23 i_mmarray_add(i_mmarray *ar,int x,int y) {
24 if (y>-1 && y<ar->lines)
26 if (x<ar->data[y].min) ar->data[y].min=x;
27 if (x>ar->data[y].max) ar->data[y].max=x;
32 i_mmarray_gmin(i_mmarray *ar,int y) {
33 if (y>-1 && y<ar->lines) return ar->data[y].min;
38 i_mmarray_getm(i_mmarray *ar,int y) {
39 if (y>-1 && y<ar->lines) return ar->data[y].max;
44 i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) {
46 for(i=0;i<ar->lines;i++) if (ar->data[i].max!=-1) for(x=ar->data[i].min;x<ar->data[i].max;x++) i_ppix(im,x,i,val);
50 i_mmarray_render_fill(i_img *im,i_mmarray *ar,i_fill_t *fill) {
52 if (im->bits == i_8_bits && fill->fill_with_color) {
53 i_color *line = mymalloc(sizeof(i_color) * im->xsize);
56 work = mymalloc(sizeof(i_color) * im->xsize);
57 for(y=0;y<ar->lines;y++) {
58 if (ar->data[y].max!=-1) {
60 w = ar->data[y].max-ar->data[y].min;
63 i_glin(im, x, x+w, y, line);
65 (fill->fill_with_color)(fill, x, y, w, im->channels, line, work);
66 i_plin(im, x, x+w, y, line);
75 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
76 i_fcolor *work = NULL;
78 work = mymalloc(sizeof(i_fcolor) * im->xsize);
79 for(y=0;y<ar->lines;y++) {
80 if (ar->data[y].max!=-1) {
82 w = ar->data[y].max-ar->data[y].min;
85 i_glinf(im, x, x+w, y, line);
87 (fill->fill_with_fcolor)(fill, x, y, w, im->channels, line, work);
88 i_plinf(im, x, x+w, y, line);
101 i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
105 alpha=(double)(y2-y1)/(double)(x2-x1);
108 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
113 i_mmarray_add(ar,x1,(int)(dsec+0.5));
120 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
125 i_mmarray_add(ar,(int)(dsec+0.5),y1);
132 i_mmarray_info(i_mmarray *ar) {
134 for(i=0;i<ar->lines;i++)
135 if (ar->data[i].max!=-1) printf("line %d: min=%d, max=%d.\n",i,ar->data[i].min,ar->data[i].max);
140 i_arc(i_img *im,int x,int y,float rad,float d1,float d2,i_color *val) {
145 mm_log((1,"i_arc(im* 0x%x,x %d,y %d,rad %.2f,d1 %.2f,d2 %.2f,val 0x%x)\n",im,x,y,rad,d1,d2,val));
147 i_mmarray_cr(&dot,im->ysize);
149 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
150 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
151 fx=(float)x1; fy=(float)y1;
153 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
154 i_arcdraw(x, y, x1, y1, &dot);
156 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
157 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
159 for(f=d1;f<=d2;f+=0.01) i_mmarray_add(&dot,(int)(x+0.5+rad*cos(f*PI/180.0)),(int)(y+0.5+rad*sin(f*PI/180.0)));
161 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
162 i_arcdraw(x, y, x1, y1, &dot);
165 i_mmarray_render(im,&dot,val);
169 i_arc_cfill(i_img *im,int x,int y,float rad,float d1,float d2,i_fill_t *fill) {
174 mm_log((1,"i_arc_cfill(im* 0x%x,x %d,y %d,rad %.2f,d1 %.2f,d2 %.2f,fill 0x%x)\n",im,x,y,rad,d1,d2,fill));
176 i_mmarray_cr(&dot,im->ysize);
178 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
179 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
180 fx=(float)x1; fy=(float)y1;
182 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
183 i_arcdraw(x, y, x1, y1, &dot);
185 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
186 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
188 for(f=d1;f<=d2;f+=0.01) i_mmarray_add(&dot,(int)(x+0.5+rad*cos(f*PI/180.0)),(int)(y+0.5+rad*sin(f*PI/180.0)));
190 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
191 i_arcdraw(x, y, x1, y1, &dot);
194 i_mmarray_render_fill(im,&dot,fill);
199 /* Temporary AA HACK */
203 static frac float_to_frac(float x) { return (frac)(0.5+x*16.0); }
204 static int frac_sub (frac x) { return (x%16); }
205 static int frac_int (frac x) { return (x/16); }
206 static float frac_to_float(float x) { return (float)x/16.0; }
210 polar_to_plane(float cx, float cy, float angle, float radius, frac *x, frac *y) {
211 *x = float_to_frac(cx+radius*cos(angle));
212 *y = float_to_frac(cy+radius*sin(angle));
217 order_pair(frac *x, frac *y) {
230 make_minmax_list(i_mmarray *dot, float x, float y, float radius) {
232 float astep = radius>0.1 ? .5/radius : 10;
233 frac cx, cy, lx, ly, sx, sy;
235 mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
237 polar_to_plane(x, y, angle, radius, &sx, &sy);
239 for(angle = 0.0; angle<361; angle +=astep) {
242 polar_to_plane(x, y, angle, radius, &cx, &cy);
245 if (fabs(cx-lx) > fabs(cy-ly)) {
248 ccx = lx; lx = cx; cx = ccx;
249 ccy = ly; ly = cy; cy = ccy;
252 for(ccx=lx; ccx<=cx; ccx++) {
253 ccy = ly + ((cy-ly)*(ccx-lx))/(cx-lx);
254 i_mmarray_add(dot, ccx, ccy);
260 ccy = ly; ly = cy; cy = ccy;
261 ccx = lx; lx = cx; cx = ccx;
264 for(ccy=ly; ccy<=cy; ccy++) {
265 if (cy-ly) ccx = lx + ((cx-lx)*(ccy-ly))/(cy-ly); else ccx = lx;
266 i_mmarray_add(dot, ccx, ccy);
272 /* Get the number of subpixels covered */
276 i_pixel_coverage(i_mmarray *dot, int x, int y) {
282 for(cy=y*16; cy<(y+1)*16; cy++) {
283 frac tmin = dot->data[cy].min;
284 frac tmax = dot->data[cy].max;
286 if (tmax == -1 || tmin > maxx || tmax < minx) continue;
288 if (tmin < minx) tmin = minx;
289 if (tmax > maxx) tmax = maxx;
297 i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) {
302 mm_log((1, "i_circle_aa(im %p, x %d, y %d, rad %.2f, val %p)\n", im, x, y, rad, val));
304 i_mmarray_cr(&dot,16*im->ysize);
305 make_minmax_list(&dot, x, y, rad);
307 for(ly = 0; ly<im->ysize; ly++) {
308 int ix, cy, cnt = 0, minx = INT_MAX, maxx = INT_MIN;
310 /* Find the left/rightmost set subpixels */
311 for(cy = 0; cy<16; cy++) {
312 frac tmin = dot.data[ly*16+cy].min;
313 frac tmax = dot.data[ly*16+cy].max;
314 if (tmax == -1) continue;
316 if (minx > tmin) minx = tmin;
317 if (maxx < tmax) maxx = tmax;
320 if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */
324 for(ix=minx; ix<=maxx; ix++) {
325 int cnt = i_pixel_coverage(&dot, ix, ly);
326 if (cnt>255) cnt = 255;
327 if (cnt) { /* should never be true */
329 float ratio = (float)cnt/255.0;
330 i_gpix(im, ix, ly, &temp);
331 for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
332 i_ppix(im, ix, ly, &temp);
344 i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
346 mm_log((1,"i_box(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
347 for(x=x1;x<x2+1;x++) {
351 for(y=y1;y<y2+1;y++) {
358 i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
360 mm_log((1,"i_box_filled(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
361 for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
365 i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) {
366 mm_log((1,"i_box_cfill(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,fill 0x%x)\n",im,x1,y1,x2,y2,fill));
369 if (im->bits == i_8_bits && fill->fill_with_color) {
370 i_color *line = mymalloc(sizeof(i_color) * (x2 - x1));
371 i_color *work = NULL;
373 work = mymalloc(sizeof(i_color) * (x2-x1));
376 i_glin(im, x1, x2, y1, line);
378 (fill->fill_with_color)(fill, x1, y1, x2-x1, im->channels, line, work);
379 i_plin(im, x1, x2, y1, line);
387 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (x2 - x1));
389 work = mymalloc(sizeof(i_fcolor) * (x2 - x1));
393 i_glinf(im, x1, x2, y1, line);
395 (fill->fill_with_fcolor)(fill, x1, y1, x2-x1, im->channels, line, work);
396 i_plinf(im, x1, x2, y1, line);
406 i_draw(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
411 mm_log((1,"i_draw(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
413 alpha=(double)(y2-y1)/(double)(x2-x1);
416 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
421 i_ppix(im,x1,(int)(dsec+0.5),val);
428 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
433 i_ppix(im,(int)(dsec+0.5),y1,val);
437 mm_log((1,"i_draw: alpha=%f.\n",alpha));
441 i_line_aa(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
445 int temp,dx,dy,isec,ch;
447 mm_log((1,"i_draw(im* 0x%x,x1 %d,y1 %d,x2 %d,y2 %d,val 0x%x)\n",im,x1,y1,x2,y2,val));
452 if (abs(dx)>abs(dy)) { /* alpha < 1 */
453 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
454 alpha=(float)(y2-y1)/(float)(x2-x1);
460 /* dfrac=1-(1-dfrac)*(1-dfrac); */
461 /* This is something we can play with to try to get better looking lines */
463 i_gpix(im,x1,isec,&tval);
464 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
465 i_ppix(im,x1,isec,&tval);
467 i_gpix(im,x1,isec+1,&tval);
468 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
469 i_ppix(im,x1,isec+1,&tval);
475 if (y2<y1) { temp=y1; y1=y2; y2=temp; temp=x1; x1=x2; x2=temp; }
476 alpha=(float)(x2-x1)/(float)(y2-y1);
481 /* dfrac=sqrt(dfrac); */
482 /* This is something we can play with */
483 i_gpix(im,isec,y1,&tval);
484 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
485 i_ppix(im,isec,y1,&tval);
487 i_gpix(im,isec+1,y1,&tval);
488 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
489 i_ppix(im,isec+1,y1,&tval);
502 for(i=k+1;i<=n;i++) r*=i;
503 for(i=1;i<=(n-k);i++) r/=i;
508 /* Note in calculating t^k*(1-t)^(n-k)
509 we can start by using t^0=1 so this simplifies to
510 t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration
511 to get a new level - this may lead to errors who knows lets test it */
514 i_bezier_multi(i_img *im,int l,double *x,double *y,i_color *val) {
523 bzcoef=mymalloc(sizeof(double)*l);
524 for(k=0;k<l;k++) bzcoef[k]=perm(n,k);
528 /* for(k=0;k<l;k++) printf("bzcoef: %d -> %f\n",k,bzcoef[k]); */
530 for(t=0;t<=1;t+=0.005) {
535 /* cx+=bzcoef[k]*x[k]*pow(t,k)*pow(1-t,n-k);
536 cy+=bzcoef[k]*y[k]*pow(t,k)*pow(1-t,n-k);*/
538 cx+=bzcoef[k]*x[k]*ccoef;
539 cy+=bzcoef[k]*y[k]*ccoef;
542 /* printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
544 i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val);
546 /* i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
558 REF: Graphics Gems I. page 282+
562 /* This should be moved into a seperate file? */
564 /* This is the truncation used:
566 a double is multiplied by 16 and then truncated.
567 This means that 0 -> 0
568 So a triangle of (0,0) (10,10) (10,0) Will look like it's
569 not filling the (10,10) point nor the (10,0)-(10,10) line segment
576 #define IMTRUNC(x) ((int)(x*16))
605 p_compy(const struct p_point *p1, const struct p_point *p2) {
606 if (p1->y > p2->y) return 1;
607 if (p1->y < p2->y) return -1;
612 p_compx(const struct p_slice *p1, const struct p_slice *p2) {
613 if (p1->x > p2->x) return 1;
614 if (p1->x < p2->x) return -1;
618 /* Change this to int? and round right goddamn it! */
621 p_eval_aty(struct p_line *l,pcord y) {
624 if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t;
625 return (l->x1+l->x2)/2.0;
629 p_eval_atx(struct p_line *l,pcord x) {
632 if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t;
633 return (l->y1+l->y2)/2.0;
637 /* Algorithm to count the pixels covered by line going through pixel (x,y)
643 p_eval_coverage(struct p_line *l, int lc, int x, pcord y1, pcord y2) {
650 /* Antialiasing polygon algorithm
652 1. only nice polygons - no crossovers
653 2. 1/16 pixel resolution # previously - floating point co-ordinates
654 3. full antialiasing ( complete spectrum of blends )
655 4. uses hardly any memory
656 5. no subsampling phase
658 For each interval we must:
659 1. find which lines are in it
660 2. order the lines from in increasing x order.
661 since we are assuming no crossovers it is sufficent
662 to check a single point on each line.
668 1. Interval: A vertical segment in which no lines cross nor end.
669 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction
670 3. Slice: A start stop line pair.
676 The variable tempflush describes if there is anything in the templine array or not.
678 if tempflush is 0 then the array is clean.
679 if tempflush is 1 then the array contains a partial filled scanline
683 /* Rendering of a single start stop pair:
687 The rendering is split in three parts
688 1. From the first start pixel to the first stop pixel
689 2. Area from the first end pixel to the last start pixel
690 3. Area from the first end pixel to the last start pixel
696 i_poly_aa(i_img *im,int l,double *x,double *y,i_color *val) {
697 int i,k; /* Index variables */
698 int clc; /* Index of next item on interval linelist */
699 int tx; /* Coarse x coord within a scanline */
700 pcord miny,maxy; /* Min and max values of the current slice in the subcord system */
701 pcord minacy,maxacy; /* Min and max values of the current scanline bounded by the slice
702 in the subcord system */
703 int cscl; /* Current scanline */
704 pcord cc; /* Current vertical centerpoint of interval */
706 int minsx,minex,maxsx,maxex; /* The horizontal stretches of the lines beloning to the current slice within a scanline */
707 int *templine; /* Line accumulator */
709 struct p_point *pset; /* List of points in polygon */
710 struct p_line *lset; /* List of lines in polygon */
711 struct p_slice *tllist; /* List of slices */
713 i_color red,blue,yellow;
726 if ( (pset=mymalloc(sizeof(struct p_point)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
727 if ( (lset=mymalloc(sizeof(struct p_line)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
728 if ( (tllist=mymalloc(sizeof(struct p_slice)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
729 if ( (templine=mymalloc(sizeof(int)*im->xsize)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
731 /* insert the lines into the line list */
735 pset[i].x=IMTRUNC(x[i]);
736 pset[i].y=IMTRUNC(y[i]);
738 lset[i].x1=IMTRUNC(x[i]);
739 lset[i].y1=IMTRUNC(y[i]);
740 lset[i].x2=IMTRUNC(x[(i+1)%l]);
741 lset[i].y2=IMTRUNC(y[(i+1)%l]);
742 lset[i].miny=min(lset[i].y1,lset[i].y2);
743 lset[i].maxy=max(lset[i].y1,lset[i].y2);
746 qsort(pset,l,sizeof(struct p_point),(int(*)(const void *,const void *))p_compy);
748 printf("post point list (sorted in ascending y order)\n");
750 printf("%d [ %d ] %d %d\n",i,pset[i].n,pset[i].x,pset[i].y);
753 printf("line list\n");
755 printf("%d [ %d ] (%d , %d) -> (%d , %d) yspan ( %d , %d )\n",i,lset[i].n,lset[i].x1,lset[i].y1,lset[i].x2,lset[i].y2,lset[i].miny,lset[i].maxy);
758 printf("MAIN LOOP\n\n");
760 /* Zero templine buffer */
761 /* Templine buffer flushed everytime a scan line ends */
762 for(i=0;i<im->xsize;i++) templine[i]=0;
765 /* loop on intervals */
767 cc=(pset[i].y+pset[i+1].y)/2;
768 printf("current slice is: %d to %d ( cpoint %d )\n",pset[i].y,pset[i+1].y,cc);
771 /* stuff this in a function ?? */
773 /* Check what lines belong to interval */
775 printf("checking line: %d [ %d ] (%d , %d) -> (%d, %d) yspan ( %d , %d )",
776 k,lset[k].n,lset[k].x1,lset[k].y1,lset[k].x2,lset[k].y2,lset[k].miny,lset[k].maxy);
777 if (cc >= lset[k].miny && cc <= lset[k].maxy) {
778 if (lset[k].miny == lset[k].maxy) printf(" HORIZONTAL - skipped\n");
781 tllist[clc].x=p_eval_aty(&lset[k],cc);
784 } else printf(" OUTSIDE\n");
788 at this point a table of pixels that need special care should
789 be generated from the line list - it should be ordered so that only
790 one needs to be checked - options: rendering to a list then order - or
791 rendering in the right order might be possible to do nicely with the
794 1. Draw leftmost pixel for this line
795 2. If preceeding pixel was occupied check next one else go to 1 again.
798 printf("lines in current interval:");
799 for(k=0;k<clc;k++) printf(" %d (%.2f)",tllist[k].n,tllist[k].x);
802 /* evaluate the lines in the middle of the slice */
804 printf("Sort lines left to right within interval\n");
805 qsort(tllist,clc,sizeof(struct p_slice),(int(*)(const void *,const void *))p_compx);
807 printf("sorted lines in interval - output:");
808 for(k=0;k<clc;k++) printf(" %d",tllist[k].n);
814 /* iterate over scanlines */
815 for(cscl=(miny)/16;cscl<=maxy/16;cscl++) {
816 minacy=max(miny,cscl*16);
817 maxacy=min(maxy,cscl*16+15);
819 printf("Scanline bound %d - %d\n",minacy, maxacy);
821 /* iterate over line pairs (slices) within interval */
822 for(k=0;k<clc-1;k+=2) {
824 mt1=p_eval_aty(&lset[tllist[k].n],minacy); /* upper corner */
825 mt2=p_eval_aty(&lset[tllist[k].n],maxacy); /* lower corner */
828 mt1=p_eval_aty(&lset[tllist[k+1].n],minacy); /* upper corner */
829 mt2=p_eval_aty(&lset[tllist[k+1].n],maxacy); /* lower corner */
833 printf("minsx: %d minex: %d\n",minsx,minex);
834 printf("maxsx: %d maxex: %d\n",maxsx,maxex);
836 if (minex/16<maxsx/16) printf("Scan slice is simple!\n");
837 else printf("Scan slice is complicated!\n");
839 if (minsx/16 == minex/16) { /* The line starts and ends in the same pixel */
840 printf("Low slant start pixel\n");
841 templine[minsx/16]=(maxacy-minacy+1)*(minex-minsx+1)/2+((minex | 0xF)-minex)*(maxacy-minacy+1);
843 for(tx=minsx/16;tx<minex/16+1;tx++) {
844 int minx,maxx,minxy,maxxy;
845 minx=max(minsx, tx*16 );
846 maxx=min(minex, tx*16+15);
849 templine[tx]=(maxacy-minacy+1);
852 minxy=p_eval_atx(&lset[tllist[k].n], minx);
853 maxxy=p_eval_atx(&lset[tllist[k].n], maxx);
855 templine[tx]+=(abs(minxy-maxxy)+1)*(minex-minsx+1)/2; /* The triangle between the points */
856 if (mt1 < mt2) { /* \ slant */
857 /* ((minex | 0xF)-minex)*(maxacy-minacy+1); FIXME: unfinished */
862 templine[tx]+=((minex | 0xF)-minex)*(maxacy-minacy+1);
869 for(tx=maxsx/16;tx<maxex/16+1;tx++) templine[tx]+=16*(maxacy-minacy+1);
871 /* for(tx=minex/16+1;tx<maxsx/16;tx++) 0; */
874 printf("line %d: painting %d - %d\n",cscl,minex/16+1,maxsx/16);
875 if ( (minacy != cscl*16) || (maxacy != cscl*16+15) ) {
876 for(tx=minsx/16;tx<maxex/16+1;tx++) {
877 i_ppix(im,tx,cscl,&yellow);
881 for(tx=minsx/16;tx<minex/16+1;tx++) i_ppix(im,tx,cscl,&red);
882 for(tx=maxsx/16;tx<maxex/16+1;tx++) i_ppix(im,tx,cscl,&blue);
883 for(tx=minex/16+1;tx<maxsx/16;tx++) i_ppix(im,tx,cscl,val);
897 /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in
912 struct stack_element {
920 /* create the link data to put push onto the stack */
923 struct stack_element*
924 crdata(int left,int right,int dadl,int dadr,int y, int dir) {
925 struct stack_element *ste;
926 ste=(struct stack_element*)mymalloc(sizeof(struct stack_element));
932 ste->myDirection=dir;
936 /* i_ccomp compares two colors and gives true if they are the same */
939 i_ccomp(i_color *val1,i_color *val2,int ch) {
941 for(i=0;i<ch;i++) if (val1->channel[i] !=val2->channel[i]) return 0;
947 i_lspan(i_img *im,int seedx,int seedy,i_color *val) {
950 if (seedx-1 < 0) break;
951 i_gpix(im,seedx-1,seedy,&cval);
952 if (!i_ccomp(val,&cval,im->channels)) break;
959 i_rspan(i_img *im,int seedx,int seedy,i_color *val) {
962 if (seedx+1 > im->xsize-1) break;
963 i_gpix(im,seedx+1,seedy,&cval);
964 if (!i_ccomp(val,&cval,im->channels)) break;
970 /* Macro to create a link and push on to the list */
972 #define ST_PUSH(left,right,dadl,dadr,y,dir) { struct stack_element *s=crdata(left,right,dadl,dadr,y,dir); llist_push(st,&s);}
974 /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */
975 /* No overflow check! */
977 #define ST_POP() { struct stack_element *s; llist_pop(st,&s); lx=s->myLx; rx=s->myRx; dadLx=s->dadLx; dadRx=s->dadRx; y=s->myY; direction=s->myDirection; myfree(s); }
979 #define ST_STACK(dir,dadLx,dadRx,lx,rx,y) { int pushrx=rx+1; int pushlx=lx-1; ST_PUSH(lx,rx,pushlx,pushrx,y+dir,dir); if (rx > dadRx) ST_PUSH(dadRx+1,rx,pushlx,pushrx,y-dir,-dir); if (lx < dadLx) ST_PUSH(lx,dadLx-1,pushlx,pushrx,y-dir,-dir); }
981 #define SET(x,y) btm_set(btm,x,y);
983 #define INSIDE(x,y) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),i_ccomp(&val,&cval,channels) ) ))
986 i_flood_fill(i_img *im,int seedx,int seedy,i_color *dcol) {
998 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1001 struct i_bitmap *btm;
1003 int channels,xsize,ysize;
1006 channels=im->channels;
1010 btm=btm_new(xsize,ysize);
1011 st=llist_new(100,sizeof(struct stack_element*));
1013 /* Get the reference color */
1014 i_gpix(im,seedx,seedy,&val);
1016 /* Find the starting span and fill it */
1017 lx=i_lspan(im,seedx,seedy,&val);
1018 rx=i_rspan(im,seedx,seedy,&val);
1020 /* printf("span: %d %d \n",lx,rx); */
1022 for(x=lx;x<=rx;x++) SET(x,seedy);
1024 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1025 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1030 if (y<0 || y>ysize-1) continue;
1032 if (bymin > y) bymin=y; /* in the worst case an extra line */
1033 if (bymax < y) bymax=y;
1035 /* printf("start of scan - on stack : %d \n",st->count); */
1038 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1042 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1044 for(ty=0;ty<ysize;ty++) {
1046 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1055 if ( (wasIn = INSIDE(lx,y)) ) {
1058 while(INSIDE(lx,y) && lx > 0) {
1064 if (bxmin > lx) bxmin=lx;
1066 while(x <= xsize-1) {
1067 /* printf("x=%d\n",x); */
1071 /* case 1: was inside, am still inside */
1074 /* case 2: was inside, am no longer inside: just found the
1075 right edge of a span */
1076 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1078 if (bxmax < x) bxmax=x;
1086 /* case 3: Wasn't inside, am now: just found the start of a new run */
1090 /* case 4: Wasn't inside, still isn't */
1095 EXT: /* out of loop */
1097 /* hit an edge of the frame buffer while inside a run */
1098 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1099 if (bxmax < x) bxmax=x;
1103 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1104 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1106 for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol);
1112 static struct i_bitmap *
1113 i_flood_fill_low(i_img *im,int seedx,int seedy,
1114 int *bxminp, int *bxmaxp, int *byminp, int *bymaxp) {
1125 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1128 struct i_bitmap *btm;
1130 int channels,xsize,ysize;
1133 channels=im->channels;
1137 btm=btm_new(xsize,ysize);
1138 st=llist_new(100,sizeof(struct stack_element*));
1140 /* Get the reference color */
1141 i_gpix(im,seedx,seedy,&val);
1143 /* Find the starting span and fill it */
1144 lx=i_lspan(im,seedx,seedy,&val);
1145 rx=i_rspan(im,seedx,seedy,&val);
1147 /* printf("span: %d %d \n",lx,rx); */
1149 for(x=lx;x<=rx;x++) SET(x,seedy);
1151 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1152 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1157 if (y<0 || y>ysize-1) continue;
1159 if (bymin > y) bymin=y; /* in the worst case an extra line */
1160 if (bymax < y) bymax=y;
1162 /* printf("start of scan - on stack : %d \n",st->count); */
1165 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1169 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1171 for(ty=0;ty<ysize;ty++) {
1173 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1182 if ( (wasIn = INSIDE(lx,y)) ) {
1185 while(INSIDE(lx,y) && lx > 0) {
1191 if (bxmin > lx) bxmin=lx;
1193 while(x <= xsize-1) {
1194 /* printf("x=%d\n",x); */
1198 /* case 1: was inside, am still inside */
1201 /* case 2: was inside, am no longer inside: just found the
1202 right edge of a span */
1203 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1205 if (bxmax < x) bxmax=x;
1213 /* case 3: Wasn't inside, am now: just found the start of a new run */
1217 /* case 4: Wasn't inside, still isn't */
1222 EXT: /* out of loop */
1224 /* hit an edge of the frame buffer while inside a run */
1225 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1226 if (bxmax < x) bxmax=x;
1230 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1231 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1244 i_flood_cfill(i_img *im, int seedx, int seedy, i_fill_t *fill) {
1245 int bxmin, bxmax, bymin, bymax;
1246 struct i_bitmap *btm;
1250 btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax);
1252 if (im->bits == i_8_bits && fill->fill_with_color) {
1253 i_color *line = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1254 i_color *work = NULL;
1256 work = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1258 for(y=bymin;y<=bymax;y++) {
1261 while (x < bxmax && !btm_test(btm, x, y)) {
1264 if (btm_test(btm, x, y)) {
1266 while (x < bxmax && btm_test(btm, x, y)) {
1270 i_glin(im, start, x, y, line);
1271 (fill->fill_with_color)(fill, start, y, x-start, im->channels,
1273 i_plin(im, start, x, y, line);
1282 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1283 i_fcolor *work = NULL;
1285 work = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1287 for(y=bymin;y<=bymax;y++) {
1290 while (x < bxmax && !btm_test(btm, x, y)) {
1293 if (btm_test(btm, x, y)) {
1295 while (x < bxmax && btm_test(btm, x, y)) {
1299 i_glinf(im, start, x, y, line);
1300 (fill->fill_with_fcolor)(fill, start, y, x-start, im->channels,
1302 i_plinf(im, start, x, y, line);