/** * $Id:$ * ***** BEGIN GPL/BL DUAL LICENSE BLOCK ***** * * The contents of this file may be used under the terms of either the GNU * General Public License Version 2 or later (the "GPL", see * http://www.gnu.org/licenses/gpl.html ), or the Blender License 1.0 or * later (the "BL", see http://www.blender.org/BL/ ) which has to be * bought from the Blender Foundation to become active, in which case the * above mentioned GPL option does not apply. * * The Original Code is Copyright (C) 2002 by NaN Holding BV. * All rights reserved. * * The Original Code is: all of this file. * * Contributor(s): none yet. * * ***** END GPL/BL DUAL LICENSE BLOCK ***** */ #include "imbuf.h" #define OBJECTBLOK "izoom" #ifndef IZOOMDEF #define IZOOMDEF #define IMPULSE 1 #define BOX 2 #define TRIANGLE 3 #define QUADRATIC 4 #define MITCHELL 5 #define GAUSSIAN 6 #define LANCZOS3 7 #define BSPLINE 8 #define BELL 9 typedef struct FILTER { int n, totw, halftotw; short *dat; short *w; } FILTER; typedef struct zoom { int (*getfunc)(); short *abuf; short *bbuf; int anx, any; int bnx, bny; short **xmap; int type; int curay; int y; FILTER *xfilt, *yfilt; /* stuff for fitered zoom */ short *tbuf; int nrows, clamp, ay; short **filtrows; int *accrow; } zoom; zoom *newzoom(); float filterinteg(); #endif typedef struct filtinteg { float rad, min, max; float *tab; } filtinteg; #define flerp(f0,f1,p) (f0 + p * (f1 - f0)) #define GRIDTOFLOAT(pos,n) (((pos)+0.5)/(n)) #define FLOATTOGRID(pos,n) ((pos)*(n)) #define SHIFT 12 #define ONE (1<rad) #define FILTTABSIZE 250 static makexmap(); static setintrow(); static xscalebuf(); static addrow(); static divrow(); static FILTER *makefilt(); static freefilt(); static applyxfilt(); float filterinteg(); static mitchellinit(); static int (*xfiltfunc)(); static float blurfactor; int izoomdebug; static filtinteg *shapeBOX; static filtinteg *shapeTRIANGLE; static filtinteg *shapeQUADRATIC; static filtinteg *shapeMITCHELL; static filtinteg *shapeGAUSSIAN; static filtinteg *shapeLANCZOS3; static filtinteg *shapeBSPLINE; static filtinteg *shapeBELL; static filtinteg *shape; float filt_box(x) float x; { if (x<-0.5) return 0.0; if (x< 0.5) return 1.0; return 0.0; } float filt_triangle(x) float x; { if (x < 0.0) x = -x; if (x < 1.0) return 1.0 - x; return 0.0; } float filt_quadratic(x) float x; { if (x<-1.5) return 0.0; if (x<-0.5) return 0.5*(x+1.5)*(x+1.5); if (x< 0.5) return 0.75-(x*x); if (x< 1.5) return 0.5*(x-1.5)*(x-1.5); return 0.0; } static float p0, p2, p3, q0, q1, q2, q3; /* * see Mitchell&Netravali, "Reconstruction Filters in Computer Graphics", * SIGGRAPH 88. Mitchell code provided by Paul Heckbert. * */ float filt_mitchell(x) /* Mitchell & Netravali's two-param cubic */ float x; { static int mitfirsted; if(!mitfirsted) { mitchellinit(1.0/3.0,1.0/3.0); mitfirsted = 1; } if (x<-2.0) return 0.0; if (x<-1.0) return (q0-x*(q1-x*(q2-x*q3))); if (x< 0.0) return (p0+x*x*(p2-x*p3)); if (x< 1.0) return (p0+x*x*(p2+x*p3)); if (x< 2.0) return (q0+x*(q1+x*(q2+x*q3))); return 0.0; } static mitchellinit(b,c) float b, c; { p0 = ( 6.0 - 2.0*b ) / 6.0; p2 = (-18.0 + 12.0*b + 6.0*c) / 6.0; p3 = ( 12.0 - 9.0*b - 6.0*c) / 6.0; q0 = ( 8.0*b + 24.0*c) / 6.0; q1 = ( - 12.0*b - 48.0*c) / 6.0; q2 = ( 6.0*b + 30.0*c) / 6.0; q3 = ( - b - 6.0*c) / 6.0; } #define NARROWNESS 1.5 float filt_gaussian(x) float x; { x = x*NARROWNESS; return (1.0/exp(x*x) - 1.0/exp(1.5*NARROWNESS*1.5*NARROWNESS)); } float filt_bell(t) /* box (*) box (*) box */ float t; { if(t < 0) t = -t; if(t < .5) return(.75 - (t * t)); if(t < 1.5) { t = (t - 1.5); return(.5 * (t * t)); } return(0.0); } float filt_bspline(t) /* box (*) box (*) box (*) box */ float t; { double tt; if(t < 0) t = -t; if(t < 1) { tt = t * t; return((.5 * tt * t) - tt + (2.0 / 3.0)); } else if(t < 2) { t = 2 - t; return((1.0 / 6.0) * (t * t * t)); } return(0.0); } float sinc(x) float x; { x *= M_PI; if(x != 0) return(sin(x) / x); return(1.0); } float filt_lanczos3(t) float t; { if(t < 0) t = -t; if(t < 3.0) return(sinc(t) * sinc(t/3.0)); return(0.0); } /* We gaan dit snel testen dus we doen niet al te netjes */ struct ImBuf * zoomin, * zoomuit; int channel; getimgrow(short * buf, int y) { uchar * rect; int x; rect = (uchar *) zoomin->rect; rect += 4 * y * zoomin->x; rect += channel; for (x = zoomin->x; x > 0; x--) { *buf++ = rect[0]; rect += 4; } } putimgrow(short * buf, int y) { uchar * rect; int x; rect = (uchar *) zoomuit->rect; rect += 4 * y * zoomuit->x; rect += channel; for (x = zoomuit->x; x > 0; x--) { rect[0] = *buf++; rect += 4; } } #define DOCLAMP(iptr) (((*(iptr) & 0xff00) == 0) ? *(iptr): ((*(iptr)>0) ? 255 : 0)) clamprow(iptr,optr,n) short *iptr, *optr; int n; { short val; while(n>=8) { optr[0] = DOCLAMP(iptr+0); optr[1] = DOCLAMP(iptr+1); optr[2] = DOCLAMP(iptr+2); optr[3] = DOCLAMP(iptr+3); optr[4] = DOCLAMP(iptr+4); optr[5] = DOCLAMP(iptr+5); optr[6] = DOCLAMP(iptr+6); optr[7] = DOCLAMP(iptr+7); iptr += 8; optr += 8; n -= 8; } while(n--) { optr[0] = DOCLAMP(iptr+0); iptr++; optr++; } } static filtinteg *integrate(filtfunc,rad) float (*filtfunc)(); float rad; { int i; float del, x, min, max; double tot; filtinteg *filt; min = -rad; max = rad; del = 2*rad; tot = 0.0; filt = (filtinteg *)malloc(sizeof(filtinteg)); filt->rad = rad; filt->min = min; filt->max = max; filt->tab = (float *)malloc(FILTTABSIZE*sizeof(float)); for(i=0; itab[i] = tot; } for(i=0; itab[i] /= tot; return filt; } float filterinteg(bmin,bmax,blurf) float bmin, bmax, blurf; { int i1, i2; float f1, f2; float *tab; float mult; bmin /= blurf; bmax /= blurf; tab = shape->tab; mult = (FILTTABSIZE-1.0)/(2.0*shape->rad); f1 = ((bmin-shape->min)*mult); i1 = ffloor(f1); f1 = f1-i1; if(i1<0) f1 = 0.0; else if(i1>=(FILTTABSIZE-1)) f1 = 1.0; else f1 = flerp(tab[i1],tab[i1+1],f1); f2 = ((bmax-shape->min)*mult); i2 = ffloor(f2); f2 = f2-i2; if(i2<0) f2 = 0.0; else if(i2>=(FILTTABSIZE-1)) f2 = 1.0; else f2 = flerp(tab[i2],tab[i2+1],f2); return f2-f1; } setfiltertype(filttype) int filttype; { switch(filttype) { case IMPULSE: shape = 0; break; case BOX: if(!shapeBOX) shapeBOX = integrate(filt_box,0.5); shape = shapeBOX; break; case TRIANGLE: if(!shapeTRIANGLE) shapeTRIANGLE = integrate(filt_triangle,1.0); shape = shapeTRIANGLE; break; case QUADRATIC: if(!shapeQUADRATIC) shapeQUADRATIC = integrate(filt_quadratic,1.5); shape = shapeQUADRATIC; break; case MITCHELL: if(!shapeMITCHELL) shapeMITCHELL = integrate(filt_mitchell,2.0); shape = shapeMITCHELL; break; case GAUSSIAN: if(!shapeGAUSSIAN) shapeGAUSSIAN = integrate(filt_gaussian,1.5); shape = shapeGAUSSIAN; break; case LANCZOS3: if (!shapeLANCZOS3) shapeLANCZOS3 = integrate(filt_lanczos3, 3.0); break; case BSPLINE: if (!shapeBSPLINE) shapeBSPLINE = integrate(filt_bspline, 2.0); break; case BELL: if (!shapeBELL) shapeBELL = integrate(filt_bell, 1.5); break; } } /* * general zoom follows * */ zoom *newzoom(getfunc,anx,any,bnx,bny,filttype,blur) int (*getfunc)(); int anx,any,bnx,bny; int filttype; float blur; { zoom *z; int i; setfiltertype(filttype); z = (zoom *)malloc(sizeof(zoom)); z->getfunc = getfunc; z->abuf = (short *)malloc(anx*sizeof(short)); z->bbuf = (short *)malloc(bnx*sizeof(short)); z->anx = anx; z->any = any; z->bnx = bnx; z->bny = bny; z->curay = -1; z->y = 0; z->type = filttype; if(filttype == IMPULSE) { if(z->anx != z->bnx) { z->xmap = (short **)malloc(z->bnx*sizeof(short *)); makexmap(z->abuf,z->xmap,z->anx,z->bnx); } } else { blurfactor = blur; if(filttype == MITCHELL) z->clamp = 1; else z->clamp = 0; z->tbuf = (short *)malloc(bnx*sizeof(short)); z->xfilt = makefilt(z->abuf,anx,bnx,&z->nrows); z->yfilt = makefilt(0,any,bny,&z->nrows); z->filtrows = (short **)malloc(z->nrows * sizeof(short *)); for(i=0; inrows; i++) z->filtrows[i] = (short *)malloc(z->bnx*sizeof(short)); z->accrow = (int *)malloc(z->bnx*sizeof(int)); z->ay = 0; } return z; } getzoomrow(z,buf,y) zoom *z; short *buf; int y; { float fy; int ay; FILTER *f; int i, max; short *row; if(y==0) { z->curay = -1; z->y = 0; z->ay = 0; } if(z->type == IMPULSE) { fy = GRIDTOFLOAT(z->y,z->bny); ay = FLOATTOGRID(fy,z->any); if(z->anx == z->bnx) { if(z->curay != ay) { z->getfunc(z->abuf,ay); z->curay = ay; if(xfiltfunc) xfiltfunc(z->abuf,z->bnx); } bcopy(z->abuf,buf,z->bnx*sizeof(short)); } else { if(z->curay != ay) { z->getfunc(z->abuf,ay); xscalebuf(z->xmap,z->bbuf,z->bnx); z->curay = ay; if(xfiltfunc) xfiltfunc(z->bbuf,z->bnx); } bcopy(z->bbuf,buf,z->bnx*sizeof(short)); } } else if(z->any == 1 && z->bny == 1) { z->getfunc(z->abuf,z->ay++); applyxfilt(z->filtrows[0],z->xfilt,z->bnx); if(xfiltfunc) xfiltfunc(z->filtrows[0],z->bnx); if(z->clamp) { clamprow(z->filtrows[0],z->tbuf,z->bnx); bcopy(z->tbuf,buf,z->bnx*sizeof(short)); } else { bcopy(z->filtrows[0],buf,z->bnx*sizeof(short)); } } else { f = z->yfilt+z->y; max = ((long)f->dat)/sizeof(short)+(f->n-1); while(z->ay<=max) { z->getfunc(z->abuf,z->ay++); row = z->filtrows[0]; for(i=0; i<(z->nrows-1); i++) z->filtrows[i] = z->filtrows[i+1]; z->filtrows[z->nrows-1] = row; applyxfilt(z->filtrows[z->nrows-1],z->xfilt,z->bnx); if(xfiltfunc) xfiltfunc(z->filtrows[z->nrows-1],z->bnx); } if(f->n == 1) { if(z->clamp) { clamprow(z->filtrows[z->nrows-1],z->tbuf,z->bnx); bcopy(z->tbuf,buf,z->bnx*sizeof(short)); } else { bcopy(z->filtrows[z->nrows-1],buf,z->bnx*sizeof(short)); } } else { setintrow(z->accrow,f->halftotw,z->bnx); for(i=0; in; i++) addrow(z->accrow, z->filtrows[i+(z->nrows-1)-(f->n-1)], f->w[i],z->bnx); divrow(z->accrow,z->bbuf,f->totw,z->bnx); if(z->clamp) { clamprow(z->bbuf,z->tbuf,z->bnx); bcopy(z->tbuf,buf,z->bnx*sizeof(short)); } else { bcopy(z->bbuf,buf,z->bnx*sizeof(short)); } } } z->y++; } static setintrow(buf,val,n) int *buf; int val, n; { while(n>=8) { buf[0] = val; buf[1] = val; buf[2] = val; buf[3] = val; buf[4] = val; buf[5] = val; buf[6] = val; buf[7] = val; buf += 8; n -= 8; } while(n--) *buf++ = val; } freezoom(z) zoom *z; { int i; if(z->type == IMPULSE) { if(z->anx != z->bnx) free(z->xmap); } else { freefilt(z->xfilt,z->bnx); freefilt(z->yfilt,z->bny); free(z->tbuf); for(i=0; inrows; i++) free(z->filtrows[i]); free(z->filtrows); free(z->accrow); } free(z->abuf); free(z->bbuf); free(z); } filterzoom(getfunc,putfunc,anx,any,bnx,bny,filttype,blur) int (*getfunc)(), (*putfunc)(); int anx, any; int bnx, bny; int filttype; float blur; { zoom *z; int y; short *buf; buf = (short *)malloc(bnx*sizeof(short)); z = newzoom(getfunc,anx,any,bnx,bny,filttype,blur); for(y=0; y=8) { bbuf[0] = *(xmap[0]); bbuf[1] = *(xmap[1]); bbuf[2] = *(xmap[2]); bbuf[3] = *(xmap[3]); bbuf[4] = *(xmap[4]); bbuf[5] = *(xmap[5]); bbuf[6] = *(xmap[6]); bbuf[7] = *(xmap[7]); bbuf += 8; xmap += 8; bnx -= 8; } while(bnx--) *bbuf++ = *(*xmap++); } zoomxfilt(filtfunc) int (*filtfunc)(); { xfiltfunc = filtfunc; } /* * filter zoom utilities * */ static addrow(iptr,sptr,w,n) int *iptr; short *sptr; int w, n; { while(n>=8) { iptr[0] += (w*sptr[0]); iptr[1] += (w*sptr[1]); iptr[2] += (w*sptr[2]); iptr[3] += (w*sptr[3]); iptr[4] += (w*sptr[4]); iptr[5] += (w*sptr[5]); iptr[6] += (w*sptr[6]); iptr[7] += (w*sptr[7]); iptr += 8; sptr += 8; n -= 8; } while(n--) *iptr++ += (w * *sptr++); } static divrow(iptr,sptr,tot,n) int *iptr; short *sptr; int tot, n; { while(n>=8) { sptr[0] = iptr[0]/tot; sptr[1] = iptr[1]/tot; sptr[2] = iptr[2]/tot; sptr[3] = iptr[3]/tot; sptr[4] = iptr[4]/tot; sptr[5] = iptr[5]/tot; sptr[6] = iptr[6]/tot; sptr[7] = iptr[7]/tot; sptr += 8; iptr += 8; n -= 8; } while(n--) *sptr++ = (*iptr++)/tot; } static FILTER *makefilt(abuf,anx,bnx,maxn) short *abuf; int anx, bnx; int *maxn; { FILTER *f, *filter; int x, min, max, n, pos; float bmin, bmax, bcent, brad; float fmin, fmax, acent, arad; int amin, amax; float coverscale; if(izoomdebug) fprintf(stderr,"makefilt\n"); f = filter = (FILTER *)malloc(bnx*sizeof(FILTER)); *maxn = 0; if(bnx=anx) amax = anx-1; f->n = 1+amax-amin; f->dat = abuf+amin; f->w = (short *)malloc(f->n*sizeof(short)); f->totw = 0; if(izoomdebug) fprintf(stderr,"| "); for(n=0; nn; n++) { bmin = bnx*((((float)amin+n)/anx)-bcent); bmax = bnx*((((float)amin+n+1)/anx)-bcent); f->w[n] = ffloor((coverscale*filterinteg(bmin,bmax,blurfactor))+0.5); if(izoomdebug) fprintf(stderr,"%d ",f->w[n]); f->totw += f->w[n]; } f->halftotw = f->totw/2; if(f->n>*maxn) *maxn = f->n; f++; } } else { coverscale = ((float)bnx/anx*ONE)/2.0; arad = FILTERRAD/anx; for(x=0; x=anx) amax = anx-1; f->n = 1+amax-amin; f->dat = abuf+amin; f->w = (short *)malloc(f->n*sizeof(short)); f->totw = 0; if(izoomdebug) fprintf(stderr,"| "); for(n=0; nn; n++) { acent = (amin+n+0.5)/anx; fmin = anx*(bmin-acent); fmax = anx*(bmax-acent); f->w[n] = ffloor((coverscale*filterinteg(fmin,fmax,blurfactor))+0.5); if(izoomdebug) fprintf(stderr,"%d ",f->w[n]); f->totw += f->w[n]; } f->halftotw = f->totw/2; if(f->n>*maxn) *maxn = f->n; f++; } } if(izoomdebug) fprintf(stderr,"|\n"); return filter; } static freefilt(filt,n) FILTER *filt; int n; { FILTER *f; f = filt; while(n--) { free(f->w); f++; } free(filt); } static applyxfilt(bbuf,xfilt,bnx) short *bbuf; FILTER *xfilt; int bnx; { short *w; short *dptr; int n, val; while(bnx--) { if((n=xfilt->n) == 1) { *bbuf++ = *xfilt->dat; } else { w = xfilt->w; dptr = xfilt->dat; val = xfilt->halftotw; n = xfilt->n; while(n--) val += *w++ * *dptr++; *bbuf++ = val / xfilt->totw; } xfilt++; } } struct ImBuf * zoomImBuf(struct ImBuf * ibuf, int newx, int newy, int filttype, double blur) { int i; if (ibuf == 0) return (0); if (ibuf->rect == 0) return (0); zoomin = ibuf; zoomuit = allocImBuf(newx, newy, ibuf->depth, IB_rect, 0); for (i = 3; i >= 0; i--) { channel = i; filterzoom(getimgrow, putimgrow, ibuf->x, ibuf->y, newx, newy, filttype, blur); } return (zoomuit); }