6 i_mmarray_cr(i_mmarray *ar,int l) {
10 ar->data=mymalloc(sizeof(minmax)*l);
11 for(i=0;i<l;i++) { ar->data[i].max=-1; ar->data[i].min=MAXINT; }
15 i_mmarray_dst(i_mmarray *ar) {
17 if (ar->data != NULL) { myfree(ar->data); ar->data=NULL; }
21 i_mmarray_add(i_mmarray *ar,int x,int y) {
22 if (y>-1 && y<ar->lines)
24 if (x<ar->data[y].min) ar->data[y].min=x;
25 if (x>ar->data[y].max) ar->data[y].max=x;
30 i_mmarray_gmin(i_mmarray *ar,int y) {
31 if (y>-1 && y<ar->lines) return ar->data[y].min;
36 i_mmarray_getm(i_mmarray *ar,int y) {
37 if (y>-1 && y<ar->lines) return ar->data[y].max;
42 i_mmarray_render(i_img *im,i_mmarray *ar,i_color *val) {
44 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_arcdraw(int x1, int y1, int x2, int y2, i_mmarray *ar) {
54 alpha=(double)(y2-y1)/(double)(x2-x1);
57 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
62 i_mmarray_add(ar,x1,(int)(dsec+0.5));
69 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
74 i_mmarray_add(ar,(int)(dsec+0.5),y1);
81 i_mmarray_info(i_mmarray *ar) {
83 for(i=0;i<ar->lines;i++)
84 if (ar->data[i].max!=-1) printf("line %d: min=%d, max=%d.\n",i,ar->data[i].min,ar->data[i].max);
89 i_arc(i_img *im,int x,int y,float rad,float d1,float d2,i_color *val) {
94 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));
96 i_mmarray_cr(&dot,im->ysize);
98 x1=(int)(x+0.5+rad*cos(d1*PI/180.0));
99 y1=(int)(y+0.5+rad*sin(d1*PI/180.0));
100 fx=(float)x1; fy=(float)y1;
102 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
103 i_arcdraw(x, y, x1, y1, &dot);
105 x1=(int)(x+0.5+rad*cos(d2*PI/180.0));
106 y1=(int)(y+0.5+rad*sin(d2*PI/180.0));
108 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)));
110 /* printf("x1: %d.\ny1: %d.\n",x1,y1); */
111 i_arcdraw(x, y, x1, y1, &dot);
114 i_mmarray_render(im,&dot,val);
118 i_box(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
120 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));
121 for(x=x1;x<x2+1;x++) {
125 for(y=y1;y<y2+1;y++) {
132 i_box_filled(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
134 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));
135 for(x=x1;x<x2+1;x++) for (y=y1;y<y2+1;y++) i_ppix(im,x,y,val);
140 i_draw(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
145 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));
147 alpha=(double)(y2-y1)/(double)(x2-x1);
150 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
155 i_ppix(im,x1,(int)(dsec+0.5),val);
162 if (y2<y1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
167 i_ppix(im,(int)(dsec+0.5),y1,val);
171 mm_log((1,"i_draw: alpha=%f.\n",alpha));
175 i_line_aa(i_img *im,int x1,int y1,int x2,int y2,i_color *val) {
179 int temp,dx,dy,isec,ch;
181 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));
186 if (abs(dx)>abs(dy)) { /* alpha < 1 */
187 if (x2<x1) { temp=x1; x1=x2; x2=temp; temp=y1; y1=y2; y2=temp; }
188 alpha=(float)(y2-y1)/(float)(x2-x1);
194 /* dfrac=1-(1-dfrac)*(1-dfrac); */
195 /* This is something we can play with to try to get better looking lines */
197 i_gpix(im,x1,isec,&tval);
198 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
199 i_ppix(im,x1,isec,&tval);
201 i_gpix(im,x1,isec+1,&tval);
202 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
203 i_ppix(im,x1,isec+1,&tval);
209 if (y2<y1) { temp=y1; y1=y2; y2=temp; temp=x1; x1=x2; x2=temp; }
210 alpha=(float)(x2-x1)/(float)(y2-y1);
215 /* dfrac=sqrt(dfrac); */
216 /* This is something we can play with */
217 i_gpix(im,isec,y1,&tval);
218 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)(dfrac*(float)tval.channel[ch]+(1-dfrac)*(float)val->channel[ch]);
219 i_ppix(im,isec,y1,&tval);
221 i_gpix(im,isec+1,y1,&tval);
222 for(ch=0;ch<im->channels;ch++) tval.channel[ch]=(unsigned char)((1-dfrac)*(float)tval.channel[ch]+dfrac*(float)val->channel[ch]);
223 i_ppix(im,isec+1,y1,&tval);
236 for(i=k+1;i<=n;i++) r*=i;
237 for(i=1;i<=(n-k);i++) r/=i;
242 /* Note in calculating t^k*(1-t)^(n-k)
243 we can start by using t^0=1 so this simplifies to
244 t^0*(1-t)^n - we want to multiply that with t/(1-t) each iteration
245 to get a new level - this may lead to errors who knows lets test it */
248 i_bezier_multi(i_img *im,int l,double *x,double *y,i_color *val) {
257 bzcoef=mymalloc(sizeof(double)*l);
258 for(k=0;k<l;k++) bzcoef[k]=perm(n,k);
262 /* for(k=0;k<l;k++) printf("bzcoef: %d -> %f\n",k,bzcoef[k]); */
264 for(t=0;t<=1;t+=0.005) {
269 /* cx+=bzcoef[k]*x[k]*pow(t,k)*pow(1-t,n-k);
270 cy+=bzcoef[k]*y[k]*pow(t,k)*pow(1-t,n-k);*/
272 cx+=bzcoef[k]*x[k]*ccoef;
273 cy+=bzcoef[k]*y[k]*ccoef;
276 /* printf("%f -> (%d,%d)\n",t,(int)(0.5+cx),(int)(0.5+cy)); */
278 i_line_aa(im,lx,ly,(int)(0.5+cx),(int)(0.5+cy),val);
280 /* i_ppix(im,(int)(0.5+cx),(int)(0.5+cy),val); */
292 REF: Graphics Gems I. page 282+
311 /* This should be moved into a seperate file? */
313 /* This is the truncation used:
315 a double is multiplied by 16 and then truncated.
316 This means that 0 -> 0
317 So a triangle of (0,0) (10,10) (10,0) Will look like it's
318 not filling the (10,10) point nor the (10,0)-(10,10) line segment
325 #define IMTRUNC(x) ((int)(x*16))
354 p_compy(const struct p_point *p1, const struct p_point *p2) {
355 if (p1->y > p2->y) return 1;
356 if (p1->y < p2->y) return -1;
361 p_compx(const struct p_slice *p1, const struct p_slice *p2) {
362 if (p1->x > p2->x) return 1;
363 if (p1->x < p2->x) return -1;
367 /* Change this to int? and round right goddamn it! */
370 p_eval_aty(struct p_line *l,pcord y) {
373 if (t) return ( (y-l->y1)*l->x2 + (l->y2-y)*l->x1 )/t;
374 return (l->x1+l->x2)/2.0;
378 p_eval_atx(struct p_line *l,pcord x) {
381 if (t) return ( (x-l->x1)*l->y2 + (l->x2-x)*l->y1 )/t;
382 return (l->y1+l->y2)/2.0;
386 /* Algorithm to count the pixels covered by line going through pixel (x,y)
392 p_eval_coverage(struct p_line *l, int lc, int x, pcord y1, pcord y2) {
399 /* Antialiasing polygon algorithm
401 1. only nice polygons - no crossovers
402 2. 1/16 pixel resolution # previously - floating point co-ordinates
403 3. full antialiasing ( complete spectrum of blends )
404 4. uses hardly any memory
405 5. no subsampling phase
407 For each interval we must:
408 1. find which lines are in it
409 2. order the lines from in increasing x order.
410 since we are assuming no crossovers it is sufficent
411 to check a single point on each line.
417 1. Interval: A vertical segment in which no lines cross nor end.
418 2. Scanline: A physical line, contains 16 subpixels in the horizontal direction
419 3. Slice: A start stop line pair.
425 The variable tempflush describes if there is anything in the templine array or not.
427 if tempflush is 0 then the array is clean.
428 if tempflush is 1 then the array contains a partial filled scanline
432 /* Rendering of a single start stop pair:
436 The rendering is split in three parts
437 1. From the first start pixel to the first stop pixel
438 2. Area from the first end pixel to the last start pixel
439 3. Area from the first end pixel to the last start pixel
445 i_poly_aa(i_img *im,int l,double *x,double *y,i_color *val) {
446 int i,k; /* Index variables */
447 int clc; /* Index of next item on interval linelist */
448 int tx; /* Coarse x coord within a scanline */
449 pcord miny,maxy; /* Min and max values of the current slice in the subcord system */
450 pcord minacy,maxacy; /* Min and max values of the current scanline bounded by the slice
451 in the subcord system */
452 int cscl; /* Current scanline */
453 pcord cc; /* Current vertical centerpoint of interval */
455 int minsx,minex,maxsx,maxex; /* The horizontal stretches of the lines beloning to the current slice within a scanline */
456 int *templine; /* Line accumulator */
458 struct p_point *pset; /* List of points in polygon */
459 struct p_line *lset; /* List of lines in polygon */
460 struct p_slice *tllist; /* List of slices */
462 i_color red,blue,yellow;
475 if ( (pset=mymalloc(sizeof(struct p_point)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
476 if ( (lset=mymalloc(sizeof(struct p_line)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
477 if ( (tllist=mymalloc(sizeof(struct p_slice)*l)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
478 if ( (templine=mymalloc(sizeof(int)*im->xsize)) == NULL) { m_fatal(2,"malloc failed\n"); return; }
480 /* insert the lines into the line list */
484 pset[i].x=IMTRUNC(x[i]);
485 pset[i].y=IMTRUNC(y[i]);
487 lset[i].x1=IMTRUNC(x[i]);
488 lset[i].y1=IMTRUNC(y[i]);
489 lset[i].x2=IMTRUNC(x[(i+1)%l]);
490 lset[i].y2=IMTRUNC(y[(i+1)%l]);
491 lset[i].miny=min(lset[i].y1,lset[i].y2);
492 lset[i].maxy=max(lset[i].y1,lset[i].y2);
495 qsort(pset,l,sizeof(struct p_point),(int(*)(const void *,const void *))p_compy);
497 printf("post point list (sorted in ascending y order)\n");
499 printf("%d [ %d ] %d %d\n",i,pset[i].n,pset[i].x,pset[i].y);
502 printf("line list\n");
504 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);
507 printf("MAIN LOOP\n\n");
509 /* Zero templine buffer */
510 /* Templine buffer flushed everytime a scan line ends */
511 for(i=0;i<im->xsize;i++) templine[i]=0;
514 /* loop on intervals */
516 cc=(pset[i].y+pset[i+1].y)/2;
517 printf("current slice is: %d to %d ( cpoint %d )\n",pset[i].y,pset[i+1].y,cc);
520 /* stuff this in a function ?? */
522 /* Check what lines belong to interval */
524 printf("checking line: %d [ %d ] (%d , %d) -> (%d, %d) yspan ( %d , %d )",
525 k,lset[k].n,lset[k].x1,lset[k].y1,lset[k].x2,lset[k].y2,lset[k].miny,lset[k].maxy);
526 if (cc >= lset[k].miny && cc <= lset[k].maxy) {
527 if (lset[k].miny == lset[k].maxy) printf(" HORIZONTAL - skipped\n");
530 tllist[clc].x=p_eval_aty(&lset[k],cc);
533 } else printf(" OUTSIDE\n");
537 at this point a table of pixels that need special care should
538 be generated from the line list - it should be ordered so that only
539 one needs to be checked - options: rendering to a list then order - or
540 rendering in the right order might be possible to do nicely with the
543 1. Draw leftmost pixel for this line
544 2. If preceeding pixel was occupied check next one else go to 1 again.
547 printf("lines in current interval:");
548 for(k=0;k<clc;k++) printf(" %d (%.2f)",tllist[k].n,tllist[k].x);
551 /* evaluate the lines in the middle of the slice */
553 printf("Sort lines left to right within interval\n");
554 qsort(tllist,clc,sizeof(struct p_slice),(int(*)(const void *,const void *))p_compx);
556 printf("sorted lines in interval - output:");
557 for(k=0;k<clc;k++) printf(" %d",tllist[k].n);
563 /* iterate over scanlines */
564 for(cscl=(miny)/16;cscl<=maxy/16;cscl++) {
565 minacy=max(miny,cscl*16);
566 maxacy=min(maxy,cscl*16+15);
568 printf("Scanline bound %d - %d\n",minacy, maxacy);
570 /* iterate over line pairs (slices) within interval */
571 for(k=0;k<clc-1;k+=2) {
573 mt1=p_eval_aty(&lset[tllist[k].n],minacy); /* upper corner */
574 mt2=p_eval_aty(&lset[tllist[k].n],maxacy); /* lower corner */
577 mt1=p_eval_aty(&lset[tllist[k+1].n],minacy); /* upper corner */
578 mt2=p_eval_aty(&lset[tllist[k+1].n],maxacy); /* lower corner */
582 printf("minsx: %d minex: %d\n",minsx,minex);
583 printf("maxsx: %d maxex: %d\n",maxsx,maxex);
585 if (minex/16<maxsx/16) printf("Scan slice is simple!\n");
586 else printf("Scan slice is complicated!\n");
588 if (minsx/16 == minex/16) { /* The line starts and ends in the same pixel */
589 printf("Low slant start pixel\n");
590 templine[minsx/16]=(maxacy-minacy+1)*(minex-minsx+1)/2+((minex | 0xF)-minex)*(maxacy-minacy+1);
592 for(tx=minsx/16;tx<minex/16+1;tx++) {
593 int minx,maxx,minxy,maxxy;
594 minx=max(minsx, tx*16 );
595 maxx=min(minex, tx*16+15);
598 templine[tx]=(maxacy-minacy+1);
601 minxy=p_eval_atx(&lset[tllist[k].n], minx);
602 maxxy=p_eval_atx(&lset[tllist[k].n], maxx);
604 templine[tx]+=(abs(minxy-maxxy)+1)*(minex-minsx+1)/2; /* The triangle between the points */
605 if (mt1 < mt2) { /* \ slant */
606 /* ((minex | 0xF)-minex)*(maxacy-minacy+1); FIXME: unfinished */
611 templine[tx]+=((minex | 0xF)-minex)*(maxacy-minacy+1);
618 for(tx=maxsx/16;tx<maxex/16+1;tx++) templine[tx]+=16*(maxacy-minacy+1);
620 /* for(tx=minex/16+1;tx<maxsx/16;tx++) 0; */
623 printf("line %d: painting %d - %d\n",cscl,minex/16+1,maxsx/16);
624 if ( (minacy != cscl*16) || (maxacy != cscl*16+15) ) {
625 for(tx=minsx/16;tx<maxex/16+1;tx++) {
626 i_ppix(im,tx,cscl,&yellow);
630 for(tx=minsx/16;tx<minex/16+1;tx++) i_ppix(im,tx,cscl,&red);
631 for(tx=maxsx/16;tx<maxex/16+1;tx++) i_ppix(im,tx,cscl,&blue);
632 for(tx=minex/16+1;tx<maxsx/16;tx++) i_ppix(im,tx,cscl,val);
646 /* Flood fill algorithm - based on the Ken Fishkins (pixar) gem in
661 struct stack_element {
669 /* create the link data to put push onto the stack */
672 struct stack_element*
673 crdata(int left,int right,int dadl,int dadr,int y, int dir) {
674 struct stack_element *ste;
675 ste=(struct stack_element*)mymalloc(sizeof(struct stack_element));
681 ste->myDirection=dir;
685 /* i_ccomp compares two colors and gives true if they are the same */
688 i_ccomp(i_color *val1,i_color *val2,int ch) {
690 for(i=0;i<ch;i++) if (val1->channel[i] !=val2->channel[i]) return 0;
696 i_lspan(i_img *im,int seedx,int seedy,i_color *val) {
699 if (seedx-1 < 0) break;
700 i_gpix(im,seedx-1,seedy,&cval);
701 if (!i_ccomp(val,&cval,im->channels)) break;
708 i_rspan(i_img *im,int seedx,int seedy,i_color *val) {
711 if (seedx+1 > im->xsize-1) break;
712 i_gpix(im,seedx+1,seedy,&cval);
713 if (!i_ccomp(val,&cval,im->channels)) break;
719 /* Macro to create a link and push on to the list */
721 #define ST_PUSH(left,right,dadl,dadr,y,dir) { struct stack_element *s=crdata(left,right,dadl,dadr,y,dir); llist_push(st,&s);}
723 /* pops the shadow on TOS into local variables lx,rx,y,direction,dadLx and dadRx */
724 /* No overflow check! */
726 #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); }
728 #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); }
730 #define SET(x,y) btm_set(btm,x,y);
732 #define INSIDE(x,y) ((!btm_test(btm,x,y) && ( i_gpix(im,x,y,&cval),i_ccomp(&val,&cval,channels) ) ))
735 i_flood_fill(i_img *im,int seedx,int seedy,i_color *dcol) {
747 int bxmin=seedx,bxmax=seedx,bymin=seedy,bymax=seedy;
750 struct i_bitmap *btm;
752 int channels,xsize,ysize;
755 channels=im->channels;
759 btm=btm_new(xsize,ysize);
760 st=llist_new(100,sizeof(struct stack_element*));
762 /* Get the reference color */
763 i_gpix(im,seedx,seedy,&val);
765 /* Find the starting span and fill it */
766 lx=i_lspan(im,seedx,seedy,&val);
767 rx=i_rspan(im,seedx,seedy,&val);
769 /* printf("span: %d %d \n",lx,rx); */
771 for(x=lx;x<=rx;x++) SET(x,seedy);
773 ST_PUSH(lx,rx,lx,rx,seedy+1,1);
774 ST_PUSH(lx,rx,lx,rx,seedy-1,-1);
779 if (y<0 || y>ysize-1) continue;
781 if (bymin > y) bymin=y; /* in the worst case an extra line */
782 if (bymax < y) bymax=y;
784 /* printf("start of scan - on stack : %d \n",st->count); */
787 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction); */
791 for(tx=0;tx<xsize;tx++) printf("%d",tx%10);
793 for(ty=0;ty<ysize;ty++) {
795 for(tx=0;tx<xsize;tx++) printf("%d",!!btm_test(btm,tx,ty));
804 if ( (wasIn = INSIDE(lx,y)) ) {
807 while(INSIDE(lx,y) && lx > 0) {
813 if (bxmin > lx) bxmin=lx;
815 while(x <= xsize-1) {
816 /* printf("x=%d\n",x); */
820 /* case 1: was inside, am still inside */
823 /* case 2: was inside, am no longer inside: just found the
824 right edge of a span */
825 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
827 if (bxmax < x) bxmax=x;
835 /* case 3: Wasn't inside, am now: just found the start of a new run */
839 /* case 4: Wasn't inside, still isn't */
844 EXT: /* out of loop */
846 /* hit an edge of the frame buffer while inside a run */
847 ST_STACK(direction,dadLx,dadRx,lx,(x-1),y);
848 if (bxmax < x) bxmax=x;
852 /* printf("lx=%d rx=%d dadLx=%d dadRx=%d y=%d direction=%d\n",lx,rx,dadLx,dadRx,y,direction);
853 printf("bounding box: [%d,%d] - [%d,%d]\n",bxmin,bymin,bxmax,bymax); */
855 for(y=bymin;y<=bymax;y++) for(x=bxmin;x<=bxmax;x++) if (btm_test(btm,x,y)) i_ppix(im,x,y,dcol);