#include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h> /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) /* * For 16-bit values, x / 255 == (t = x+1, (t+(t>>8)) >> 8). * We add another 127 to round to the nearest value rather * than truncate. * * CALCxy does x bytewise calculations on y input images (x=1,4; y=1,2). * CALC2x does two parallel 16-bit calculations on y input images (y=1,2). */#define CALC11(a, v, tmp) \ (tmp=(a)*(v)+128, (tmp+(tmp>>8))>>8) #define CALC12(a1, v1, a2, v2, tmp) \ (tmp=(a1)*(v1)+(a2)*(v2)+128, (tmp+(tmp>>8))>>8) #define MASK 0xFF00FF #define CALC21(a, vvuu, tmp) \ (tmp=(a)*(vvuu)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC41(a, rgba, tmp1, tmp2) \ (CALC21(a, rgba & MASK, tmp1) | \ (CALC21(a, (rgba>>8)&MASK, tmp2)<<8)) #define CALC22(a1, vvuu1, a2, vvuu2, tmp) \ (tmp=(a1)*(vvuu1)+(a2)*(vvuu2)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC42(a1, rgba1, a2, rgba2, tmp1, tmp2) \ (CALC22(a1, rgba1 & MASK, a2, rgba2 & MASK, tmp1) | \ (CALC22(a1, (rgba1>>8) & MASK, a2, (rgba2>>8) & MASK, tmp2)<<8)) static void mktables(void);typedef int Subdraw(Memdrawparam*);static Subdraw chardraw, alphadraw, memoptdraw; static Memimage* memones;static Memimage* memzeros;Memimage *memwhite;Memimage *memblack;Memimage *memtransparent;Memimage *memopaque; int _ifmt(Fmt*); intmemimageinit(void){ static int didinit = 0; if(didinit) return 0; mktables(); _memmkcmap(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); memones = allocmemimage(Rect(0,0,1,1), GREY1); memzeros = allocmemimage(Rect(0,0,1,1), GREY1); if(memones == nil || memzeros == nil) return -1; memones->flags |= Frepl; memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memones, ZP) = ~0; memzeros->flags |= Frepl; memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memzeros, ZP) = 0; memwhite = memones; memblack = memzeros; memopaque = memones; memtransparent = memzeros; didinit = 1; return 0;} static ulong imgtorgba(Memimage*, ulong);static ulong rgbatoimg(Memimage*, ulong);static ulong pixelbits(Memimage*, Point); voidmemimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op){ Memdrawparam par; if(mask == nil) mask = memopaque; if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0) return; if(op < Clear || op > SoverD) return; par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = imgtorgba(src, par.sval); par.sdval = rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)) return; /* no-op successfully handled */ } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)) return; /* no-op successfully handled */ par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = imgtorgba(mask, par.mval); } } /* * Now that we've clipped the parameters down to be consistent, we * simply try sub-drawing routines in order until we find one that was able * to handle us. If the sub-drawing routine returns zero, it means it was * unable to satisfy the request, so we do not return. */ /* * Hardware support. Each video driver provides this function, * which checks to see if there is anything it can help with. * There could be an if around this checking to see if dst is in video memory. */ if(hwdraw(&par)) return; /* * Optimizations using memmove and memset. */ if(memoptdraw(&par)) return; /* * Character drawing. * Solid source color being painted through a boolean mask onto a high res image. */ if(chardraw(&par)) return; /* * General calculation-laden case that does alpha for each pixel. */ alphadraw(&par);} /* * Clip the destination rectangle further based on the properties of the * source and mask rectangles. Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * * Return zero if the final rectangle is null. */intdrawclipnorepl(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr){ Point rmin, delta; int splitcoords; Rectangle omr; if(badrect(*r)) return 0; splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); /* clip to destination */ rmin = r->min; if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) return 0; /* move mask point */ p1->x += r->min.x-rmin.x; p1->y += r->min.y-rmin.y; /* move source point */ p0->x += r->min.x-rmin.x; p0->y += r->min.y-rmin.y; /* map destination rectangle into source */ sr->min = *p0; sr->max.x = p0->x+Dx(*r); sr->max.y = p0->y+Dy(*r); /* sr is r in source coordinates; clip to source */ if(!(src->flags&Frepl) && !rectclip(sr, src->r)) return 0; if(!rectclip(sr, src->clipr)) return 0; /* compute and clip rectangle in mask */ if(splitcoords){ /* move mask point with source */ p1->x += sr->min.x-p0->x; p1->y += sr->min.y-p0->y; mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); omr = *mr; /* mr is now rectangle in mask; clip it */ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) return 0; if(!rectclip(mr, mask->clipr)) return 0; /* reflect any clips back to source */ sr->min.x += mr->min.x-omr.min.x; sr->min.y += mr->min.y-omr.min.y; sr->max.x += mr->max.x-omr.max.x; sr->max.y += mr->max.y-omr.max.y; }else{ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) return 0; if(!rectclip(sr, mask->clipr)) return 0; *mr = *sr; } /* move source clipping back to destination */ delta.x = r->min.x - p0->x; delta.y = r->min.y - p0->y; r->min.x = sr->min.x + delta.x; r->min.y = sr->min.y + delta.y; r->max.x = sr->max.x + delta.x; r->max.y = sr->max.y + delta.y; *p0 = sr->min; *p1 = mr->min; assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); assert(ptinrect(r->min, dst->r)); return 1;} /* * like drawclipnorepl() above, but if source or mask is replicated, * move its clipped rectangle so that its minimum point falls within * the repl rectangle. * * Return zero if the final rectangle is null. */intdrawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr){ Point delta; if(!drawclipnorepl(dst, r, src, p0, mask, p1, sr, mr)) return 0; /* move source rectangle so sr->min is in src->r */ if(src->flags&Frepl) { delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; sr->min.x += delta.x; sr->min.y += delta.y; sr->max.x += delta.x; sr->max.y += delta.y; *p0 = sr->min; } /* move mask point so it is in mask->r */ *p1 = drawrepl(mask->r, *p1); mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); assert(ptinrect(*p0, src->r)); assert(ptinrect(*p1, mask->r)); return 1;} /* * Conversion tables. */static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */static uchar conv28[256][4]; /* ... */static uchar conv48[256][2]; /* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit. On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */#define a ((((((((((((((((0#define X *2+1)#define _ *2)static int replmul[1+8] = { 0, a X X X X X X X X X X X X X X X X, a _ X _ X _ X _ X _ X _ X _ X _ X, a _ _ X _ _ X _ _ X _ _ X _ _ X _, a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,};#undef a#undef X#undef _ static voidmktables(void){ int i, j, mask, sh, small; /* bit replication up to 8 bits */ for(i=0; i<256; i++){ for(j=0; j<=8; j++){ /* j <= 8 [sic] */ small = i & ((1<<j)-1); replbit[j][i] = (small*replmul[j])>>8; } } /* bit unpacking up to 8 bits, only powers of 2 */ for(i=0; i<256; i++){ for(j=0, sh=7, mask=1; j<8; j++, sh--) conv18[i][j] = replbit[1][(i>>sh)&mask]; for(j=0, sh=6, mask=3; j<4; j++, sh-=2) conv28[i][j] = replbit[2][(i>>sh)&mask]; for(j=0, sh=4, mask=15; j<2; j++, sh-=4) conv48[i][j] = replbit[4][(i>>sh)&mask]; }} static uchar ones = 0xff; /* * General alpha drawing case. Can handle anything. */typedef struct Buffer Buffer;struct Buffer { /* used by most routines */ uchar *red; uchar *grn; uchar *blu; uchar *alpha; /* is &ones when unused, never nil */ uchar *grey; ulong *rgba; int delta; /* number of bytes to add to pointer to get next pixel to the right */ /* used by boolcalc* for mask data */ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ int mskip; /* no. of left bits to skip in *m */ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ int bmskip; /* no. of left bits to skip in *bm */ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ int emskip; /* no. of right bits to skip in *em */}; typedef struct Param Param;typedef Buffer Readfn(Param*, uchar*, int);typedef void Writefn(Param*, uchar*, Buffer);typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int); enum { MAXBCACHE = 16}; /* giant rathole to customize functions with */struct Param { Readfn *replcall; Readfn *greymaskcall; Readfn *convreadcall; Writefn *convwritecall; Memimage *img; Rectangle r; int dx; /* of r */ int needbuf; int convgrey; int alphaonly; uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ int bwidth; int replcache; /* if set, cache buffers */ Buffer bcache[MAXBCACHE]; ulong bfilled; uchar *bufbase; int bufoff; int bufdelta; int dir; int convbufoff; uchar *convbuf; Param *convdpar; int convdx;}; static Readfn greymaskread, replread, readptr;static Writefn nullwrite;static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;static Calcfn boolcalc14, boolcalc236789, boolcalc1011; static Readfn* readfn(Memimage*);static Readfn* readalphafn(Memimage*);static Writefn* writefn(Memimage*); static Calcfn* boolcopyfn(Memimage*, Memimage*);static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*); static Calcfn *alphacalc[Ncomp] = { alphacalc0, /* Clear */ alphacalc14, /* DoutS */ alphacalc2810, /* SoutD */ alphacalc3679, /* DxorS */ alphacalc14, /* DinS */ alphacalc5, /* D */ alphacalc3679, /* DatopS */ alphacalc3679, /* DoverS */ alphacalc2810, /* SinD */ alphacalc3679, /* SatopD */ alphacalc2810, /* S */ alphacalc11, /* SoverD */}; static Calcfn *boolcalc[Ncomp] ={ alphacalc0, /* Clear */ boolcalc14, /* DoutS */ boolcalc236789, /* SoutD */ boolcalc236789, /* DxorS */ boolcalc14, /* DinS */ alphacalc5, /* D */ boolcalc236789, /* DatopS */ boolcalc236789, /* DoverS */ boolcalc236789, /* SinD */ boolcalc236789, /* SatopD */ boolcalc1011, /* S */ boolcalc1011, /* SoverD */}; /* * Avoid standard Lock, QLock so that can be used in kernel. */typedef struct Dbuf Dbuf;struct Dbuf{ uchar *p; int n; Param spar, mpar, dpar; int inuse;};static Dbuf dbuf[10]; static Dbuf*allocdbuf(void){ int i; for(i=0; i<nelem(dbuf); i++){ if(dbuf[i].inuse) continue; if(!tas(&dbuf[i].inuse)) return &dbuf[i]; } return nil;} static voidgetparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf){ int nbuf; memset(p, 0, sizeof *p); Lines 1–500 of 2436. Load more
#include <u.h> #include <libc.h> #include <draw.h> #include <memdraw.h> /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) /* * For 16-bit values, x / 255 == (t = x+1, (t+(t>>8)) >> 8). * We add another 127 to round to the nearest value rather * than truncate. * * CALCxy does x bytewise calculations on y input images (x=1,4; y=1,2). * CALC2x does two parallel 16-bit calculations on y input images (y=1,2). */ #define CALC11(a, v, tmp) \ (tmp=(a)*(v)+128, (tmp+(tmp>>8))>>8) #define CALC12(a1, v1, a2, v2, tmp) \ (tmp=(a1)*(v1)+(a2)*(v2)+128, (tmp+(tmp>>8))>>8) #define MASK 0xFF00FF #define CALC21(a, vvuu, tmp) \ (tmp=(a)*(vvuu)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC41(a, rgba, tmp1, tmp2) \ (CALC21(a, rgba & MASK, tmp1) | \ (CALC21(a, (rgba>>8)&MASK, tmp2)<<8)) #define CALC22(a1, vvuu1, a2, vvuu2, tmp) \ (tmp=(a1)*(vvuu1)+(a2)*(vvuu2)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK) #define CALC42(a1, rgba1, a2, rgba2, tmp1, tmp2) \ (CALC22(a1, rgba1 & MASK, a2, rgba2 & MASK, tmp1) | \ (CALC22(a1, (rgba1>>8) & MASK, a2, (rgba2>>8) & MASK, tmp2)<<8)) static void mktables(void); typedef int Subdraw(Memdrawparam*); static Subdraw chardraw, alphadraw, memoptdraw; static Memimage* memones; static Memimage* memzeros; Memimage *memwhite; Memimage *memblack; Memimage *memtransparent; Memimage *memopaque; int _ifmt(Fmt*); int memimageinit(void) { static int didinit = 0; if(didinit) return 0; mktables(); _memmkcmap(); fmtinstall('R', Rfmt); fmtinstall('P', Pfmt); memones = allocmemimage(Rect(0,0,1,1), GREY1); memzeros = allocmemimage(Rect(0,0,1,1), GREY1); if(memones == nil || memzeros == nil) return -1; memones->flags |= Frepl; memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memones, ZP) = ~0; memzeros->flags |= Frepl; memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); *byteaddr(memzeros, ZP) = 0; memwhite = memones; memblack = memzeros; memopaque = memones; memtransparent = memzeros; didinit = 1; return 0; } static ulong imgtorgba(Memimage*, ulong); static ulong rgbatoimg(Memimage*, ulong); static ulong pixelbits(Memimage*, Point); void memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op) { Memdrawparam par; if(mask == nil) mask = memopaque; if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0) return; if(op < Clear || op > SoverD) return; par.op = op; par.dst = dst; par.r = r; par.src = src; /* par.sr set by drawclip */ par.mask = mask; /* par.mr set by drawclip */ par.state = 0; if(src->flags&Frepl){ par.state |= Replsrc; if(Dx(src->r)==1 && Dy(src->r)==1){ par.sval = pixelbits(src, src->r.min); par.state |= Simplesrc; par.srgba = imgtorgba(src, par.sval); par.sdval = rgbatoimg(dst, par.srgba); if((par.srgba&0xFF) == 0 && (op&DoutS)) return; /* no-op successfully handled */ } } if(mask->flags & Frepl){ par.state |= Replmask; if(Dx(mask->r)==1 && Dy(mask->r)==1){ par.mval = pixelbits(mask, mask->r.min); if(par.mval == 0 && (op&DoutS)) return; /* no-op successfully handled */ par.state |= Simplemask; if(par.mval == ~0) par.state |= Fullmask; par.mrgba = imgtorgba(mask, par.mval); } } /* * Now that we've clipped the parameters down to be consistent, we * simply try sub-drawing routines in order until we find one that was able * to handle us. If the sub-drawing routine returns zero, it means it was * unable to satisfy the request, so we do not return. */ /* * Hardware support. Each video driver provides this function, * which checks to see if there is anything it can help with. * There could be an if around this checking to see if dst is in video memory. */ if(hwdraw(&par)) return; /* * Optimizations using memmove and memset. */ if(memoptdraw(&par)) return; /* * Character drawing. * Solid source color being painted through a boolean mask onto a high res image. */ if(chardraw(&par)) return; /* * General calculation-laden case that does alpha for each pixel. */ alphadraw(&par); } /* * Clip the destination rectangle further based on the properties of the * source and mask rectangles. Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * * Return zero if the final rectangle is null. */ int drawclipnorepl(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) { Point rmin, delta; int splitcoords; Rectangle omr; if(badrect(*r)) return 0; splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); /* clip to destination */ rmin = r->min; if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) return 0; /* move mask point */ p1->x += r->min.x-rmin.x; p1->y += r->min.y-rmin.y; /* move source point */ p0->x += r->min.x-rmin.x; p0->y += r->min.y-rmin.y; /* map destination rectangle into source */ sr->min = *p0; sr->max.x = p0->x+Dx(*r); sr->max.y = p0->y+Dy(*r); /* sr is r in source coordinates; clip to source */ if(!(src->flags&Frepl) && !rectclip(sr, src->r)) return 0; if(!rectclip(sr, src->clipr)) return 0; /* compute and clip rectangle in mask */ if(splitcoords){ /* move mask point with source */ p1->x += sr->min.x-p0->x; p1->y += sr->min.y-p0->y; mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); omr = *mr; /* mr is now rectangle in mask; clip it */ if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) return 0; if(!rectclip(mr, mask->clipr)) return 0; /* reflect any clips back to source */ sr->min.x += mr->min.x-omr.min.x; sr->min.y += mr->min.y-omr.min.y; sr->max.x += mr->max.x-omr.max.x; sr->max.y += mr->max.y-omr.max.y; }else{ if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) return 0; if(!rectclip(sr, mask->clipr)) return 0; *mr = *sr; } /* move source clipping back to destination */ delta.x = r->min.x - p0->x; delta.y = r->min.y - p0->y; r->min.x = sr->min.x + delta.x; r->min.y = sr->min.y + delta.y; r->max.x = sr->max.x + delta.x; r->max.y = sr->max.y + delta.y; *p0 = sr->min; *p1 = mr->min; assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); assert(ptinrect(r->min, dst->r)); return 1; } /* * like drawclipnorepl() above, but if source or mask is replicated, * move its clipped rectangle so that its minimum point falls within * the repl rectangle. * * Return zero if the final rectangle is null. */ int drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) { Point delta; if(!drawclipnorepl(dst, r, src, p0, mask, p1, sr, mr)) return 0; /* move source rectangle so sr->min is in src->r */ if(src->flags&Frepl) { delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; sr->min.x += delta.x; sr->min.y += delta.y; sr->max.x += delta.x; sr->max.y += delta.y; *p0 = sr->min; } /* move mask point so it is in mask->r */ *p1 = drawrepl(mask->r, *p1); mr->min = *p1; mr->max.x = p1->x+Dx(*sr); mr->max.y = p1->y+Dy(*sr); assert(ptinrect(*p0, src->r)); assert(ptinrect(*p1, mask->r)); return 1; } /* * Conversion tables. */ static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */ static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */ static uchar conv28[256][4]; /* ... */ static uchar conv48[256][2]; /* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit. On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */ #define a ((((((((((((((((0 #define X *2+1) #define _ *2) static int replmul[1+8] = { 0, a X X X X X X X X X X X X X X X X, a _ X _ X _ X _ X _ X _ X _ X _ X, a _ _ X _ _ X _ _ X _ _ X _ _ X _, a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X, }; #undef a #undef X #undef _ static void mktables(void) { int i, j, mask, sh, small; /* bit replication up to 8 bits */ for(i=0; i<256; i++){ for(j=0; j<=8; j++){ /* j <= 8 [sic] */ small = i & ((1<<j)-1); replbit[j][i] = (small*replmul[j])>>8; } } /* bit unpacking up to 8 bits, only powers of 2 */ for(i=0; i<256; i++){ for(j=0, sh=7, mask=1; j<8; j++, sh--) conv18[i][j] = replbit[1][(i>>sh)&mask]; for(j=0, sh=6, mask=3; j<4; j++, sh-=2) conv28[i][j] = replbit[2][(i>>sh)&mask]; for(j=0, sh=4, mask=15; j<2; j++, sh-=4) conv48[i][j] = replbit[4][(i>>sh)&mask]; } } static uchar ones = 0xff; /* * General alpha drawing case. Can handle anything. */ typedef struct Buffer Buffer; struct Buffer { /* used by most routines */ uchar *red; uchar *grn; uchar *blu; uchar *alpha; /* is &ones when unused, never nil */ uchar *grey; ulong *rgba; int delta; /* number of bytes to add to pointer to get next pixel to the right */ /* used by boolcalc* for mask data */ uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ int mskip; /* no. of left bits to skip in *m */ uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ int bmskip; /* no. of left bits to skip in *bm */ uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ int emskip; /* no. of right bits to skip in *em */ }; typedef struct Param Param; typedef Buffer Readfn(Param*, uchar*, int); typedef void Writefn(Param*, uchar*, Buffer); typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int); enum { MAXBCACHE = 16 }; /* giant rathole to customize functions with */ struct Param { Readfn *replcall; Readfn *greymaskcall; Readfn *convreadcall; Writefn *convwritecall; Memimage *img; Rectangle r; int dx; /* of r */ int needbuf; int convgrey; int alphaonly; uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ int bwidth; int replcache; /* if set, cache buffers */ Buffer bcache[MAXBCACHE]; ulong bfilled; uchar *bufbase; int bufoff; int bufdelta; int dir; int convbufoff; uchar *convbuf; Param *convdpar; int convdx; }; static Readfn greymaskread, replread, readptr; static Writefn nullwrite; static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS; static Calcfn boolcalc14, boolcalc236789, boolcalc1011; static Readfn* readfn(Memimage*); static Readfn* readalphafn(Memimage*); static Writefn* writefn(Memimage*); static Calcfn* boolcopyfn(Memimage*, Memimage*); static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*); static Calcfn *alphacalc[Ncomp] = { alphacalc0, /* Clear */ alphacalc14, /* DoutS */ alphacalc2810, /* SoutD */ alphacalc3679, /* DxorS */ alphacalc14, /* DinS */ alphacalc5, /* D */ alphacalc3679, /* DatopS */ alphacalc3679, /* DoverS */ alphacalc2810, /* SinD */ alphacalc3679, /* SatopD */ alphacalc2810, /* S */ alphacalc11, /* SoverD */ }; static Calcfn *boolcalc[Ncomp] = { alphacalc0, /* Clear */ boolcalc14, /* DoutS */ boolcalc236789, /* SoutD */ boolcalc236789, /* DxorS */ boolcalc14, /* DinS */ alphacalc5, /* D */ boolcalc236789, /* DatopS */ boolcalc236789, /* DoverS */ boolcalc236789, /* SinD */ boolcalc236789, /* SatopD */ boolcalc1011, /* S */ boolcalc1011, /* SoverD */ }; /* * Avoid standard Lock, QLock so that can be used in kernel. */ typedef struct Dbuf Dbuf; struct Dbuf { uchar *p; int n; Param spar, mpar, dpar; int inuse; }; static Dbuf dbuf[10]; static Dbuf* allocdbuf(void) { int i; for(i=0; i<nelem(dbuf); i++){ if(dbuf[i].inuse) continue; if(!tas(&dbuf[i].inuse)) return &dbuf[i]; } return nil; } static void getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf) { int nbuf; memset(p, 0, sizeof *p);