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);
54 for(y=0;y<ar->lines;y++) {
55 if (ar->data[y].max!=-1) {
57 w = ar->data[y].max-ar->data[y].min;
60 i_glin(im, x, x+w, y, line);
62 (fill->fill_with_color)(fill, x, y, w, im->channels, line);
63 i_plin(im, x, x+w, y, line);
70 i_fcolor *line = mymalloc(sizeof(i_fcolor) * im->xsize);
71 for(y=0;y<ar->lines;y++) {
72 if (ar->data[y].max!=-1) {
74 w = ar->data[y].max-ar->data[y].min;
77 i_glinf(im, x, x+w, y, line);
79 (fill->fill_with_fcolor)(fill, x, y, w, im->channels, line);
80 i_plinf(im, x, x+w, y, line);
91 i_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
95 alpha=(double)(y2-y1)/(double)(x2-x1);
98 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
103 i_mmarray_add(ar,x1,(int)(dsec+0.5));
110 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
115 i_mmarray_add(ar,(int)(dsec+0.5),y1);
122 i_mmarray_info(i_mmarray *ar) {
124 for(i=0;i<ar->lines;i++)
125 if (ar->data[i].max!=-1) printf("line %d: min=%d, max=%d.\n",i,ar->data[i].min,ar->data[i].max);
130 i_arc(i_img *im,int x,int y,float rad,float d1,float d2,i_color *val) {
135 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));
137 i_mmarray_cr(&dot,im->ysize);
139 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
140 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
141 fx=(float)x1; fy=(float)y1;
143 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
144 i_arcdraw(x, y, x1, y1, &dot);
146 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
147 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
149 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)));
151 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
152 i_arcdraw(x, y, x1, y1, &dot);
155 i_mmarray_render(im,&dot,val);
159 i_arc_cfill(i_img *im,int x,int y,float rad,float d1,float d2,i_fill_t *fill) {
164 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));
166 i_mmarray_cr(&dot,im->ysize);
168 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
169 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
170 fx=(float)x1; fy=(float)y1;
172 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
173 i_arcdraw(x, y, x1, y1, &dot);
175 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
176 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
178 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)));
180 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
181 i_arcdraw(x, y, x1, y1, &dot);
184 i_mmarray_render_fill(im,&dot,fill);
189 /* Temporary AA HACK */
193 static frac float_to_frac(float x) { return (frac)(0.5+x*16.0); }
194 static int frac_sub (frac x) { return (x%16); }
195 static int frac_int (frac x) { return (x/16); }
196 static float frac_to_float(float x) { return (float)x/16.0; }
200 polar_to_plane(float cx, float cy, float angle, float radius, frac *x, frac *y) {
201 *x = float_to_frac(cx+radius*cos(angle));
202 *y = float_to_frac(cy+radius*sin(angle));
207 order_pair(frac *x, frac *y) {
220 make_minmax_list(i_mmarray *dot, float x, float y, float radius) {
222 float astep = radius>0.1 ? .5/radius : 10;
223 frac cx, cy, lx, ly, sx, sy;
225 mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
227 polar_to_plane(x, y, angle, radius, &sx, &sy);
229 for(angle = 0.0; angle<361; angle +=astep) {
232 polar_to_plane(x, y, angle, radius, &cx, &cy);
235 if (fabs(cx-lx) > fabs(cy-ly)) {
238 ccx = lx; lx = cx; cx = ccx;
239 ccy = ly; ly = cy; cy = ccy;
242 for(ccx=lx; ccx<=cx; ccx++) {
243 ccy = ly + ((cy-ly)*(ccx-lx))/(cx-lx);
244 i_mmarray_add(dot, ccx, ccy);
250 ccy = ly; ly = cy; cy = ccy;
251 ccx = lx; lx = cx; cx = ccx;
254 for(ccy=ly; ccy<=cy; ccy++) {
255 if (cy-ly) ccx = lx + ((cx-lx)*(ccy-ly))/(cy-ly); else ccx = lx;
256 i_mmarray_add(dot, ccx, ccy);
262 /* Get the number of subpixels covered */
266 i_pixel_coverage(i_mmarray *dot, int x, int y) {
272 for(cy=y*16; cy<(y+1)*16; cy++) {
273 frac tmin = dot->data[cy].min;
274 frac tmax = dot->data[cy].max;
276 if (tmax == -1 || tmin > maxx || tmax < minx) continue;
278 if (tmin < minx) tmin = minx;
279 if (tmax > maxx) tmax = maxx;
287 i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) {
292 mm_log((1, "i_circle_aa(im %p, x %d, y %d, rad %.2f, val %p)\n", im, x, y, rad, val));
294 i_mmarray_cr(&dot,16*im->ysize);
295 make_minmax_list(&dot, x, y, rad);
297 for(ly = 0; ly<im->ysize; ly++) {
298 int ix, cy, cnt = 0, minx = INT_MAX, maxx = INT_MIN;
300 /* Find the left/rightmost set subpixels */
301 for(cy = 0; cy<16; cy++) {
302 frac tmin = dot.data[ly*16+cy].min;
303 frac tmax = dot.data[ly*16+cy].max;
304 if (tmax == -1) continue;
306 if (minx > tmin) minx = tmin;
307 if (maxx < tmax) maxx = tmax;
310 if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */
314 for(ix=minx; ix<=maxx; ix++) {
315 int cnt = i_pixel_coverage(&dot, ix, ly);
316 if (cnt>255) cnt = 255;
317 if (cnt) { /* should never be true */
319 float ratio = (float)cnt/255.0;
320 i_gpix(im, ix, ly, &temp);
321 for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
322 i_ppix(im, ix, ly, &temp);
334 i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
336 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));
337 for(x=x1;x<x2+1;x++) {
341 for(y=y1;y<y2+1;y++) {
348 i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
350 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));
351 for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
355 i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) {
356 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));
359 if (im->bits == i_8_bits && fill->fill_with_color) {
360 i_color *line = mymalloc(sizeof(i_color) * (x2 - x1));
363 i_glin(im, x1, x2, y1, line);
365 (fill->fill_with_color)(fill, x1, y1, x2-x1, im->channels, line);
366 i_plin(im, x1, x2, y1, line);
372 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (x2 - x1));
375 i_glinf(im, x1, x2, y1, line);
377 (fill->fill_with_fcolor)(fill, x1, y1, x2-x1, im->channels, line);
378 i_plinf(im, x1, x2, y1, line);
386 i_draw(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
391 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));
393 alpha=(double)(y2-y1)/(double)(x2-x1);
396 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
401 i_ppix(im,x1,(int)(dsec+0.5),val);
408 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
413 i_ppix(im,(int)(dsec+0.5),y1,val);
417 mm_log((1,"i_draw: alpha=%f.\n",alpha));
421 i_line_aa(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
425 int temp,dx,dy,isec,ch;
427 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));
432 if (abs(dx)>abs(dy)) { /* alpha < 1 */
433 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
434 alpha=(float)(y2-y1)/(float)(x2-x1);
440 /* dfrac=1-(1-dfrac)*(1-dfrac); */
441 /* This is something we can play with to try to get better looking lines */
443 i_gpix(im,x1,isec,&tval);
444 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
445 i_ppix(im,x1,isec,&tval);
447 i_gpix(im,x1,isec+1,&tval);
448 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
449 i_ppix(im,x1,isec+1,&tval);
455 if (y2<y1) { temp=y1; y1=y2; y2=temp; temp=x1; x1=x2; x2=temp; }
456 alpha=(float)(x2-x1)/(float)(y2-y1);
461 /* dfrac=sqrt(dfrac); */
462 /* This is something we can play with */
463 i_gpix(im,isec,y1,&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,isec,y1,&tval);
467 i_gpix(im,isec+1,y1,&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,isec+1,y1,&tval);
482 for(i=k+1;i<=n;i++) r*=i;
483 for(i=1;i<=(n-k);i++) r/=i;
488 /* Note in calculating t^k*(1-t)^(n-k)
489 we can start by using t^0=1 so this simplifies to
490 t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration
491 to get a new level - this may lead to errors who knows lets test it */
494 i_bezier_multi(i_img *im,int l,double *x,double *y,i_color *val) {
503 bzcoef=mymalloc(sizeof(double)*l);
504 for(k=0;k<l;k++) bzcoef[k]=perm(n,k);
508 /* for(k=0;k<l;k++) printf("bzcoef: %d -> %f\n",k,bzcoef[k]); */
510 for(t=0;t<=1;t+=0.005) {
515 /* cx+=bzcoef[k]*x[k]*pow(t,k)*pow(1-t,n-k);
516 cy+=bzcoef[k]*y[k]*pow(t,k)*pow(1-t,n-k);*/
518 cx+=bzcoef[k]*x[k]*ccoef;
519 cy+=bzcoef[k]*y[k]*ccoef;
522 /* printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
524 i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val);
526 /* i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
538 REF: Graphics Gems I. page 282+
557 /* This should be moved into a seperate file? */
559 /* This is the truncation used:
561 a double is multiplied by 16 and then truncated.
562 This means that 0 -> 0
563 So a triangle of (0,0) (10,10) (10,0) Will look like it's
564 not filling the (10,10) point nor the (10,0)-(10,10) line segment
571 #define IMTRUNC(x) ((int)(x*16))
600 p_compy(const struct p_point *p1, const struct p_point *p2) {
601 if (p1->y > p2->y) return 1;
602 if (p1->y < p2->y) return -1;
607 p_compx(const struct p_slice *p1, const struct p_slice *p2) {
608 if (p1->x > p2->x) return 1;
609 if (p1->x < p2->x) return -1;
613 /* Change this to int? and round right goddamn it! */
616 p_eval_aty(struct p_line *l,pcord y) {
619 if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t;
620 return (l->x1+l->x2)/2.0;
624 p_eval_atx(struct p_line *l,pcord x) {
627 if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t;
628 return (l->y1+l->y2)/2.0;
632 /* Algorithm to count the pixels covered by line going through pixel (x,y)
638 p_eval_coverage(struct p_line *l, int lc, int x, pcord y1, pcord y2) {
645 /* Antialiasing polygon algorithm
647 1. only nice polygons - no crossovers
648 2. 1/16 pixel resolution # previously - floating point co-ordinates
649 3. full antialiasing ( complete spectrum of blends )
650 4. uses hardly any memory
651 5. no subsampling phase
653 For each interval we must:
654 1. find which lines are in it
655 2. order the lines from in increasing x order.
656 since we are assuming no crossovers it is sufficent
657 to check a single point on each line.
663 1. Interval: A vertical segment in which no lines cross nor end.
664 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction
665 3. Slice: A start stop line pair.
671 The variable tempflush describes if there is anything in the templine array or not.
673 if tempflush is 0 then the array is clean.
674 if tempflush is 1 then the array contains a partial filled scanline
678 /* Rendering of a single start stop pair:
682 The rendering is split in three parts
683 1. From the first start pixel to the first stop pixel
684 2. Area from the first end pixel to the last start pixel
685 3. Area from the first end pixel to the last start pixel
691 i_poly_aa(i_img *im,int l,double *x,double *y,i_color *val) {
692 int i,k; /* Index variables */
693 int clc; /* Index of next item on interval linelist */
694 int tx; /* Coarse x coord within a scanline */
695 pcord miny,maxy; /* Min and max values of the current slice in the subcord system */
696 pcord minacy,maxacy; /* Min and max values of the current scanline bounded by the slice
697 in the subcord system */
698 int cscl; /* Current scanline */
699 pcord cc; /* Current vertical centerpoint of interval */
701 int minsx,minex,maxsx,maxex; /* The horizontal stretches of the lines beloning to the current slice within a scanline */
702 int *templine; /* Line accumulator */
704 struct p_point *pset; /* List of points in polygon */
705 struct p_line *lset; /* List of lines in polygon */
706 struct p_slice *tllist; /* List of slices */
708 i_color red,blue,yellow;
721 if ( (pset=mymalloc(sizeof(struct p_point)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
722 if ( (lset=mymalloc(sizeof(struct p_line)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
723 if ( (tllist=mymalloc(sizeof(struct p_slice)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
724 if ( (templine=mymalloc(sizeof(int)*im->xsize)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
726 /* insert the lines into the line list */
730 pset[i].x=IMTRUNC(x[i]);
731 pset[i].y=IMTRUNC(y[i]);
733 lset[i].x1=IMTRUNC(x[i]);
734 lset[i].y1=IMTRUNC(y[i]);
735 lset[i].x2=IMTRUNC(x[(i+1)%l]);
736 lset[i].y2=IMTRUNC(y[(i+1)%l]);
737 lset[i].miny=min(lset[i].y1,lset[i].y2);
738 lset[i].maxy=max(lset[i].y1,lset[i].y2);
741 qsort(pset,l,sizeof(struct p_point),(int(*)(const void *,const void *))p_compy);
743 printf("post point list (sorted in ascending y order)\n");
745 printf("%d [ %d ] %d %d\n",i,pset[i].n,pset[i].x,pset[i].y);
748 printf("line list\n");
750 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);
753 printf("MAIN LOOP\n\n");
755 /* Zero templine buffer */
756 /* Templine buffer flushed everytime a scan line ends */
757 for(i=0;i<im->xsize;i++) templine[i]=0;
760 /* loop on intervals */
762 cc=(pset[i].y+pset[i+1].y)/2;
763 printf("current slice is: %d to %d ( cpoint %d )\n",pset[i].y,pset[i+1].y,cc);
766 /* stuff this in a function ?? */
768 /* Check what lines belong to interval */
770 printf("checking line: %d [ %d ] (%d , %d) -> (%d, %d) yspan ( %d , %d )",
771 k,lset[k].n,lset[k].x1,lset[k].y1,lset[k].x2,lset[k].y2,lset[k].miny,lset[k].maxy);
772 if (cc >= lset[k].miny && cc <= lset[k].maxy) {
773 if (lset[k].miny == lset[k].maxy) printf(" HORIZONTAL - skipped\n");
776 tllist[clc].x=p_eval_aty(&lset[k],cc);
779 } else printf(" OUTSIDE\n");
783 at this point a table of pixels that need special care should
784 be generated from the line list - it should be ordered so that only
785 one needs to be checked - options: rendering to a list then order - or
786 rendering in the right order might be possible to do nicely with the
789 1. Draw leftmost pixel for this line
790 2. If preceeding pixel was occupied check next one else go to 1 again.
793 printf("lines in current interval:");
794 for(k=0;k<clc;k++) printf(" %d (%.2f)",tllist[k].n,tllist[k].x);
797 /* evaluate the lines in the middle of the slice */
799 printf("Sort lines left to right within interval\n");
800 qsort(tllist,clc,sizeof(struct p_slice),(int(*)(const void *,const void *))p_compx);
802 printf("sorted lines in interval - output:");
803 for(k=0;k<clc;k++) printf(" %d",tllist[k].n);
809 /* iterate over scanlines */
810 for(cscl=(miny)/16;cscl<=maxy/16;cscl++) {
811 minacy=max(miny,cscl*16);
812 maxacy=min(maxy,cscl*16+15);
814 printf("Scanline bound %d - %d\n",minacy, maxacy);
816 /* iterate over line pairs (slices) within interval */
817 for(k=0;k<clc-1;k+=2) {
819 mt1=p_eval_aty(&lset[tllist[k].n],minacy); /* upper corner */
820 mt2=p_eval_aty(&lset[tllist[k].n],maxacy); /* lower corner */
823 mt1=p_eval_aty(&lset[tllist[k+1].n],minacy); /* upper corner */
824 mt2=p_eval_aty(&lset[tllist[k+1].n],maxacy); /* lower corner */
828 printf("minsx: %d minex: %d\n",minsx,minex);
829 printf("maxsx: %d maxex: %d\n",maxsx,maxex);
831 if (minex/16<maxsx/16) printf("Scan slice is simple!\n");
832 else printf("Scan slice is complicated!\n");
834 if (minsx/16 == minex/16) { /* The line starts and ends in the same pixel */
835 printf("Low slant start pixel\n");
836 templine[minsx/16]=(maxacy-minacy+1)*(minex-minsx+1)/2+((minex | 0xF)-minex)*(maxacy-minacy+1);
838 for(tx=minsx/16;tx<minex/16+1;tx++) {
839 int minx,maxx,minxy,maxxy;
840 minx=max(minsx, tx*16 );
841 maxx=min(minex, tx*16+15);
844 templine[tx]=(maxacy-minacy+1);
847 minxy=p_eval_atx(&lset[tllist[k].n], minx);
848 maxxy=p_eval_atx(&lset[tllist[k].n], maxx);
850 templine[tx]+=(abs(minxy-maxxy)+1)*(minex-minsx+1)/2; /* The triangle between the points */
851 if (mt1 < mt2) { /* \ slant */
852 /* ((minex | 0xF)-minex)*(maxacy-minacy+1); FIXME: unfinished */
857 templine[tx]+=((minex | 0xF)-minex)*(maxacy-minacy+1);
864 for(tx=maxsx/16;tx<maxex/16+1;tx++) templine[tx]+=16*(maxacy-minacy+1);
866 /* for(tx=minex/16+1;tx<maxsx/16;tx++) 0; */
869 printf("line %d: painting %d - %d\n",cscl,minex/16+1,maxsx/16);
870 if ( (minacy != cscl*16) || (maxacy != cscl*16+15) ) {
871 for(tx=minsx/16;tx<maxex/16+1;tx++) {
872 i_ppix(im,tx,cscl,&yellow);
876 for(tx=minsx/16;tx<minex/16+1;tx++) i_ppix(im,tx,cscl,&red);
877 for(tx=maxsx/16;tx<maxex/16+1;tx++) i_ppix(im,tx,cscl,&blue);
878 for(tx=minex/16+1;tx<maxsx/16;tx++) i_ppix(im,tx,cscl,val);
892 /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in
907 struct stack_element {
915 /* create the link data to put push onto the stack */
918 struct stack_element*
919 crdata(int left,int right,int dadl,int dadr,int y, int dir) {
920 struct stack_element *ste;
921 ste=(struct stack_element*)mymalloc(sizeof(struct stack_element));
927 ste->myDirection=dir;
931 /* i_ccomp compares two colors and gives true if they are the same */
934 i_ccomp(i_color *val1,i_color *val2,int ch) {
936 for(i=0;i<ch;i++) if (val1->channel[i] !=val2->channel[i]) return 0;
942 i_lspan(i_img *im,int seedx,int seedy,i_color *val) {
945 if (seedx-1 < 0) break;
946 i_gpix(im,seedx-1,seedy,&cval);
947 if (!i_ccomp(val,&cval,im->channels)) break;
954 i_rspan(i_img *im,int seedx,int seedy,i_color *val) {
957 if (seedx+1 > im->xsize-1) break;
958 i_gpix(im,seedx+1,seedy,&cval);
959 if (!i_ccomp(val,&cval,im->channels)) break;
965 /* Macro to create a link and push on to the list */
967 #define ST_PUSH(left,right,dadl,dadr,y,dir) { struct stack_element *s=crdata(left,right,dadl,dadr,y,dir); llist_push(st,&s);}
969 /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */
970 /* No overflow check! */
972 #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); }
974 #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); }
976 #define SET(x,y) btm_set(btm,x,y);
978 #define INSIDE(x,y) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),i_ccomp(&val,&cval,channels) ) ))
981 i_flood_fill(i_img *im,int seedx,int seedy,i_color *dcol) {
993 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
996 struct i_bitmap *btm;
998 int channels,xsize,ysize;
1001 channels=im->channels;
1005 btm=btm_new(xsize,ysize);
1006 st=llist_new(100,sizeof(struct stack_element*));
1008 /* Get the reference color */
1009 i_gpix(im,seedx,seedy,&val);
1011 /* Find the starting span and fill it */
1012 lx=i_lspan(im,seedx,seedy,&val);
1013 rx=i_rspan(im,seedx,seedy,&val);
1015 /* printf("span: %d %d \n",lx,rx); */
1017 for(x=lx;x<=rx;x++) SET(x,seedy);
1019 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1020 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1025 if (y<0 || y>ysize-1) continue;
1027 if (bymin > y) bymin=y; /* in the worst case an extra line */
1028 if (bymax < y) bymax=y;
1030 /* printf("start of scan - on stack : %d \n",st->count); */
1033 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1037 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1039 for(ty=0;ty<ysize;ty++) {
1041 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1050 if ( (wasIn = INSIDE(lx,y)) ) {
1053 while(INSIDE(lx,y) && lx > 0) {
1059 if (bxmin > lx) bxmin=lx;
1061 while(x <= xsize-1) {
1062 /* printf("x=%d\n",x); */
1066 /* case 1: was inside, am still inside */
1069 /* case 2: was inside, am no longer inside: just found the
1070 right edge of a span */
1071 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1073 if (bxmax < x) bxmax=x;
1081 /* case 3: Wasn't inside, am now: just found the start of a new run */
1085 /* case 4: Wasn't inside, still isn't */
1090 EXT: /* out of loop */
1092 /* hit an edge of the frame buffer while inside a run */
1093 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1094 if (bxmax < x) bxmax=x;
1098 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1099 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1101 for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol);