#include #include #include #include "plot.h" #include "font.h" #include "istack.h" #include "text-flags.h" static int havesize; static unsigned int xsize; static unsigned int ysize; static double scale_xmin; static double scale_xmax; static double scale_ymin; static double scale_ymax; static double swin_xmin; static double swin_xmax; static double swin_ymin; static double swin_ymax; static double s_xmul; static double s_xadd; static double s_ymul; static double s_yadd; static int clip_xmin; static int clip_xmax; static int clip_ymin; static int clip_ymax; static int clip_all; static unsigned int *pic; static unsigned int fg; static FILETYPE fgft; static unsigned int bg; static FILETYPE bgft; static FILETYPE filetype; static FILETYPE forcetype; static unsigned int (*combine)(unsigned int, unsigned int); static FONT *curfont; static void default_scale(void) { scale_xmin = 0; scale_xmax = xsize; scale_ymin = 0; scale_ymax = ysize; } static void default_scalewin(void) { swin_xmin = 0; swin_xmax = xsize; swin_ymin = 0; swin_ymax = ysize; } static void default_clipwin(void) { clip_xmin = 0; clip_xmax = xsize; clip_ymin = 0; clip_ymax = ysize; clip_all = 0; } static void scale_changed(void) { s_xmul = (swin_xmax - swin_xmin) / (scale_xmax - scale_xmin); s_xadd = swin_xmin - (s_xmul * scale_xmin); s_ymul = (swin_ymax - swin_ymin) / (scale_ymax - scale_ymin); s_yadd = swin_ymin - (s_ymul * scale_ymin); } static void reset_scale_clip(void) { default_scale(); default_scalewin(); default_clipwin(); scale_changed(); } static FILETYPE ft_upgrade_v(unsigned int v) { if ((v == 0) || (v == 0x010101)) return(FT_PBM); else if ((v % 0x010101) == 0) return(FT_PGM); else return(FT_PPM); } static int have_size(void) { if (! havesize) { istack_err("no size specified"); return(0); } return(1); } static double alpha(double v1, double num, double den, double v2) { return(((v2*num)/den)+(v1*(den-num)/den)); } static void walk_line( double a1, double a2, int amin, int amax, double b1, double b2, int bmin, int bmax, void (*plot)(double, double) ) { double a; if (a1 > a2) { double t; t = a1; a1 = a2; a2 = t; t = b1; b1 = b2; b2 = t; } if (a2 <= amin) return; if (a1 >= amax) return; if ((b1 <= bmin) && (b2 <= bmin)) return; if ((b1 >= bmax) && (b2 >= bmax)) return; if (a2-a1 < .0001) { (*plot)((a1+a2)/2,(b1+b2)/2); return; } if (a1 < amin) { b1 = alpha(b1,amin-a1,a2-a1,b2); a1 = amin; } if (a2 > amax) { b2 = alpha(b1,amax-a1,a2-a1,b2); a2 = amax; } if ((b1 <= bmin) && (b2 <= bmin)) return; if ((b1 >= bmax) && (b2 >= bmax)) return; if (floor(b1) == floor(b2)) { int ib; int i; int l; ib = floor(b1); l = floor(a2-.5); for (i=floor(a1+.5);i<=l;i++) (*plot)(i,ib); return; } for (a=floor(a1+.5)+.5;a> 8)&255,(new>> 8)&255) << 8) | (min((old>>16)&255,(new>>16)&255) << 16) ); } static unsigned int combine_max(unsigned int old, unsigned int new) { __inline__ int max(int a, int b) { return((a>b)?a:b); } return( (max((old )&255,(new )&255) ) | (max((old>> 8)&255,(new>> 8)&255) << 8) | (max((old>>16)&255,(new>>16)&255) << 16) ); } void plot_init(void) { filetype = FT_NONE; forcetype = FT_NONE; havesize = 0; fg = 0x010101; bg = 0; combine = &combine_set; curfont = font_builtin(); } void plot_clear(unsigned int x, unsigned int y, unsigned int bg) { unsigned long long int p; p = x * (unsigned long long int)y; if (p > (1ULL<<30)) { istack_err("plot too big - max is a gigapixel"); return; } if (p < 1) { istack_err("plot too small - no pixels"); return; } if (havesize) free(pic); xsize = x; ysize = y; pic = malloc(xsize*ysize*sizeof(unsigned int)); havesize = 1; plot_justclear(bg); reset_scale_clip(); } void plot_justclear(unsigned int bg) { int n; int p; if (! have_size()) return; pic[0] = bg; p = xsize * ysize; n = 1; while ((n<<1) <= p) { bcopy(pic,pic+n,n*sizeof(*pic)); n <<= 1; } if (n < p) bcopy(pic,pic+n,(p-n)*sizeof(*pic)); filetype = ft_upgrade_v(bg); } void plot_fg(unsigned int arg) { fg = arg; fgft = ft_upgrade_v(fg); } void plot_bg(unsigned int arg) { bg = arg; bgft = ft_upgrade_v(bg); } void plot_scale(double x1, double x2, double y1, double y2) { if (! have_size()) return; if (x1 == x2) { istack_err("zero X range"); return; } if (y1 == y2) { istack_err("zero Y range"); return; } scale_xmin = x1; scale_xmax = x2; scale_ymin = y1; scale_ymax = y2; scale_changed(); } void plot_scale_default(void) { if (! have_size()) return; default_scale(); scale_changed(); } void plot_scalewin(double x1, double x2, double y1, double y2) { if (! have_size()) return; if (x1 == x2) { istack_err("zero X range"); return; } if (y1 == y2) { istack_err("zero Y range"); return; } swin_xmin = x1; swin_xmax = x2; swin_ymin = y1; swin_ymax = y2; scale_changed(); } void plot_scalewin_default(void) { if (! have_size()) return; default_scalewin(); scale_changed(); } void plot_clipwin(int x1, int x2, int y1, int y2) { if (! have_size()) return; clip_xmin = x1; clip_xmax = x2; clip_ymin = y1; clip_ymax = y2; if (clip_xmin < 0) clip_xmin = 0; if (clip_xmax > xsize) clip_xmax = xsize; if (clip_ymin < 0) clip_ymin = 0; if (clip_ymax > ysize) clip_ymax = ysize; clip_all = ((clip_xmin >= clip_xmax) || (clip_ymin >= clip_ymax)); } void plot_clipwin_default(void) { if (! have_size()) return; default_clipwin(); } void plot_point(double x, double y) { unsigned int *pp; if (!have_size() || clip_all) return; x = floor((x * s_xmul) + s_xadd); y = floor((y * s_ymul) + s_yadd); if ( (x < clip_xmin) || (x >= clip_xmax) || (y < clip_ymin) || (y >= clip_ymax) ) return; pp = &pic[(xsize*(int)y)+(int)x]; *pp = (*combine)(*pp,fg); if (fgft > filetype) filetype = fgft; } void plot_line(double x1, double y1, double x2, double y2) { void pxy(double x, double y) { unsigned int *pp; x = floor(x); y = floor(y); if ( (x < clip_xmin) || (x >= clip_xmax) || (y < clip_ymin) || (y >= clip_ymax) ) return; pp = &pic[(xsize*(int)y)+(int)x]; *pp = (*combine)(*pp,fg); if (fgft > filetype) filetype = fgft; } void pyx(double y, double x) { unsigned int *pp; x = floor(x); y = floor(y); if ( (x < clip_xmin) || (x >= clip_xmax) || (y < clip_ymin) || (y >= clip_ymax) ) return; pp = &pic[(xsize*(int)y)+(int)x]; *pp = (*combine)(*pp,fg); if (fgft > filetype) filetype = fgft; } if (!have_size() || clip_all) return; x1 = (x1 * s_xmul) + s_xadd; x2 = (x2 * s_xmul) + s_xadd; y1 = (y1 * s_ymul) + s_yadd; y2 = (y2 * s_ymul) + s_yadd; if (fabs(x1-x2) > fabs(y1-y2)) { walk_line(x1,x2,clip_xmin,clip_xmax,y1,y2,clip_ymin,clip_ymax,&pxy); } else { walk_line(y1,y2,clip_ymin,clip_ymax,x1,x2,clip_xmin,clip_xmax,&pyx); } } void plot_rect(double x1, double y1, double x2, double y2) { int ix1; int iy1; int ix2; int iy2; int x; int y; if (!have_size() || clip_all) return; x1 = (x1 * s_xmul) + s_xadd; x2 = (x2 * s_xmul) + s_xadd; y1 = (y1 * s_ymul) + s_yadd; y2 = (y2 * s_ymul) + s_yadd; if (x1 < x2) { ix1 = floor(x1); ix2 = ceil(x2); } else { ix1 = floor(x2); ix2 = ceil(x1); } if (y1 < y2) { iy1 = floor(y1); iy2 = ceil(y2); } else { iy1 = floor(y2); iy2 = ceil(y1); } if ( (ix2 < clip_xmin) || (ix1 > clip_xmax) || (iy2 < clip_ymin) || (iy1 > clip_ymax) ) return; if (ix1 < clip_xmin) ix1 = clip_xmin; if (ix2 > clip_xmax) ix2 = clip_xmax; if (iy1 < clip_ymin) iy1 = clip_ymin; if (iy2 > clip_ymax) iy2 = clip_ymax; for (y=iy1;y<=iy2;y++) { unsigned int *pp; pp = &pic[(xsize*y)+ix1]; for (x=ix1;x<=ix2;x++) { *pp = (*combine)(*pp,fg); pp ++; } } } void plot_output(FILE *f) { int y; int x; unsigned int *pp; unsigned char buf; if (! havesize) { istack_err("no plot to output"); return; } pp = pic; switch ((forcetype == FT_NONE) ? filetype : forcetype) { case FT_PBM: fprintf(f,"P4\n%u %u\n",xsize,ysize); for (y=0;y> 8)&255) * .587) + (((v>>16)&255) * .114); putc((c>255)?255:c,f); } break; default: abort(); break; } } } break; case FT_PPM: fprintf(f,"P6\n%u %u\n255\n",xsize,ysize); for (y=0;y>8)&255,f); putc((v>>16)&255,f); } } break; default: abort(); break; } } void plot_op(PLOTOP op) { switch (op) { case OP_SET: combine = &combine_set; break; case OP_MIN: combine = &combine_min; break; case OP_MAX: combine = &combine_max; break; default: abort(); break; } } void plot_force_type(FILETYPE t) { forcetype = t; } void plot_set_font(const char *fn) { FONT *f; f = font_load(fn); if (f) { font_unload(curfont); curfont = f; } } void plot_text(const char *txt, double atx, double aty, unsigned int flags) { int atix; int atiy; int ow; int oh; int ox; int oy; int xw; int xh; int xx; int xy; unsigned char *bits; int x; int y; int dx; int dy; unsigned int *pp; if (!have_size() || clip_all) return; atix = floor((atx * s_xmul) + s_xadd); atiy = floor((aty * s_ymul) + s_yadd); font_render(curfont,txt,flags,&bits,&ow,&oh,&ox,&oy); if ((ow == 0) || (oh == 0)) return; if (! (flags & TEXTFLAG_NO_AUTO_SWAP)) { if (s_xmul < 0) flags = (flags & ~TEXTFLAG_XF) | textflag_xf_compose(flags,TEXTFLAG_XF_FLIP_X); if (s_ymul < 0) flags = (flags & ~TEXTFLAG_XF) | textflag_xf_compose(flags,TEXTFLAG_XF_FLIP_Y); } /* Flip it (again, possibly) because the bitmap from font_render() is a fourth-quadrant bitmap rather than a first-quadrant bitmap. */ flags = (flags & ~TEXTFLAG_XF) | textflag_xf_compose(flags,TEXTFLAG_XF_FLIP_Y); xw = textflag_xf_sx(flags,ow,oh); xh = textflag_xf_sy(flags,ow,oh); xx = textflag_xf_x(flags,ox,oy,ow,oh); xy = textflag_xf_y(flags,ox,oy,ow,oh); for (y=oh-1;y>=0;y--) { for (x=ow-1;x>=0;x--) { dx = textflag_xf_x(flags,x,y,ow,oh) + atix - xx; dy = textflag_xf_y(flags,x,y,ow,oh) + atiy - xy; if ( (dx < clip_xmin) || (dx >= clip_xmax) || (dy < clip_ymin) || (dy >= clip_ymax) ) continue; pp = &pic[(xsize*dy)+dx]; if (bits[(y*ow)+x]) { *pp = (*combine)(*pp,fg); } else if (flags & TEXTFLAG_RECTBG) { *pp = (*combine)(*pp,bg); } } } if (fgft > filetype) filetype = fgft; }