xref: /plan9/sys/src/libmemdraw/draw.c (revision 2c1878b464655de2e19be44392cdaf1bb089d01d)
17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <draw.h>
47dd7cddfSDavid du Colombier #include <memdraw.h>
57dd7cddfSDavid du Colombier #include <pool.h>
67dd7cddfSDavid du Colombier 
76a9fc400SDavid du Colombier extern Pool* imagmem;
859cc4ca5SDavid du Colombier int drawdebug;
96a9fc400SDavid du Colombier static int	tablesbuilt;
1059cc4ca5SDavid du Colombier 
117dd7cddfSDavid du Colombier /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
127dd7cddfSDavid du Colombier #define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)
137dd7cddfSDavid du Colombier 
147dd7cddfSDavid du Colombier /*
157dd7cddfSDavid du Colombier  * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation.
167dd7cddfSDavid du Colombier  * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation.
177dd7cddfSDavid du Colombier  * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole.
187dd7cddfSDavid du Colombier  */
197dd7cddfSDavid du Colombier /* #define DIV255(x) (((x)*257+256)>>16)  */
207dd7cddfSDavid du Colombier #define DIV255(x) ((((x)+1)*257)>>16)
217dd7cddfSDavid du Colombier /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */
227dd7cddfSDavid du Colombier 
236a9fc400SDavid du Colombier #define MUL(x, y, t)	(t = (x)*(y)+128, (t+(t>>8))>>8)
246a9fc400SDavid du Colombier #define MASK13	0xFF00FF00
256a9fc400SDavid du Colombier #define MASK02	0x00FF00FF
266a9fc400SDavid du Colombier #define MUL13(a, x, t)		(t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
276a9fc400SDavid du Colombier #define MUL02(a, x, t)		(t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
286a9fc400SDavid du Colombier #define MUL0123(a, x, s, t)	((MUL13(a, x, s)<<8)|MUL02(a, x, t))
296a9fc400SDavid du Colombier 
306a9fc400SDavid du Colombier #define MUL2(u, v, x, y)	(t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)
316a9fc400SDavid du Colombier 
327dd7cddfSDavid du Colombier static void mktables(void);
337dd7cddfSDavid du Colombier typedef int Subdraw(Memdrawparam*);
347dd7cddfSDavid du Colombier static Subdraw chardraw, alphadraw, memoptdraw;
357dd7cddfSDavid du Colombier 
367dd7cddfSDavid du Colombier static Memimage*	memones;
377dd7cddfSDavid du Colombier static Memimage*	memzeros;
387dd7cddfSDavid du Colombier Memimage *memwhite;
397dd7cddfSDavid du Colombier Memimage *memblack;
407dd7cddfSDavid du Colombier Memimage *memtransparent;
417dd7cddfSDavid du Colombier Memimage *memopaque;
427dd7cddfSDavid du Colombier 
439a747e4fSDavid du Colombier int	_ifmt(Fmt*);
449a747e4fSDavid du Colombier 
457dd7cddfSDavid du Colombier void
memimageinit(void)467dd7cddfSDavid du Colombier memimageinit(void)
477dd7cddfSDavid du Colombier {
487dd7cddfSDavid du Colombier 	static int didinit = 0;
497dd7cddfSDavid du Colombier 
507dd7cddfSDavid du Colombier 	if(didinit)
517dd7cddfSDavid du Colombier 		return;
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	didinit = 1;
547dd7cddfSDavid du Colombier 
556a9fc400SDavid du Colombier 	if(strcmp(imagmem->name, "Image") == 0 || strcmp(imagmem->name, "image") == 0)
567dd7cddfSDavid du Colombier 		imagmem->move = memimagemove;
577dd7cddfSDavid du Colombier 
587dd7cddfSDavid du Colombier 	mktables();
597dd7cddfSDavid du Colombier 	_memmkcmap();
607dd7cddfSDavid du Colombier 
619a747e4fSDavid du Colombier 	fmtinstall('R', Rfmt);
629a747e4fSDavid du Colombier 	fmtinstall('P', Pfmt);
639a747e4fSDavid du Colombier 	fmtinstall('b', _ifmt);
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	memones = allocmemimage(Rect(0,0,1,1), GREY1);
667dd7cddfSDavid du Colombier 	memones->flags |= Frepl;
677dd7cddfSDavid du Colombier 	memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
687dd7cddfSDavid du Colombier 	*byteaddr(memones, ZP) = ~0;
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
717dd7cddfSDavid du Colombier 	memzeros->flags |= Frepl;
727dd7cddfSDavid du Colombier 	memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
737dd7cddfSDavid du Colombier 	*byteaddr(memzeros, ZP) = 0;
747dd7cddfSDavid du Colombier 
757dd7cddfSDavid du Colombier 	if(memones == nil || memzeros == nil)
767dd7cddfSDavid du Colombier 		assert(0 /*cannot initialize memimage library */);	/* RSC BUG */
777dd7cddfSDavid du Colombier 
787dd7cddfSDavid du Colombier 	memwhite = memones;
797dd7cddfSDavid du Colombier 	memblack = memzeros;
807dd7cddfSDavid du Colombier 	memopaque = memones;
817dd7cddfSDavid du Colombier 	memtransparent = memzeros;
827dd7cddfSDavid du Colombier }
837dd7cddfSDavid du Colombier 
847dd7cddfSDavid du Colombier static ulong imgtorgba(Memimage*, ulong);
857dd7cddfSDavid du Colombier static ulong rgbatoimg(Memimage*, ulong);
867dd7cddfSDavid du Colombier static ulong pixelbits(Memimage*, Point);
877dd7cddfSDavid du Colombier 
887dd7cddfSDavid du Colombier #define DBG if(0)
897dd7cddfSDavid du Colombier void
memimagedraw(Memimage * dst,Rectangle r,Memimage * src,Point p0,Memimage * mask,Point p1,int op)906a9fc400SDavid du Colombier memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
917dd7cddfSDavid du Colombier {
927dd7cddfSDavid du Colombier 	static int n = 0;
937dd7cddfSDavid du Colombier 	Memdrawparam par;
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	if(mask == nil)
967dd7cddfSDavid du Colombier 		mask = memopaque;
977dd7cddfSDavid du Colombier 
9880ee5cbfSDavid du Colombier DBG	print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);
997dd7cddfSDavid du Colombier 
1007dd7cddfSDavid du Colombier 	if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
10159cc4ca5SDavid du Colombier //		if(drawdebug)
10259cc4ca5SDavid du Colombier //			iprint("empty clipped rectangle\n");
1037dd7cddfSDavid du Colombier 		return;
1047dd7cddfSDavid du Colombier 	}
1057dd7cddfSDavid du Colombier 
1066a9fc400SDavid du Colombier 	if(op < Clear || op > SoverD){
1076a9fc400SDavid du Colombier //		if(drawdebug)
1086a9fc400SDavid du Colombier //			iprint("op out of range: %d\n", op);
1096a9fc400SDavid du Colombier 		return;
1106a9fc400SDavid du Colombier 	}
1116a9fc400SDavid du Colombier 
1126a9fc400SDavid du Colombier 	par.op = op;
1137dd7cddfSDavid du Colombier 	par.dst = dst;
1147dd7cddfSDavid du Colombier 	par.r = r;
1157dd7cddfSDavid du Colombier 	par.src = src;
1167dd7cddfSDavid du Colombier 	/* par.sr set by drawclip */
1177dd7cddfSDavid du Colombier 	par.mask = mask;
1187dd7cddfSDavid du Colombier 	/* par.mr set by drawclip */
1197dd7cddfSDavid du Colombier 
1207dd7cddfSDavid du Colombier 	par.state = 0;
1217dd7cddfSDavid du Colombier 	if(src->flags&Frepl){
1227dd7cddfSDavid du Colombier 		par.state |= Replsrc;
1237dd7cddfSDavid du Colombier 		if(Dx(src->r)==1 && Dy(src->r)==1){
1247dd7cddfSDavid du Colombier 			par.sval = pixelbits(src, src->r.min);
1257dd7cddfSDavid du Colombier 			par.state |= Simplesrc;
1267dd7cddfSDavid du Colombier 			par.srgba = imgtorgba(src, par.sval);
1277dd7cddfSDavid du Colombier 			par.sdval = rgbatoimg(dst, par.srgba);
1286a9fc400SDavid du Colombier 			if((par.srgba&0xFF) == 0 && (op&DoutS)){
1293ff48bf5SDavid du Colombier //				if (drawdebug) iprint("fill with transparent source\n");
1303ff48bf5SDavid du Colombier 				return;	/* no-op successfully handled */
1313ff48bf5SDavid du Colombier 			}
1327dd7cddfSDavid du Colombier 		}
1337dd7cddfSDavid du Colombier 	}
1347dd7cddfSDavid du Colombier 
1357dd7cddfSDavid du Colombier 	if(mask->flags & Frepl){
1367dd7cddfSDavid du Colombier 		par.state |= Replmask;
1377dd7cddfSDavid du Colombier 		if(Dx(mask->r)==1 && Dy(mask->r)==1){
1387dd7cddfSDavid du Colombier 			par.mval = pixelbits(mask, mask->r.min);
1396a9fc400SDavid du Colombier 			if(par.mval == 0 && (op&DoutS)){
14059cc4ca5SDavid du Colombier //				if(drawdebug) iprint("fill with zero mask\n");
1417dd7cddfSDavid du Colombier 				return;	/* no-op successfully handled */
1427dd7cddfSDavid du Colombier 			}
1437dd7cddfSDavid du Colombier 			par.state |= Simplemask;
1447dd7cddfSDavid du Colombier 			if(par.mval == ~0)
1457dd7cddfSDavid du Colombier 				par.state |= Fullmask;
1467dd7cddfSDavid du Colombier 			par.mrgba = imgtorgba(mask, par.mval);
1477dd7cddfSDavid du Colombier 		}
1487dd7cddfSDavid du Colombier 	}
1497dd7cddfSDavid du Colombier 
15059cc4ca5SDavid du Colombier //	if(drawdebug)
15159cc4ca5SDavid du Colombier //		iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);
15259cc4ca5SDavid du Colombier DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
1537dd7cddfSDavid du Colombier 
1547dd7cddfSDavid du Colombier 	/*
1557dd7cddfSDavid du Colombier 	 * Now that we've clipped the parameters down to be consistent, we
1567dd7cddfSDavid du Colombier 	 * simply try sub-drawing routines in order until we find one that was able
1577dd7cddfSDavid du Colombier 	 * to handle us.  If the sub-drawing routine returns zero, it means it was
1587dd7cddfSDavid du Colombier 	 * unable to satisfy the request, so we do not return.
1597dd7cddfSDavid du Colombier 	 */
1607dd7cddfSDavid du Colombier 
1617dd7cddfSDavid du Colombier 	/*
1627dd7cddfSDavid du Colombier 	 * Hardware support.  Each video driver provides this function,
1637dd7cddfSDavid du Colombier 	 * which checks to see if there is anything it can help with.
1647dd7cddfSDavid du Colombier 	 * There could be an if around this checking to see if dst is in video memory.
1657dd7cddfSDavid du Colombier 	 */
16680ee5cbfSDavid du Colombier DBG print("test hwdraw\n");
16759cc4ca5SDavid du Colombier 	if(hwdraw(&par)){
16859cc4ca5SDavid du Colombier //if(drawdebug) iprint("hw handled\n");
16959cc4ca5SDavid du Colombier DBG print("hwdraw handled\n");
1707dd7cddfSDavid du Colombier 		return;
1717dd7cddfSDavid du Colombier 	}
1727dd7cddfSDavid du Colombier 	/*
1737dd7cddfSDavid du Colombier 	 * Optimizations using memmove and memset.
1747dd7cddfSDavid du Colombier 	 */
17580ee5cbfSDavid du Colombier DBG print("test memoptdraw\n");
1767dd7cddfSDavid du Colombier 	if(memoptdraw(&par)){
17759cc4ca5SDavid du Colombier //if(drawdebug) iprint("memopt handled\n");
17859cc4ca5SDavid du Colombier DBG print("memopt handled\n");
1797dd7cddfSDavid du Colombier 		return;
1807dd7cddfSDavid du Colombier 	}
1817dd7cddfSDavid du Colombier 
1827dd7cddfSDavid du Colombier 	/*
1837dd7cddfSDavid du Colombier 	 * Character drawing.
1847dd7cddfSDavid du Colombier 	 * Solid source color being painted through a boolean mask onto a high res image.
1857dd7cddfSDavid du Colombier 	 */
18680ee5cbfSDavid du Colombier DBG print("test chardraw\n");
1877dd7cddfSDavid du Colombier 	if(chardraw(&par)){
18859cc4ca5SDavid du Colombier //if(drawdebug) iprint("chardraw handled\n");
18959cc4ca5SDavid du Colombier DBG print("chardraw handled\n");
1907dd7cddfSDavid du Colombier 		return;
1917dd7cddfSDavid du Colombier 	}
1927dd7cddfSDavid du Colombier 
1937dd7cddfSDavid du Colombier 	/*
1947dd7cddfSDavid du Colombier 	 * General calculation-laden case that does alpha for each pixel.
1957dd7cddfSDavid du Colombier 	 */
19680ee5cbfSDavid du Colombier DBG print("do alphadraw\n");
1977dd7cddfSDavid du Colombier 	alphadraw(&par);
19859cc4ca5SDavid du Colombier //if(drawdebug) iprint("alphadraw handled\n");
19959cc4ca5SDavid du Colombier DBG print("alphadraw handled\n");
2007dd7cddfSDavid du Colombier }
2017dd7cddfSDavid du Colombier #undef DBG
2027dd7cddfSDavid du Colombier 
2037dd7cddfSDavid du Colombier /*
2047dd7cddfSDavid du Colombier  * Clip the destination rectangle further based on the properties of the
2057dd7cddfSDavid du Colombier  * source and mask rectangles.  Once the destination rectangle is properly
2067dd7cddfSDavid du Colombier  * clipped, adjust the source and mask rectangles to be the same size.
2077dd7cddfSDavid du Colombier  * Then if source or mask is replicated, move its clipped rectangle
2087dd7cddfSDavid du Colombier  * so that its minimum point falls within the repl rectangle.
2097dd7cddfSDavid du Colombier  *
2107dd7cddfSDavid du Colombier  * Return zero if the final rectangle is null.
2117dd7cddfSDavid du Colombier  */
2127dd7cddfSDavid du Colombier int
drawclip(Memimage * dst,Rectangle * r,Memimage * src,Point * p0,Memimage * mask,Point * p1,Rectangle * sr,Rectangle * mr)2137dd7cddfSDavid du Colombier drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
2147dd7cddfSDavid du Colombier {
2157dd7cddfSDavid du Colombier 	Point rmin, delta;
2167dd7cddfSDavid du Colombier 	int splitcoords;
2177dd7cddfSDavid du Colombier 	Rectangle omr;
2187dd7cddfSDavid du Colombier 
2197dd7cddfSDavid du Colombier 	if(r->min.x>=r->max.x || r->min.y>=r->max.y)
2207dd7cddfSDavid du Colombier 		return 0;
2217dd7cddfSDavid du Colombier 	splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
2227dd7cddfSDavid du Colombier 	/* clip to destination */
2237dd7cddfSDavid du Colombier 	rmin = r->min;
2247dd7cddfSDavid du Colombier 	if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
2257dd7cddfSDavid du Colombier 		return 0;
2267dd7cddfSDavid du Colombier 	/* move mask point */
2277dd7cddfSDavid du Colombier 	p1->x += r->min.x-rmin.x;
2287dd7cddfSDavid du Colombier 	p1->y += r->min.y-rmin.y;
2297dd7cddfSDavid du Colombier 	/* move source point */
2307dd7cddfSDavid du Colombier 	p0->x += r->min.x-rmin.x;
2317dd7cddfSDavid du Colombier 	p0->y += r->min.y-rmin.y;
2327dd7cddfSDavid du Colombier 	/* map destination rectangle into source */
2337dd7cddfSDavid du Colombier 	sr->min = *p0;
2347dd7cddfSDavid du Colombier 	sr->max.x = p0->x+Dx(*r);
2357dd7cddfSDavid du Colombier 	sr->max.y = p0->y+Dy(*r);
2367dd7cddfSDavid du Colombier 	/* sr is r in source coordinates; clip to source */
2377dd7cddfSDavid du Colombier 	if(!(src->flags&Frepl) && !rectclip(sr, src->r))
2387dd7cddfSDavid du Colombier 		return 0;
2397dd7cddfSDavid du Colombier 	if(!rectclip(sr, src->clipr))
2407dd7cddfSDavid du Colombier 		return 0;
2417dd7cddfSDavid du Colombier 	/* compute and clip rectangle in mask */
2427dd7cddfSDavid du Colombier 	if(splitcoords){
2437dd7cddfSDavid du Colombier 		/* move mask point with source */
2447dd7cddfSDavid du Colombier 		p1->x += sr->min.x-p0->x;
2457dd7cddfSDavid du Colombier 		p1->y += sr->min.y-p0->y;
2467dd7cddfSDavid du Colombier 		mr->min = *p1;
2477dd7cddfSDavid du Colombier 		mr->max.x = p1->x+Dx(*sr);
2487dd7cddfSDavid du Colombier 		mr->max.y = p1->y+Dy(*sr);
2497dd7cddfSDavid du Colombier 		omr = *mr;
2507dd7cddfSDavid du Colombier 		/* mr is now rectangle in mask; clip it */
2517dd7cddfSDavid du Colombier 		if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
2527dd7cddfSDavid du Colombier 			return 0;
2537dd7cddfSDavid du Colombier 		if(!rectclip(mr, mask->clipr))
2547dd7cddfSDavid du Colombier 			return 0;
2557dd7cddfSDavid du Colombier 		/* reflect any clips back to source */
2567dd7cddfSDavid du Colombier 		sr->min.x += mr->min.x-omr.min.x;
2577dd7cddfSDavid du Colombier 		sr->min.y += mr->min.y-omr.min.y;
2587dd7cddfSDavid du Colombier 		sr->max.x += mr->max.x-omr.max.x;
2597dd7cddfSDavid du Colombier 		sr->max.y += mr->max.y-omr.max.y;
2607dd7cddfSDavid du Colombier 		*p1 = mr->min;
2617dd7cddfSDavid du Colombier 	}else{
2627dd7cddfSDavid du Colombier 		if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
2637dd7cddfSDavid du Colombier 			return 0;
2647dd7cddfSDavid du Colombier 		if(!rectclip(sr, mask->clipr))
2657dd7cddfSDavid du Colombier 			return 0;
2667dd7cddfSDavid du Colombier 		*p1 = sr->min;
2677dd7cddfSDavid du Colombier 	}
2687dd7cddfSDavid du Colombier 
2697dd7cddfSDavid du Colombier 	/* move source clipping back to destination */
2707dd7cddfSDavid du Colombier 	delta.x = r->min.x - p0->x;
2717dd7cddfSDavid du Colombier 	delta.y = r->min.y - p0->y;
2727dd7cddfSDavid du Colombier 	r->min.x = sr->min.x + delta.x;
2737dd7cddfSDavid du Colombier 	r->min.y = sr->min.y + delta.y;
2747dd7cddfSDavid du Colombier 	r->max.x = sr->max.x + delta.x;
2757dd7cddfSDavid du Colombier 	r->max.y = sr->max.y + delta.y;
2767dd7cddfSDavid du Colombier 
2777dd7cddfSDavid du Colombier 	/* move source rectangle so sr->min is in src->r */
2787dd7cddfSDavid du Colombier 	if(src->flags&Frepl) {
2797dd7cddfSDavid du Colombier 		delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
2807dd7cddfSDavid du Colombier 		delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
2817dd7cddfSDavid du Colombier 		sr->min.x += delta.x;
2827dd7cddfSDavid du Colombier 		sr->min.y += delta.y;
2837dd7cddfSDavid du Colombier 		sr->max.x += delta.x;
2847dd7cddfSDavid du Colombier 		sr->max.y += delta.y;
2857dd7cddfSDavid du Colombier 	}
2867dd7cddfSDavid du Colombier 	*p0 = sr->min;
2877dd7cddfSDavid du Colombier 
2887dd7cddfSDavid du Colombier 	/* move mask point so it is in mask->r */
2897dd7cddfSDavid du Colombier 	*p1 = drawrepl(mask->r, *p1);
2907dd7cddfSDavid du Colombier 	mr->min = *p1;
2917dd7cddfSDavid du Colombier 	mr->max.x = p1->x+Dx(*sr);
2927dd7cddfSDavid du Colombier 	mr->max.y = p1->y+Dy(*sr);
2937dd7cddfSDavid du Colombier 
2947dd7cddfSDavid du Colombier 	assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
2957dd7cddfSDavid du Colombier 	assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
2967dd7cddfSDavid du Colombier 	assert(ptinrect(*p0, src->r));
2977dd7cddfSDavid du Colombier 	assert(ptinrect(*p1, mask->r));
2987dd7cddfSDavid du Colombier 	assert(ptinrect(r->min, dst->r));
2997dd7cddfSDavid du Colombier 
3007dd7cddfSDavid du Colombier 	return 1;
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier 
3037dd7cddfSDavid du Colombier /*
3047dd7cddfSDavid du Colombier  * Conversion tables.
3057dd7cddfSDavid du Colombier  */
3067dd7cddfSDavid du Colombier static uchar replbit[1+8][256];		/* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
3077dd7cddfSDavid du Colombier static uchar conv18[256][8];		/* conv18[x][y] is the yth pixel in the depth-1 pixel x */
3087dd7cddfSDavid du Colombier static uchar conv28[256][4];		/* ... */
3097dd7cddfSDavid du Colombier static uchar conv48[256][2];
3107dd7cddfSDavid du Colombier 
3117dd7cddfSDavid du Colombier /*
3127dd7cddfSDavid du Colombier  * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
3137dd7cddfSDavid du Colombier  * the X's are where to put the bottom (ones) bit of the n-bit pattern.
3147dd7cddfSDavid du Colombier  * only the top 8 bits of the result are actually used.
3157dd7cddfSDavid du Colombier  * (the lower 8 bits are needed to get bits in the right place
3167dd7cddfSDavid du Colombier  * when n is not a divisor of 8.)
3177dd7cddfSDavid du Colombier  *
3187dd7cddfSDavid du Colombier  * Should check to see if its easier to just refer to replmul than
3197dd7cddfSDavid du Colombier  * use the precomputed values in replbit.  On PCs it may well
3207dd7cddfSDavid du Colombier  * be; on machines with slow multiply instructions it probably isn't.
3217dd7cddfSDavid du Colombier  */
3227dd7cddfSDavid du Colombier #define a ((((((((((((((((0
3237dd7cddfSDavid du Colombier #define X *2+1)
3247dd7cddfSDavid du Colombier #define _ *2)
3257dd7cddfSDavid du Colombier static int replmul[1+8] = {
3267dd7cddfSDavid du Colombier 	0,
3277dd7cddfSDavid du Colombier 	a X X X X X X X X X X X X X X X X,
3287dd7cddfSDavid du Colombier 	a _ X _ X _ X _ X _ X _ X _ X _ X,
3297dd7cddfSDavid du Colombier 	a _ _ X _ _ X _ _ X _ _ X _ _ X _,
3307dd7cddfSDavid du Colombier 	a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
3317dd7cddfSDavid du Colombier 	a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
3327dd7cddfSDavid du Colombier 	a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _,
3337dd7cddfSDavid du Colombier 	a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
3347dd7cddfSDavid du Colombier 	a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
3357dd7cddfSDavid du Colombier };
3367dd7cddfSDavid du Colombier #undef a
3377dd7cddfSDavid du Colombier #undef X
3387dd7cddfSDavid du Colombier #undef _
3397dd7cddfSDavid du Colombier 
3407dd7cddfSDavid du Colombier static void
mktables(void)3417dd7cddfSDavid du Colombier mktables(void)
3427dd7cddfSDavid du Colombier {
3437dd7cddfSDavid du Colombier 	int i, j, mask, sh, small;
3447dd7cddfSDavid du Colombier 
3457dd7cddfSDavid du Colombier 	if(tablesbuilt)
3467dd7cddfSDavid du Colombier 		return;
3477dd7cddfSDavid du Colombier 
3489a747e4fSDavid du Colombier 	fmtinstall('R', Rfmt);
3499a747e4fSDavid du Colombier 	fmtinstall('P', Pfmt);
3507dd7cddfSDavid du Colombier 	tablesbuilt = 1;
3516a9fc400SDavid du Colombier 
3527dd7cddfSDavid du Colombier 	/* bit replication up to 8 bits */
3537dd7cddfSDavid du Colombier 	for(i=0; i<256; i++){
3547dd7cddfSDavid du Colombier 		for(j=0; j<=8; j++){	/* j <= 8 [sic] */
3557dd7cddfSDavid du Colombier 			small = i & ((1<<j)-1);
3567dd7cddfSDavid du Colombier 			replbit[j][i] = (small*replmul[j])>>8;
3577dd7cddfSDavid du Colombier 		}
3587dd7cddfSDavid du Colombier 	}
3597dd7cddfSDavid du Colombier 
3607dd7cddfSDavid du Colombier 	/* bit unpacking up to 8 bits, only powers of 2 */
3617dd7cddfSDavid du Colombier 	for(i=0; i<256; i++){
3627dd7cddfSDavid du Colombier 		for(j=0, sh=7, mask=1; j<8; j++, sh--)
3637dd7cddfSDavid du Colombier 			conv18[i][j] = replbit[1][(i>>sh)&mask];
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier 		for(j=0, sh=6, mask=3; j<4; j++, sh-=2)
3667dd7cddfSDavid du Colombier 			conv28[i][j] = replbit[2][(i>>sh)&mask];
3677dd7cddfSDavid du Colombier 
3687dd7cddfSDavid du Colombier 		for(j=0, sh=4, mask=15; j<2; j++, sh-=4)
3697dd7cddfSDavid du Colombier 			conv48[i][j] = replbit[4][(i>>sh)&mask];
3707dd7cddfSDavid du Colombier 	}
3717dd7cddfSDavid du Colombier }
3727dd7cddfSDavid du Colombier 
3736a9fc400SDavid du Colombier static uchar ones = 0xff;
3746a9fc400SDavid du Colombier 
3757dd7cddfSDavid du Colombier /*
3767dd7cddfSDavid du Colombier  * General alpha drawing case.  Can handle anything.
3777dd7cddfSDavid du Colombier  */
3786a9fc400SDavid du Colombier typedef struct	Buffer	Buffer;
3796a9fc400SDavid du Colombier struct Buffer {
3806a9fc400SDavid du Colombier 	/* used by most routines */
3817dd7cddfSDavid du Colombier 	uchar	*red;
3827dd7cddfSDavid du Colombier 	uchar	*grn;
3837dd7cddfSDavid du Colombier 	uchar	*blu;
3847dd7cddfSDavid du Colombier 	uchar	*alpha;
3857dd7cddfSDavid du Colombier 	uchar	*grey;
3866a9fc400SDavid du Colombier 	ulong	*rgba;
3877dd7cddfSDavid du Colombier 	int	delta;	/* number of bytes to add to pointer to get next pixel to the right */
3886a9fc400SDavid du Colombier 
3896a9fc400SDavid du Colombier 	/* used by boolcalc* for mask data */
3907dd7cddfSDavid du Colombier 	uchar	*m;		/* ptr to mask data r.min byte; like p->bytermin */
3917dd7cddfSDavid du Colombier 	int		mskip;	/* no. of left bits to skip in *m */
3927dd7cddfSDavid du Colombier 	uchar	*bm;		/* ptr to mask data img->r.min byte; like p->bytey0s */
3937dd7cddfSDavid du Colombier 	int		bmskip;	/* no. of left bits to skip in *bm */
3947dd7cddfSDavid du Colombier 	uchar	*em;		/* ptr to mask data img->r.max.x byte; like p->bytey0e */
3957dd7cddfSDavid du Colombier 	int		emskip;	/* no. of right bits to skip in *em */
3967dd7cddfSDavid du Colombier };
3977dd7cddfSDavid du Colombier 
3987dd7cddfSDavid du Colombier typedef struct	Param	Param;
3997dd7cddfSDavid du Colombier typedef Buffer	Readfn(Param*, uchar*, int);
4007dd7cddfSDavid du Colombier typedef void	Writefn(Param*, uchar*, Buffer);
4016a9fc400SDavid du Colombier typedef Buffer	Calcfn(Buffer, Buffer, Buffer, int, int, int);
4027dd7cddfSDavid du Colombier 
4037dd7cddfSDavid du Colombier enum {
4047dd7cddfSDavid du Colombier 	MAXBCACHE = 16
4057dd7cddfSDavid du Colombier };
4067dd7cddfSDavid du Colombier 
4077dd7cddfSDavid du Colombier /* giant rathole to customize functions with */
4087dd7cddfSDavid du Colombier struct Param {
4097dd7cddfSDavid du Colombier 	Readfn	*replcall;
4107dd7cddfSDavid du Colombier 	Readfn	*greymaskcall;
4117dd7cddfSDavid du Colombier 	Readfn	*convreadcall;
4127dd7cddfSDavid du Colombier 	Writefn	*convwritecall;
4137dd7cddfSDavid du Colombier 
4147dd7cddfSDavid du Colombier 	Memimage *img;
4157dd7cddfSDavid du Colombier 	Rectangle	r;
4167dd7cddfSDavid du Colombier 	int	dx;	/* of r */
4177dd7cddfSDavid du Colombier 	int	needbuf;
4187dd7cddfSDavid du Colombier 	int	convgrey;
4197dd7cddfSDavid du Colombier 	int	alphaonly;
4207dd7cddfSDavid du Colombier 
4217dd7cddfSDavid du Colombier 	uchar	*bytey0s;		/* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
4227dd7cddfSDavid du Colombier 	uchar	*bytermin;	/* byteaddr(Pt(r.min.x, img->r.min.y)) */
4237dd7cddfSDavid du Colombier 	uchar	*bytey0e;		/* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
4247dd7cddfSDavid du Colombier 	int		bwidth;
4257dd7cddfSDavid du Colombier 
4267dd7cddfSDavid du Colombier 	int	replcache;	/* if set, cache buffers */
4277dd7cddfSDavid du Colombier 	Buffer	bcache[MAXBCACHE];
4287dd7cddfSDavid du Colombier 	ulong	bfilled;
4297dd7cddfSDavid du Colombier 	uchar	*bufbase;
4307dd7cddfSDavid du Colombier 	int	bufoff;
4317dd7cddfSDavid du Colombier 	int	bufdelta;
4327dd7cddfSDavid du Colombier 
4337dd7cddfSDavid du Colombier 	int	dir;
4347dd7cddfSDavid du Colombier 
4357dd7cddfSDavid du Colombier 	int	convbufoff;
4367dd7cddfSDavid du Colombier 	uchar	*convbuf;
4377dd7cddfSDavid du Colombier 	Param	*convdpar;
4387dd7cddfSDavid du Colombier 	int	convdx;
4397dd7cddfSDavid du Colombier };
4407dd7cddfSDavid du Colombier 
4417dd7cddfSDavid du Colombier static uchar *drawbuf;
4427dd7cddfSDavid du Colombier static int	ndrawbuf;
4437dd7cddfSDavid du Colombier static int	mdrawbuf;
4447dd7cddfSDavid du Colombier static Readfn	greymaskread, replread, readptr;
4457dd7cddfSDavid du Colombier static Writefn	nullwrite;
4466a9fc400SDavid du Colombier static Calcfn	alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
4476a9fc400SDavid du Colombier static Calcfn	boolcalc14, boolcalc236789, boolcalc1011;
4487dd7cddfSDavid du Colombier 
4497dd7cddfSDavid du Colombier static Readfn*	readfn(Memimage*);
4507dd7cddfSDavid du Colombier static Readfn*	readalphafn(Memimage*);
4517dd7cddfSDavid du Colombier static Writefn*	writefn(Memimage*);
4527dd7cddfSDavid du Colombier 
4537dd7cddfSDavid du Colombier static Calcfn*	boolcopyfn(Memimage*, Memimage*);
454*2c1878b4SDavid du Colombier static Readfn*	convfn(Memimage*, Param*, Memimage*, Param*, int*);
4557dd7cddfSDavid du Colombier static Readfn*	ptrfn(Memimage*);
4567dd7cddfSDavid du Colombier 
4576a9fc400SDavid du Colombier static Calcfn *alphacalc[Ncomp] =
4586a9fc400SDavid du Colombier {
4596a9fc400SDavid du Colombier 	alphacalc0,		/* Clear */
4606a9fc400SDavid du Colombier 	alphacalc14,		/* DoutS */
4616a9fc400SDavid du Colombier 	alphacalc2810,		/* SoutD */
4626a9fc400SDavid du Colombier 	alphacalc3679,		/* DxorS */
4636a9fc400SDavid du Colombier 	alphacalc14,		/* DinS */
4646a9fc400SDavid du Colombier 	alphacalc5,		/* D */
4656a9fc400SDavid du Colombier 	alphacalc3679,		/* DatopS */
4666a9fc400SDavid du Colombier 	alphacalc3679,		/* DoverS */
4676a9fc400SDavid du Colombier 	alphacalc2810,		/* SinD */
4686a9fc400SDavid du Colombier 	alphacalc3679,		/* SatopD */
4696a9fc400SDavid du Colombier 	alphacalc2810,		/* S */
4706a9fc400SDavid du Colombier 	alphacalc11,		/* SoverD */
4716a9fc400SDavid du Colombier };
4726a9fc400SDavid du Colombier 
4736a9fc400SDavid du Colombier static Calcfn *boolcalc[Ncomp] =
4746a9fc400SDavid du Colombier {
4756a9fc400SDavid du Colombier 	alphacalc0,		/* Clear */
4766a9fc400SDavid du Colombier 	boolcalc14,		/* DoutS */
4776a9fc400SDavid du Colombier 	boolcalc236789,		/* SoutD */
4786a9fc400SDavid du Colombier 	boolcalc236789,		/* DxorS */
4796a9fc400SDavid du Colombier 	boolcalc14,		/* DinS */
4806a9fc400SDavid du Colombier 	alphacalc5,		/* D */
4816a9fc400SDavid du Colombier 	boolcalc236789,		/* DatopS */
4826a9fc400SDavid du Colombier 	boolcalc236789,		/* DoverS */
4836a9fc400SDavid du Colombier 	boolcalc236789,		/* SinD */
4846a9fc400SDavid du Colombier 	boolcalc236789,		/* SatopD */
4856a9fc400SDavid du Colombier 	boolcalc1011,		/* S */
4866a9fc400SDavid du Colombier 	boolcalc1011,		/* SoverD */
4876a9fc400SDavid du Colombier };
4886a9fc400SDavid du Colombier 
489*2c1878b4SDavid du Colombier /*
490*2c1878b4SDavid du Colombier  * Avoid standard Lock, QLock so that can be used in kernel.
491*2c1878b4SDavid du Colombier  */
492*2c1878b4SDavid du Colombier typedef struct Dbuf Dbuf;
493*2c1878b4SDavid du Colombier struct Dbuf
4947dd7cddfSDavid du Colombier {
4957dd7cddfSDavid du Colombier 	uchar *p;
496*2c1878b4SDavid du Colombier 	int n;
497*2c1878b4SDavid du Colombier 	Param spar, mpar, dpar;
498*2c1878b4SDavid du Colombier 	int inuse;
499*2c1878b4SDavid du Colombier };
500*2c1878b4SDavid du Colombier static Dbuf dbuf[10];
5017dd7cddfSDavid du Colombier 
502*2c1878b4SDavid du Colombier static Dbuf*
allocdbuf(void)503*2c1878b4SDavid du Colombier allocdbuf(void)
5047dd7cddfSDavid du Colombier {
505*2c1878b4SDavid du Colombier 	int i;
506*2c1878b4SDavid du Colombier 
507*2c1878b4SDavid du Colombier 	for(i=0; i<nelem(dbuf); i++){
508*2c1878b4SDavid du Colombier 		if(dbuf[i].inuse)
509*2c1878b4SDavid du Colombier 			continue;
510*2c1878b4SDavid du Colombier 		if(!_tas(&dbuf[i].inuse))
511*2c1878b4SDavid du Colombier 			return &dbuf[i];
512*2c1878b4SDavid du Colombier 	}
513*2c1878b4SDavid du Colombier 	return nil;
514*2c1878b4SDavid du Colombier }
515*2c1878b4SDavid du Colombier 
516*2c1878b4SDavid du Colombier static void
getparam(Param * p,Memimage * img,Rectangle r,int convgrey,int needbuf,int * ndrawbuf)517*2c1878b4SDavid du Colombier getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf)
518*2c1878b4SDavid du Colombier {
5197dd7cddfSDavid du Colombier 	int nbuf;
5207dd7cddfSDavid du Colombier 
521*2c1878b4SDavid du Colombier 	memset(p, 0, sizeof *p);
5227dd7cddfSDavid du Colombier 
523*2c1878b4SDavid du Colombier 	p->img = img;
524*2c1878b4SDavid du Colombier 	p->r = r;
525*2c1878b4SDavid du Colombier 	p->dx = Dx(r);
526*2c1878b4SDavid du Colombier 	p->needbuf = needbuf;
527*2c1878b4SDavid du Colombier 	p->convgrey = convgrey;
5287dd7cddfSDavid du Colombier 
5297dd7cddfSDavid du Colombier 	assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
5307dd7cddfSDavid du Colombier 
531*2c1878b4SDavid du Colombier 	p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
532*2c1878b4SDavid du Colombier 	p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
533*2c1878b4SDavid du Colombier 	p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
534*2c1878b4SDavid du Colombier 	p->bwidth = sizeof(ulong)*img->width;
5357dd7cddfSDavid du Colombier 
536*2c1878b4SDavid du Colombier 	assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);
5377dd7cddfSDavid du Colombier 
538*2c1878b4SDavid du Colombier 	if(p->r.min.x == p->img->r.min.x)
539*2c1878b4SDavid du Colombier 		assert(p->bytermin == p->bytey0s);
5407dd7cddfSDavid du Colombier 
5417dd7cddfSDavid du Colombier 	nbuf = 1;
5427dd7cddfSDavid du Colombier 	if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
543*2c1878b4SDavid du Colombier 		p->replcache = 1;
5447dd7cddfSDavid du Colombier 		nbuf = Dy(img->r);
5457dd7cddfSDavid du Colombier 	}
546*2c1878b4SDavid du Colombier 	p->bufdelta = 4*p->dx;
547*2c1878b4SDavid du Colombier 	p->bufoff = *ndrawbuf;
548*2c1878b4SDavid du Colombier 	*ndrawbuf += p->bufdelta*nbuf;
5497dd7cddfSDavid du Colombier }
5507dd7cddfSDavid du Colombier 
5517dd7cddfSDavid du Colombier static void
clipy(Memimage * img,int * y)5527dd7cddfSDavid du Colombier clipy(Memimage *img, int *y)
5537dd7cddfSDavid du Colombier {
5547dd7cddfSDavid du Colombier 	int dy;
5557dd7cddfSDavid du Colombier 
5567dd7cddfSDavid du Colombier 	dy = Dy(img->r);
5577dd7cddfSDavid du Colombier 	if(*y == dy)
5587dd7cddfSDavid du Colombier 		*y = 0;
5597dd7cddfSDavid du Colombier 	else if(*y == -1)
5607dd7cddfSDavid du Colombier 		*y = dy-1;
5617dd7cddfSDavid du Colombier 	assert(0 <= *y && *y < dy);
5627dd7cddfSDavid du Colombier }
5637dd7cddfSDavid du Colombier 
5647dd7cddfSDavid du Colombier static void
dumpbuf(char * s,Buffer b,int n)5657dd7cddfSDavid du Colombier dumpbuf(char *s, Buffer b, int n)
5667dd7cddfSDavid du Colombier {
5677dd7cddfSDavid du Colombier 	int i;
5687dd7cddfSDavid du Colombier 	uchar *p;
5697dd7cddfSDavid du Colombier 
5707dd7cddfSDavid du Colombier 	print("%s", s);
5717dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
5727dd7cddfSDavid du Colombier 		print(" ");
5737dd7cddfSDavid du Colombier 		if(p=b.grey){
5747dd7cddfSDavid du Colombier 			print(" k%.2uX", *p);
5757dd7cddfSDavid du Colombier 			b.grey += b.delta;
5767dd7cddfSDavid du Colombier 		}else{
5777dd7cddfSDavid du Colombier 			if(p=b.red){
5787dd7cddfSDavid du Colombier 				print(" r%.2uX", *p);
5797dd7cddfSDavid du Colombier 				b.red += b.delta;
5807dd7cddfSDavid du Colombier 			}
5817dd7cddfSDavid du Colombier 			if(p=b.grn){
5827dd7cddfSDavid du Colombier 				print(" g%.2uX", *p);
5837dd7cddfSDavid du Colombier 				b.grn += b.delta;
5847dd7cddfSDavid du Colombier 			}
5857dd7cddfSDavid du Colombier 			if(p=b.blu){
5867dd7cddfSDavid du Colombier 				print(" b%.2uX", *p);
5877dd7cddfSDavid du Colombier 				b.blu += b.delta;
5887dd7cddfSDavid du Colombier 			}
5897dd7cddfSDavid du Colombier 		}
5906a9fc400SDavid du Colombier 		if((p=b.alpha) != &ones){
5917dd7cddfSDavid du Colombier 			print(" α%.2uX", *p);
5927dd7cddfSDavid du Colombier 			b.alpha += b.delta;
5937dd7cddfSDavid du Colombier 		}
5947dd7cddfSDavid du Colombier 	}
5957dd7cddfSDavid du Colombier 	print("\n");
5967dd7cddfSDavid du Colombier }
5977dd7cddfSDavid du Colombier 
5987dd7cddfSDavid du Colombier /*
5997dd7cddfSDavid du Colombier  * For each scan line, we expand the pixels from source, mask, and destination
6007dd7cddfSDavid du Colombier  * into byte-aligned red, green, blue, alpha, and grey channels.  If buffering is not
6017dd7cddfSDavid du Colombier  * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
6027dd7cddfSDavid du Colombier  * the readers need not copy the data: they can simply return pointers to the data.
6037dd7cddfSDavid du Colombier  * If the destination image is grey and the source is not, it is converted using the NTSC
6047dd7cddfSDavid du Colombier  * formula.
6057dd7cddfSDavid du Colombier  *
6067dd7cddfSDavid du Colombier  * Once we have all the channels, we call either rgbcalc or greycalc, depending on
6077dd7cddfSDavid du Colombier  * whether the destination image is color.  This is allowed to overwrite the dst buffer (perhaps
6087dd7cddfSDavid du Colombier  * the actual data, perhaps a copy) with its result.  It should only overwrite the dst buffer
6097dd7cddfSDavid du Colombier  * with the same format (i.e. red bytes with red bytes, etc.)  A new buffer is returned from
6107dd7cddfSDavid du Colombier  * the calculator, and that buffer is passed to a function to write it to the destination.
6117dd7cddfSDavid du Colombier  * If the buffer is already pointing at the destination, the writing function is a no-op.
6127dd7cddfSDavid du Colombier  */
6137dd7cddfSDavid du Colombier #define DBG if(0)
6147dd7cddfSDavid du Colombier static int
alphadraw(Memdrawparam * par)6157dd7cddfSDavid du Colombier alphadraw(Memdrawparam *par)
6167dd7cddfSDavid du Colombier {
6176a9fc400SDavid du Colombier 	int isgrey, starty, endy, op;
6187dd7cddfSDavid du Colombier 	int needbuf, dsty, srcy, masky;
619*2c1878b4SDavid du Colombier 	int y, dir, dx, dy, ndrawbuf;
620*2c1878b4SDavid du Colombier 	uchar *drawbuf;
6217dd7cddfSDavid du Colombier 	Buffer bsrc, bdst, bmask;
6227dd7cddfSDavid du Colombier 	Readfn *rdsrc, *rdmask, *rddst;
6237dd7cddfSDavid du Colombier 	Calcfn *calc;
6247dd7cddfSDavid du Colombier 	Writefn *wrdst;
6257dd7cddfSDavid du Colombier 	Memimage *src, *mask, *dst;
6267dd7cddfSDavid du Colombier 	Rectangle r, sr, mr;
627*2c1878b4SDavid du Colombier 	Dbuf *z;
6287dd7cddfSDavid du Colombier 
6297dd7cddfSDavid du Colombier 	r = par->r;
6307dd7cddfSDavid du Colombier 	dx = Dx(r);
6317dd7cddfSDavid du Colombier 	dy = Dy(r);
6327dd7cddfSDavid du Colombier 
633*2c1878b4SDavid du Colombier 	z = allocdbuf();
634*2c1878b4SDavid du Colombier 	if(z == nil)
635*2c1878b4SDavid du Colombier 		return 0;
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 	src = par->src;
6387dd7cddfSDavid du Colombier 	mask = par->mask;
6397dd7cddfSDavid du Colombier 	dst = par->dst;
6407dd7cddfSDavid du Colombier 	sr = par->sr;
6417dd7cddfSDavid du Colombier 	mr = par->mr;
6426a9fc400SDavid du Colombier 	op = par->op;
6437dd7cddfSDavid du Colombier 
6447dd7cddfSDavid du Colombier 	isgrey = dst->flags&Fgrey;
6457dd7cddfSDavid du Colombier 
6467dd7cddfSDavid du Colombier 	/*
6477dd7cddfSDavid du Colombier 	 * Buffering when src and dst are the same bitmap is sufficient but not
6487dd7cddfSDavid du Colombier 	 * necessary.  There are stronger conditions we could use.  We could
6497dd7cddfSDavid du Colombier 	 * check to see if the rectangles intersect, and if simply moving in the
6507dd7cddfSDavid du Colombier 	 * correct y direction can avoid the need to buffer.
6517dd7cddfSDavid du Colombier 	 */
6527dd7cddfSDavid du Colombier 	needbuf = (src->data == dst->data);
6537dd7cddfSDavid du Colombier 
654*2c1878b4SDavid du Colombier 	ndrawbuf = 0;
655*2c1878b4SDavid du Colombier 	getparam(&z->spar, src, sr, isgrey, needbuf, &ndrawbuf);
656*2c1878b4SDavid du Colombier 	getparam(&z->dpar, dst, r, isgrey, needbuf, &ndrawbuf);
657*2c1878b4SDavid du Colombier 	getparam(&z->mpar, mask, mr, 0, needbuf, &ndrawbuf);
6587dd7cddfSDavid du Colombier 
6597dd7cddfSDavid du Colombier 	dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
660*2c1878b4SDavid du Colombier 	z->spar.dir = z->mpar.dir = z->dpar.dir = dir;
6617dd7cddfSDavid du Colombier 
6627dd7cddfSDavid du Colombier 	/*
6637dd7cddfSDavid du Colombier 	 * If the mask is purely boolean, we can convert from src to dst format
6647dd7cddfSDavid du Colombier 	 * when we read src, and then just copy it to dst where the mask tells us to.
6657dd7cddfSDavid du Colombier 	 * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
6667dd7cddfSDavid du Colombier 	 *
6677dd7cddfSDavid du Colombier 	 * The computation is accomplished by assigning the function pointers as follows:
6687dd7cddfSDavid du Colombier 	 *	rdsrc - read and convert source into dst format in a buffer
6697dd7cddfSDavid du Colombier 	 * 	rdmask - convert mask to bytes, set pointer to it
6707dd7cddfSDavid du Colombier 	 * 	rddst - fill with pointer to real dst data, but do no reads
6717dd7cddfSDavid du Colombier 	 *	calc - copy src onto dst when mask says to.
6727dd7cddfSDavid du Colombier 	 *	wrdst - do nothing
6737dd7cddfSDavid du Colombier 	 * This is slightly sleazy, since things aren't doing exactly what their names say,
6747dd7cddfSDavid du Colombier 	 * but it avoids a fair amount of code duplication to make this a case here
6757dd7cddfSDavid du Colombier 	 * rather than have a separate booldraw.
6767dd7cddfSDavid du Colombier 	 */
6777dd7cddfSDavid du Colombier //if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
6786a9fc400SDavid du Colombier 	if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
6797dd7cddfSDavid du Colombier //if(drawdebug) iprint("boolcopy...");
680*2c1878b4SDavid du Colombier 		rdsrc = convfn(dst, &z->dpar, src, &z->spar, &ndrawbuf);
6817dd7cddfSDavid du Colombier 		rddst = readptr;
6827dd7cddfSDavid du Colombier 		rdmask = readfn(mask);
6837dd7cddfSDavid du Colombier 		calc = boolcopyfn(dst, mask);
6847dd7cddfSDavid du Colombier 		wrdst = nullwrite;
6857dd7cddfSDavid du Colombier 	}else{
6867dd7cddfSDavid du Colombier 		/* usual alphadraw parameter fetching */
6877dd7cddfSDavid du Colombier 		rdsrc = readfn(src);
6887dd7cddfSDavid du Colombier 		rddst = readfn(dst);
6897dd7cddfSDavid du Colombier 		wrdst = writefn(dst);
6906a9fc400SDavid du Colombier 		calc = alphacalc[op];
6917dd7cddfSDavid du Colombier 
6927dd7cddfSDavid du Colombier 		/*
6937dd7cddfSDavid du Colombier 		 * If there is no alpha channel, we'll ask for a grey channel
6947dd7cddfSDavid du Colombier 		 * and pretend it is the alpha.
6957dd7cddfSDavid du Colombier 		 */
6967dd7cddfSDavid du Colombier 		if(mask->flags&Falpha){
6977dd7cddfSDavid du Colombier 			rdmask = readalphafn(mask);
698*2c1878b4SDavid du Colombier 			z->mpar.alphaonly = 1;
6997dd7cddfSDavid du Colombier 		}else{
700*2c1878b4SDavid du Colombier 			z->mpar.greymaskcall = readfn(mask);
701*2c1878b4SDavid du Colombier 			z->mpar.convgrey = 1;
7027dd7cddfSDavid du Colombier 			rdmask = greymaskread;
7037dd7cddfSDavid du Colombier 
7047dd7cddfSDavid du Colombier 			/*
7057dd7cddfSDavid du Colombier 			 * Should really be above, but then boolcopyfns would have
7067dd7cddfSDavid du Colombier 			 * to deal with bit alignment, and I haven't written that.
7077dd7cddfSDavid du Colombier 			 *
7087dd7cddfSDavid du Colombier 			 * This is a common case for things like ellipse drawing.
7097dd7cddfSDavid du Colombier 			 * When there's no alpha involved and the mask is boolean,
7107dd7cddfSDavid du Colombier 			 * we can avoid all the division and multiplication.
7117dd7cddfSDavid du Colombier 			 */
7127dd7cddfSDavid du Colombier 			if(mask->chan == GREY1 && !(src->flags&Falpha))
7136a9fc400SDavid du Colombier 				calc = boolcalc[op];
7146a9fc400SDavid du Colombier 			else if(op == SoverD && !(src->flags&Falpha))
7156a9fc400SDavid du Colombier 				calc = alphacalcS;
7167dd7cddfSDavid du Colombier 		}
7177dd7cddfSDavid du Colombier 	}
7187dd7cddfSDavid du Colombier 
7197dd7cddfSDavid du Colombier 	/*
7207dd7cddfSDavid du Colombier 	 * If the image has a small enough repl rectangle,
7217dd7cddfSDavid du Colombier 	 * we can just read each line once and cache them.
7227dd7cddfSDavid du Colombier 	 */
723*2c1878b4SDavid du Colombier 	if(z->spar.replcache){
724*2c1878b4SDavid du Colombier 		z->spar.replcall = rdsrc;
7257dd7cddfSDavid du Colombier 		rdsrc = replread;
7267dd7cddfSDavid du Colombier 	}
727*2c1878b4SDavid du Colombier 	if(z->mpar.replcache){
728*2c1878b4SDavid du Colombier 		z->mpar.replcall = rdmask;
7297dd7cddfSDavid du Colombier 		rdmask = replread;
7307dd7cddfSDavid du Colombier 	}
7317dd7cddfSDavid du Colombier 
732*2c1878b4SDavid du Colombier 	if(z->n < ndrawbuf){
733*2c1878b4SDavid du Colombier 		free(z->p);
734*2c1878b4SDavid du Colombier 		if((z->p = mallocz(ndrawbuf, 0)) == nil){
735*2c1878b4SDavid du Colombier 			z->inuse = 0;
7367dd7cddfSDavid du Colombier 			return 0;
737*2c1878b4SDavid du Colombier 		}
738*2c1878b4SDavid du Colombier 		z->n = ndrawbuf;
739*2c1878b4SDavid du Colombier 	}
740*2c1878b4SDavid du Colombier 	drawbuf = z->p;
7417dd7cddfSDavid du Colombier 
7427dd7cddfSDavid du Colombier 	/*
7437dd7cddfSDavid du Colombier 	 * Before we were saving only offsets from drawbuf in the parameter
7447dd7cddfSDavid du Colombier 	 * structures; now that drawbuf has been grown to accomodate us,
7457dd7cddfSDavid du Colombier 	 * we can fill in the pointers.
7467dd7cddfSDavid du Colombier 	 */
747*2c1878b4SDavid du Colombier 	z->spar.bufbase = drawbuf+z->spar.bufoff;
748*2c1878b4SDavid du Colombier 	z->mpar.bufbase = drawbuf+z->mpar.bufoff;
749*2c1878b4SDavid du Colombier 	z->dpar.bufbase = drawbuf+z->dpar.bufoff;
750*2c1878b4SDavid du Colombier 	z->spar.convbuf = drawbuf+z->spar.convbufoff;
7517dd7cddfSDavid du Colombier 
7527dd7cddfSDavid du Colombier 	if(dir == 1){
7537dd7cddfSDavid du Colombier 		starty = 0;
7547dd7cddfSDavid du Colombier 		endy = dy;
7557dd7cddfSDavid du Colombier 	}else{
7567dd7cddfSDavid du Colombier 		starty = dy-1;
7577dd7cddfSDavid du Colombier 		endy = -1;
7587dd7cddfSDavid du Colombier 	}
7597dd7cddfSDavid du Colombier 
7607dd7cddfSDavid du Colombier 	/*
7617dd7cddfSDavid du Colombier 	 * srcy, masky, and dsty are offsets from the top of their
7627dd7cddfSDavid du Colombier 	 * respective Rectangles.  they need to be contained within
7637dd7cddfSDavid du Colombier 	 * the rectangles, so clipy can keep them there without division.
7647dd7cddfSDavid du Colombier  	 */
7657dd7cddfSDavid du Colombier 	srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
7667dd7cddfSDavid du Colombier 	masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
7677dd7cddfSDavid du Colombier 	dsty = starty + r.min.y - dst->r.min.y;
7687dd7cddfSDavid du Colombier 
7697dd7cddfSDavid du Colombier 	assert(0 <= srcy && srcy < Dy(src->r));
7707dd7cddfSDavid du Colombier 	assert(0 <= masky && masky < Dy(mask->r));
7717dd7cddfSDavid du Colombier 	assert(0 <= dsty && dsty < Dy(dst->r));
7727dd7cddfSDavid du Colombier 
7737dd7cddfSDavid du Colombier 	for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
7747dd7cddfSDavid du Colombier 		clipy(src, &srcy);
7757dd7cddfSDavid du Colombier 		clipy(dst, &dsty);
7767dd7cddfSDavid du Colombier 		clipy(mask, &masky);
7777dd7cddfSDavid du Colombier 
778*2c1878b4SDavid du Colombier 		bsrc = rdsrc(&z->spar, z->spar.bufbase, srcy);
7797dd7cddfSDavid du Colombier DBG print("[");
780*2c1878b4SDavid du Colombier 		bmask = rdmask(&z->mpar, z->mpar.bufbase, masky);
7817dd7cddfSDavid du Colombier DBG print("]\n");
782*2c1878b4SDavid du Colombier 		bdst = rddst(&z->dpar, z->dpar.bufbase, dsty);
7837dd7cddfSDavid du Colombier DBG		dumpbuf("src", bsrc, dx);
7847dd7cddfSDavid du Colombier DBG		dumpbuf("mask", bmask, dx);
7857dd7cddfSDavid du Colombier DBG		dumpbuf("dst", bdst, dx);
7866a9fc400SDavid du Colombier 		bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
787*2c1878b4SDavid du Colombier 		wrdst(&z->dpar, z->dpar.bytermin+dsty*z->dpar.bwidth, bdst);
7887dd7cddfSDavid du Colombier 	}
7897dd7cddfSDavid du Colombier 
790*2c1878b4SDavid du Colombier 	z->inuse = 0;
7917dd7cddfSDavid du Colombier 	return 1;
7927dd7cddfSDavid du Colombier }
7937dd7cddfSDavid du Colombier #undef DBG
7947dd7cddfSDavid du Colombier 
7957dd7cddfSDavid du Colombier static Buffer
alphacalc0(Buffer bdst,Buffer b1,Buffer b2,int dx,int grey,int op)7966a9fc400SDavid du Colombier alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
7976a9fc400SDavid du Colombier {
7986a9fc400SDavid du Colombier 	USED(grey);
7996a9fc400SDavid du Colombier 	USED(op);
8006a9fc400SDavid du Colombier 	USED(b1);
8016a9fc400SDavid du Colombier 	USED(b2);
8026a9fc400SDavid du Colombier 	memset(bdst.rgba, 0, dx*bdst.delta);
8036a9fc400SDavid du Colombier 	return bdst;
8046a9fc400SDavid du Colombier }
8056a9fc400SDavid du Colombier 
8066a9fc400SDavid du Colombier static Buffer
alphacalc14(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)8076a9fc400SDavid du Colombier alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
8087dd7cddfSDavid du Colombier {
8097dd7cddfSDavid du Colombier 	Buffer obdst;
8106a9fc400SDavid du Colombier 	int fd, sadelta;
8116a9fc400SDavid du Colombier 	int i, sa, ma, q;
8126a9fc400SDavid du Colombier 	ulong s, t;
8137dd7cddfSDavid du Colombier 
8147dd7cddfSDavid du Colombier 	obdst = bdst;
8156a9fc400SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
8166a9fc400SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
8177dd7cddfSDavid du Colombier 
8187dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
8196a9fc400SDavid du Colombier 		sa = *bsrc.alpha;
8207dd7cddfSDavid du Colombier 		ma = *bmask.alpha;
8216a9fc400SDavid du Colombier 		fd = MUL(sa, ma, t);
8226a9fc400SDavid du Colombier 		if(op == DoutS)
8236a9fc400SDavid du Colombier 			fd = 255-fd;
8247dd7cddfSDavid du Colombier 
8257dd7cddfSDavid du Colombier 		if(grey){
8266a9fc400SDavid du Colombier 			*bdst.grey = MUL(fd, *bdst.grey, t);
8277dd7cddfSDavid du Colombier 			bsrc.grey += bsrc.delta;
8287dd7cddfSDavid du Colombier 			bdst.grey += bdst.delta;
8297dd7cddfSDavid du Colombier 		}else{
8306a9fc400SDavid du Colombier 			if(q){
8316a9fc400SDavid du Colombier 				*bdst.rgba = MUL0123(fd, *bdst.rgba, s, t);
8326a9fc400SDavid du Colombier 				bsrc.rgba++;
8336a9fc400SDavid du Colombier 				bdst.rgba++;
8346a9fc400SDavid du Colombier 				bsrc.alpha += sadelta;
8356a9fc400SDavid du Colombier 				bmask.alpha += bmask.delta;
8366a9fc400SDavid du Colombier 				continue;
8376a9fc400SDavid du Colombier 			}
8386a9fc400SDavid du Colombier 			*bdst.red = MUL(fd, *bdst.red, t);
8396a9fc400SDavid du Colombier 			*bdst.grn = MUL(fd, *bdst.grn, t);
8406a9fc400SDavid du Colombier 			*bdst.blu = MUL(fd, *bdst.blu, t);
8417dd7cddfSDavid du Colombier 			bsrc.red += bsrc.delta;
8427dd7cddfSDavid du Colombier 			bsrc.blu += bsrc.delta;
8437dd7cddfSDavid du Colombier 			bsrc.grn += bsrc.delta;
8447dd7cddfSDavid du Colombier 			bdst.red += bdst.delta;
8457dd7cddfSDavid du Colombier 			bdst.blu += bdst.delta;
8467dd7cddfSDavid du Colombier 			bdst.grn += bdst.delta;
8477dd7cddfSDavid du Colombier 		}
8486a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
8496a9fc400SDavid du Colombier 			*bdst.alpha = MUL(fd, *bdst.alpha, t);
8506a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
8516a9fc400SDavid du Colombier 		}
8527dd7cddfSDavid du Colombier 		bmask.alpha += bmask.delta;
8536a9fc400SDavid du Colombier 		bsrc.alpha += sadelta;
8546a9fc400SDavid du Colombier 	}
8556a9fc400SDavid du Colombier 	return obdst;
8566a9fc400SDavid du Colombier }
8577dd7cddfSDavid du Colombier 
8586a9fc400SDavid du Colombier static Buffer
alphacalc2810(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)8596a9fc400SDavid du Colombier alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
8606a9fc400SDavid du Colombier {
8616a9fc400SDavid du Colombier 	Buffer obdst;
8626a9fc400SDavid du Colombier 	int fs, sadelta;
8636a9fc400SDavid du Colombier 	int i, ma, da, q;
8646a9fc400SDavid du Colombier 	ulong s, t;
8656a9fc400SDavid du Colombier 
8666a9fc400SDavid du Colombier 	obdst = bdst;
8676a9fc400SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
8686a9fc400SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
8696a9fc400SDavid du Colombier 
8706a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
8716a9fc400SDavid du Colombier 		ma = *bmask.alpha;
8726a9fc400SDavid du Colombier 		da = *bdst.alpha;
8736a9fc400SDavid du Colombier 		if(op == SoutD)
8746a9fc400SDavid du Colombier 			da = 255-da;
8756a9fc400SDavid du Colombier 		fs = ma;
8766a9fc400SDavid du Colombier 		if(op != S)
8776a9fc400SDavid du Colombier 			fs = MUL(fs, da, t);
8786a9fc400SDavid du Colombier 
8796a9fc400SDavid du Colombier 		if(grey){
8806a9fc400SDavid du Colombier 			*bdst.grey = MUL(fs, *bsrc.grey, t);
8816a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
8826a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
8836a9fc400SDavid du Colombier 		}else{
8846a9fc400SDavid du Colombier 			if(q){
8856a9fc400SDavid du Colombier 				*bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t);
8866a9fc400SDavid du Colombier 				bsrc.rgba++;
8876a9fc400SDavid du Colombier 				bdst.rgba++;
8886a9fc400SDavid du Colombier 				bmask.alpha += bmask.delta;
8896a9fc400SDavid du Colombier 				bdst.alpha += bdst.delta;
8906a9fc400SDavid du Colombier 				continue;
8916a9fc400SDavid du Colombier 			}
8926a9fc400SDavid du Colombier 			*bdst.red = MUL(fs, *bsrc.red, t);
8936a9fc400SDavid du Colombier 			*bdst.grn = MUL(fs, *bsrc.grn, t);
8946a9fc400SDavid du Colombier 			*bdst.blu = MUL(fs, *bsrc.blu, t);
8956a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
8966a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
8976a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
8986a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
8996a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
9006a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
9016a9fc400SDavid du Colombier 		}
9026a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
9036a9fc400SDavid du Colombier 			*bdst.alpha = MUL(fs, *bsrc.alpha, t);
9046a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
9056a9fc400SDavid du Colombier 		}
9066a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
9076a9fc400SDavid du Colombier 		bsrc.alpha += sadelta;
9086a9fc400SDavid du Colombier 	}
9096a9fc400SDavid du Colombier 	return obdst;
9106a9fc400SDavid du Colombier }
9116a9fc400SDavid du Colombier 
9126a9fc400SDavid du Colombier static Buffer
alphacalc3679(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)9136a9fc400SDavid du Colombier alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
9146a9fc400SDavid du Colombier {
9156a9fc400SDavid du Colombier 	Buffer obdst;
9166a9fc400SDavid du Colombier 	int fs, fd, sadelta;
9176a9fc400SDavid du Colombier 	int i, sa, ma, da, q;
9186a9fc400SDavid du Colombier 	ulong s, t, u, v;
9196a9fc400SDavid du Colombier 
9206a9fc400SDavid du Colombier 	obdst = bdst;
9216a9fc400SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
9226a9fc400SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
9236a9fc400SDavid du Colombier 
9246a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
9256a9fc400SDavid du Colombier 		sa = *bsrc.alpha;
9266a9fc400SDavid du Colombier 		ma = *bmask.alpha;
9276a9fc400SDavid du Colombier 		da = *bdst.alpha;
9286a9fc400SDavid du Colombier 		if(op == SatopD)
9296a9fc400SDavid du Colombier 			fs = MUL(ma, da, t);
9306a9fc400SDavid du Colombier 		else
9316a9fc400SDavid du Colombier 			fs = MUL(ma, 255-da, t);
9326a9fc400SDavid du Colombier 		if(op == DoverS)
9336a9fc400SDavid du Colombier 			fd = 255;
9346a9fc400SDavid du Colombier 		else{
9356a9fc400SDavid du Colombier 			fd = MUL(sa, ma, t);
9366a9fc400SDavid du Colombier 			if(op != DatopS)
9376a9fc400SDavid du Colombier 				fd = 255-fd;
9386a9fc400SDavid du Colombier 		}
9396a9fc400SDavid du Colombier 
9406a9fc400SDavid du Colombier 		if(grey){
9416a9fc400SDavid du Colombier 			*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
9426a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
9436a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
9446a9fc400SDavid du Colombier 		}else{
9456a9fc400SDavid du Colombier 			if(q){
9466a9fc400SDavid du Colombier 				*bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
9476a9fc400SDavid du Colombier 				bsrc.rgba++;
9486a9fc400SDavid du Colombier 				bdst.rgba++;
9496a9fc400SDavid du Colombier 				bsrc.alpha += sadelta;
9506a9fc400SDavid du Colombier 				bmask.alpha += bmask.delta;
9516a9fc400SDavid du Colombier 				bdst.alpha += bdst.delta;
9526a9fc400SDavid du Colombier 				continue;
9536a9fc400SDavid du Colombier 			}
9546a9fc400SDavid du Colombier 			*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
9556a9fc400SDavid du Colombier 			*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
9566a9fc400SDavid du Colombier 			*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
9576a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
9586a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
9596a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
9606a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
9616a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
9626a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
9636a9fc400SDavid du Colombier 		}
9646a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
9656a9fc400SDavid du Colombier 			*bdst.alpha = MUL(fs, sa, s)+MUL(fd, da, t);
9666a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
9676a9fc400SDavid du Colombier 		}
9686a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
9696a9fc400SDavid du Colombier 		bsrc.alpha += sadelta;
9706a9fc400SDavid du Colombier 	}
9716a9fc400SDavid du Colombier 	return obdst;
9726a9fc400SDavid du Colombier }
9736a9fc400SDavid du Colombier 
9746a9fc400SDavid du Colombier static Buffer
alphacalc5(Buffer bdst,Buffer b1,Buffer b2,int dx,int grey,int op)9756a9fc400SDavid du Colombier alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
9766a9fc400SDavid du Colombier {
9776a9fc400SDavid du Colombier 	USED(dx);
9786a9fc400SDavid du Colombier 	USED(grey);
9796a9fc400SDavid du Colombier 	USED(op);
9806a9fc400SDavid du Colombier 	USED(b1);
9816a9fc400SDavid du Colombier 	USED(b2);
9826a9fc400SDavid du Colombier 	return bdst;
9836a9fc400SDavid du Colombier }
9846a9fc400SDavid du Colombier 
9856a9fc400SDavid du Colombier static Buffer
alphacalc11(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)9866a9fc400SDavid du Colombier alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
9876a9fc400SDavid du Colombier {
9886a9fc400SDavid du Colombier 	Buffer obdst;
9896a9fc400SDavid du Colombier 	int fd, sadelta;
9906a9fc400SDavid du Colombier 	int i, sa, ma, q;
9916a9fc400SDavid du Colombier 	ulong s, t, u, v;
9926a9fc400SDavid du Colombier 
9936a9fc400SDavid du Colombier 	USED(op);
9946a9fc400SDavid du Colombier 	obdst = bdst;
9956a9fc400SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
9966a9fc400SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
9976a9fc400SDavid du Colombier 
9986a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
9996a9fc400SDavid du Colombier 		sa = *bsrc.alpha;
10006a9fc400SDavid du Colombier 		ma = *bmask.alpha;
10016a9fc400SDavid du Colombier 		fd = 255-MUL(sa, ma, t);
10026a9fc400SDavid du Colombier 
10036a9fc400SDavid du Colombier 		if(grey){
10046a9fc400SDavid du Colombier 			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
10056a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
10066a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
10076a9fc400SDavid du Colombier 		}else{
10086a9fc400SDavid du Colombier 			if(q){
10096a9fc400SDavid du Colombier 				*bdst.rgba = MUL0123(ma, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
10106a9fc400SDavid du Colombier 				bsrc.rgba++;
10116a9fc400SDavid du Colombier 				bdst.rgba++;
10126a9fc400SDavid du Colombier 				bsrc.alpha += sadelta;
10136a9fc400SDavid du Colombier 				bmask.alpha += bmask.delta;
10146a9fc400SDavid du Colombier 				continue;
10156a9fc400SDavid du Colombier 			}
10166a9fc400SDavid du Colombier 			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
10176a9fc400SDavid du Colombier 			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
10186a9fc400SDavid du Colombier 			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
10196a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
10206a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
10216a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
10226a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
10236a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
10246a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
10256a9fc400SDavid du Colombier 		}
10266a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
10276a9fc400SDavid du Colombier 			*bdst.alpha = MUL(ma, sa, s)+MUL(fd, *bdst.alpha, t);
10286a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
10296a9fc400SDavid du Colombier 		}
10306a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
10316a9fc400SDavid du Colombier 		bsrc.alpha += sadelta;
10326a9fc400SDavid du Colombier 	}
10336a9fc400SDavid du Colombier 	return obdst;
10346a9fc400SDavid du Colombier }
10356a9fc400SDavid du Colombier 
10366a9fc400SDavid du Colombier /*
10376a9fc400SDavid du Colombier not used yet
10386a9fc400SDavid du Colombier source and mask alpha 1
10396a9fc400SDavid du Colombier static Buffer
10406a9fc400SDavid du Colombier alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
10416a9fc400SDavid du Colombier {
10426a9fc400SDavid du Colombier 	Buffer obdst;
10436a9fc400SDavid du Colombier 	int i;
10446a9fc400SDavid du Colombier 
10456a9fc400SDavid du Colombier 	USED(op);
10466a9fc400SDavid du Colombier 	obdst = bdst;
10476a9fc400SDavid du Colombier 	if(bsrc.delta == bdst.delta){
10486a9fc400SDavid du Colombier 		memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
10496a9fc400SDavid du Colombier 		return obdst;
10506a9fc400SDavid du Colombier 	}
10516a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
10526a9fc400SDavid du Colombier 		if(grey){
10536a9fc400SDavid du Colombier 			*bdst.grey = *bsrc.grey;
10546a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
10556a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
10566a9fc400SDavid du Colombier 		}else{
10576a9fc400SDavid du Colombier 			*bdst.red = *bsrc.red;
10586a9fc400SDavid du Colombier 			*bdst.grn = *bsrc.grn;
10596a9fc400SDavid du Colombier 			*bdst.blu = *bsrc.blu;
10606a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
10616a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
10626a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
10636a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
10646a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
10656a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
10666a9fc400SDavid du Colombier 		}
10676a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
10686a9fc400SDavid du Colombier 			*bdst.alpha = 255;
10697dd7cddfSDavid du Colombier 			bdst.alpha += bdst.delta;
10707dd7cddfSDavid du Colombier 		}
10717dd7cddfSDavid du Colombier 	}
10727dd7cddfSDavid du Colombier 	return obdst;
10737dd7cddfSDavid du Colombier }
10746a9fc400SDavid du Colombier */
10757dd7cddfSDavid du Colombier 
10766a9fc400SDavid du Colombier /* source alpha 1 */
10777dd7cddfSDavid du Colombier static Buffer
alphacalcS(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)10786a9fc400SDavid du Colombier alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
10797dd7cddfSDavid du Colombier {
10807dd7cddfSDavid du Colombier 	Buffer obdst;
10816a9fc400SDavid du Colombier 	int fd;
10827dd7cddfSDavid du Colombier 	int i, ma;
10836a9fc400SDavid du Colombier 	ulong s, t;
10847dd7cddfSDavid du Colombier 
10856a9fc400SDavid du Colombier 	USED(op);
10867dd7cddfSDavid du Colombier 	obdst = bdst;
10876a9fc400SDavid du Colombier 
10887dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
10897dd7cddfSDavid du Colombier 		ma = *bmask.alpha;
10906a9fc400SDavid du Colombier 		fd = 255-ma;
10917dd7cddfSDavid du Colombier 
10927dd7cddfSDavid du Colombier 		if(grey){
10936a9fc400SDavid du Colombier 			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
10946a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
10956a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
10966a9fc400SDavid du Colombier 		}else{
10976a9fc400SDavid du Colombier 			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
10986a9fc400SDavid du Colombier 			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
10996a9fc400SDavid du Colombier 			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
11006a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
11016a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
11026a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
11036a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
11046a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
11056a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
11066a9fc400SDavid du Colombier 		}
11076a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
11086a9fc400SDavid du Colombier 			*bdst.alpha = ma+MUL(fd, *bdst.alpha, t);
11096a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
11106a9fc400SDavid du Colombier 		}
11116a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
11126a9fc400SDavid du Colombier 	}
11136a9fc400SDavid du Colombier 	return obdst;
11146a9fc400SDavid du Colombier }
11156a9fc400SDavid du Colombier 
11166a9fc400SDavid du Colombier static Buffer
boolcalc14(Buffer bdst,Buffer b1,Buffer bmask,int dx,int grey,int op)11176a9fc400SDavid du Colombier boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
11186a9fc400SDavid du Colombier {
11196a9fc400SDavid du Colombier 	Buffer obdst;
11206a9fc400SDavid du Colombier 	int i, ma, zero;
11216a9fc400SDavid du Colombier 
11226a9fc400SDavid du Colombier 	USED(b1);
11236a9fc400SDavid du Colombier 
11246a9fc400SDavid du Colombier 	obdst = bdst;
11256a9fc400SDavid du Colombier 
11266a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
11276a9fc400SDavid du Colombier 		ma = *bmask.alpha;
11286a9fc400SDavid du Colombier 		zero = ma ? op == DoutS : op == DinS;
11296a9fc400SDavid du Colombier 
11306a9fc400SDavid du Colombier 		if(grey){
11316a9fc400SDavid du Colombier 			if(zero)
11326a9fc400SDavid du Colombier 				*bdst.grey = 0;
11336a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
11346a9fc400SDavid du Colombier 		}else{
11356a9fc400SDavid du Colombier 			if(zero)
11366a9fc400SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
11376a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
11386a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
11396a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
11406a9fc400SDavid du Colombier 		}
11416a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
11426a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
11436a9fc400SDavid du Colombier 			if(zero)
11446a9fc400SDavid du Colombier 				*bdst.alpha = 0;
11456a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
11466a9fc400SDavid du Colombier 		}
11476a9fc400SDavid du Colombier 	}
11486a9fc400SDavid du Colombier 	return obdst;
11496a9fc400SDavid du Colombier }
11506a9fc400SDavid du Colombier 
11516a9fc400SDavid du Colombier static Buffer
boolcalc236789(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)11526a9fc400SDavid du Colombier boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
11536a9fc400SDavid du Colombier {
11546a9fc400SDavid du Colombier 	Buffer obdst;
11556a9fc400SDavid du Colombier 	int fs, fd;
11566a9fc400SDavid du Colombier 	int i, ma, da, zero;
11576a9fc400SDavid du Colombier 	ulong s, t;
11586a9fc400SDavid du Colombier 
11596a9fc400SDavid du Colombier 	obdst = bdst;
11606a9fc400SDavid du Colombier 	zero = !(op&1);
11616a9fc400SDavid du Colombier 
11626a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
11636a9fc400SDavid du Colombier 		ma = *bmask.alpha;
11646a9fc400SDavid du Colombier 		da = *bdst.alpha;
11656a9fc400SDavid du Colombier 		fs = da;
11666a9fc400SDavid du Colombier 		if(op&2)
11676a9fc400SDavid du Colombier 			fs = 255-da;
11686a9fc400SDavid du Colombier 		fd = 0;
11696a9fc400SDavid du Colombier 		if(op&4)
11706a9fc400SDavid du Colombier 			fd = 255;
11716a9fc400SDavid du Colombier 
11726a9fc400SDavid du Colombier 		if(grey){
11737dd7cddfSDavid du Colombier 			if(ma)
11746a9fc400SDavid du Colombier 				*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
11756a9fc400SDavid du Colombier 			else if(zero)
11766a9fc400SDavid du Colombier 				*bdst.grey = 0;
11777dd7cddfSDavid du Colombier 			bsrc.grey += bsrc.delta;
11787dd7cddfSDavid du Colombier 			bdst.grey += bdst.delta;
11797dd7cddfSDavid du Colombier 		}else{
11807dd7cddfSDavid du Colombier 			if(ma){
11816a9fc400SDavid du Colombier 				*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
11826a9fc400SDavid du Colombier 				*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
11836a9fc400SDavid du Colombier 				*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
11847dd7cddfSDavid du Colombier 			}
11856a9fc400SDavid du Colombier 			else if(zero)
11866a9fc400SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
11877dd7cddfSDavid du Colombier 			bsrc.red += bsrc.delta;
11887dd7cddfSDavid du Colombier 			bsrc.blu += bsrc.delta;
11897dd7cddfSDavid du Colombier 			bsrc.grn += bsrc.delta;
11907dd7cddfSDavid du Colombier 			bdst.red += bdst.delta;
11917dd7cddfSDavid du Colombier 			bdst.blu += bdst.delta;
11927dd7cddfSDavid du Colombier 			bdst.grn += bdst.delta;
11937dd7cddfSDavid du Colombier 		}
11947dd7cddfSDavid du Colombier 		bmask.alpha += bmask.delta;
11956a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
11967dd7cddfSDavid du Colombier 			if(ma)
11976a9fc400SDavid du Colombier 				*bdst.alpha = fs+MUL(fd, da, t);
11986a9fc400SDavid du Colombier 			else if(zero)
11996a9fc400SDavid du Colombier 				*bdst.alpha = 0;
12007dd7cddfSDavid du Colombier 			bdst.alpha += bdst.delta;
12017dd7cddfSDavid du Colombier 		}
12027dd7cddfSDavid du Colombier 	}
12037dd7cddfSDavid du Colombier 	return obdst;
12047dd7cddfSDavid du Colombier }
12057dd7cddfSDavid du Colombier 
12066a9fc400SDavid du Colombier static Buffer
boolcalc1011(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int grey,int op)12076a9fc400SDavid du Colombier boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
12086a9fc400SDavid du Colombier {
12096a9fc400SDavid du Colombier 	Buffer obdst;
12106a9fc400SDavid du Colombier 	int i, ma, zero;
12116a9fc400SDavid du Colombier 
12126a9fc400SDavid du Colombier 	obdst = bdst;
12136a9fc400SDavid du Colombier 	zero = !(op&1);
12146a9fc400SDavid du Colombier 
12156a9fc400SDavid du Colombier 	for(i=0; i<dx; i++){
12166a9fc400SDavid du Colombier 		ma = *bmask.alpha;
12176a9fc400SDavid du Colombier 
12186a9fc400SDavid du Colombier 		if(grey){
12196a9fc400SDavid du Colombier 			if(ma)
12206a9fc400SDavid du Colombier 				*bdst.grey = *bsrc.grey;
12216a9fc400SDavid du Colombier 			else if(zero)
12226a9fc400SDavid du Colombier 				*bdst.grey = 0;
12236a9fc400SDavid du Colombier 			bsrc.grey += bsrc.delta;
12246a9fc400SDavid du Colombier 			bdst.grey += bdst.delta;
12256a9fc400SDavid du Colombier 		}else{
12266a9fc400SDavid du Colombier 			if(ma){
12276a9fc400SDavid du Colombier 				*bdst.red = *bsrc.red;
12286a9fc400SDavid du Colombier 				*bdst.grn = *bsrc.grn;
12296a9fc400SDavid du Colombier 				*bdst.blu = *bsrc.blu;
12306a9fc400SDavid du Colombier 			}
12316a9fc400SDavid du Colombier 			else if(zero)
12326a9fc400SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
12336a9fc400SDavid du Colombier 			bsrc.red += bsrc.delta;
12346a9fc400SDavid du Colombier 			bsrc.blu += bsrc.delta;
12356a9fc400SDavid du Colombier 			bsrc.grn += bsrc.delta;
12366a9fc400SDavid du Colombier 			bdst.red += bdst.delta;
12376a9fc400SDavid du Colombier 			bdst.blu += bdst.delta;
12386a9fc400SDavid du Colombier 			bdst.grn += bdst.delta;
12396a9fc400SDavid du Colombier 		}
12406a9fc400SDavid du Colombier 		bmask.alpha += bmask.delta;
12416a9fc400SDavid du Colombier 		if(bdst.alpha != &ones){
12426a9fc400SDavid du Colombier 			if(ma)
12436a9fc400SDavid du Colombier 				*bdst.alpha = 255;
12446a9fc400SDavid du Colombier 			else if(zero)
12456a9fc400SDavid du Colombier 				*bdst.alpha = 0;
12466a9fc400SDavid du Colombier 			bdst.alpha += bdst.delta;
12476a9fc400SDavid du Colombier 		}
12486a9fc400SDavid du Colombier 	}
12496a9fc400SDavid du Colombier 	return obdst;
12506a9fc400SDavid du Colombier }
12517dd7cddfSDavid du Colombier /*
12527dd7cddfSDavid du Colombier  * Replicated cached scan line read.  Call the function listed in the Param,
12537dd7cddfSDavid du Colombier  * but cache the result so that for replicated images we only do the work once.
12547dd7cddfSDavid du Colombier  */
12557dd7cddfSDavid du Colombier static Buffer
replread(Param * p,uchar * s,int y)12566a9fc400SDavid du Colombier replread(Param *p, uchar *s, int y)
12577dd7cddfSDavid du Colombier {
12587dd7cddfSDavid du Colombier 	Buffer *b;
12597dd7cddfSDavid du Colombier 
12606a9fc400SDavid du Colombier 	USED(s);
12617dd7cddfSDavid du Colombier 	b = &p->bcache[y];
12627dd7cddfSDavid du Colombier 	if((p->bfilled & (1<<y)) == 0){
12637dd7cddfSDavid du Colombier 		p->bfilled |= 1<<y;
12647dd7cddfSDavid du Colombier 		*b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
12657dd7cddfSDavid du Colombier 	}
12667dd7cddfSDavid du Colombier 	return *b;
12677dd7cddfSDavid du Colombier }
12687dd7cddfSDavid du Colombier 
12697dd7cddfSDavid du Colombier /*
12707dd7cddfSDavid du Colombier  * Alpha reading function that simply relabels the grey pointer.
12717dd7cddfSDavid du Colombier  */
12727dd7cddfSDavid du Colombier static Buffer
greymaskread(Param * p,uchar * buf,int y)12737dd7cddfSDavid du Colombier greymaskread(Param *p, uchar *buf, int y)
12747dd7cddfSDavid du Colombier {
12757dd7cddfSDavid du Colombier 	Buffer b;
12767dd7cddfSDavid du Colombier 
12777dd7cddfSDavid du Colombier 	b = p->greymaskcall(p, buf, y);
12787dd7cddfSDavid du Colombier 	b.alpha = b.grey;
12797dd7cddfSDavid du Colombier 	return b;
12807dd7cddfSDavid du Colombier }
12817dd7cddfSDavid du Colombier 
12827dd7cddfSDavid du Colombier #define DBG if(0)
12837dd7cddfSDavid du Colombier static Buffer
readnbit(Param * p,uchar * buf,int y)12847dd7cddfSDavid du Colombier readnbit(Param *p, uchar *buf, int y)
12857dd7cddfSDavid du Colombier {
12867dd7cddfSDavid du Colombier 	Buffer b;
12877dd7cddfSDavid du Colombier 	Memimage *img;
12887dd7cddfSDavid du Colombier 	uchar *repl, *r, *w, *ow, bits;
12897dd7cddfSDavid du Colombier 	int i, n, sh, depth, x, dx, npack, nbits;
12907dd7cddfSDavid du Colombier 
12916a9fc400SDavid du Colombier 	b.rgba = (ulong*)buf;
12927dd7cddfSDavid du Colombier 	b.grey = w = buf;
12937dd7cddfSDavid du Colombier 	b.red = b.blu = b.grn = w;
12946a9fc400SDavid du Colombier 	b.alpha = &ones;
12957dd7cddfSDavid du Colombier 	b.delta = 1;
12967dd7cddfSDavid du Colombier 
12977dd7cddfSDavid du Colombier 	dx = p->dx;
12987dd7cddfSDavid du Colombier 	img = p->img;
12997dd7cddfSDavid du Colombier 	depth = img->depth;
13007dd7cddfSDavid du Colombier 	repl = &replbit[depth][0];
13017dd7cddfSDavid du Colombier 	npack = 8/depth;
13027dd7cddfSDavid du Colombier 	sh = 8-depth;
13037dd7cddfSDavid du Colombier 
13047dd7cddfSDavid du Colombier 	/* copy from p->r.min.x until end of repl rectangle */
13057dd7cddfSDavid du Colombier 	x = p->r.min.x;
13067dd7cddfSDavid du Colombier 	n = dx;
13077dd7cddfSDavid du Colombier 	if(n > p->img->r.max.x - x)
13087dd7cddfSDavid du Colombier 		n = p->img->r.max.x - x;
13097dd7cddfSDavid du Colombier 
13107dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
13117dd7cddfSDavid du Colombier DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
13127dd7cddfSDavid du Colombier 	bits = *r++;
13137dd7cddfSDavid du Colombier 	nbits = 8;
13147dd7cddfSDavid du Colombier 	if(i=x&(npack-1)){
13157dd7cddfSDavid du Colombier DBG print("throwaway %d...", i);
13167dd7cddfSDavid du Colombier 		bits <<= depth*i;
13177dd7cddfSDavid du Colombier 		nbits -= depth*i;
13187dd7cddfSDavid du Colombier 	}
13197dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
13207dd7cddfSDavid du Colombier 		if(nbits == 0){
13217dd7cddfSDavid du Colombier DBG print("(%.2ux)...", *r);
13227dd7cddfSDavid du Colombier 			bits = *r++;
13237dd7cddfSDavid du Colombier 			nbits = 8;
13247dd7cddfSDavid du Colombier 		}
13257dd7cddfSDavid du Colombier 		*w++ = repl[bits>>sh];
13267dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]);
13277dd7cddfSDavid du Colombier 		bits <<= depth;
13287dd7cddfSDavid du Colombier 		nbits -= depth;
13297dd7cddfSDavid du Colombier 	}
13307dd7cddfSDavid du Colombier 	dx -= n;
13317dd7cddfSDavid du Colombier 	if(dx == 0)
13327dd7cddfSDavid du Colombier 		return b;
13337dd7cddfSDavid du Colombier 
13347dd7cddfSDavid du Colombier 	assert(x+i == p->img->r.max.x);
13357dd7cddfSDavid du Colombier 
13367dd7cddfSDavid du Colombier 	/* copy from beginning of repl rectangle until where we were before. */
13377dd7cddfSDavid du Colombier 	x = p->img->r.min.x;
13387dd7cddfSDavid du Colombier 	n = dx;
13397dd7cddfSDavid du Colombier 	if(n > p->r.min.x - x)
13407dd7cddfSDavid du Colombier 		n = p->r.min.x - x;
13417dd7cddfSDavid du Colombier 
13427dd7cddfSDavid du Colombier 	r = p->bytey0s + y*p->bwidth;
13437dd7cddfSDavid du Colombier DBG print("x=%d r=%p...", x, r);
13447dd7cddfSDavid du Colombier 	bits = *r++;
13457dd7cddfSDavid du Colombier 	nbits = 8;
13467dd7cddfSDavid du Colombier 	if(i=x&(npack-1)){
13477dd7cddfSDavid du Colombier 		bits <<= depth*i;
13487dd7cddfSDavid du Colombier 		nbits -= depth*i;
13497dd7cddfSDavid du Colombier 	}
13507dd7cddfSDavid du Colombier DBG print("nbits=%d...", nbits);
13517dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
13527dd7cddfSDavid du Colombier 		if(nbits == 0){
13537dd7cddfSDavid du Colombier 			bits = *r++;
13547dd7cddfSDavid du Colombier 			nbits = 8;
13557dd7cddfSDavid du Colombier 		}
13567dd7cddfSDavid du Colombier 		*w++ = repl[bits>>sh];
13577dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]);
13587dd7cddfSDavid du Colombier 		bits <<= depth;
13597dd7cddfSDavid du Colombier 		nbits -= depth;
13607dd7cddfSDavid du Colombier DBG print("bits %x nbits %d...", bits, nbits);
13617dd7cddfSDavid du Colombier 	}
13627dd7cddfSDavid du Colombier 	dx -= n;
13637dd7cddfSDavid du Colombier 	if(dx == 0)
13647dd7cddfSDavid du Colombier 		return b;
13657dd7cddfSDavid du Colombier 
13667dd7cddfSDavid du Colombier 	assert(dx > 0);
13677dd7cddfSDavid du Colombier 	/* now we have exactly one full scan line: just replicate the buffer itself until we are done */
13687dd7cddfSDavid du Colombier 	ow = buf;
13697dd7cddfSDavid du Colombier 	while(dx--)
13707dd7cddfSDavid du Colombier 		*w++ = *ow++;
13717dd7cddfSDavid du Colombier 
13727dd7cddfSDavid du Colombier 	return b;
13737dd7cddfSDavid du Colombier }
13747dd7cddfSDavid du Colombier #undef DBG
13757dd7cddfSDavid du Colombier 
13767dd7cddfSDavid du Colombier #define DBG if(0)
13777dd7cddfSDavid du Colombier static void
writenbit(Param * p,uchar * w,Buffer src)13787dd7cddfSDavid du Colombier writenbit(Param *p, uchar *w, Buffer src)
13797dd7cddfSDavid du Colombier {
13807dd7cddfSDavid du Colombier 	uchar *r;
13817dd7cddfSDavid du Colombier 	ulong bits;
13827dd7cddfSDavid du Colombier 	int i, sh, depth, npack, nbits, x, ex;
13837dd7cddfSDavid du Colombier 
13847dd7cddfSDavid du Colombier 	assert(src.grey != nil && src.delta == 1);
13857dd7cddfSDavid du Colombier 
13867dd7cddfSDavid du Colombier 	x = p->r.min.x;
13877dd7cddfSDavid du Colombier 	ex = x+p->dx;
13887dd7cddfSDavid du Colombier 	depth = p->img->depth;
13897dd7cddfSDavid du Colombier 	npack = 8/depth;
13907dd7cddfSDavid du Colombier 
13917dd7cddfSDavid du Colombier 	i=x&(npack-1);
13927dd7cddfSDavid du Colombier 	bits = i ? (*w >> (8-depth*i)) : 0;
13937dd7cddfSDavid du Colombier 	nbits = depth*i;
13947dd7cddfSDavid du Colombier 	sh = 8-depth;
13957dd7cddfSDavid du Colombier 	r = src.grey;
13967dd7cddfSDavid du Colombier 
13977dd7cddfSDavid du Colombier 	for(; x<ex; x++){
13987dd7cddfSDavid du Colombier 		bits <<= depth;
13997dd7cddfSDavid du Colombier DBG print(" %x", *r);
14007dd7cddfSDavid du Colombier 		bits |= (*r++ >> sh);
14017dd7cddfSDavid du Colombier 		nbits += depth;
14027dd7cddfSDavid du Colombier 		if(nbits == 8){
14037dd7cddfSDavid du Colombier 			*w++ = bits;
14047dd7cddfSDavid du Colombier 			nbits = 0;
14057dd7cddfSDavid du Colombier 		}
14067dd7cddfSDavid du Colombier 	}
14077dd7cddfSDavid du Colombier 
14087dd7cddfSDavid du Colombier 	if(nbits){
14097dd7cddfSDavid du Colombier 		sh = 8-nbits;
14107dd7cddfSDavid du Colombier 		bits <<= sh;
14117dd7cddfSDavid du Colombier 		bits |= *w & ((1<<sh)-1);
14127dd7cddfSDavid du Colombier 		*w = bits;
14137dd7cddfSDavid du Colombier 	}
14147dd7cddfSDavid du Colombier DBG print("\n");
14157dd7cddfSDavid du Colombier 	return;
14167dd7cddfSDavid du Colombier }
14177dd7cddfSDavid du Colombier #undef DBG
14187dd7cddfSDavid du Colombier 
14197dd7cddfSDavid du Colombier static Buffer
readcmap(Param * p,uchar * buf,int y)14207dd7cddfSDavid du Colombier readcmap(Param *p, uchar *buf, int y)
14217dd7cddfSDavid du Colombier {
14227dd7cddfSDavid du Colombier 	Buffer b;
142380ee5cbfSDavid du Colombier 	int a, convgrey, copyalpha, dx, i, m;
14247dd7cddfSDavid du Colombier 	uchar *q, *cmap, *begin, *end, *r, *w;
14257dd7cddfSDavid du Colombier 
14267dd7cddfSDavid du Colombier 	begin = p->bytey0s + y*p->bwidth;
14277dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
14287dd7cddfSDavid du Colombier 	end = p->bytey0e + y*p->bwidth;
14297dd7cddfSDavid du Colombier 	cmap = p->img->cmap->cmap2rgb;
14307dd7cddfSDavid du Colombier 	convgrey = p->convgrey;
143180ee5cbfSDavid du Colombier 	copyalpha = (p->img->flags&Falpha) ? 1 : 0;
14327dd7cddfSDavid du Colombier 
14337dd7cddfSDavid du Colombier 	w = buf;
14347dd7cddfSDavid du Colombier 	dx = p->dx;
143580ee5cbfSDavid du Colombier 	if(copyalpha){
143680ee5cbfSDavid du Colombier 		b.alpha = buf++;
143780ee5cbfSDavid du Colombier 		a = p->img->shift[CAlpha]/8;
143880ee5cbfSDavid du Colombier 		m = p->img->shift[CMap]/8;
143980ee5cbfSDavid du Colombier 		for(i=0; i<dx; i++){
144080ee5cbfSDavid du Colombier 			*w++ = r[a];
144180ee5cbfSDavid du Colombier 			q = cmap+r[m]*3;
144280ee5cbfSDavid du Colombier 			r += 2;
144380ee5cbfSDavid du Colombier 			if(r == end)
144480ee5cbfSDavid du Colombier 				r = begin;
144580ee5cbfSDavid du Colombier 			if(convgrey){
144680ee5cbfSDavid du Colombier 				*w++ = RGB2K(q[0], q[1], q[2]);
144780ee5cbfSDavid du Colombier 			}else{
144880ee5cbfSDavid du Colombier 				*w++ = q[2];	/* blue */
144980ee5cbfSDavid du Colombier 				*w++ = q[1];	/* green */
145080ee5cbfSDavid du Colombier 				*w++ = q[0];	/* red */
145180ee5cbfSDavid du Colombier 			}
145280ee5cbfSDavid du Colombier 		}
145380ee5cbfSDavid du Colombier 	}else{
14546a9fc400SDavid du Colombier 		b.alpha = &ones;
14557dd7cddfSDavid du Colombier 		for(i=0; i<dx; i++){
14567dd7cddfSDavid du Colombier 			q = cmap+*r++*3;
14577dd7cddfSDavid du Colombier 			if(r == end)
14587dd7cddfSDavid du Colombier 				r = begin;
14597dd7cddfSDavid du Colombier 			if(convgrey){
14607dd7cddfSDavid du Colombier 				*w++ = RGB2K(q[0], q[1], q[2]);
14617dd7cddfSDavid du Colombier 			}else{
14627dd7cddfSDavid du Colombier 				*w++ = q[2];	/* blue */
14637dd7cddfSDavid du Colombier 				*w++ = q[1];	/* green */
14647dd7cddfSDavid du Colombier 				*w++ = q[0];	/* red */
14657dd7cddfSDavid du Colombier 			}
14667dd7cddfSDavid du Colombier 		}
146780ee5cbfSDavid du Colombier 	}
14687dd7cddfSDavid du Colombier 
14696a9fc400SDavid du Colombier 	b.rgba = (ulong*)(buf-copyalpha);
14706a9fc400SDavid du Colombier 
14717dd7cddfSDavid du Colombier 	if(convgrey){
14727dd7cddfSDavid du Colombier 		b.grey = buf;
14737dd7cddfSDavid du Colombier 		b.red = b.blu = b.grn = buf;
147480ee5cbfSDavid du Colombier 		b.delta = 1+copyalpha;
14757dd7cddfSDavid du Colombier 	}else{
14767dd7cddfSDavid du Colombier 		b.blu = buf;
14777dd7cddfSDavid du Colombier 		b.grn = buf+1;
14787dd7cddfSDavid du Colombier 		b.red = buf+2;
14797dd7cddfSDavid du Colombier 		b.grey = nil;
148080ee5cbfSDavid du Colombier 		b.delta = 3+copyalpha;
14817dd7cddfSDavid du Colombier 	}
14827dd7cddfSDavid du Colombier 	return b;
14837dd7cddfSDavid du Colombier }
14847dd7cddfSDavid du Colombier 
14857dd7cddfSDavid du Colombier static void
writecmap(Param * p,uchar * w,Buffer src)14867dd7cddfSDavid du Colombier writecmap(Param *p, uchar *w, Buffer src)
14877dd7cddfSDavid du Colombier {
14887dd7cddfSDavid du Colombier 	uchar *cmap, *red, *grn, *blu;
14897dd7cddfSDavid du Colombier 	int i, dx, delta;
14907dd7cddfSDavid du Colombier 
14917dd7cddfSDavid du Colombier 	cmap = p->img->cmap->rgb2cmap;
14927dd7cddfSDavid du Colombier 
14937dd7cddfSDavid du Colombier 	delta = src.delta;
14947dd7cddfSDavid du Colombier 	red= src.red;
14957dd7cddfSDavid du Colombier 	grn = src.grn;
14967dd7cddfSDavid du Colombier 	blu = src.blu;
14977dd7cddfSDavid du Colombier 
14987dd7cddfSDavid du Colombier 	dx = p->dx;
14997dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
15007dd7cddfSDavid du Colombier 		*w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
15017dd7cddfSDavid du Colombier }
15027dd7cddfSDavid du Colombier 
150359cc4ca5SDavid du Colombier #define DBG if(0)
15047dd7cddfSDavid du Colombier static Buffer
readbyte(Param * p,uchar * buf,int y)15057dd7cddfSDavid du Colombier readbyte(Param *p, uchar *buf, int y)
15067dd7cddfSDavid du Colombier {
15077dd7cddfSDavid du Colombier 	Buffer b;
15087dd7cddfSDavid du Colombier 	Memimage *img;
15097dd7cddfSDavid du Colombier 	int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
15107dd7cddfSDavid du Colombier 	uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
15117dd7cddfSDavid du Colombier 	uchar ured, ugrn, ublu;
15127dd7cddfSDavid du Colombier 	ulong u;
15137dd7cddfSDavid du Colombier 
15147dd7cddfSDavid du Colombier 	img = p->img;
15157dd7cddfSDavid du Colombier 	begin = p->bytey0s + y*p->bwidth;
15167dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
15177dd7cddfSDavid du Colombier 	end = p->bytey0e + y*p->bwidth;
15187dd7cddfSDavid du Colombier 
15197dd7cddfSDavid du Colombier 	w = buf;
15207dd7cddfSDavid du Colombier 	dx = p->dx;
15217dd7cddfSDavid du Colombier 	nb = img->depth/8;
15227dd7cddfSDavid du Colombier 
15237dd7cddfSDavid du Colombier 	convgrey = p->convgrey;	/* convert rgb to grey */
15247dd7cddfSDavid du Colombier 	isgrey = img->flags&Fgrey;
15257dd7cddfSDavid du Colombier 	alphaonly = p->alphaonly;
152659cc4ca5SDavid du Colombier 	copyalpha = (img->flags&Falpha) ? 1 : 0;
15277dd7cddfSDavid du Colombier 
152859cc4ca5SDavid du Colombier DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
15297dd7cddfSDavid du Colombier 	/* if we can, avoid processing everything */
15307dd7cddfSDavid du Colombier 	if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
15317dd7cddfSDavid du Colombier 		memset(&b, 0, sizeof b);
15327dd7cddfSDavid du Colombier 		if(p->needbuf){
15337dd7cddfSDavid du Colombier 			memmove(buf, r, dx*nb);
15347dd7cddfSDavid du Colombier 			r = buf;
15357dd7cddfSDavid du Colombier 		}
15366a9fc400SDavid du Colombier 		b.rgba = (ulong*)r;
15377dd7cddfSDavid du Colombier 		if(copyalpha)
15387dd7cddfSDavid du Colombier 			b.alpha = r+img->shift[CAlpha]/8;
15396a9fc400SDavid du Colombier 		else
15406a9fc400SDavid du Colombier 			b.alpha = &ones;
15417dd7cddfSDavid du Colombier 		if(isgrey){
15427dd7cddfSDavid du Colombier 			b.grey = r+img->shift[CGrey]/8;
15437dd7cddfSDavid du Colombier 			b.red = b.grn = b.blu = b.grey;
15447dd7cddfSDavid du Colombier 		}else{
15457dd7cddfSDavid du Colombier 			b.red = r+img->shift[CRed]/8;
15467dd7cddfSDavid du Colombier 			b.grn = r+img->shift[CGreen]/8;
15477dd7cddfSDavid du Colombier 			b.blu = r+img->shift[CBlue]/8;
15487dd7cddfSDavid du Colombier 		}
15497dd7cddfSDavid du Colombier 		b.delta = nb;
15507dd7cddfSDavid du Colombier 		return b;
15517dd7cddfSDavid du Colombier 	}
15527dd7cddfSDavid du Colombier 
155359cc4ca5SDavid du Colombier DBG print("2\n");
15547dd7cddfSDavid du Colombier 	rrepl = replbit[img->nbits[CRed]];
15557dd7cddfSDavid du Colombier 	grepl = replbit[img->nbits[CGreen]];
15567dd7cddfSDavid du Colombier 	brepl = replbit[img->nbits[CBlue]];
15577dd7cddfSDavid du Colombier 	arepl = replbit[img->nbits[CAlpha]];
15587dd7cddfSDavid du Colombier 	krepl = replbit[img->nbits[CGrey]];
15597dd7cddfSDavid du Colombier 
15607dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
15617dd7cddfSDavid du Colombier 		u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
156259cc4ca5SDavid du Colombier 		if(copyalpha) {
15637dd7cddfSDavid du Colombier 			*w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
156459cc4ca5SDavid du Colombier DBG print("a %x\n", w[-1]);
156559cc4ca5SDavid du Colombier 		}
15667dd7cddfSDavid du Colombier 
15677dd7cddfSDavid du Colombier 		if(isgrey)
15687dd7cddfSDavid du Colombier 			*w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
15697dd7cddfSDavid du Colombier 		else if(!alphaonly){
15707dd7cddfSDavid du Colombier 			ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
15717dd7cddfSDavid du Colombier 			ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
15727dd7cddfSDavid du Colombier 			ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
15737dd7cddfSDavid du Colombier 			if(convgrey){
157459cc4ca5SDavid du Colombier DBG print("g %x %x %x\n", ured, ugrn, ublu);
15757dd7cddfSDavid du Colombier 				*w++ = RGB2K(ured, ugrn, ublu);
157659cc4ca5SDavid du Colombier DBG print("%x\n", w[-1]);
15777dd7cddfSDavid du Colombier 			}else{
15787dd7cddfSDavid du Colombier 				*w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
15797dd7cddfSDavid du Colombier 				*w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
15807dd7cddfSDavid du Colombier 				*w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
15817dd7cddfSDavid du Colombier 			}
15827dd7cddfSDavid du Colombier 		}
15837dd7cddfSDavid du Colombier 		r += nb;
15847dd7cddfSDavid du Colombier 		if(r == end)
15857dd7cddfSDavid du Colombier 			r = begin;
15867dd7cddfSDavid du Colombier 	}
15877dd7cddfSDavid du Colombier 
15886a9fc400SDavid du Colombier 	b.alpha = copyalpha ? buf : &ones;
15896a9fc400SDavid du Colombier 	b.rgba = (ulong*)buf;
15907dd7cddfSDavid du Colombier 	if(alphaonly){
15917dd7cddfSDavid du Colombier 		b.red = b.grn = b.blu = b.grey = nil;
15926a9fc400SDavid du Colombier 		if(!copyalpha)
15936a9fc400SDavid du Colombier 			b.rgba = nil;
15947dd7cddfSDavid du Colombier 		b.delta = 1;
15957dd7cddfSDavid du Colombier 	}else if(isgrey || convgrey){
15967dd7cddfSDavid du Colombier 		b.grey = buf+copyalpha;
15977dd7cddfSDavid du Colombier 		b.red = b.grn = b.blu = buf+copyalpha;
15987dd7cddfSDavid du Colombier 		b.delta = copyalpha+1;
159959cc4ca5SDavid du Colombier DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey);
16007dd7cddfSDavid du Colombier 	}else{
16017dd7cddfSDavid du Colombier 		b.blu = buf+copyalpha;
16027dd7cddfSDavid du Colombier 		b.grn = buf+copyalpha+1;
16037dd7cddfSDavid du Colombier 		b.grey = nil;
16047dd7cddfSDavid du Colombier 		b.red = buf+copyalpha+2;
16057dd7cddfSDavid du Colombier 		b.delta = copyalpha+3;
16067dd7cddfSDavid du Colombier 	}
16077dd7cddfSDavid du Colombier 	return b;
16087dd7cddfSDavid du Colombier }
160959cc4ca5SDavid du Colombier #undef DBG
16107dd7cddfSDavid du Colombier 
16117dd7cddfSDavid du Colombier #define DBG if(0)
16127dd7cddfSDavid du Colombier static void
writebyte(Param * p,uchar * w,Buffer src)16137dd7cddfSDavid du Colombier writebyte(Param *p, uchar *w, Buffer src)
16147dd7cddfSDavid du Colombier {
16157dd7cddfSDavid du Colombier 	Memimage *img;
16167dd7cddfSDavid du Colombier 	int i, isalpha, isgrey, nb, delta, dx, adelta;
16177dd7cddfSDavid du Colombier 	uchar ff, *red, *grn, *blu, *grey, *alpha;
16187dd7cddfSDavid du Colombier 	ulong u, mask;
16197dd7cddfSDavid du Colombier 
16207dd7cddfSDavid du Colombier 	img = p->img;
16217dd7cddfSDavid du Colombier 
16227dd7cddfSDavid du Colombier 	red = src.red;
16237dd7cddfSDavid du Colombier 	grn = src.grn;
16247dd7cddfSDavid du Colombier 	blu = src.blu;
16257dd7cddfSDavid du Colombier 	alpha = src.alpha;
16267dd7cddfSDavid du Colombier 	delta = src.delta;
16277dd7cddfSDavid du Colombier 	grey = src.grey;
16287dd7cddfSDavid du Colombier 	dx = p->dx;
16297dd7cddfSDavid du Colombier 
16307dd7cddfSDavid du Colombier 	nb = img->depth/8;
16317dd7cddfSDavid du Colombier 	mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
16327dd7cddfSDavid du Colombier 
16337dd7cddfSDavid du Colombier 	isalpha = img->flags&Falpha;
16347dd7cddfSDavid du Colombier 	isgrey = img->flags&Fgrey;
16357dd7cddfSDavid du Colombier 	adelta = src.delta;
16367dd7cddfSDavid du Colombier 
16376a9fc400SDavid du Colombier 	if(isalpha && (alpha == nil || alpha == &ones)){
16387dd7cddfSDavid du Colombier 		ff = 0xFF;
16397dd7cddfSDavid du Colombier 		alpha = &ff;
16407dd7cddfSDavid du Colombier 		adelta = 0;
16417dd7cddfSDavid du Colombier 	}
16427dd7cddfSDavid du Colombier 
16437dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
16447dd7cddfSDavid du Colombier 		u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
16457dd7cddfSDavid du Colombier DBG print("u %.8lux...", u);
16467dd7cddfSDavid du Colombier 		u &= mask;
16477dd7cddfSDavid du Colombier DBG print("&mask %.8lux...", u);
16487dd7cddfSDavid du Colombier 		if(isgrey){
16497dd7cddfSDavid du Colombier 			u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
16507dd7cddfSDavid du Colombier DBG print("|grey %.8lux...", u);
16517dd7cddfSDavid du Colombier 			grey += delta;
16527dd7cddfSDavid du Colombier 		}else{
16537dd7cddfSDavid du Colombier 			u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
16547dd7cddfSDavid du Colombier 			u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
16557dd7cddfSDavid du Colombier 			u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
16567dd7cddfSDavid du Colombier 			red += delta;
16577dd7cddfSDavid du Colombier 			grn += delta;
16587dd7cddfSDavid du Colombier 			blu += delta;
16597dd7cddfSDavid du Colombier DBG print("|rgb %.8lux...", u);
16607dd7cddfSDavid du Colombier 		}
16617dd7cddfSDavid du Colombier 
16627dd7cddfSDavid du Colombier 		if(isalpha){
16637dd7cddfSDavid du Colombier 			u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
16647dd7cddfSDavid du Colombier 			alpha += adelta;
16657dd7cddfSDavid du Colombier DBG print("|alpha %.8lux...", u);
16667dd7cddfSDavid du Colombier 		}
16677dd7cddfSDavid du Colombier 
16687dd7cddfSDavid du Colombier 		w[0] = u;
16697dd7cddfSDavid du Colombier 		w[1] = u>>8;
16707dd7cddfSDavid du Colombier 		w[2] = u>>16;
16717dd7cddfSDavid du Colombier 		w[3] = u>>24;
16727dd7cddfSDavid du Colombier 		w += nb;
16737dd7cddfSDavid du Colombier 	}
16747dd7cddfSDavid du Colombier }
16757dd7cddfSDavid du Colombier #undef DBG
16767dd7cddfSDavid du Colombier 
16777dd7cddfSDavid du Colombier static Readfn*
readfn(Memimage * img)16787dd7cddfSDavid du Colombier readfn(Memimage *img)
16797dd7cddfSDavid du Colombier {
16807dd7cddfSDavid du Colombier 	if(img->depth < 8)
16817dd7cddfSDavid du Colombier 		return readnbit;
168280ee5cbfSDavid du Colombier 	if(img->nbits[CMap] == 8)
16837dd7cddfSDavid du Colombier 		return readcmap;
16847dd7cddfSDavid du Colombier 	return readbyte;
16857dd7cddfSDavid du Colombier }
16867dd7cddfSDavid du Colombier 
16877dd7cddfSDavid du Colombier static Readfn*
readalphafn(Memimage * m)16886a9fc400SDavid du Colombier readalphafn(Memimage *m)
16897dd7cddfSDavid du Colombier {
16906a9fc400SDavid du Colombier 	USED(m);
16917dd7cddfSDavid du Colombier 	return readbyte;
16927dd7cddfSDavid du Colombier }
16937dd7cddfSDavid du Colombier 
16947dd7cddfSDavid du Colombier static Writefn*
writefn(Memimage * img)16957dd7cddfSDavid du Colombier writefn(Memimage *img)
16967dd7cddfSDavid du Colombier {
16977dd7cddfSDavid du Colombier 	if(img->depth < 8)
16987dd7cddfSDavid du Colombier 		return writenbit;
16997dd7cddfSDavid du Colombier 	if(img->chan == CMAP8)
17007dd7cddfSDavid du Colombier 		return writecmap;
17017dd7cddfSDavid du Colombier 	return writebyte;
17027dd7cddfSDavid du Colombier }
17037dd7cddfSDavid du Colombier 
17047dd7cddfSDavid du Colombier static void
nullwrite(Param * p,uchar * s,Buffer b)17056a9fc400SDavid du Colombier nullwrite(Param *p, uchar *s, Buffer b)
17067dd7cddfSDavid du Colombier {
17076a9fc400SDavid du Colombier 	USED(p);
17086a9fc400SDavid du Colombier 	USED(s);
17096a9fc400SDavid du Colombier 	USED(b);
17107dd7cddfSDavid du Colombier }
17117dd7cddfSDavid du Colombier 
17127dd7cddfSDavid du Colombier static Buffer
readptr(Param * p,uchar * s,int y)17136a9fc400SDavid du Colombier readptr(Param *p, uchar *s, int y)
17147dd7cddfSDavid du Colombier {
17157dd7cddfSDavid du Colombier 	Buffer b;
17167dd7cddfSDavid du Colombier 	uchar *q;
17177dd7cddfSDavid du Colombier 
17186a9fc400SDavid du Colombier 	USED(s);
17197dd7cddfSDavid du Colombier 	q = p->bytermin + y*p->bwidth;
17207dd7cddfSDavid du Colombier 	b.red = q;	/* ptr to data */
17217dd7cddfSDavid du Colombier 	b.grn = b.blu = b.grey = b.alpha = nil;
17226a9fc400SDavid du Colombier 	b.rgba = (ulong*)q;
17237dd7cddfSDavid du Colombier 	b.delta = p->img->depth/8;
17247dd7cddfSDavid du Colombier 	return b;
17257dd7cddfSDavid du Colombier }
17267dd7cddfSDavid du Colombier 
17277dd7cddfSDavid du Colombier static Buffer
boolmemmove(Buffer bdst,Buffer bsrc,Buffer b1,int dx,int i,int o)17286a9fc400SDavid du Colombier boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
17297dd7cddfSDavid du Colombier {
17306a9fc400SDavid du Colombier 	USED(i);
17316a9fc400SDavid du Colombier 	USED(o);
17326a9fc400SDavid du Colombier 	USED(b1);
17336a9fc400SDavid du Colombier 	USED(bsrc);
17347dd7cddfSDavid du Colombier 	memmove(bdst.red, bsrc.red, dx*bdst.delta);
17357dd7cddfSDavid du Colombier 	return bdst;
17367dd7cddfSDavid du Colombier }
17377dd7cddfSDavid du Colombier 
17387dd7cddfSDavid du Colombier static Buffer
boolcopy8(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int i,int o)17396a9fc400SDavid du Colombier boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17407dd7cddfSDavid du Colombier {
17417dd7cddfSDavid du Colombier 	uchar *m, *r, *w, *ew;
17427dd7cddfSDavid du Colombier 
17436a9fc400SDavid du Colombier 	USED(i);
17446a9fc400SDavid du Colombier 	USED(o);
17457dd7cddfSDavid du Colombier 	m = bmask.grey;
17467dd7cddfSDavid du Colombier 	w = bdst.red;
17477dd7cddfSDavid du Colombier 	r = bsrc.red;
17487dd7cddfSDavid du Colombier 	ew = w+dx;
17497dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
17507dd7cddfSDavid du Colombier 		if(*m++)
17517dd7cddfSDavid du Colombier 			*w = *r;
17527dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17537dd7cddfSDavid du Colombier }
17547dd7cddfSDavid du Colombier 
17557dd7cddfSDavid du Colombier static Buffer
boolcopy16(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int i,int o)17566a9fc400SDavid du Colombier boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17577dd7cddfSDavid du Colombier {
17587dd7cddfSDavid du Colombier 	uchar *m;
17597dd7cddfSDavid du Colombier 	ushort *r, *w, *ew;
17607dd7cddfSDavid du Colombier 
17616a9fc400SDavid du Colombier 	USED(i);
17626a9fc400SDavid du Colombier 	USED(o);
17637dd7cddfSDavid du Colombier 	m = bmask.grey;
17647dd7cddfSDavid du Colombier 	w = (ushort*)bdst.red;
17657dd7cddfSDavid du Colombier 	r = (ushort*)bsrc.red;
17667dd7cddfSDavid du Colombier 	ew = w+dx;
17677dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
17687dd7cddfSDavid du Colombier 		if(*m++)
17697dd7cddfSDavid du Colombier 			*w = *r;
17707dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17717dd7cddfSDavid du Colombier }
17727dd7cddfSDavid du Colombier 
17737dd7cddfSDavid du Colombier static Buffer
boolcopy24(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int i,int o)17746a9fc400SDavid du Colombier boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17757dd7cddfSDavid du Colombier {
17767dd7cddfSDavid du Colombier 	uchar *m;
17777dd7cddfSDavid du Colombier 	uchar *r, *w, *ew;
17787dd7cddfSDavid du Colombier 
17796a9fc400SDavid du Colombier 	USED(i);
17806a9fc400SDavid du Colombier 	USED(o);
17817dd7cddfSDavid du Colombier 	m = bmask.grey;
17827dd7cddfSDavid du Colombier 	w = bdst.red;
17837dd7cddfSDavid du Colombier 	r = bsrc.red;
17847dd7cddfSDavid du Colombier 	ew = w+dx*3;
17857dd7cddfSDavid du Colombier 	while(w < ew){
17867dd7cddfSDavid du Colombier 		if(*m++){
17877dd7cddfSDavid du Colombier 			*w++ = *r++;
17887dd7cddfSDavid du Colombier 			*w++ = *r++;
17897dd7cddfSDavid du Colombier 			*w++ = *r++;
17907dd7cddfSDavid du Colombier 		}else{
17917dd7cddfSDavid du Colombier 			w += 3;
17927dd7cddfSDavid du Colombier 			r += 3;
17937dd7cddfSDavid du Colombier 		}
17947dd7cddfSDavid du Colombier 	}
17957dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17967dd7cddfSDavid du Colombier }
17977dd7cddfSDavid du Colombier 
17987dd7cddfSDavid du Colombier static Buffer
boolcopy32(Buffer bdst,Buffer bsrc,Buffer bmask,int dx,int i,int o)17996a9fc400SDavid du Colombier boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
18007dd7cddfSDavid du Colombier {
18017dd7cddfSDavid du Colombier 	uchar *m;
18027dd7cddfSDavid du Colombier 	ulong *r, *w, *ew;
18037dd7cddfSDavid du Colombier 
18046a9fc400SDavid du Colombier 	USED(i);
18056a9fc400SDavid du Colombier 	USED(o);
18067dd7cddfSDavid du Colombier 	m = bmask.grey;
18077dd7cddfSDavid du Colombier 	w = (ulong*)bdst.red;
18087dd7cddfSDavid du Colombier 	r = (ulong*)bsrc.red;
18097dd7cddfSDavid du Colombier 	ew = w+dx;
18107dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
18117dd7cddfSDavid du Colombier 		if(*m++)
18127dd7cddfSDavid du Colombier 			*w = *r;
18137dd7cddfSDavid du Colombier 	return bdst;	/* not used */
18147dd7cddfSDavid du Colombier }
18157dd7cddfSDavid du Colombier 
18167dd7cddfSDavid du Colombier static Buffer
genconv(Param * p,uchar * buf,int y)18177dd7cddfSDavid du Colombier genconv(Param *p, uchar *buf, int y)
18187dd7cddfSDavid du Colombier {
18197dd7cddfSDavid du Colombier 	Buffer b;
18207dd7cddfSDavid du Colombier 	int nb;
18217dd7cddfSDavid du Colombier 	uchar *r, *w, *ew;
18227dd7cddfSDavid du Colombier 
18237dd7cddfSDavid du Colombier 	/* read from source into RGB format in convbuf */
18247dd7cddfSDavid du Colombier 	b = p->convreadcall(p, p->convbuf, y);
18257dd7cddfSDavid du Colombier 
18267dd7cddfSDavid du Colombier 	/* write RGB format into dst format in buf */
18277dd7cddfSDavid du Colombier 	p->convwritecall(p->convdpar, buf, b);
18287dd7cddfSDavid du Colombier 
18297dd7cddfSDavid du Colombier 	if(p->convdx){
18307dd7cddfSDavid du Colombier 		nb = p->convdpar->img->depth/8;
18317dd7cddfSDavid du Colombier 		r = buf;
18327dd7cddfSDavid du Colombier 		w = buf+nb*p->dx;
18337dd7cddfSDavid du Colombier 		ew = buf+nb*p->convdx;
18347dd7cddfSDavid du Colombier 		while(w<ew)
18357dd7cddfSDavid du Colombier 			*w++ = *r++;
18367dd7cddfSDavid du Colombier 	}
18377dd7cddfSDavid du Colombier 
18387dd7cddfSDavid du Colombier 	b.red = buf;
18397dd7cddfSDavid du Colombier 	b.blu = b.grn = b.grey = b.alpha = nil;
18406a9fc400SDavid du Colombier 	b.rgba = (ulong*)buf;
18417dd7cddfSDavid du Colombier 	b.delta = 0;
18427dd7cddfSDavid du Colombier 
18437dd7cddfSDavid du Colombier 	return b;
18447dd7cddfSDavid du Colombier }
18457dd7cddfSDavid du Colombier 
18467dd7cddfSDavid du Colombier static Readfn*
convfn(Memimage * dst,Param * dpar,Memimage * src,Param * spar,int * ndrawbuf)1847*2c1878b4SDavid du Colombier convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar, int *ndrawbuf)
18487dd7cddfSDavid du Colombier {
18497dd7cddfSDavid du Colombier 	if(dst->chan == src->chan && !(src->flags&Frepl)){
18507dd7cddfSDavid du Colombier //if(drawdebug) iprint("readptr...");
18517dd7cddfSDavid du Colombier 		return readptr;
18527dd7cddfSDavid du Colombier 	}
18537dd7cddfSDavid du Colombier 
18547dd7cddfSDavid du Colombier 	if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
18557dd7cddfSDavid du Colombier 		/* cheat because we know the replicated value is exactly the color map entry. */
18567dd7cddfSDavid du Colombier //if(drawdebug) iprint("Readnbit...");
18577dd7cddfSDavid du Colombier 		return readnbit;
18587dd7cddfSDavid du Colombier 	}
18597dd7cddfSDavid du Colombier 
18607dd7cddfSDavid du Colombier 	spar->convreadcall = readfn(src);
18617dd7cddfSDavid du Colombier 	spar->convwritecall = writefn(dst);
18627dd7cddfSDavid du Colombier 	spar->convdpar = dpar;
18637dd7cddfSDavid du Colombier 
18647dd7cddfSDavid du Colombier 	/* allocate a conversion buffer */
1865*2c1878b4SDavid du Colombier 	spar->convbufoff = *ndrawbuf;
1866*2c1878b4SDavid du Colombier 	*ndrawbuf += spar->dx*4;
18677dd7cddfSDavid du Colombier 
18687dd7cddfSDavid du Colombier 	if(spar->dx > Dx(spar->img->r)){
18697dd7cddfSDavid du Colombier 		spar->convdx = spar->dx;
18707dd7cddfSDavid du Colombier 		spar->dx = Dx(spar->img->r);
18717dd7cddfSDavid du Colombier 	}
18727dd7cddfSDavid du Colombier 
18737dd7cddfSDavid du Colombier //if(drawdebug) iprint("genconv...");
18747dd7cddfSDavid du Colombier 	return genconv;
18757dd7cddfSDavid du Colombier }
18767dd7cddfSDavid du Colombier 
18777dd7cddfSDavid du Colombier static ulong
pixelbits(Memimage * i,Point pt)18787dd7cddfSDavid du Colombier pixelbits(Memimage *i, Point pt)
18797dd7cddfSDavid du Colombier {
18807dd7cddfSDavid du Colombier 	uchar *p;
18817dd7cddfSDavid du Colombier 	ulong val;
18827dd7cddfSDavid du Colombier 	int off, bpp, npack;
18837dd7cddfSDavid du Colombier 
18847dd7cddfSDavid du Colombier 	val = 0;
18857dd7cddfSDavid du Colombier 	p = byteaddr(i, pt);
18867dd7cddfSDavid du Colombier 	switch(bpp=i->depth){
18877dd7cddfSDavid du Colombier 	case 1:
18887dd7cddfSDavid du Colombier 	case 2:
18897dd7cddfSDavid du Colombier 	case 4:
18907dd7cddfSDavid du Colombier 		npack = 8/bpp;
18917dd7cddfSDavid du Colombier 		off = pt.x%npack;
18927dd7cddfSDavid du Colombier 		val = p[0] >> bpp*(npack-1-off);
18937dd7cddfSDavid du Colombier 		val &= (1<<bpp)-1;
18947dd7cddfSDavid du Colombier 		break;
18957dd7cddfSDavid du Colombier 	case 8:
18967dd7cddfSDavid du Colombier 		val = p[0];
18977dd7cddfSDavid du Colombier 		break;
18987dd7cddfSDavid du Colombier 	case 16:
18997dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8);
19007dd7cddfSDavid du Colombier 		break;
19017dd7cddfSDavid du Colombier 	case 24:
19027dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8)|(p[2]<<16);
19037dd7cddfSDavid du Colombier 		break;
19047dd7cddfSDavid du Colombier 	case 32:
19057dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
19067dd7cddfSDavid du Colombier 		break;
19077dd7cddfSDavid du Colombier 	}
19087dd7cddfSDavid du Colombier 	while(bpp<32){
19097dd7cddfSDavid du Colombier 		val |= val<<bpp;
19107dd7cddfSDavid du Colombier 		bpp *= 2;
19117dd7cddfSDavid du Colombier 	}
19127dd7cddfSDavid du Colombier 	return val;
19137dd7cddfSDavid du Colombier }
19147dd7cddfSDavid du Colombier 
19157dd7cddfSDavid du Colombier static Calcfn*
boolcopyfn(Memimage * img,Memimage * mask)19167dd7cddfSDavid du Colombier boolcopyfn(Memimage *img, Memimage *mask)
19177dd7cddfSDavid du Colombier {
19187dd7cddfSDavid du Colombier 	if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
19197dd7cddfSDavid du Colombier 		return boolmemmove;
19207dd7cddfSDavid du Colombier 
19217dd7cddfSDavid du Colombier 	switch(img->depth){
19227dd7cddfSDavid du Colombier 	case 8:
19237dd7cddfSDavid du Colombier 		return boolcopy8;
19247dd7cddfSDavid du Colombier 	case 16:
19257dd7cddfSDavid du Colombier 		return boolcopy16;
19267dd7cddfSDavid du Colombier 	case 24:
19277dd7cddfSDavid du Colombier 		return boolcopy24;
19287dd7cddfSDavid du Colombier 	case 32:
19297dd7cddfSDavid du Colombier 		return boolcopy32;
19307dd7cddfSDavid du Colombier 	default:
19317dd7cddfSDavid du Colombier 		assert(0 /* boolcopyfn */);
19327dd7cddfSDavid du Colombier 	}
19337dd7cddfSDavid du Colombier 	return nil;
19347dd7cddfSDavid du Colombier }
19357dd7cddfSDavid du Colombier 
19367dd7cddfSDavid du Colombier /*
19377dd7cddfSDavid du Colombier  * Optimized draw for filling and scrolling; uses memset and memmove.
19387dd7cddfSDavid du Colombier  */
19397dd7cddfSDavid du Colombier static void
memsetb(void * vp,uchar val,int n)19407dd7cddfSDavid du Colombier memsetb(void *vp, uchar val, int n)
19417dd7cddfSDavid du Colombier {
19427dd7cddfSDavid du Colombier 	uchar *p, *ep;
19437dd7cddfSDavid du Colombier 
19447dd7cddfSDavid du Colombier 	p = vp;
19457dd7cddfSDavid du Colombier 	ep = p+n;
19467dd7cddfSDavid du Colombier 	while(p<ep)
19477dd7cddfSDavid du Colombier 		*p++ = val;
19487dd7cddfSDavid du Colombier }
19497dd7cddfSDavid du Colombier 
19507dd7cddfSDavid du Colombier static void
memsets(void * vp,ushort val,int n)19517dd7cddfSDavid du Colombier memsets(void *vp, ushort val, int n)
19527dd7cddfSDavid du Colombier {
19537dd7cddfSDavid du Colombier 	ushort *p, *ep;
19547dd7cddfSDavid du Colombier 
19557dd7cddfSDavid du Colombier 	p = vp;
19567dd7cddfSDavid du Colombier 	ep = p+n;
19577dd7cddfSDavid du Colombier 	while(p<ep)
19587dd7cddfSDavid du Colombier 		*p++ = val;
19597dd7cddfSDavid du Colombier }
19607dd7cddfSDavid du Colombier 
19617dd7cddfSDavid du Colombier static void
memsetl(void * vp,ulong val,int n)19627dd7cddfSDavid du Colombier memsetl(void *vp, ulong val, int n)
19637dd7cddfSDavid du Colombier {
19647dd7cddfSDavid du Colombier 	ulong *p, *ep;
19657dd7cddfSDavid du Colombier 
19667dd7cddfSDavid du Colombier 	p = vp;
19677dd7cddfSDavid du Colombier 	ep = p+n;
19687dd7cddfSDavid du Colombier 	while(p<ep)
19697dd7cddfSDavid du Colombier 		*p++ = val;
19707dd7cddfSDavid du Colombier }
19717dd7cddfSDavid du Colombier 
19727dd7cddfSDavid du Colombier static void
memset24(void * vp,ulong val,int n)19737dd7cddfSDavid du Colombier memset24(void *vp, ulong val, int n)
19747dd7cddfSDavid du Colombier {
19757dd7cddfSDavid du Colombier 	uchar *p, *ep;
19767dd7cddfSDavid du Colombier 	uchar a,b,c;
19777dd7cddfSDavid du Colombier 
19787dd7cddfSDavid du Colombier 	p = vp;
19797dd7cddfSDavid du Colombier 	ep = p+3*n;
19807dd7cddfSDavid du Colombier 	a = val;
19817dd7cddfSDavid du Colombier 	b = val>>8;
19827dd7cddfSDavid du Colombier 	c = val>>16;
19837dd7cddfSDavid du Colombier 	while(p<ep){
19847dd7cddfSDavid du Colombier 		*p++ = a;
19857dd7cddfSDavid du Colombier 		*p++ = b;
19867dd7cddfSDavid du Colombier 		*p++ = c;
19877dd7cddfSDavid du Colombier 	}
19887dd7cddfSDavid du Colombier }
19897dd7cddfSDavid du Colombier 
19907dd7cddfSDavid du Colombier static ulong
imgtorgba(Memimage * img,ulong val)19917dd7cddfSDavid du Colombier imgtorgba(Memimage *img, ulong val)
19927dd7cddfSDavid du Colombier {
19937dd7cddfSDavid du Colombier 	uchar r, g, b, a;
19947dd7cddfSDavid du Colombier 	int nb, ov, v;
19957dd7cddfSDavid du Colombier 	ulong chan;
19967dd7cddfSDavid du Colombier 	uchar *p;
19977dd7cddfSDavid du Colombier 
19987dd7cddfSDavid du Colombier 	a = 0xFF;
19997dd7cddfSDavid du Colombier 	r = g = b = 0xAA;	/* garbage */
20007dd7cddfSDavid du Colombier 	for(chan=img->chan; chan; chan>>=8){
20017dd7cddfSDavid du Colombier 		nb = NBITS(chan);
20027dd7cddfSDavid du Colombier 		ov = v = val&((1<<nb)-1);
20037dd7cddfSDavid du Colombier 		val >>= nb;
20047dd7cddfSDavid du Colombier 
20057dd7cddfSDavid du Colombier 		while(nb < 8){
20067dd7cddfSDavid du Colombier 			v |= v<<nb;
20077dd7cddfSDavid du Colombier 			nb *= 2;
20087dd7cddfSDavid du Colombier 		}
20097dd7cddfSDavid du Colombier 		v >>= (nb-8);
20107dd7cddfSDavid du Colombier 
20117dd7cddfSDavid du Colombier 		switch(TYPE(chan)){
20127dd7cddfSDavid du Colombier 		case CRed:
20137dd7cddfSDavid du Colombier 			r = v;
20147dd7cddfSDavid du Colombier 			break;
20157dd7cddfSDavid du Colombier 		case CGreen:
20167dd7cddfSDavid du Colombier 			g = v;
20177dd7cddfSDavid du Colombier 			break;
20187dd7cddfSDavid du Colombier 		case CBlue:
20197dd7cddfSDavid du Colombier 			b = v;
20207dd7cddfSDavid du Colombier 			break;
20217dd7cddfSDavid du Colombier 		case CAlpha:
20227dd7cddfSDavid du Colombier 			a = v;
20237dd7cddfSDavid du Colombier 			break;
20247dd7cddfSDavid du Colombier 		case CGrey:
20257dd7cddfSDavid du Colombier 			r = g = b = v;
20267dd7cddfSDavid du Colombier 			break;
20277dd7cddfSDavid du Colombier 		case CMap:
20287dd7cddfSDavid du Colombier 			p = img->cmap->cmap2rgb+3*ov;
20297dd7cddfSDavid du Colombier 			r = *p++;
20307dd7cddfSDavid du Colombier 			g = *p++;
20317dd7cddfSDavid du Colombier 			b = *p;
20327dd7cddfSDavid du Colombier 			break;
20337dd7cddfSDavid du Colombier 		}
20347dd7cddfSDavid du Colombier 	}
20357dd7cddfSDavid du Colombier 	return (r<<24)|(g<<16)|(b<<8)|a;
20367dd7cddfSDavid du Colombier }
20377dd7cddfSDavid du Colombier 
20387dd7cddfSDavid du Colombier static ulong
rgbatoimg(Memimage * img,ulong rgba)20397dd7cddfSDavid du Colombier rgbatoimg(Memimage *img, ulong rgba)
20407dd7cddfSDavid du Colombier {
20417dd7cddfSDavid du Colombier 	ulong chan;
20427dd7cddfSDavid du Colombier 	int d, nb;
20437dd7cddfSDavid du Colombier 	ulong v;
20447dd7cddfSDavid du Colombier 	uchar *p, r, g, b, a, m;
20457dd7cddfSDavid du Colombier 
20467dd7cddfSDavid du Colombier 	v = 0;
20477dd7cddfSDavid du Colombier 	r = rgba>>24;
20487dd7cddfSDavid du Colombier 	g = rgba>>16;
20497dd7cddfSDavid du Colombier 	b = rgba>>8;
20507dd7cddfSDavid du Colombier 	a = rgba;
20517dd7cddfSDavid du Colombier 	d = 0;
20527dd7cddfSDavid du Colombier 	for(chan=img->chan; chan; chan>>=8){
20537dd7cddfSDavid du Colombier 		nb = NBITS(chan);
20547dd7cddfSDavid du Colombier 		switch(TYPE(chan)){
20557dd7cddfSDavid du Colombier 		case CRed:
20567dd7cddfSDavid du Colombier 			v |= (r>>(8-nb))<<d;
20577dd7cddfSDavid du Colombier 			break;
20587dd7cddfSDavid du Colombier 		case CGreen:
20597dd7cddfSDavid du Colombier 			v |= (g>>(8-nb))<<d;
20607dd7cddfSDavid du Colombier 			break;
20617dd7cddfSDavid du Colombier 		case CBlue:
20627dd7cddfSDavid du Colombier 			v |= (b>>(8-nb))<<d;
20637dd7cddfSDavid du Colombier 			break;
20647dd7cddfSDavid du Colombier 		case CAlpha:
20657dd7cddfSDavid du Colombier 			v |= (a>>(8-nb))<<d;
20667dd7cddfSDavid du Colombier 			break;
20677dd7cddfSDavid du Colombier 		case CMap:
20687dd7cddfSDavid du Colombier 			p = img->cmap->rgb2cmap;
20697dd7cddfSDavid du Colombier 			m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
207059cc4ca5SDavid du Colombier 			v |= (m>>(8-nb))<<d;
20717dd7cddfSDavid du Colombier 			break;
20727dd7cddfSDavid du Colombier 		case CGrey:
20737dd7cddfSDavid du Colombier 			m = RGB2K(r,g,b);
207459cc4ca5SDavid du Colombier 			v |= (m>>(8-nb))<<d;
20757dd7cddfSDavid du Colombier 			break;
20767dd7cddfSDavid du Colombier 		}
20777dd7cddfSDavid du Colombier 		d += nb;
20787dd7cddfSDavid du Colombier 	}
20797dd7cddfSDavid du Colombier //	print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
20807dd7cddfSDavid du Colombier 	return v;
20817dd7cddfSDavid du Colombier }
20827dd7cddfSDavid du Colombier 
208380ee5cbfSDavid du Colombier #define DBG if(0)
20847dd7cddfSDavid du Colombier static int
memoptdraw(Memdrawparam * par)20857dd7cddfSDavid du Colombier memoptdraw(Memdrawparam *par)
20867dd7cddfSDavid du Colombier {
20876a9fc400SDavid du Colombier 	int m, y, dy, dx, op;
20887dd7cddfSDavid du Colombier 	ulong v;
20897dd7cddfSDavid du Colombier 	Memimage *src;
20907dd7cddfSDavid du Colombier 	Memimage *dst;
20917dd7cddfSDavid du Colombier 
20927dd7cddfSDavid du Colombier 	dx = Dx(par->r);
20937dd7cddfSDavid du Colombier 	dy = Dy(par->r);
20947dd7cddfSDavid du Colombier 	src = par->src;
20957dd7cddfSDavid du Colombier 	dst = par->dst;
20966a9fc400SDavid du Colombier 	op = par->op;
20977dd7cddfSDavid du Colombier 
209880ee5cbfSDavid du Colombier DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
20997dd7cddfSDavid du Colombier 	/*
21007dd7cddfSDavid du Colombier 	 * If we have an opaque mask and source is one opaque pixel we can convert to the
21017dd7cddfSDavid du Colombier 	 * destination format and just replicate with memset.
21027dd7cddfSDavid du Colombier 	 */
21037dd7cddfSDavid du Colombier 	m = Simplesrc|Simplemask|Fullmask;
21046a9fc400SDavid du Colombier 	if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
21057dd7cddfSDavid du Colombier 		uchar *dp, p[4];
210659cc4ca5SDavid du Colombier 		int d, dwid, ppb, np, nb;
21077dd7cddfSDavid du Colombier 		uchar lm, rm;
21087dd7cddfSDavid du Colombier 
210980ee5cbfSDavid du Colombier DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
21107dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
21117dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
21127dd7cddfSDavid du Colombier 		v = par->sdval;
211380ee5cbfSDavid du Colombier DBG print("sdval %lud, depth %d\n", v, dst->depth);
21147dd7cddfSDavid du Colombier 		switch(dst->depth){
21157dd7cddfSDavid du Colombier 		case 1:
21167dd7cddfSDavid du Colombier 		case 2:
21177dd7cddfSDavid du Colombier 		case 4:
211859cc4ca5SDavid du Colombier 			for(d=dst->depth; d<8; d*=2)
211959cc4ca5SDavid du Colombier 				v |= (v<<d);
21207dd7cddfSDavid du Colombier 			ppb = 8/dst->depth;	/* pixels per byte */
21217dd7cddfSDavid du Colombier 			m = ppb-1;
21227dd7cddfSDavid du Colombier 			/* left edge */
21237dd7cddfSDavid du Colombier 			np = par->r.min.x&m;		/* no. pixels unused on left side of word */
21247dd7cddfSDavid du Colombier 			dx -= (ppb-np);
21257dd7cddfSDavid du Colombier 			nb = 8 - np * dst->depth;		/* no. bits used on right side of word */
21267dd7cddfSDavid du Colombier 			lm = (1<<nb)-1;
212780ee5cbfSDavid du Colombier DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m);
21287dd7cddfSDavid du Colombier 
21297dd7cddfSDavid du Colombier 			/* right edge */
21307dd7cddfSDavid du Colombier 			np = par->r.max.x&m;	/* no. pixels used on left side of word */
21317dd7cddfSDavid du Colombier 			dx -= np;
21327dd7cddfSDavid du Colombier 			nb = 8 - np * dst->depth;		/* no. bits unused on right side of word */
21337dd7cddfSDavid du Colombier 			rm = ~((1<<nb)-1);
213480ee5cbfSDavid du Colombier DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m);
21357dd7cddfSDavid du Colombier 
213680ee5cbfSDavid du Colombier DBG print("dx %d Dx %d\n", dx, Dx(par->r));
21377dd7cddfSDavid du Colombier 			/* lm, rm are masks that are 1 where we should touch the bits */
21387dd7cddfSDavid du Colombier 			if(dx < 0){	/* just one byte */
21397dd7cddfSDavid du Colombier 				lm &= rm;
21407dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid)
21417dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & lm;
21427dd7cddfSDavid du Colombier 			}else if(dx == 0){	/* no full bytes */
21437dd7cddfSDavid du Colombier 				if(lm)
21447dd7cddfSDavid du Colombier 					dwid--;
21457dd7cddfSDavid du Colombier 
21467dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid){
21477dd7cddfSDavid du Colombier 					if(lm){
214880ee5cbfSDavid du Colombier DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
21497dd7cddfSDavid du Colombier 						*dp ^= (v ^ *dp) & lm;
21507dd7cddfSDavid du Colombier 						dp++;
21517dd7cddfSDavid du Colombier 					}
21527dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & rm;
21537dd7cddfSDavid du Colombier 				}
21547dd7cddfSDavid du Colombier 			}else{		/* full bytes in middle */
21557dd7cddfSDavid du Colombier 				dx /= ppb;
21567dd7cddfSDavid du Colombier 				if(lm)
21577dd7cddfSDavid du Colombier 					dwid--;
21587dd7cddfSDavid du Colombier 				dwid -= dx;
21597dd7cddfSDavid du Colombier 
21607dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid){
21617dd7cddfSDavid du Colombier 					if(lm){
21627dd7cddfSDavid du Colombier 						*dp ^= (v ^ *dp) & lm;
21637dd7cddfSDavid du Colombier 						dp++;
21647dd7cddfSDavid du Colombier 					}
21657dd7cddfSDavid du Colombier 					memset(dp, v, dx);
21667dd7cddfSDavid du Colombier 					dp += dx;
21677dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & rm;
21687dd7cddfSDavid du Colombier 				}
21697dd7cddfSDavid du Colombier 			}
21707dd7cddfSDavid du Colombier 			return 1;
21717dd7cddfSDavid du Colombier 		case 8:
21727dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21737dd7cddfSDavid du Colombier 				memset(dp, v, dx);
21747dd7cddfSDavid du Colombier 			return 1;
21757dd7cddfSDavid du Colombier 		case 16:
21767dd7cddfSDavid du Colombier 			p[0] = v;		/* make little endian */
21777dd7cddfSDavid du Colombier 			p[1] = v>>8;
21787dd7cddfSDavid du Colombier 			v = *(ushort*)p;
217980ee5cbfSDavid du Colombier DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
218080ee5cbfSDavid du Colombier 	dp, dx, dy, dwid);
21817dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21827dd7cddfSDavid du Colombier 				memsets(dp, v, dx);
21837dd7cddfSDavid du Colombier 			return 1;
21847dd7cddfSDavid du Colombier 		case 24:
21857dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21867dd7cddfSDavid du Colombier 				memset24(dp, v, dx);
21877dd7cddfSDavid du Colombier 			return 1;
21887dd7cddfSDavid du Colombier 		case 32:
21897dd7cddfSDavid du Colombier 			p[0] = v;		/* make little endian */
21907dd7cddfSDavid du Colombier 			p[1] = v>>8;
21917dd7cddfSDavid du Colombier 			p[2] = v>>16;
21927dd7cddfSDavid du Colombier 			p[3] = v>>24;
21937dd7cddfSDavid du Colombier 			v = *(ulong*)p;
21947dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21957dd7cddfSDavid du Colombier 				memsetl(dp, v, dx);
21967dd7cddfSDavid du Colombier 			return 1;
21977dd7cddfSDavid du Colombier 		default:
21987dd7cddfSDavid du Colombier 			assert(0 /* bad dest depth in memoptdraw */);
21997dd7cddfSDavid du Colombier 		}
22007dd7cddfSDavid du Colombier 	}
22017dd7cddfSDavid du Colombier 
22027dd7cddfSDavid du Colombier 	/*
22037dd7cddfSDavid du Colombier 	 * If no source alpha, an opaque mask, we can just copy the
22047dd7cddfSDavid du Colombier 	 * source onto the destination.  If the channels are the same and
22057dd7cddfSDavid du Colombier 	 * the source is not replicated, memmove suffices.
22067dd7cddfSDavid du Colombier 	 */
22077dd7cddfSDavid du Colombier 	m = Simplemask|Fullmask;
22087dd7cddfSDavid du Colombier 	if((par->state&(m|Replsrc))==m && src->depth >= 8
22096a9fc400SDavid du Colombier 	&& src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){
22107dd7cddfSDavid du Colombier 		uchar *sp, *dp;
22117dd7cddfSDavid du Colombier 		long swid, dwid, nb;
22127dd7cddfSDavid du Colombier 		int dir;
22137dd7cddfSDavid du Colombier 
22147dd7cddfSDavid du Colombier 		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
22157dd7cddfSDavid du Colombier 			dir = -1;
22167dd7cddfSDavid du Colombier 		else
22177dd7cddfSDavid du Colombier 			dir = 1;
22187dd7cddfSDavid du Colombier 
22197dd7cddfSDavid du Colombier 		swid = src->width*sizeof(ulong);
22207dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
22217dd7cddfSDavid du Colombier 		sp = byteaddr(src, par->sr.min);
22227dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
22237dd7cddfSDavid du Colombier 		if(dir == -1){
22247dd7cddfSDavid du Colombier 			sp += (dy-1)*swid;
22257dd7cddfSDavid du Colombier 			dp += (dy-1)*dwid;
22267dd7cddfSDavid du Colombier 			swid = -swid;
22277dd7cddfSDavid du Colombier 			dwid = -dwid;
22287dd7cddfSDavid du Colombier 		}
22297dd7cddfSDavid du Colombier 		nb = (dx*src->depth)/8;
22307dd7cddfSDavid du Colombier 		for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
22317dd7cddfSDavid du Colombier 			memmove(dp, sp, nb);
22327dd7cddfSDavid du Colombier 		return 1;
22337dd7cddfSDavid du Colombier 	}
22347dd7cddfSDavid du Colombier 
22357dd7cddfSDavid du Colombier 	/*
22367dd7cddfSDavid du Colombier 	 * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
22377dd7cddfSDavid du Colombier 	 * they're all bit aligned, we can just use bit operators.  This happens
22387dd7cddfSDavid du Colombier 	 * when we're manipulating boolean masks, e.g. in the arc code.
22397dd7cddfSDavid du Colombier 	 */
22407dd7cddfSDavid du Colombier 	if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0
22417dd7cddfSDavid du Colombier 	&& dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1
22427dd7cddfSDavid du Colombier 	&& (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
22437dd7cddfSDavid du Colombier 		uchar *sp, *dp, *mp;
22447dd7cddfSDavid du Colombier 		uchar lm, rm;
22457dd7cddfSDavid du Colombier 		long swid, dwid, mwid;
22467dd7cddfSDavid du Colombier 		int i, x, dir;
22477dd7cddfSDavid du Colombier 
22487dd7cddfSDavid du Colombier 		sp = byteaddr(src, par->sr.min);
22497dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
22507dd7cddfSDavid du Colombier 		mp = byteaddr(par->mask, par->mr.min);
22517dd7cddfSDavid du Colombier 		swid = src->width*sizeof(ulong);
22527dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
22537dd7cddfSDavid du Colombier 		mwid = par->mask->width*sizeof(ulong);
22547dd7cddfSDavid du Colombier 
22557dd7cddfSDavid du Colombier 		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
22567dd7cddfSDavid du Colombier 			dir = -1;
22577dd7cddfSDavid du Colombier 		}else
22587dd7cddfSDavid du Colombier 			dir = 1;
22597dd7cddfSDavid du Colombier 
22607dd7cddfSDavid du Colombier 		lm = 0xFF>>(par->r.min.x&7);
22617dd7cddfSDavid du Colombier 		rm = 0xFF<<(8-(par->r.max.x&7));
22627dd7cddfSDavid du Colombier 		dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
22637dd7cddfSDavid du Colombier 
22647dd7cddfSDavid du Colombier 		if(dx < 0){	/* one byte wide */
22657dd7cddfSDavid du Colombier 			lm &= rm;
22667dd7cddfSDavid du Colombier 			if(dir == -1){
22677dd7cddfSDavid du Colombier 				dp += dwid*(dy-1);
22687dd7cddfSDavid du Colombier 				sp += swid*(dy-1);
22697dd7cddfSDavid du Colombier 				mp += mwid*(dy-1);
22707dd7cddfSDavid du Colombier 				dwid = -dwid;
22717dd7cddfSDavid du Colombier 				swid = -swid;
22727dd7cddfSDavid du Colombier 				mwid = -mwid;
22737dd7cddfSDavid du Colombier 			}
22747dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++){
22757dd7cddfSDavid du Colombier 				*dp ^= (*dp ^ *sp) & *mp & lm;
22767dd7cddfSDavid du Colombier 				dp += dwid;
22777dd7cddfSDavid du Colombier 				sp += swid;
22787dd7cddfSDavid du Colombier 				mp += mwid;
22797dd7cddfSDavid du Colombier 			}
22807dd7cddfSDavid du Colombier 			return 1;
22817dd7cddfSDavid du Colombier 		}
22827dd7cddfSDavid du Colombier 
22837dd7cddfSDavid du Colombier 		dx /= 8;
22847dd7cddfSDavid du Colombier 		if(dir == 1){
22857dd7cddfSDavid du Colombier 			i = (lm!=0)+dx+(rm!=0);
22867dd7cddfSDavid du Colombier 			mwid -= i;
22877dd7cddfSDavid du Colombier 			swid -= i;
22887dd7cddfSDavid du Colombier 			dwid -= i;
22897dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
22907dd7cddfSDavid du Colombier 				if(lm){
22917dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++ & lm;
22927dd7cddfSDavid du Colombier 					dp++;
22937dd7cddfSDavid du Colombier 				}
22947dd7cddfSDavid du Colombier 				for(x=0; x<dx; x++){
22957dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++;
22967dd7cddfSDavid du Colombier 					dp++;
22977dd7cddfSDavid du Colombier 				}
22987dd7cddfSDavid du Colombier 				if(rm){
22997dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++ & rm;
23007dd7cddfSDavid du Colombier 					dp++;
23017dd7cddfSDavid du Colombier 				}
23027dd7cddfSDavid du Colombier 			}
23037dd7cddfSDavid du Colombier 			return 1;
23047dd7cddfSDavid du Colombier 		}else{
23057dd7cddfSDavid du Colombier 		/* dir == -1 */
23067dd7cddfSDavid du Colombier 			i = (lm!=0)+dx+(rm!=0);
23077dd7cddfSDavid du Colombier 			dp += dwid*(dy-1)+i-1;
23087dd7cddfSDavid du Colombier 			sp += swid*(dy-1)+i-1;
23097dd7cddfSDavid du Colombier 			mp += mwid*(dy-1)+i-1;
23107dd7cddfSDavid du Colombier 			dwid = -dwid+i;
23117dd7cddfSDavid du Colombier 			swid = -swid+i;
23127dd7cddfSDavid du Colombier 			mwid = -mwid+i;
23137dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
23147dd7cddfSDavid du Colombier 				if(rm){
23157dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp-- & rm;
23167dd7cddfSDavid du Colombier 					dp--;
23177dd7cddfSDavid du Colombier 				}
23187dd7cddfSDavid du Colombier 				for(x=0; x<dx; x++){
23197dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp--;
23207dd7cddfSDavid du Colombier 					dp--;
23217dd7cddfSDavid du Colombier 				}
23227dd7cddfSDavid du Colombier 				if(lm){
23237dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp-- & lm;
23247dd7cddfSDavid du Colombier 					dp--;
23257dd7cddfSDavid du Colombier 				}
23267dd7cddfSDavid du Colombier 			}
23277dd7cddfSDavid du Colombier 		}
23287dd7cddfSDavid du Colombier 		return 1;
23297dd7cddfSDavid du Colombier 	}
23307dd7cddfSDavid du Colombier 	return 0;
23317dd7cddfSDavid du Colombier }
233280ee5cbfSDavid du Colombier #undef DBG
23337dd7cddfSDavid du Colombier 
23347dd7cddfSDavid du Colombier /*
23357dd7cddfSDavid du Colombier  * Boolean character drawing.
23367dd7cddfSDavid du Colombier  * Solid opaque color through a 1-bit greyscale mask.
23377dd7cddfSDavid du Colombier  */
23387dd7cddfSDavid du Colombier #define DBG if(0)
23397dd7cddfSDavid du Colombier static int
chardraw(Memdrawparam * par)23407dd7cddfSDavid du Colombier chardraw(Memdrawparam *par)
23417dd7cddfSDavid du Colombier {
23427dd7cddfSDavid du Colombier 	ulong bits;
23436a9fc400SDavid du Colombier 	int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
23447dd7cddfSDavid du Colombier 	ulong v, maskwid, dstwid;
23457dd7cddfSDavid du Colombier 	uchar *wp, *rp, *q, *wc;
23467dd7cddfSDavid du Colombier 	ushort *ws;
23477dd7cddfSDavid du Colombier 	ulong *wl;
23487dd7cddfSDavid du Colombier 	uchar sp[4];
23497dd7cddfSDavid du Colombier 	Rectangle r, mr;
23507dd7cddfSDavid du Colombier 	Memimage *mask, *src, *dst;
23517dd7cddfSDavid du Colombier 
23527dd7cddfSDavid du Colombier if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n",
23537dd7cddfSDavid du Colombier 		par->mask->flags, par->mask->depth, par->src->flags,
23547dd7cddfSDavid du Colombier 		Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
23557dd7cddfSDavid du Colombier 
23567dd7cddfSDavid du Colombier 	mask = par->mask;
23577dd7cddfSDavid du Colombier 	src = par->src;
23587dd7cddfSDavid du Colombier 	dst = par->dst;
23597dd7cddfSDavid du Colombier 	r = par->r;
23607dd7cddfSDavid du Colombier 	mr = par->mr;
23616a9fc400SDavid du Colombier 	op = par->op;
23627dd7cddfSDavid du Colombier 
23637dd7cddfSDavid du Colombier 	if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc)
23646a9fc400SDavid du Colombier 	|| mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data
23656a9fc400SDavid du Colombier 	|| op != SoverD)
23667dd7cddfSDavid du Colombier 		return 0;
23677dd7cddfSDavid du Colombier 
23687dd7cddfSDavid du Colombier //if(drawdebug) iprint("chardraw...");
23697dd7cddfSDavid du Colombier 
23707dd7cddfSDavid du Colombier 	depth = mask->depth;
23717dd7cddfSDavid du Colombier 	maskwid = mask->width*sizeof(ulong);
23727dd7cddfSDavid du Colombier 	rp = byteaddr(mask, mr.min);
23737dd7cddfSDavid du Colombier 	npack = 8/depth;
23747dd7cddfSDavid du Colombier 	bsh = (mr.min.x % npack) * depth;
23757dd7cddfSDavid du Colombier 
23767dd7cddfSDavid du Colombier 	wp = byteaddr(dst, r.min);
23777dd7cddfSDavid du Colombier 	dstwid = dst->width*sizeof(ulong);
23787dd7cddfSDavid du Colombier DBG print("bsh %d\n", bsh);
23797dd7cddfSDavid du Colombier 	dy = Dy(r);
23807dd7cddfSDavid du Colombier 	dx = Dx(r);
23817dd7cddfSDavid du Colombier 
23827dd7cddfSDavid du Colombier 	ddepth = dst->depth;
23837dd7cddfSDavid du Colombier 
23847dd7cddfSDavid du Colombier 	/*
23857dd7cddfSDavid du Colombier 	 * for loop counts from bsh to bsh+dx
23867dd7cddfSDavid du Colombier 	 *
23877dd7cddfSDavid du Colombier 	 * we want the bottom bits to be the amount
23887dd7cddfSDavid du Colombier 	 * to shift the pixels down, so for n≡0 (mod 8) we want
23897dd7cddfSDavid du Colombier 	 * bottom bits 7.  for n≡1, 6, etc.
23907dd7cddfSDavid du Colombier 	 * the bits come from -n-1.
23917dd7cddfSDavid du Colombier 	 */
23927dd7cddfSDavid du Colombier 
23937dd7cddfSDavid du Colombier 	bx = -bsh-1;
23947dd7cddfSDavid du Colombier 	ex = -bsh-1-dx;
23957dd7cddfSDavid du Colombier 	SET(bits);
23967dd7cddfSDavid du Colombier 	v = par->sdval;
23977dd7cddfSDavid du Colombier 
23987dd7cddfSDavid du Colombier 	/* make little endian */
23997dd7cddfSDavid du Colombier 	sp[0] = v;
24007dd7cddfSDavid du Colombier 	sp[1] = v>>8;
24017dd7cddfSDavid du Colombier 	sp[2] = v>>16;
24027dd7cddfSDavid du Colombier 	sp[3] = v>>24;
24037dd7cddfSDavid du Colombier 
24047dd7cddfSDavid du Colombier //print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
24057dd7cddfSDavid du Colombier 	for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
24067dd7cddfSDavid du Colombier 		q = rp;
24077dd7cddfSDavid du Colombier 		if(bsh)
24087dd7cddfSDavid du Colombier 			bits = *q++;
24097dd7cddfSDavid du Colombier 		switch(ddepth){
24107dd7cddfSDavid du Colombier 		case 8:
24117dd7cddfSDavid du Colombier //if(drawdebug) iprint("8loop...");
24127dd7cddfSDavid du Colombier 			wc = wp;
24137dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wc++){
24147dd7cddfSDavid du Colombier 				i = x&7;
24157dd7cddfSDavid du Colombier 				if(i == 8-1)
24167dd7cddfSDavid du Colombier 					bits = *q++;
24177dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
24187dd7cddfSDavid du Colombier 				if((bits>>i)&1)
24197dd7cddfSDavid du Colombier 					*wc = v;
24207dd7cddfSDavid du Colombier 			}
24217dd7cddfSDavid du Colombier 			break;
24227dd7cddfSDavid du Colombier 		case 16:
24237dd7cddfSDavid du Colombier 			ws = (ushort*)wp;
24247dd7cddfSDavid du Colombier 			v = *(ushort*)sp;
24257dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, ws++){
24267dd7cddfSDavid du Colombier 				i = x&7;
24277dd7cddfSDavid du Colombier 				if(i == 8-1)
24287dd7cddfSDavid du Colombier 					bits = *q++;
24297dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
24307dd7cddfSDavid du Colombier 				if((bits>>i)&1)
24317dd7cddfSDavid du Colombier 					*ws = v;
24327dd7cddfSDavid du Colombier 			}
24337dd7cddfSDavid du Colombier 			break;
24347dd7cddfSDavid du Colombier 		case 24:
24357dd7cddfSDavid du Colombier 			wc = wp;
24367dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wc+=3){
24377dd7cddfSDavid du Colombier 				i = x&7;
24387dd7cddfSDavid du Colombier 				if(i == 8-1)
24397dd7cddfSDavid du Colombier 					bits = *q++;
24407dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
24417dd7cddfSDavid du Colombier 				if((bits>>i)&1){
24427dd7cddfSDavid du Colombier 					wc[0] = sp[0];
24437dd7cddfSDavid du Colombier 					wc[1] = sp[1];
24447dd7cddfSDavid du Colombier 					wc[2] = sp[2];
24457dd7cddfSDavid du Colombier 				}
24467dd7cddfSDavid du Colombier 			}
24477dd7cddfSDavid du Colombier 			break;
24487dd7cddfSDavid du Colombier 		case 32:
24497dd7cddfSDavid du Colombier 			wl = (ulong*)wp;
24507dd7cddfSDavid du Colombier 			v = *(ulong*)sp;
24517dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wl++){
24527dd7cddfSDavid du Colombier 				i = x&7;
24537dd7cddfSDavid du Colombier 				if(i == 8-1)
24547dd7cddfSDavid du Colombier 					bits = *q++;
24557dd7cddfSDavid du Colombier DBG iprint("bits %lux sh %d...", bits, i);
24567dd7cddfSDavid du Colombier 				if((bits>>i)&1)
24577dd7cddfSDavid du Colombier 					*wl = v;
24587dd7cddfSDavid du Colombier 			}
24597dd7cddfSDavid du Colombier 			break;
24607dd7cddfSDavid du Colombier 		}
24617dd7cddfSDavid du Colombier 	}
24627dd7cddfSDavid du Colombier 
24637dd7cddfSDavid du Colombier DBG print("\n");
24647dd7cddfSDavid du Colombier 	return 1;
24657dd7cddfSDavid du Colombier }
24667dd7cddfSDavid du Colombier #undef DBG
24677dd7cddfSDavid du Colombier 
24687dd7cddfSDavid du Colombier 
24697dd7cddfSDavid du Colombier /*
24707dd7cddfSDavid du Colombier  * Fill entire byte with replicated (if necessary) copy of source pixel,
24717dd7cddfSDavid du Colombier  * assuming destination ldepth is >= source ldepth.
24727dd7cddfSDavid du Colombier  *
24737dd7cddfSDavid du Colombier  * This code is just plain wrong for >8bpp.
24747dd7cddfSDavid du Colombier  *
24757dd7cddfSDavid du Colombier ulong
24767dd7cddfSDavid du Colombier membyteval(Memimage *src)
24777dd7cddfSDavid du Colombier {
24787dd7cddfSDavid du Colombier 	int i, val, bpp;
24797dd7cddfSDavid du Colombier 	uchar uc;
24807dd7cddfSDavid du Colombier 
24817dd7cddfSDavid du Colombier 	unloadmemimage(src, src->r, &uc, 1);
24827dd7cddfSDavid du Colombier 	bpp = src->depth;
24837dd7cddfSDavid du Colombier 	uc <<= (src->r.min.x&(7/src->depth))*src->depth;
24847dd7cddfSDavid du Colombier 	uc &= ~(0xFF>>bpp);
24857dd7cddfSDavid du Colombier 	/* pixel value is now in high part of byte. repeat throughout byte
24867dd7cddfSDavid du Colombier 	val = uc;
24877dd7cddfSDavid du Colombier 	for(i=bpp; i<8; i<<=1)
24887dd7cddfSDavid du Colombier 		val |= val>>i;
24897dd7cddfSDavid du Colombier 	return val;
24907dd7cddfSDavid du Colombier }
24917dd7cddfSDavid du Colombier  *
24927dd7cddfSDavid du Colombier  */
249359cc4ca5SDavid du Colombier 
249459cc4ca5SDavid du Colombier void
memfillcolor(Memimage * i,ulong val)249559cc4ca5SDavid du Colombier memfillcolor(Memimage *i, ulong val)
249659cc4ca5SDavid du Colombier {
249759cc4ca5SDavid du Colombier 	ulong bits;
249859cc4ca5SDavid du Colombier 	int d, y;
249959cc4ca5SDavid du Colombier 
250059cc4ca5SDavid du Colombier 	if(val == DNofill)
250159cc4ca5SDavid du Colombier 		return;
250259cc4ca5SDavid du Colombier 
250359cc4ca5SDavid du Colombier 	bits = rgbatoimg(i, val);
250459cc4ca5SDavid du Colombier 	switch(i->depth){
250559cc4ca5SDavid du Colombier 	case 24:	/* 24-bit images suck */
250659cc4ca5SDavid du Colombier 		for(y=i->r.min.y; y<i->r.max.y; y++)
250759cc4ca5SDavid du Colombier 			memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
250859cc4ca5SDavid du Colombier 		break;
250959cc4ca5SDavid du Colombier 	default:	/* 1, 2, 4, 8, 16, 32 */
251059cc4ca5SDavid du Colombier 		for(d=i->depth; d<32; d*=2)
251159cc4ca5SDavid du Colombier 			bits = (bits << d) | bits;
251259cc4ca5SDavid du Colombier 		memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));
251359cc4ca5SDavid du Colombier 		break;
251459cc4ca5SDavid du Colombier 	}
251559cc4ca5SDavid du Colombier }
251659cc4ca5SDavid du Colombier 
2517