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);
200 /* Temporary AA HACK */
204 static frac float_to_frac(float x) { return (frac)(0.5+x*16.0); }
205 static int frac_sub (frac x) { return (x%16); }
206 static int frac_int (frac x) { return (x/16); }
207 static float frac_to_float(float x) { return (float)x/16.0; }
211 polar_to_plane(float cx, float cy, float angle, float radius, frac *x, frac *y) {
212 *x = float_to_frac(cx+radius*cos(angle));
213 *y = float_to_frac(cy+radius*sin(angle));
218 order_pair(frac *x, frac *y) {
231 make_minmax_list(i_mmarray *dot, float x, float y, float radius) {
233 float astep = radius>0.1 ? .5/radius : 10;
234 frac cx, cy, lx, ly, sx, sy;
236 mm_log((1, "make_minmax_list(dot %p, x %.2f, y %.2f, radius %.2f)\n", dot, x, y, radius));
238 polar_to_plane(x, y, angle, radius, &sx, &sy);
240 for(angle = 0.0; angle<361; angle +=astep) {
243 polar_to_plane(x, y, angle, radius, &cx, &cy);
246 if (fabs(cx-lx) > fabs(cy-ly)) {
249 ccx = lx; lx = cx; cx = ccx;
250 ccy = ly; ly = cy; cy = ccy;
253 for(ccx=lx; ccx<=cx; ccx++) {
254 ccy = ly + ((cy-ly)*(ccx-lx))/(cx-lx);
255 i_mmarray_add(dot, ccx, ccy);
261 ccy = ly; ly = cy; cy = ccy;
262 ccx = lx; lx = cx; cx = ccx;
265 for(ccy=ly; ccy<=cy; ccy++) {
266 if (cy-ly) ccx = lx + ((cx-lx)*(ccy-ly))/(cy-ly); else ccx = lx;
267 i_mmarray_add(dot, ccx, ccy);
273 /* Get the number of subpixels covered */
277 i_pixel_coverage(i_mmarray *dot, int x, int y) {
283 for(cy=y*16; cy<(y+1)*16; cy++) {
284 frac tmin = dot->data[cy].min;
285 frac tmax = dot->data[cy].max;
287 if (tmax == -1 || tmin > maxx || tmax < minx) continue;
289 if (tmin < minx) tmin = minx;
290 if (tmax > maxx) tmax = maxx;
298 i_circle_aa(i_img *im, float x, float y, float rad, i_color *val) {
303 mm_log((1, "i_circle_aa(im %p, x %d, y %d, rad %.2f, val %p)\n", im, x, y, rad, val));
305 i_mmarray_cr(&dot,16*im->ysize);
306 make_minmax_list(&dot, x, y, rad);
308 for(ly = 0; ly<im->ysize; ly++) {
309 int ix, cy, cnt = 0, minx = INT_MAX, maxx = INT_MIN;
311 /* Find the left/rightmost set subpixels */
312 for(cy = 0; cy<16; cy++) {
313 frac tmin = dot.data[ly*16+cy].min;
314 frac tmax = dot.data[ly*16+cy].max;
315 if (tmax == -1) continue;
317 if (minx > tmin) minx = tmin;
318 if (maxx < tmax) maxx = tmax;
321 if (maxx == INT_MIN) continue; /* no work to be done for this row of pixels */
325 for(ix=minx; ix<=maxx; ix++) {
326 int cnt = i_pixel_coverage(&dot, ix, ly);
327 if (cnt>255) cnt = 255;
328 if (cnt) { /* should never be true */
330 float ratio = (float)cnt/255.0;
331 i_gpix(im, ix, ly, &temp);
332 for(ch=0;ch<im->channels; ch++) temp.channel[ch] = (unsigned char)((float)val->channel[ch]*ratio + (float)temp.channel[ch]*(1.0-ratio));
333 i_ppix(im, ix, ly, &temp);
345 i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
347 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));
348 for(x=x1;x<x2+1;x++) {
352 for(y=y1;y<y2+1;y++) {
359 i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
361 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));
362 for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
366 i_box_cfill(i_img *im,int x1,int y1,int x2,int y2,i_fill_t *fill) {
367 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));
370 if (im->bits == i_8_bits && fill->fill_with_color) {
371 i_color *line = mymalloc(sizeof(i_color) * (x2 - x1));
372 i_color *work = NULL;
374 work = mymalloc(sizeof(i_color) * (x2-x1));
377 i_glin(im, x1, x2, y1, line);
379 (fill->fill_with_color)(fill, x1, y1, x2-x1, im->channels, line, work);
380 i_plin(im, x1, x2, y1, line);
388 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (x2 - x1));
390 work = mymalloc(sizeof(i_fcolor) * (x2 - x1));
394 i_glinf(im, x1, x2, y1, line);
396 (fill->fill_with_fcolor)(fill, x1, y1, x2-x1, im->channels, line, work);
397 i_plinf(im, x1, x2, y1, line);
407 i_draw(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
412 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));
414 alpha=(double)(y2-y1)/(double)(x2-x1);
417 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
422 i_ppix(im,x1,(int)(dsec+0.5),val);
429 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
434 i_ppix(im,(int)(dsec+0.5),y1,val);
438 mm_log((1,"i_draw: alpha=%f.\n",alpha));
442 i_line_aa(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
446 int temp,dx,dy,isec,ch;
448 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));
453 if (abs(dx)>abs(dy)) { /* alpha < 1 */
454 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
455 alpha=(float)(y2-y1)/(float)(x2-x1);
461 /* dfrac=1-(1-dfrac)*(1-dfrac); */
462 /* This is something we can play with to try to get better looking lines */
464 i_gpix(im,x1,isec,&tval);
465 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
466 i_ppix(im,x1,isec,&tval);
468 i_gpix(im,x1,isec+1,&tval);
469 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
470 i_ppix(im,x1,isec+1,&tval);
476 if (y2<y1) { temp=y1; y1=y2; y2=temp; temp=x1; x1=x2; x2=temp; }
477 alpha=(float)(x2-x1)/(float)(y2-y1);
482 /* dfrac=sqrt(dfrac); */
483 /* This is something we can play with */
484 i_gpix(im,isec,y1,&tval);
485 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
486 i_ppix(im,isec,y1,&tval);
488 i_gpix(im,isec+1,y1,&tval);
489 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
490 i_ppix(im,isec+1,y1,&tval);
503 for(i=k+1;i<=n;i++) r*=i;
504 for(i=1;i<=(n-k);i++) r/=i;
509 /* Note in calculating t^k*(1-t)^(n-k)
510 we can start by using t^0=1 so this simplifies to
511 t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration
512 to get a new level - this may lead to errors who knows lets test it */
515 i_bezier_multi(i_img *im,int l,double *x,double *y,i_color *val) {
524 bzcoef=mymalloc(sizeof(double)*l);
525 for(k=0;k<l;k++) bzcoef[k]=perm(n,k);
529 /* for(k=0;k<l;k++) printf("bzcoef: %d -> %f\n",k,bzcoef[k]); */
531 for(t=0;t<=1;t+=0.005) {
536 /* cx+=bzcoef[k]*x[k]*pow(t,k)*pow(1-t,n-k);
537 cy+=bzcoef[k]*y[k]*pow(t,k)*pow(1-t,n-k);*/
539 cx+=bzcoef[k]*x[k]*ccoef;
540 cy+=bzcoef[k]*y[k]*ccoef;
543 /* printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
545 i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val);
547 /* i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
559 REF: Graphics Gems I. page 282+
563 /* This should be moved into a seperate file? */
565 /* This is the truncation used:
567 a double is multiplied by 16 and then truncated.
568 This means that 0 -> 0
569 So a triangle of (0,0) (10,10) (10,0) Will look like it's
570 not filling the (10,10) point nor the (10,0)-(10,10) line segment
577 #define IMTRUNC(x) ((int)(x*16))
606 p_compy(const struct p_point *p1, const struct p_point *p2) {
607 if (p1->y > p2->y) return 1;
608 if (p1->y < p2->y) return -1;
613 p_compx(const struct p_slice *p1, const struct p_slice *p2) {
614 if (p1->x > p2->x) return 1;
615 if (p1->x < p2->x) return -1;
619 /* Change this to int? and round right goddamn it! */
622 p_eval_aty(struct p_line *l,pcord y) {
625 if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t;
626 return (l->x1+l->x2)/2.0;
630 p_eval_atx(struct p_line *l,pcord x) {
633 if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t;
634 return (l->y1+l->y2)/2.0;
638 /* Algorithm to count the pixels covered by line going through pixel (x,y)
644 p_eval_coverage(struct p_line *l, int lc, int x, pcord y1, pcord y2) {
651 /* Antialiasing polygon algorithm
653 1. only nice polygons - no crossovers
654 2. 1/16 pixel resolution # previously - floating point co-ordinates
655 3. full antialiasing ( complete spectrum of blends )
656 4. uses hardly any memory
657 5. no subsampling phase
659 For each interval we must:
660 1. find which lines are in it
661 2. order the lines from in increasing x order.
662 since we are assuming no crossovers it is sufficent
663 to check a single point on each line.
669 1. Interval: A vertical segment in which no lines cross nor end.
670 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction
671 3. Slice: A start stop line pair.
677 The variable tempflush describes if there is anything in the templine array or not.
679 if tempflush is 0 then the array is clean.
680 if tempflush is 1 then the array contains a partial filled scanline
684 /* Rendering of a single start stop pair:
688 The rendering is split in three parts
689 1. From the first start pixel to the first stop pixel
690 2. Area from the first end pixel to the last start pixel
691 3. Area from the first end pixel to the last start pixel
697 i_poly_aa(i_img *im,int l,double *x,double *y,i_color *val) {
698 int i,k; /* Index variables */
699 int clc; /* Index of next item on interval linelist */
700 int tx; /* Coarse x coord within a scanline */
701 pcord miny,maxy; /* Min and max values of the current slice in the subcord system */
702 pcord minacy,maxacy; /* Min and max values of the current scanline bounded by the slice
703 in the subcord system */
704 int cscl; /* Current scanline */
705 pcord cc; /* Current vertical centerpoint of interval */
707 int minsx,minex,maxsx,maxex; /* The horizontal stretches of the lines beloning to the current slice within a scanline */
708 int *templine; /* Line accumulator */
710 struct p_point *pset; /* List of points in polygon */
711 struct p_line *lset; /* List of lines in polygon */
712 struct p_slice *tllist; /* List of slices */
714 i_color red,blue,yellow;
727 if ( (pset=mymalloc(sizeof(struct p_point)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
728 if ( (lset=mymalloc(sizeof(struct p_line)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
729 if ( (tllist=mymalloc(sizeof(struct p_slice)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
730 if ( (templine=mymalloc(sizeof(int)*im->xsize)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
732 /* insert the lines into the line list */
736 pset[i].x=IMTRUNC(x[i]);
737 pset[i].y=IMTRUNC(y[i]);
739 lset[i].x1=IMTRUNC(x[i]);
740 lset[i].y1=IMTRUNC(y[i]);
741 lset[i].x2=IMTRUNC(x[(i+1)%l]);
742 lset[i].y2=IMTRUNC(y[(i+1)%l]);
743 lset[i].miny=min(lset[i].y1,lset[i].y2);
744 lset[i].maxy=max(lset[i].y1,lset[i].y2);
747 qsort(pset,l,sizeof(struct p_point),(int(*)(const void *,const void *))p_compy);
749 printf("post point list (sorted in ascending y order)\n");
751 printf("%d [ %d ] %d %d\n",i,pset[i].n,pset[i].x,pset[i].y);
754 printf("line list\n");
756 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);
759 printf("MAIN LOOP\n\n");
761 /* Zero templine buffer */
762 /* Templine buffer flushed everytime a scan line ends */
763 for(i=0;i<im->xsize;i++) templine[i]=0;
766 /* loop on intervals */
768 cc=(pset[i].y+pset[i+1].y)/2;
769 printf("current slice is: %d to %d ( cpoint %d )\n",pset[i].y,pset[i+1].y,cc);
772 /* stuff this in a function ?? */
774 /* Check what lines belong to interval */
776 printf("checking line: %d [ %d ] (%d , %d) -> (%d, %d) yspan ( %d , %d )",
777 k,lset[k].n,lset[k].x1,lset[k].y1,lset[k].x2,lset[k].y2,lset[k].miny,lset[k].maxy);
778 if (cc >= lset[k].miny && cc <= lset[k].maxy) {
779 if (lset[k].miny == lset[k].maxy) printf(" HORIZONTAL - skipped\n");
782 tllist[clc].x=p_eval_aty(&lset[k],cc);
785 } else printf(" OUTSIDE\n");
789 at this point a table of pixels that need special care should
790 be generated from the line list - it should be ordered so that only
791 one needs to be checked - options: rendering to a list then order - or
792 rendering in the right order might be possible to do nicely with the
795 1. Draw leftmost pixel for this line
796 2. If preceeding pixel was occupied check next one else go to 1 again.
799 printf("lines in current interval:");
800 for(k=0;k<clc;k++) printf(" %d (%.2f)",tllist[k].n,tllist[k].x);
803 /* evaluate the lines in the middle of the slice */
805 printf("Sort lines left to right within interval\n");
806 qsort(tllist,clc,sizeof(struct p_slice),(int(*)(const void *,const void *))p_compx);
808 printf("sorted lines in interval - output:");
809 for(k=0;k<clc;k++) printf(" %d",tllist[k].n);
815 /* iterate over scanlines */
816 for(cscl=(miny)/16;cscl<=maxy/16;cscl++) {
817 minacy=max(miny,cscl*16);
818 maxacy=min(maxy,cscl*16+15);
820 printf("Scanline bound %d - %d\n",minacy, maxacy);
822 /* iterate over line pairs (slices) within interval */
823 for(k=0;k<clc-1;k+=2) {
825 mt1=p_eval_aty(&lset[tllist[k].n],minacy); /* upper corner */
826 mt2=p_eval_aty(&lset[tllist[k].n],maxacy); /* lower corner */
829 mt1=p_eval_aty(&lset[tllist[k+1].n],minacy); /* upper corner */
830 mt2=p_eval_aty(&lset[tllist[k+1].n],maxacy); /* lower corner */
834 printf("minsx: %d minex: %d\n",minsx,minex);
835 printf("maxsx: %d maxex: %d\n",maxsx,maxex);
837 if (minex/16<maxsx/16) printf("Scan slice is simple!\n");
838 else printf("Scan slice is complicated!\n");
840 if (minsx/16 == minex/16) { /* The line starts and ends in the same pixel */
841 printf("Low slant start pixel\n");
842 templine[minsx/16]=(maxacy-minacy+1)*(minex-minsx+1)/2+((minex | 0xF)-minex)*(maxacy-minacy+1);
844 for(tx=minsx/16;tx<minex/16+1;tx++) {
845 int minx,maxx,minxy,maxxy;
846 minx=max(minsx, tx*16 );
847 maxx=min(minex, tx*16+15);
850 templine[tx]=(maxacy-minacy+1);
853 minxy=p_eval_atx(&lset[tllist[k].n], minx);
854 maxxy=p_eval_atx(&lset[tllist[k].n], maxx);
856 templine[tx]+=(abs(minxy-maxxy)+1)*(minex-minsx+1)/2; /* The triangle between the points */
857 if (mt1 < mt2) { /* \ slant */
858 /* ((minex | 0xF)-minex)*(maxacy-minacy+1); FIXME: unfinished */
863 templine[tx]+=((minex | 0xF)-minex)*(maxacy-minacy+1);
870 for(tx=maxsx/16;tx<maxex/16+1;tx++) templine[tx]+=16*(maxacy-minacy+1);
872 /* for(tx=minex/16+1;tx<maxsx/16;tx++) 0; */
875 printf("line %d: painting %d - %d\n",cscl,minex/16+1,maxsx/16);
876 if ( (minacy != cscl*16) || (maxacy != cscl*16+15) ) {
877 for(tx=minsx/16;tx<maxex/16+1;tx++) {
878 i_ppix(im,tx,cscl,&yellow);
882 for(tx=minsx/16;tx<minex/16+1;tx++) i_ppix(im,tx,cscl,&red);
883 for(tx=maxsx/16;tx<maxex/16+1;tx++) i_ppix(im,tx,cscl,&blue);
884 for(tx=minex/16+1;tx<maxsx/16;tx++) i_ppix(im,tx,cscl,val);
898 /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in
913 struct stack_element {
921 /* create the link data to put push onto the stack */
924 struct stack_element*
925 crdata(int left,int right,int dadl,int dadr,int y, int dir) {
926 struct stack_element *ste;
927 ste=(struct stack_element*)mymalloc(sizeof(struct stack_element));
933 ste->myDirection=dir;
937 /* i_ccomp compares two colors and gives true if they are the same */
940 i_ccomp(i_color *val1,i_color *val2,int ch) {
942 for(i=0;i<ch;i++) if (val1->channel[i] !=val2->channel[i]) return 0;
948 i_lspan(i_img *im,int seedx,int seedy,i_color *val) {
951 if (seedx-1 < 0) break;
952 i_gpix(im,seedx-1,seedy,&cval);
953 if (!i_ccomp(val,&cval,im->channels)) break;
960 i_rspan(i_img *im,int seedx,int seedy,i_color *val) {
963 if (seedx+1 > im->xsize-1) break;
964 i_gpix(im,seedx+1,seedy,&cval);
965 if (!i_ccomp(val,&cval,im->channels)) break;
971 /* Macro to create a link and push on to the list */
973 #define ST_PUSH(left,right,dadl,dadr,y,dir) { struct stack_element *s=crdata(left,right,dadl,dadr,y,dir); llist_push(st,&s);}
975 /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */
976 /* No overflow check! */
978 #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); }
980 #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); }
982 #define SET(x,y) btm_set(btm,x,y);
984 #define INSIDE(x,y) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),i_ccomp(&val,&cval,channels) ) ))
987 i_flood_fill(i_img *im,int seedx,int seedy,i_color *dcol) {
999 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1002 struct i_bitmap *btm;
1004 int channels,xsize,ysize;
1007 channels=im->channels;
1011 btm=btm_new(xsize,ysize);
1012 st=llist_new(100,sizeof(struct stack_element*));
1014 /* Get the reference color */
1015 i_gpix(im,seedx,seedy,&val);
1017 /* Find the starting span and fill it */
1018 lx=i_lspan(im,seedx,seedy,&val);
1019 rx=i_rspan(im,seedx,seedy,&val);
1021 /* printf("span: %d %d \n",lx,rx); */
1023 for(x=lx;x<=rx;x++) SET(x,seedy);
1025 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1026 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1031 if (y<0 || y>ysize-1) continue;
1033 if (bymin > y) bymin=y; /* in the worst case an extra line */
1034 if (bymax < y) bymax=y;
1036 /* printf("start of scan - on stack : %d \n",st->count); */
1039 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1043 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1045 for(ty=0;ty<ysize;ty++) {
1047 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1056 if ( (wasIn = INSIDE(lx,y)) ) {
1059 while(INSIDE(lx,y) && lx > 0) {
1065 if (bxmin > lx) bxmin=lx;
1067 while(x <= xsize-1) {
1068 /* printf("x=%d\n",x); */
1072 /* case 1: was inside, am still inside */
1075 /* case 2: was inside, am no longer inside: just found the
1076 right edge of a span */
1077 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1079 if (bxmax < x) bxmax=x;
1087 /* case 3: Wasn't inside, am now: just found the start of a new run */
1091 /* case 4: Wasn't inside, still isn't */
1096 EXT: /* out of loop */
1098 /* hit an edge of the frame buffer while inside a run */
1099 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1100 if (bxmax < x) bxmax=x;
1104 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1105 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1107 for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol);
1113 static struct i_bitmap *
1114 i_flood_fill_low(i_img *im,int seedx,int seedy,
1115 int *bxminp, int *bxmaxp, int *byminp, int *bymaxp) {
1126 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
1129 struct i_bitmap *btm;
1131 int channels,xsize,ysize;
1134 channels=im->channels;
1138 btm=btm_new(xsize,ysize);
1139 st=llist_new(100,sizeof(struct stack_element*));
1141 /* Get the reference color */
1142 i_gpix(im,seedx,seedy,&val);
1144 /* Find the starting span and fill it */
1145 lx=i_lspan(im,seedx,seedy,&val);
1146 rx=i_rspan(im,seedx,seedy,&val);
1148 /* printf("span: %d %d \n",lx,rx); */
1150 for(x=lx;x<=rx;x++) SET(x,seedy);
1152 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
1153 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
1158 if (y<0 || y>ysize-1) continue;
1160 if (bymin > y) bymin=y; /* in the worst case an extra line */
1161 if (bymax < y) bymax=y;
1163 /* printf("start of scan - on stack : %d \n",st->count); */
1166 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
1170 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
1172 for(ty=0;ty<ysize;ty++) {
1174 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
1183 if ( (wasIn = INSIDE(lx,y)) ) {
1186 while(INSIDE(lx,y) && lx > 0) {
1192 if (bxmin > lx) bxmin=lx;
1194 while(x <= xsize-1) {
1195 /* printf("x=%d\n",x); */
1199 /* case 1: was inside, am still inside */
1202 /* case 2: was inside, am no longer inside: just found the
1203 right edge of a span */
1204 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1206 if (bxmax < x) bxmax=x;
1214 /* case 3: Wasn't inside, am now: just found the start of a new run */
1218 /* case 4: Wasn't inside, still isn't */
1223 EXT: /* out of loop */
1225 /* hit an edge of the frame buffer while inside a run */
1226 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
1227 if (bxmax < x) bxmax=x;
1231 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
1232 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
1245 i_flood_cfill(i_img *im, int seedx, int seedy, i_fill_t *fill) {
1246 int bxmin, bxmax, bymin, bymax;
1247 struct i_bitmap *btm;
1251 btm = i_flood_fill_low(im, seedx, seedy, &bxmin, &bxmax, &bymin, &bymax);
1253 if (im->bits == i_8_bits && fill->fill_with_color) {
1254 i_color *line = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1255 i_color *work = NULL;
1257 work = mymalloc(sizeof(i_color) * (bxmax - bxmin));
1259 for(y=bymin;y<=bymax;y++) {
1262 while (x < bxmax && !btm_test(btm, x, y)) {
1265 if (btm_test(btm, x, y)) {
1267 while (x < bxmax && btm_test(btm, x, y)) {
1271 i_glin(im, start, x, y, line);
1272 (fill->fill_with_color)(fill, start, y, x-start, im->channels,
1274 i_plin(im, start, x, y, line);
1283 i_fcolor *line = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1284 i_fcolor *work = NULL;
1286 work = mymalloc(sizeof(i_fcolor) * (bxmax - bxmin));
1288 for(y=bymin;y<=bymax;y++) {
1291 while (x < bxmax && !btm_test(btm, x, y)) {
1294 if (btm_test(btm, x, y)) {
1296 while (x < bxmax && btm_test(btm, x, y)) {
1300 i_glinf(im, start, x, y, line);
1301 (fill->fill_with_fcolor)(fill, start, y, x-start, im->channels,
1303 i_plinf(im, start, x, y, line);