/* Ok, one other line algorithm. * With subpixel and anti-alias, that's the point ! * Starting : Tue Sep 21 17:44:20 MET DST 1999 * Wed Sep 22 00:11:58 MET DST 1999 : almost done. * I had some eating time and washing too, so I did not * spend all this time on it. I must do a max routine * (put the max value between the point and the current * point). Not sure about my anti-alias stuff. Gonna watch some * demos to see what it give with them. * Let's go. */ #include "line.h" #include #include #include #include "screen.h" #include "device.h" #include "poly.h" device_line *the_lines; /* returns a*b/c in int 16:16 */ static inline int muldiv(int a, int b, int c) { #ifdef PC_ARCHI register int r; __asm__ volatile ("imul %2 \n" "idiv %3 \n" : "=a" (r) : "a" (a), "b" (b), "c" (c) : "eax", "ebx", "ecx", "edx" ); return r; #else return (double)a*(double)b/(double)c; #endif } void drawline8(device *d, line *l) { /* lots of goto for lisibility (if if else if if else else is impossible to debug) */ register int x1=l->p1.x*65536., x2=l->p2.x*65536., y1=l->p1.y*65536., y2=l->p2.y*65536., dx, dy; register int xcur; register int xinc; register int ycur; register int yinc; register int i; register int y1i=(y1+65535)>>16, y2i=(y2+65535)>>16; register int x1i=(x1+65535)>>16, x2i=(x2+65535)>>16; register unsigned char *dest; register unsigned char col1=l->color; register int xf; register int yf; /* in asm, those two subs are good for us, because we can test if x10) goto x1_eq_x2_and_y1_inf_y2; /* here x1==x2 && y1==y2 */ if (y1ibuffer+y1i*SCREEN_X+(x1>>16); } else { dest=d->buffer+y2i*SCREEN_X+(x1>>16); } *dest=col1; return; x1_eq_x2_and_y1_sup_y2: dest=d->buffer+y2i*SCREEN_X+(x1>>16); for (i=y2i; ibuffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; i0) goto x1_inf_x2_and_y1_inf_y2; /* x1buffer+(y1>>16)*SCREEN_X+x1i; for (i=x1i; iabs(dy)) goto x1_inf_x2_and_y1_sup_y2_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i>x1i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_sup_y2_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; iabs(dy)) goto x1_inf_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_inf_y2_and_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2: if (dy<0) goto x1_sup_x2_and_y1_sup_y2; if (dy>0) goto x1_sup_x2_and_y1_inf_y2; /* x1>x2 && y1==y2 */ dest=d->buffer+(y2>>16)*SCREEN_X+x2i; for (i=x2i; iabs(dy)) goto x1_sup_x2_and_y1_sup_y2_and_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_sup_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2_and_y1_inf_y2: /* (x1, y1) (x2, y2) */ if (abs(dx)>abs(dy)) goto x1_sup_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i>x2i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_inf_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; ip1.x*65536., x2=l->p2.x*65536., y1=l->p1.y*65536., y2=l->p2.y*65536., dx, dy; register int xcur; register int xinc; register int ycur; register int yinc; register int i; register int y1i=(y1+65535)>>16, y2i=(y2+65535)>>16; register int x1i=(x1+65535)>>16, x2i=(x2+65535)>>16; register unsigned short *dest; register unsigned short col1=l->color; register int xf; register int yf; /* in asm, those two subs are good for us, because we can test if x10) goto x1_eq_x2_and_y1_inf_y2; /* here x1==x2 && y1==y2 */ if (y1ibuffer+y1i*SCREEN_X+(x1>>16); } else { dest=(unsigned short *)d->buffer+y2i*SCREEN_X+(x1>>16); } *dest=col1; return; x1_eq_x2_and_y1_sup_y2: dest=(unsigned short *)d->buffer+y2i*SCREEN_X+(x1>>16); for (i=y2i; ibuffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; i0) goto x1_inf_x2_and_y1_inf_y2; /* x1buffer+(y1>>16)*SCREEN_X+x1i; for (i=x1i; iabs(dy)) goto x1_inf_x2_and_y1_sup_y2_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i>x1i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_sup_y2_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=(unsigned short *)d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; iabs(dy)) goto x1_inf_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_inf_y2_and_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=(unsigned short *)d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2: if (dy<0) goto x1_sup_x2_and_y1_sup_y2; if (dy>0) goto x1_sup_x2_and_y1_inf_y2; /* x1>x2 && y1==y2 */ dest=(unsigned short *)d->buffer+(y2>>16)*SCREEN_X+x2i; for (i=x2i; iabs(dy)) goto x1_sup_x2_and_y1_sup_y2_and_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_sup_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=(unsigned short *)d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2_and_y1_inf_y2: /* (x1, y1) (x2, y2) */ if (abs(dx)>abs(dy)) goto x1_sup_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i>x2i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_inf_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=(unsigned short *)d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; ip1.x*65536., x2=l->p2.x*65536., y1=l->p1.y*65536., y2=l->p2.y*65536., dx, dy; register int xcur; register int xinc; register int ycur; register int yinc; register int i; register int y1i=(y1+65535)>>16, y2i=(y2+65535)>>16; register int x1i=(x1+65535)>>16, x2i=(x2+65535)>>16; register unsigned char *dest; register unsigned char col1=l->color&255; register unsigned char col2=(l->color>>8)&255; register unsigned char col3=l->color>>16; register int xf; register int yf; /* in asm, those two subs are good for us, because we can test if x10) goto x1_eq_x2_and_y1_inf_y2; /* here x1==x2 && y1==y2 */ if (y1ibuffer+(y1i*SCREEN_X+(x1>>16))*3; } else { dest=d->buffer+(y2i*SCREEN_X+(x1>>16))*3; } *dest=col1; *(dest+1)=col2; *(dest+2)=col3; return; x1_eq_x2_and_y1_sup_y2: dest=d->buffer+(y2i*SCREEN_X+(x1>>16))*3; for (i=y2i; ibuffer+(y1i*SCREEN_X+(x1>>16))*3; for (i=y1i; i0) goto x1_inf_x2_and_y1_inf_y2; /* x1buffer+((y1>>16)*SCREEN_X+x1i)*3; for (i=x1i; iabs(dy)) goto x1_inf_x2_and_y1_sup_y2_dx_sup_dy; if (abs(dx)buffer+(y2i*SCREEN_X+(x2>>16))*3; for (i=y2i; ibuffer+((ycur>>16)*SCREEN_X+x2i)*3; for (i=x2i; i>x1i; i--, dest-=3) { *dest=col1; *(dest+1)=col2; *(dest+2)=col3; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X*3; } } return; x1_inf_x2_and_y1_sup_y2_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=d->buffer+(y2i*SCREEN_X+(xcur>>16))*3; for (i=y2i; iabs(dy)) goto x1_inf_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+(y1i*SCREEN_X+(x1>>16))*3; for (i=y1i; ibuffer+((ycur>>16)*SCREEN_X+x1i)*3; for (i=x1i; i65535) { yf-=65536; dest+=SCREEN_X*3; } } return; x1_inf_x2_and_y1_inf_y2_and_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=d->buffer+(y1i*SCREEN_X+(xcur>>16))*3; for (i=y1i; i65536) { xf-=65536; dest+=3; } } return; x1_sup_x2: if (dy<0) goto x1_sup_x2_and_y1_sup_y2; if (dy>0) goto x1_sup_x2_and_y1_inf_y2; /* x1>x2 && y1==y2 */ dest=d->buffer+((y2>>16)*SCREEN_X+x2i)*3; for (i=x2i; iabs(dy)) goto x1_sup_x2_and_y1_sup_y2_and_dx_sup_dy; if (abs(dx)buffer+(y2i*SCREEN_X+(x2>>16))*3; for (i=y2i; ibuffer+((ycur>>16)*SCREEN_X+x2i)*3; for (i=x2i; i65535) { yf-=65536; dest+=SCREEN_X*3; } } return; x1_sup_x2_and_y1_sup_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=d->buffer+(y2i*SCREEN_X+(xcur>>16))*3; for (i=y2i; i65536) { xf-=65536; dest+=3; } } return; x1_sup_x2_and_y1_inf_y2: /* (x1, y1) (x2, y2) */ if (abs(dx)>abs(dy)) goto x1_sup_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+(y1i*SCREEN_X+(x1>>16))*3; for (i=y1i; ibuffer+((ycur>>16)*SCREEN_X+x1i)*3; for (i=x1i; i>x2i; i--, dest-=3) { *dest=col1; *(dest+1)=col2; *(dest+2)=col3; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X*3; } } return; x1_sup_x2_and_y1_inf_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=d->buffer+(y1i*SCREEN_X+(xcur>>16))*3; for (i=y1i; ip1.x*65536., x2=l->p2.x*65536., y1=l->p1.y*65536., y2=l->p2.y*65536.; register int dx, dy; register int xcur; register int xinc; register int ycur; register int yinc; register int i; register int y1i=(y1+65535)>>16, y2i=(y2+65535)>>16; register int x1i=(x1+65535)>>16, x2i=(x2+65535)>>16; /* register int y1i=y1>>16, y2i=y2>>16; register int x1i=x1>>16, x2i=x2>>16; */ register unsigned int *dest; register unsigned int col1=l->color; register int xf; register int yf; /* in asm, those two subs are good for us, because we can test if x10) goto x1_eq_x2_and_y1_inf_y2; /* here x1==x2 && y1==y2 */ if (y1ibuffer+y1i*SCREEN_X+(x1>>16); } else { dest=(unsigned int *)d->buffer+y2i*SCREEN_X+(x1>>16); } *dest=col1; return; x1_eq_x2_and_y1_sup_y2: dest=(unsigned int *)d->buffer+y2i*SCREEN_X+(x1>>16); for (i=y2i; ibuffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; i0) goto x1_inf_x2_and_y1_inf_y2; /* x1buffer+(y1>>16)*SCREEN_X+x1i; for (i=x1i; iabs(dy)) goto x1_inf_x2_and_y1_sup_y2_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i>x1i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_sup_y2_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=(unsigned int *)d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; iabs(dy)) goto x1_inf_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_inf_x2_and_y1_inf_y2_and_dx_inf_dy: /* x x x x x x x x x */ xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=(unsigned int *)d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2: if (dy<0) goto x1_sup_x2_and_y1_sup_y2; if (dy>0) goto x1_sup_x2_and_y1_inf_y2; /* x1>x2 && y1==y2 */ dest=(unsigned int *)d->buffer+(y2>>16)*SCREEN_X+x2i; for (i=x2i; iabs(dy)) goto x1_sup_x2_and_y1_sup_y2_and_dx_sup_dy; if (abs(dx)buffer+y2i*SCREEN_X+(x2>>16); for (i=y2i; ibuffer+(ycur>>16)*SCREEN_X+x2i; for (i=x2i; i65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_sup_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x2+muldiv(xinc, (y2i<<16)-y2, 65536); xf=xcur&65535; dest=(unsigned int *)d->buffer+y2i*SCREEN_X+(xcur>>16); for (i=y2i; i65536) { xf-=65536; dest++; } } return; x1_sup_x2_and_y1_inf_y2: /* (x1, y1) (x2, y2) */ if (abs(dx)>abs(dy)) goto x1_sup_x2_and_y1_inf_y2_and_dx_sup_dy; if (abs(dx)buffer+y1i*SCREEN_X+(x1>>16); for (i=y1i; ibuffer+(ycur>>16)*SCREEN_X+x1i; for (i=x1i; i>x2i; i--, dest--) { *dest=col1; yf-=yinc; if (yf>65535) { yf-=65536; dest+=SCREEN_X; } } return; x1_sup_x2_and_y1_inf_y2_and_dx_inf_dy: xinc=muldiv(dx, 65536, dy); xcur=x1+muldiv(xinc, (y1i<<16)-y1, 65536); xf=xcur&65535; dest=(unsigned int *)d->buffer+y1i*SCREEN_X+(xcur>>16); for (i=y1i; ip1.yp2.y) { miny=((int)(l->p1.y*65536.)+65535)>>16; maxy=((int)(l->p2.y*65536.)+65535)>>16; } else { miny=((int)(l->p2.y*65536.)+65535)>>16; maxy=((int)(l->p1.y*65536.)+65535)>>16; } fill_left(d, &l->p1, &l->p2); minx=the_lines[miny].x_left/65536+1; maxx=the_lines[maxy-1].x_left/65536+1; if (d->depth==8) { register int i, j; register int col=l->color; register unsigned char *p=(unsigned char *)d->buffer, *q; register device_line *cur_line=&the_lines[(int)miny]; p+=miny*SCREEN_X; if (minxx_left/65536)+1; register /*const */int xright=((cur_line+1)->x_left/65536); q=p; q+=xleft; if (xleft>xright) xright++; for (j=xleft; j<=xright /*cur_line->x_right*/; j++, q++) *q=col; } } else { for (i=miny; ix_left/65536)+1; register const int xleft=(cur_line+1)->x_left/65536; q=p; q+=xleft; if (xleft>xright) xright++; for (j=xleft; j<=xright /*cur_line->x_right*/; j++, q++) *q=col; } } } else drawline16(d, l); #endif if (d->depth==8) drawline8(d, l); else if (d->depth==16) drawline16(d, l); else if (d->depth==24) drawline24(d, l); else if (d->depth==32) drawline32(d, l); } #define LEFT 1 #define RIGHT 2 #define UP 4 #define DOWN 8 static inline void copy_point(point *dest, point *src) { /* this one is useless, take it away !!! */ memcpy(dest, src, sizeof(point)); } static inline void do_clip_left(point *res, point *p1, point *p2) { register double factor=p2->x/(p2->x-p1->x); res->x=0; res->y=p2->y-(p2->y-p1->y)*factor; } static inline void do_clip_right(point *res, point *p1, point *p2) { register double factor=(p2->x-SCREEN_X+2)/(p2->x-p1->x); res->x=SCREEN_X-2; res->y=p2->y-(p2->y-p1->y)*factor; } static inline void do_clip_up(point *res, point *p1, point *p2) { register double factor=p2->y/(p2->y-p1->y); res->x=p2->x-(p2->x-p1->x)*factor; res->y=0; } static inline void do_clip_down(point *res, point *p1, point *p2) { register double factor=(p2->y-(SCREEN_Y-2))/(p2->y-p1->y); res->x=p2->x-(p2->x-p1->x)*factor; res->y=SCREEN_Y-2; } void clip_and_draw_line(device *d, line *l) { register int clip=0; register double a, b; register point *pp, *pp1; point next; /* step 1 - do we clip ? */ a=l->p1.x; b=l->p1.y; if (a<0) clip|=LEFT; if (a>SCREEN_X-2) clip|=RIGHT; if (b<0) clip|=UP; if (b>SCREEN_Y-2) clip|=DOWN; a=l->p2.x; b=l->p2.y; if (a<0) clip|=LEFT; if (a>SCREEN_X-2) clip|=RIGHT; if (b<0) clip|=UP; if (b>SCREEN_Y-2) clip|=DOWN; pp=&l->p1; pp1=&l->p2; /* step 2 - clip left ? */ if (!(clip&LEFT)) goto no_left; if (pp->x>0 && pp1->x<0) { do_clip_left(&next, pp, pp1); copy_point(pp1, &next); } else if (pp->x<0 && pp1->x>0) { do_clip_left(&next, pp, pp1); copy_point(pp, &next); } no_left: /* step 3 - right ? */ if (!(clip&RIGHT)) goto no_right; if (pp->xx>SCREEN_X-2) { do_clip_right(&next, pp, pp1); copy_point(pp1, &next); } else if (pp->x>SCREEN_X-2 && pp1->xy>0 && pp1->y<0) { do_clip_up(&next, pp, pp1); copy_point(pp1, &next); } else if (pp->y<0 && pp1->y>0) { do_clip_up(&next, pp, pp1); copy_point(pp, &next); } no_up: /* step 5 - down ? */ if (!(clip&DOWN)) goto no_down; if (pp->yy>SCREEN_Y-2) { do_clip_down(&next, pp, pp1); copy_point(pp1, &next); } else if (pp->y>SCREEN_Y-2 && pp1->yx>=0 && pp->x<=SCREEN_X-2 && pp->y>=0 && pp->y<=SCREEN_Y-2 && pp1->x>=0 && pp1->x<=SCREEN_X-2 && pp1->y>=0 && pp1->y<=SCREEN_Y-2) drawline(d, l); #if 0 else fprintf(stderr, "clip=%d p1=%f %f, p2=%f %f\n", clip, pp->x, pp->y, pp1->x, pp1->y); #endif }