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);
170 i_arc_cfill(i_img *im,int x,int y,float rad,float d1,float d2,i_fill_t *fill) {
175 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));
177 i_mmarray_cr(&dot,im->ysize);
179 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
180 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
181 fx=(float)x1; fy=(float)y1;
183 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
184 i_arcdraw(x, y, x1, y1, &dot);
186 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
187 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
189 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)));
191 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
192 i_arcdraw(x, y, x1, y1, &dot);
195 i_mmarray_render_fill(im,&dot,fill);
201 /* Temporary AA HACK */
205 static frac float_to_frac(float x) { return (frac)(0.5+x*16.0); }
206 static int frac_sub (frac x) { return (x%16); }
207 static int frac_int (frac x) { return (x/16); }
208 static float frac_to_float(float x) { return (float)x/16.0; }
212 polar_to_plane(float cx, float cy, float angle, float radius, frac *x, frac *y) {
213 *x = float_to_frac(cx+radius*cos(angle));
214 *y = float_to_frac(cy+radius*sin(angle));
219 order_pair(frac *x, frac *y) {
232 make_minmax_list(i_mmarray *dot, float x, float y, float radius) {
234 float astep = radius>0.1 ? .5/radius : 10;
235 frac cx, cy, lx, ly, sx, sy;
237 mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
239 polar_to_plane(x, y, angle, radius, &sx, &sy);
241 for(angle = 0.0; angle<361; angle +=astep) {
244 polar_to_plane(x, y, angle, radius, &cx, &cy);
247 if (fabs(cx-lx) > fabs(cy-ly)) {
250 ccx = lx; lx = cx; cx = ccx;
251 ccy = ly; ly = cy; cy = ccy;
254 for(ccx=lx; ccx<=cx; ccx++) {
255 ccy = ly + ((cy-ly)*(ccx-lx))/(cx-lx);
256 i_mmarray_add(dot, ccx, ccy);
262 ccy = ly; ly = cy; cy = ccy;
263 ccx = lx; lx = cx; cx = ccx;
266 for(ccy=ly; ccy<=cy; ccy++) {
267 if (cy-ly) ccx = lx + ((cx-lx)*(ccy-ly))/(cy-ly); else ccx = lx;
268 i_mmarray_add(dot, ccx, ccy);
274 /* Get the number of subpixels covered */
278 i_pixel_coverage(i_mmarray *dot, int x, int y) {
284 for(cy=y*16; cy<(y+1)*16; cy++) {
285 frac tmin = dot->data[cy].min;
286 frac tmax = dot->data[cy].max;
288 if (tmax == -1 || tmin > maxx || tmax < minx) continue;
290 if (tmin < minx) tmin = minx;
291 if (tmax > maxx) tmax = maxx;
299 i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) {
304 mm_log((1, "i_circle_aa(im %p, x %d, y %d, rad %.2f, val %p)\n", im, x, y, rad, val));
306 i_mmarray_cr(&dot,16*im->ysize);
307 make_minmax_list(&dot, x, y, rad);
309 for(ly = 0; ly<im->ysize; ly++) {
310 int ix, cy, cnt = 0, minx = INT_MAX, maxx = INT_MIN;
312 /* Find the left/rightmost set subpixels */
313 for(cy = 0; cy<16; cy++) {
314 frac tmin = dot.data[ly*16+cy].min;
315 frac tmax = dot.data[ly*16+cy].max;
316 if (tmax == -1) continue;
318 if (minx > tmin) minx = tmin;
319 if (maxx < tmax) maxx = tmax;
322 if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */
326 for(ix=minx; ix<=maxx; ix++) {
327 int cnt = i_pixel_coverage(&dot, ix, ly);
328 if (cnt>255) cnt = 255;
329 if (cnt) { /* should never be true */
331 float ratio = (float)cnt/255.0;
332 i_gpix(im, ix, ly, &temp);
333 for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
334 i_ppix(im, ix, ly, &temp);
347 i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
349 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));
350 for(x=x1;x<x2+1;x++) {
354 for(y=y1;y<y2+1;y++) {
361 i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
363 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));
364 for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
368 i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) {
369 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));
372 if (im->bits == i_8_bits && fill->fill_with_color) {
373 i_color *line = mymalloc(sizeof(i_color) * (x2 - x1));
374 i_color *work = NULL;
376 work = mymalloc(sizeof(i_color) * (x2-x1));
379 i_glin(im, x1, x2, y1, line);
381 (fill->fill_with_color)(fill, x1, y1, x2-x1, im->channels, line, work);
382 i_plin(im, x1, x2, y1, line);
390 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (x2 - x1));
392 work = mymalloc(sizeof(i_fcolor) * (x2 - x1));
396 i_glinf(im, x1, x2, y1, line);
398 (fill->fill_with_fcolor)(fill, x1, y1, x2-x1, im->channels, line, work);
399 i_plinf(im, x1, x2, y1, line);
409 i_draw(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
414 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));
416 alpha=(double)(y2-y1)/(double)(x2-x1);
419 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
424 i_ppix(im,x1,(int)(dsec+0.5),val);
431 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
436 i_ppix(im,(int)(dsec+0.5),y1,val);
440 mm_log((1,"i_draw: alpha=%f.\n",alpha));
444 i_line_aa(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
448 int temp,dx,dy,isec,ch;
450 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));
455 if (abs(dx)>abs(dy)) { /* alpha < 1 */
456 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
457 alpha=(float)(y2-y1)/(float)(x2-x1);
463 /* dfrac=1-(1-dfrac)*(1-dfrac); */
464 /* This is something we can play with to try to get better looking lines */
466 i_gpix(im,x1,isec,&tval);
467 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
468 i_ppix(im,x1,isec,&tval);
470 i_gpix(im,x1,isec+1,&tval);
471 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
472 i_ppix(im,x1,isec+1,&tval);
478 if (y2<y1) { temp=y1; y1=y2; y2=temp; temp=x1; x1=x2; x2=temp; }
479 alpha=(float)(x2-x1)/(float)(y2-y1);
484 /* dfrac=sqrt(dfrac); */
485 /* This is something we can play with */
486 i_gpix(im,isec,y1,&tval);
487 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
488 i_ppix(im,isec,y1,&tval);
490 i_gpix(im,isec+1,y1,&tval);
491 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
492 i_ppix(im,isec+1,y1,&tval);
505 for(i=k+1;i<=n;i++) r*=i;
506 for(i=1;i<=(n-k);i++) r/=i;
511 /* Note in calculating t^k*(1-t)^(n-k)
512 we can start by using t^0=1 so this simplifies to
513 t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration
514 to get a new level - this may lead to errors who knows lets test it */
517 i_bezier_multi(i_img *im,int l,double *x,double *y,i_color *val) {
526 bzcoef=mymalloc(sizeof(double)*l);
527 for(k=0;k<l;k++) bzcoef[k]=perm(n,k);
531 /* for(k=0;k<l;k++) printf("bzcoef: %d -> %f\n",k,bzcoef[k]); */
533 for(t=0;t<=1;t+=0.005) {
538 /* cx+=bzcoef[k]*x[k]*pow(t,k)*pow(1-t,n-k);
539 cy+=bzcoef[k]*y[k]*pow(t,k)*pow(1-t,n-k);*/
541 cx+=bzcoef[k]*x[k]*ccoef;
542 cy+=bzcoef[k]*y[k]*ccoef;
545 /* printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
547 i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val);
549 /* i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
561 REF: Graphics Gems I. page 282+
565 /* This should be moved into a seperate file? */
567 /* This is the truncation used:
569 a double is multiplied by 16 and then truncated.
570 This means that 0 -> 0
571 So a triangle of (0,0) (10,10) (10,0) Will look like it's
572 not filling the (10,10) point nor the (10,0)-(10,10) line segment
579 #define IMTRUNC(x) ((int)(x*16))
608 p_compy(const struct p_point *p1, const struct p_point *p2) {
609 if (p1->y > p2->y) return 1;
610 if (p1->y < p2->y) return -1;
615 p_compx(const struct p_slice *p1, const struct p_slice *p2) {
616 if (p1->x > p2->x) return 1;
617 if (p1->x < p2->x) return -1;
621 /* Change this to int? and round right goddamn it! */
624 p_eval_aty(struct p_line *l,pcord y) {
627 if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t;
628 return (l->x1+l->x2)/2.0;
632 p_eval_atx(struct p_line *l,pcord x) {
635 if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t;
636 return (l->y1+l->y2)/2.0;
640 /* Algorithm to count the pixels covered by line going through pixel (x,y)
646 p_eval_coverage(struct p_line *l, int lc, int x, pcord y1, pcord y2) {
653 /* Antialiasing polygon algorithm
655 1. only nice polygons - no crossovers
656 2. 1/16 pixel resolution # previously - floating point co-ordinates
657 3. full antialiasing ( complete spectrum of blends )
658 4. uses hardly any memory
659 5. no subsampling phase
661 For each interval we must:
662 1. find which lines are in it
663 2. order the lines from in increasing x order.
664 since we are assuming no crossovers it is sufficent
665 to check a single point on each line.
671 1. Interval: A vertical segment in which no lines cross nor end.
672 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction
673 3. Slice: A start stop line pair.
679 The variable tempflush describes if there is anything in the templine array or not.
681 if tempflush is 0 then the array is clean.
682 if tempflush is 1 then the array contains a partial filled scanline
686 /* Rendering of a single start stop pair:
690 The rendering is split in three parts
691 1. From the first start pixel to the first stop pixel
692 2. Area from the first end pixel to the last start pixel
693 3. Area from the first end pixel to the last start pixel
699 i_poly_aa(i_img *im,int l,double *x,double *y,i_color *val) {
700 int i,k; /* Index variables */
701 int clc; /* Index of next item on interval linelist */
702 int tx; /* Coarse x coord within a scanline */
703 pcord miny,maxy; /* Min and max values of the current slice in the subcord system */
704 pcord minacy,maxacy; /* Min and max values of the current scanline bounded by the slice
705 in the subcord system */
706 int cscl; /* Current scanline */
707 pcord cc; /* Current vertical centerpoint of interval */
709 int minsx,minex,maxsx,maxex; /* The horizontal stretches of the lines beloning to the current slice within a scanline */
710 int *templine; /* Line accumulator */
712 struct p_point *pset; /* List of points in polygon */
713 struct p_line *lset; /* List of lines in polygon */
714 struct p_slice *tllist; /* List of slices */
716 i_color red,blue,yellow;
729 if ( (pset=mymalloc(sizeof(struct p_point)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
730 if ( (lset=mymalloc(sizeof(struct p_line)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
731 if ( (tllist=mymalloc(sizeof(struct p_slice)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
732 if ( (templine=mymalloc(sizeof(int)*im->xsize)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
734 /* insert the lines into the line list */
738 pset[i].x=IMTRUNC(x[i]);
739 pset[i].y=IMTRUNC(y[i]);
741 lset[i].x1=IMTRUNC(x[i]);
742 lset[i].y1=IMTRUNC(y[i]);
743 lset[i].x2=IMTRUNC(x[(i+1)%l]);
744 lset[i].y2=IMTRUNC(y[(i+1)%l]);
745 lset[i].miny=min(lset[i].y1,lset[i].y2);
746 lset[i].maxy=max(lset[i].y1,lset[i].y2);
749 qsort(pset,l,sizeof(struct p_point),(int(*)(const void *,const void *))p_compy);
751 printf("post point list (sorted in ascending y order)\n");
753 printf("%d [ %d ] %d %d\n",i,pset[i].n,pset[i].x,pset[i].y);
756 printf("line list\n");
758 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);
761 printf("MAIN LOOP\n\n");
763 /* Zero templine buffer */
764 /* Templine buffer flushed everytime a scan line ends */
765 for(i=0;i<im->xsize;i++) templine[i]=0;
768 /* loop on intervals */
770 cc=(pset[i].y+pset[i+1].y)/2;
771 printf("current slice is: %d to %d ( cpoint %d )\n",pset[i].y,pset[i+1].y,cc);
774 /* stuff this in a function ?? */
776 /* Check what lines belong to interval */
778 printf("checking line: %d [ %d ] (%d , %d) -> (%d, %d) yspan ( %d , %d )",
779 k,lset[k].n,lset[k].x1,lset[k].y1,lset[k].x2,lset[k].y2,lset[k].miny,lset[k].maxy);
780 if (cc >= lset[k].miny && cc <= lset[k].maxy) {
781 if (lset[k].miny == lset[k].maxy) printf(" HORIZONTAL - skipped\n");
784 tllist[clc].x=p_eval_aty(&lset[k],cc);
787 } else printf(" OUTSIDE\n");
791 at this point a table of pixels that need special care should
792 be generated from the line list - it should be ordered so that only
793 one needs to be checked - options: rendering to a list then order - or
794 rendering in the right order might be possible to do nicely with the
797 1. Draw leftmost pixel for this line
798 2. If preceeding pixel was occupied check next one else go to 1 again.
801 printf("lines in current interval:");
802 for(k=0;k<clc;k++) printf(" %d (%.2f)",tllist[k].n,tllist[k].x);
805 /* evaluate the lines in the middle of the slice */
807 printf("Sort lines left to right within interval\n");
808 qsort(tllist,clc,sizeof(struct p_slice),(int(*)(const void *,const void *))p_compx);
810 printf("sorted lines in interval - output:");
811 for(k=0;k<clc;k++) printf(" %d",tllist[k].n);
817 /* iterate over scanlines */
818 for(cscl=(miny)/16;cscl<=maxy/16;cscl++) {
819 minacy=max(miny,cscl*16);
820 maxacy=min(maxy,cscl*16+15);
822 printf("Scanline bound %d - %d\n",minacy, maxacy);
824 /* iterate over line pairs (slices) within interval */
825 for(k=0;k<clc-1;k+=2) {
827 mt1=p_eval_aty(&lset[tllist[k].n],minacy); /* upper corner */
828 mt2=p_eval_aty(&lset[tllist[k].n],maxacy); /* lower corner */
831 mt1=p_eval_aty(&lset[tllist[k+1].n],minacy); /* upper corner */
832 mt2=p_eval_aty(&lset[tllist[k+1].n],maxacy); /* lower corner */
836 printf("minsx: %d minex: %d\n",minsx,minex);
837 printf("maxsx: %d maxex: %d\n",maxsx,maxex);
839 if (minex/16<maxsx/16) printf("Scan slice is simple!\n");
840 else printf("Scan slice is complicated!\n");
842 if (minsx/16 == minex/16) { /* The line starts and ends in the same pixel */
843 printf("Low slant start pixel\n");
844 templine[minsx/16]=(maxacy-minacy+1)*(minex-minsx+1)/2+((minex | 0xF)-minex)*(maxacy-minacy+1);
846 for(tx=minsx/16;tx<minex/16+1;tx++) {
847 int minx,maxx,minxy,maxxy;
848 minx=max(minsx, tx*16 );
849 maxx=min(minex, tx*16+15);
852 templine[tx]=(maxacy-minacy+1);
855 minxy=p_eval_atx(&lset[tllist[k].n], minx);
856 maxxy=p_eval_atx(&lset[tllist[k].n], maxx);
858 templine[tx]+=(abs(minxy-maxxy)+1)*(minex-minsx+1)/2; /* The triangle between the points */
859 if (mt1 < mt2) { /* \ slant */
860 /* ((minex | 0xF)-minex)*(maxacy-minacy+1); FIXME: unfinished */
865 templine[tx]+=((minex | 0xF)-minex)*(maxacy-minacy+1);
872 for(tx=maxsx/16;tx<maxex/16+1;tx++) templine[tx]+=16*(maxacy-minacy+1);
874 /* for(tx=minex/16+1;tx<maxsx/16;tx++) 0; */
877 printf("line %d: painting %d - %d\n",cscl,minex/16+1,maxsx/16);
878 if ( (minacy != cscl*16) || (maxacy != cscl*16+15) ) {
879 for(tx=minsx/16;tx<maxex/16+1;tx++) {
880 i_ppix(im,tx,cscl,&yellow);
884 for(tx=minsx/16;tx<minex/16+1;tx++) i_ppix(im,tx,cscl,&red);
885 for(tx=maxsx/16;tx<maxex/16+1;tx++) i_ppix(im,tx,cscl,&blue);
886 for(tx=minex/16+1;tx<maxsx/16;tx++) i_ppix(im,tx,cscl,val);
900 /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in
915 struct stack_element {
923 /* create the link data to put push onto the stack */
926 struct stack_element*
927 crdata(int left,int right,int dadl,int dadr,int y, int dir) {
928 struct stack_element *ste;
929 ste = mymalloc(sizeof(struct stack_element));
935 ste->myDirection = dir;
939 /* i_ccomp compares two colors and gives true if they are the same */
942 i_ccomp(i_color *val1,i_color *val2,int ch) {
944 for(i=0;i<ch;i++) if (val1->channel[i] !=val2->channel[i]) return 0;
950 i_lspan(i_img *im,int seedx,int seedy,i_color *val) {
953 if (seedx-1 < 0) break;
954 i_gpix(im,seedx-1,seedy,&cval);
955 if (!i_ccomp(val,&cval,im->channels)) break;
962 i_rspan(i_img *im,int seedx,int seedy,i_color *val) {
965 if (seedx+1 > im->xsize-1) break;
966 i_gpix(im,seedx+1,seedy,&cval);
967 if (!i_ccomp(val,&cval,im->channels)) break;
973 /* Macro to create a link and push on to the list */
975 #define ST_PUSH(left,right,dadl,dadr,y,dir) { struct stack_element *s = crdata(left,right,dadl,dadr,y,dir); llist_push(st,&s); }
977 /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */
978 /* No overflow check! */
980 #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); }
982 #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); }
984 #define SET(x,y) btm_set(btm,x,y);
986 #define INSIDE(x,y) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),i_ccomp(&val,&cval,channels) ) ))
989 i_flood_fill(i_img *im,int seedx,int seedy,i_color *dcol) {
1001 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1004 struct i_bitmap *btm;
1006 int channels,xsize,ysize;
1009 channels = im->channels;
1013 btm = btm_new(xsize,ysize);
1014 st = llist_new(100,sizeof(struct stack_element*));
1016 /* Get the reference color */
1017 i_gpix(im,seedx,seedy,&val);
1019 /* Find the starting span and fill it */
1020 lx = i_lspan(im,seedx,seedy,&val);
1021 rx = i_rspan(im,seedx,seedy,&val);
1023 /* printf("span: %d %d \n",lx,rx); */
1025 for(x=lx; x<=rx; x++) SET(x,seedy);
1027 ST_PUSH(lx, rx, lx, rx, seedy+1, 1);
1028 ST_PUSH(lx, rx, lx, rx, seedy-1,-1);
1033 if (y<0 || y>ysize-1) continue;
1035 if (bymin > y) bymin=y; /* in the worst case an extra line */
1036 if (bymax < y) bymax=y;
1038 /* printf("start of scan - on stack : %d \n",st->count); */
1041 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1045 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1047 for(ty=0;ty<ysize;ty++) {
1049 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1058 if ( (wasIn = INSIDE(lx,y)) ) {
1061 while(INSIDE(lx,y) && lx > 0) {
1067 if (bxmin > lx) bxmin=lx;
1069 while(x <= xsize-1) {
1070 /* printf("x=%d\n",x); */
1074 /* case 1: was inside, am still inside */
1077 /* case 2: was inside, am no longer inside: just found the
1078 right edge of a span */
1079 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1081 if (bxmax < x) bxmax=x;
1089 /* case 3: Wasn't inside, am now: just found the start of a new run */
1093 /* case 4: Wasn't inside, still isn't */
1098 EXT: /* out of loop */
1100 /* hit an edge of the frame buffer while inside a run */
1101 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1102 if (bxmax < x) bxmax=x;
1106 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1107 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1109 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 mm_log((1, "DESTROY\n"));
1116 static struct i_bitmap *
1117 i_flood_fill_low(i_img *im,int seedx,int seedy,
1118 int *bxminp, int *bxmaxp, int *byminp, int *bymaxp) {
1129 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1132 struct i_bitmap *btm;
1134 int channels,xsize,ysize;
1137 channels=im->channels;
1141 btm=btm_new(xsize,ysize);
1142 st=llist_new(100,sizeof(struct stack_element*));
1144 /* Get the reference color */
1145 i_gpix(im,seedx,seedy,&val);
1147 /* Find the starting span and fill it */
1148 lx=i_lspan(im,seedx,seedy,&val);
1149 rx=i_rspan(im,seedx,seedy,&val);
1151 /* printf("span: %d %d \n",lx,rx); */
1153 for(x=lx;x<=rx;x++) SET(x,seedy);
1155 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1156 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1161 if (y<0 || y>ysize-1) continue;
1163 if (bymin > y) bymin=y; /* in the worst case an extra line */
1164 if (bymax < y) bymax=y;
1166 /* printf("start of scan - on stack : %d \n",st->count); */
1169 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1173 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1175 for(ty=0;ty<ysize;ty++) {
1177 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1186 if ( (wasIn = INSIDE(lx,y)) ) {
1189 while(INSIDE(lx,y) && lx > 0) {
1195 if (bxmin > lx) bxmin=lx;
1197 while(x <= xsize-1) {
1198 /* printf("x=%d\n",x); */
1202 /* case 1: was inside, am still inside */
1205 /* case 2: was inside, am no longer inside: just found the
1206 right edge of a span */
1207 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1209 if (bxmax < x) bxmax=x;
1217 /* case 3: Wasn't inside, am now: just found the start of a new run */
1221 /* case 4: Wasn't inside, still isn't */
1226 EXT: /* out of loop */
1228 /* hit an edge of the frame buffer while inside a run */
1229 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1230 if (bxmax < x) bxmax=x;
1234 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1235 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1248 i_flood_cfill(i_img *im, int seedx, int seedy, i_fill_t *fill) {
1249 int bxmin, bxmax, bymin, bymax;
1250 struct i_bitmap *btm;
1254 btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax);
1256 if (im->bits == i_8_bits && fill->fill_with_color) {
1257 i_color *line = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1258 i_color *work = NULL;
1260 work = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1262 for(y=bymin;y<=bymax;y++) {
1265 while (x < bxmax && !btm_test(btm, x, y)) {
1268 if (btm_test(btm, x, y)) {
1270 while (x < bxmax && btm_test(btm, x, y)) {
1274 i_glin(im, start, x, y, line);
1275 (fill->fill_with_color)(fill, start, y, x-start, im->channels,
1277 i_plin(im, start, x, y, line);
1286 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1287 i_fcolor *work = NULL;
1289 work = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1291 for(y=bymin;y<=bymax;y++) {
1294 while (x < bxmax && !btm_test(btm, x, y)) {
1297 if (btm_test(btm, x, y)) {
1299 while (x < bxmax && btm_test(btm, x, y)) {
1303 i_glinf(im, start, x, y, line);
1304 (fill->fill_with_fcolor)(fill, start, y, x-start, im->channels,
1306 i_plinf(im, start, x, y, line);