xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/draw.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <draw.h>
4*8ccd4a63SDavid du Colombier #include <memdraw.h>
57dd7cddfSDavid du Colombier 
6*8ccd4a63SDavid du Colombier int drawdebug;
7*8ccd4a63SDavid du Colombier static int	tablesbuilt;
87dd7cddfSDavid du Colombier 
97dd7cddfSDavid du Colombier /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
107dd7cddfSDavid du Colombier #define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)
117dd7cddfSDavid du Colombier 
127dd7cddfSDavid du Colombier /*
137dd7cddfSDavid du Colombier  * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation.
147dd7cddfSDavid du Colombier  * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation.
157dd7cddfSDavid du Colombier  * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole.
167dd7cddfSDavid du Colombier  */
177dd7cddfSDavid du Colombier /* #define DIV255(x) (((x)*257+256)>>16)  */
187dd7cddfSDavid du Colombier #define DIV255(x) ((((x)+1)*257)>>16)
197dd7cddfSDavid du Colombier /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */
207dd7cddfSDavid du Colombier 
21*8ccd4a63SDavid du Colombier #define MUL(x, y, t)	(t = (x)*(y)+128, (t+(t>>8))>>8)
22*8ccd4a63SDavid du Colombier #define MASK13	0xFF00FF00
23*8ccd4a63SDavid du Colombier #define MASK02	0x00FF00FF
24*8ccd4a63SDavid du Colombier #define MUL13(a, x, t)		(t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
25*8ccd4a63SDavid du Colombier #define MUL02(a, x, t)		(t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)
26*8ccd4a63SDavid du Colombier #define MUL0123(a, x, s, t)	((MUL13(a, x, s)<<8)|MUL02(a, x, t))
27*8ccd4a63SDavid du Colombier 
28*8ccd4a63SDavid du Colombier #define MUL2(u, v, x, y)	(t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)
29*8ccd4a63SDavid du Colombier 
307dd7cddfSDavid du Colombier static void mktables(void);
317dd7cddfSDavid du Colombier typedef int Subdraw(Memdrawparam*);
327dd7cddfSDavid du Colombier static Subdraw chardraw, alphadraw, memoptdraw;
337dd7cddfSDavid du Colombier 
347dd7cddfSDavid du Colombier static Memimage*	memones;
357dd7cddfSDavid du Colombier static Memimage*	memzeros;
367dd7cddfSDavid du Colombier Memimage *memwhite;
377dd7cddfSDavid du Colombier Memimage *memblack;
387dd7cddfSDavid du Colombier Memimage *memtransparent;
397dd7cddfSDavid du Colombier Memimage *memopaque;
407dd7cddfSDavid du Colombier 
41*8ccd4a63SDavid du Colombier int	_ifmt(Fmt*);
427dd7cddfSDavid du Colombier 
437dd7cddfSDavid du Colombier void
447dd7cddfSDavid du Colombier _memimageinit(void)
457dd7cddfSDavid du Colombier {
467dd7cddfSDavid du Colombier 	static int didinit = 0;
477dd7cddfSDavid du Colombier 
487dd7cddfSDavid du Colombier 	if(didinit)
497dd7cddfSDavid du Colombier 		return;
507dd7cddfSDavid du Colombier 
517dd7cddfSDavid du Colombier 	didinit = 1;
527dd7cddfSDavid du Colombier 
537dd7cddfSDavid du Colombier 	mktables();
54*8ccd4a63SDavid du Colombier 	_memmkcmap();
55*8ccd4a63SDavid du Colombier 
56*8ccd4a63SDavid du Colombier 	fmtinstall('R', Rfmt);
57*8ccd4a63SDavid du Colombier 	fmtinstall('P', Pfmt);
58*8ccd4a63SDavid du Colombier 	fmtinstall('b', _ifmt);
597dd7cddfSDavid du Colombier 
607dd7cddfSDavid du Colombier 	memones = allocmemimage(Rect(0,0,1,1), GREY1);
617dd7cddfSDavid du Colombier 	memones->flags |= Frepl;
627dd7cddfSDavid du Colombier 	memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
637dd7cddfSDavid du Colombier 	*byteaddr(memones, ZP) = ~0;
647dd7cddfSDavid du Colombier 
657dd7cddfSDavid du Colombier 	memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
667dd7cddfSDavid du Colombier 	memzeros->flags |= Frepl;
677dd7cddfSDavid du Colombier 	memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
687dd7cddfSDavid du Colombier 	*byteaddr(memzeros, ZP) = 0;
697dd7cddfSDavid du Colombier 
707dd7cddfSDavid du Colombier 	if(memones == nil || memzeros == nil)
717dd7cddfSDavid du Colombier 		assert(0 /*cannot initialize memimage library */);	/* RSC BUG */
727dd7cddfSDavid du Colombier 
737dd7cddfSDavid du Colombier 	memwhite = memones;
747dd7cddfSDavid du Colombier 	memblack = memzeros;
757dd7cddfSDavid du Colombier 	memopaque = memones;
767dd7cddfSDavid du Colombier 	memtransparent = memzeros;
777dd7cddfSDavid du Colombier }
787dd7cddfSDavid du Colombier 
79*8ccd4a63SDavid du Colombier ulong _imgtorgba(Memimage*, ulong);
80*8ccd4a63SDavid du Colombier ulong _rgbatoimg(Memimage*, ulong);
81*8ccd4a63SDavid du Colombier ulong _pixelbits(Memimage*, Point);
827dd7cddfSDavid du Colombier 
837dd7cddfSDavid du Colombier #define DBG if(0)
84*8ccd4a63SDavid du Colombier static Memdrawparam par;
85*8ccd4a63SDavid du Colombier 
867dd7cddfSDavid du Colombier Memdrawparam*
87*8ccd4a63SDavid du Colombier _memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
887dd7cddfSDavid du Colombier {
897dd7cddfSDavid du Colombier 
907dd7cddfSDavid du Colombier 	if(mask == nil)
917dd7cddfSDavid du Colombier 		mask = memopaque;
927dd7cddfSDavid du Colombier 
93*8ccd4a63SDavid 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);
947dd7cddfSDavid du Colombier 
957dd7cddfSDavid du Colombier 	if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
96*8ccd4a63SDavid du Colombier //		if(drawdebug)
97*8ccd4a63SDavid du Colombier //			iprint("empty clipped rectangle\n");
987dd7cddfSDavid du Colombier 		return nil;
997dd7cddfSDavid du Colombier 	}
1007dd7cddfSDavid du Colombier 
101*8ccd4a63SDavid du Colombier 	if(op < Clear || op > SoverD){
102*8ccd4a63SDavid du Colombier //		if(drawdebug)
103*8ccd4a63SDavid du Colombier //			iprint("op out of range: %d\n", op);
104*8ccd4a63SDavid du Colombier 		return nil;
105*8ccd4a63SDavid du Colombier 	}
106*8ccd4a63SDavid du Colombier 
107*8ccd4a63SDavid du Colombier 	par.op = op;
1087dd7cddfSDavid du Colombier 	par.dst = dst;
1097dd7cddfSDavid du Colombier 	par.r = r;
1107dd7cddfSDavid du Colombier 	par.src = src;
1117dd7cddfSDavid du Colombier 	/* par.sr set by drawclip */
1127dd7cddfSDavid du Colombier 	par.mask = mask;
1137dd7cddfSDavid du Colombier 	/* par.mr set by drawclip */
1147dd7cddfSDavid du Colombier 
1157dd7cddfSDavid du Colombier 	par.state = 0;
1167dd7cddfSDavid du Colombier 	if(src->flags&Frepl){
1177dd7cddfSDavid du Colombier 		par.state |= Replsrc;
1187dd7cddfSDavid du Colombier 		if(Dx(src->r)==1 && Dy(src->r)==1){
119*8ccd4a63SDavid du Colombier 			par.sval = _pixelbits(src, src->r.min);
1207dd7cddfSDavid du Colombier 			par.state |= Simplesrc;
1217dd7cddfSDavid du Colombier 			par.srgba = _imgtorgba(src, par.sval);
1227dd7cddfSDavid du Colombier 			par.sdval = _rgbatoimg(dst, par.srgba);
123*8ccd4a63SDavid du Colombier 			if((par.srgba&0xFF) == 0 && (op&DoutS)){
124*8ccd4a63SDavid du Colombier //				if (drawdebug) iprint("fill with transparent source\n");
125*8ccd4a63SDavid du Colombier 				return nil;	/* no-op successfully handled */
126*8ccd4a63SDavid du Colombier 			}
1277dd7cddfSDavid du Colombier 		}
1287dd7cddfSDavid du Colombier 	}
1297dd7cddfSDavid du Colombier 
1307dd7cddfSDavid du Colombier 	if(mask->flags & Frepl){
1317dd7cddfSDavid du Colombier 		par.state |= Replmask;
1327dd7cddfSDavid du Colombier 		if(Dx(mask->r)==1 && Dy(mask->r)==1){
133*8ccd4a63SDavid du Colombier 			par.mval = _pixelbits(mask, mask->r.min);
134*8ccd4a63SDavid du Colombier 			if(par.mval == 0 && (op&DoutS)){
135*8ccd4a63SDavid du Colombier //				if(drawdebug) iprint("fill with zero mask\n");
1367dd7cddfSDavid du Colombier 				return nil;	/* no-op successfully handled */
1377dd7cddfSDavid du Colombier 			}
1387dd7cddfSDavid du Colombier 			par.state |= Simplemask;
1397dd7cddfSDavid du Colombier 			if(par.mval == ~0)
1407dd7cddfSDavid du Colombier 				par.state |= Fullmask;
1417dd7cddfSDavid du Colombier 			par.mrgba = _imgtorgba(mask, par.mval);
1427dd7cddfSDavid du Colombier 		}
1437dd7cddfSDavid du Colombier 	}
1447dd7cddfSDavid du Colombier 
145*8ccd4a63SDavid du Colombier //	if(drawdebug)
146*8ccd4a63SDavid du Colombier //		iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);
147*8ccd4a63SDavid du Colombier DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
1487dd7cddfSDavid du Colombier 
1497dd7cddfSDavid du Colombier 	return &par;
1507dd7cddfSDavid du Colombier }
1517dd7cddfSDavid du Colombier 
1527dd7cddfSDavid du Colombier void
1537dd7cddfSDavid du Colombier _memimagedraw(Memdrawparam *par)
1547dd7cddfSDavid du Colombier {
1557dd7cddfSDavid du Colombier 	if (par == nil)
1567dd7cddfSDavid du Colombier 		return;
1577dd7cddfSDavid du Colombier 
1587dd7cddfSDavid du Colombier 	/*
1597dd7cddfSDavid du Colombier 	 * Now that we've clipped the parameters down to be consistent, we
1607dd7cddfSDavid du Colombier 	 * simply try sub-drawing routines in order until we find one that was able
1617dd7cddfSDavid du Colombier 	 * to handle us.  If the sub-drawing routine returns zero, it means it was
1627dd7cddfSDavid du Colombier 	 * unable to satisfy the request, so we do not return.
1637dd7cddfSDavid du Colombier 	 */
1647dd7cddfSDavid du Colombier 
1657dd7cddfSDavid du Colombier 	/*
1667dd7cddfSDavid du Colombier 	 * Hardware support.  Each video driver provides this function,
1677dd7cddfSDavid du Colombier 	 * which checks to see if there is anything it can help with.
1687dd7cddfSDavid du Colombier 	 * There could be an if around this checking to see if dst is in video memory.
1697dd7cddfSDavid du Colombier 	 */
170*8ccd4a63SDavid du Colombier DBG print("test hwdraw\n");
171*8ccd4a63SDavid du Colombier 	if(hwdraw(par)){
172*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("hw handled\n");
173*8ccd4a63SDavid du Colombier DBG print("hwdraw handled\n");
1747dd7cddfSDavid du Colombier 		return;
1757dd7cddfSDavid du Colombier 	}
1767dd7cddfSDavid du Colombier 	/*
1777dd7cddfSDavid du Colombier 	 * Optimizations using memmove and memset.
1787dd7cddfSDavid du Colombier 	 */
179*8ccd4a63SDavid du Colombier DBG print("test memoptdraw\n");
1807dd7cddfSDavid du Colombier 	if(memoptdraw(par)){
181*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("memopt handled\n");
182*8ccd4a63SDavid du Colombier DBG print("memopt handled\n");
1837dd7cddfSDavid du Colombier 		return;
1847dd7cddfSDavid du Colombier 	}
1857dd7cddfSDavid du Colombier 
1867dd7cddfSDavid du Colombier 	/*
1877dd7cddfSDavid du Colombier 	 * Character drawing.
1887dd7cddfSDavid du Colombier 	 * Solid source color being painted through a boolean mask onto a high res image.
1897dd7cddfSDavid du Colombier 	 */
190*8ccd4a63SDavid du Colombier DBG print("test chardraw\n");
1917dd7cddfSDavid du Colombier 	if(chardraw(par)){
192*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("chardraw handled\n");
193*8ccd4a63SDavid du Colombier DBG print("chardraw handled\n");
1947dd7cddfSDavid du Colombier 		return;
1957dd7cddfSDavid du Colombier 	}
1967dd7cddfSDavid du Colombier 
1977dd7cddfSDavid du Colombier 	/*
1987dd7cddfSDavid du Colombier 	 * General calculation-laden case that does alpha for each pixel.
1997dd7cddfSDavid du Colombier 	 */
200*8ccd4a63SDavid du Colombier DBG print("do alphadraw\n");
2017dd7cddfSDavid du Colombier 	alphadraw(par);
202*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("alphadraw handled\n");
203*8ccd4a63SDavid du Colombier DBG print("alphadraw handled\n");
2047dd7cddfSDavid du Colombier }
2057dd7cddfSDavid du Colombier #undef DBG
2067dd7cddfSDavid du Colombier 
2077dd7cddfSDavid du Colombier /*
2087dd7cddfSDavid du Colombier  * Clip the destination rectangle further based on the properties of the
2097dd7cddfSDavid du Colombier  * source and mask rectangles.  Once the destination rectangle is properly
2107dd7cddfSDavid du Colombier  * clipped, adjust the source and mask rectangles to be the same size.
2117dd7cddfSDavid du Colombier  * Then if source or mask is replicated, move its clipped rectangle
2127dd7cddfSDavid du Colombier  * so that its minimum point falls within the repl rectangle.
2137dd7cddfSDavid du Colombier  *
2147dd7cddfSDavid du Colombier  * Return zero if the final rectangle is null.
2157dd7cddfSDavid du Colombier  */
2167dd7cddfSDavid du Colombier int
2177dd7cddfSDavid du Colombier drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
2187dd7cddfSDavid du Colombier {
2197dd7cddfSDavid du Colombier 	Point rmin, delta;
2207dd7cddfSDavid du Colombier 	int splitcoords;
2217dd7cddfSDavid du Colombier 	Rectangle omr;
2227dd7cddfSDavid du Colombier 
2237dd7cddfSDavid du Colombier 	if(r->min.x>=r->max.x || r->min.y>=r->max.y)
2247dd7cddfSDavid du Colombier 		return 0;
2257dd7cddfSDavid du Colombier 	splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
2267dd7cddfSDavid du Colombier 	/* clip to destination */
2277dd7cddfSDavid du Colombier 	rmin = r->min;
2287dd7cddfSDavid du Colombier 	if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
2297dd7cddfSDavid du Colombier 		return 0;
2307dd7cddfSDavid du Colombier 	/* move mask point */
2317dd7cddfSDavid du Colombier 	p1->x += r->min.x-rmin.x;
2327dd7cddfSDavid du Colombier 	p1->y += r->min.y-rmin.y;
2337dd7cddfSDavid du Colombier 	/* move source point */
2347dd7cddfSDavid du Colombier 	p0->x += r->min.x-rmin.x;
2357dd7cddfSDavid du Colombier 	p0->y += r->min.y-rmin.y;
2367dd7cddfSDavid du Colombier 	/* map destination rectangle into source */
2377dd7cddfSDavid du Colombier 	sr->min = *p0;
2387dd7cddfSDavid du Colombier 	sr->max.x = p0->x+Dx(*r);
2397dd7cddfSDavid du Colombier 	sr->max.y = p0->y+Dy(*r);
2407dd7cddfSDavid du Colombier 	/* sr is r in source coordinates; clip to source */
2417dd7cddfSDavid du Colombier 	if(!(src->flags&Frepl) && !rectclip(sr, src->r))
2427dd7cddfSDavid du Colombier 		return 0;
2437dd7cddfSDavid du Colombier 	if(!rectclip(sr, src->clipr))
2447dd7cddfSDavid du Colombier 		return 0;
2457dd7cddfSDavid du Colombier 	/* compute and clip rectangle in mask */
2467dd7cddfSDavid du Colombier 	if(splitcoords){
2477dd7cddfSDavid du Colombier 		/* move mask point with source */
2487dd7cddfSDavid du Colombier 		p1->x += sr->min.x-p0->x;
2497dd7cddfSDavid du Colombier 		p1->y += sr->min.y-p0->y;
2507dd7cddfSDavid du Colombier 		mr->min = *p1;
2517dd7cddfSDavid du Colombier 		mr->max.x = p1->x+Dx(*sr);
2527dd7cddfSDavid du Colombier 		mr->max.y = p1->y+Dy(*sr);
2537dd7cddfSDavid du Colombier 		omr = *mr;
2547dd7cddfSDavid du Colombier 		/* mr is now rectangle in mask; clip it */
2557dd7cddfSDavid du Colombier 		if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
2567dd7cddfSDavid du Colombier 			return 0;
2577dd7cddfSDavid du Colombier 		if(!rectclip(mr, mask->clipr))
2587dd7cddfSDavid du Colombier 			return 0;
2597dd7cddfSDavid du Colombier 		/* reflect any clips back to source */
2607dd7cddfSDavid du Colombier 		sr->min.x += mr->min.x-omr.min.x;
2617dd7cddfSDavid du Colombier 		sr->min.y += mr->min.y-omr.min.y;
2627dd7cddfSDavid du Colombier 		sr->max.x += mr->max.x-omr.max.x;
2637dd7cddfSDavid du Colombier 		sr->max.y += mr->max.y-omr.max.y;
2647dd7cddfSDavid du Colombier 		*p1 = mr->min;
2657dd7cddfSDavid du Colombier 	}else{
2667dd7cddfSDavid du Colombier 		if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
2677dd7cddfSDavid du Colombier 			return 0;
2687dd7cddfSDavid du Colombier 		if(!rectclip(sr, mask->clipr))
2697dd7cddfSDavid du Colombier 			return 0;
2707dd7cddfSDavid du Colombier 		*p1 = sr->min;
2717dd7cddfSDavid du Colombier 	}
2727dd7cddfSDavid du Colombier 
2737dd7cddfSDavid du Colombier 	/* move source clipping back to destination */
2747dd7cddfSDavid du Colombier 	delta.x = r->min.x - p0->x;
2757dd7cddfSDavid du Colombier 	delta.y = r->min.y - p0->y;
2767dd7cddfSDavid du Colombier 	r->min.x = sr->min.x + delta.x;
2777dd7cddfSDavid du Colombier 	r->min.y = sr->min.y + delta.y;
2787dd7cddfSDavid du Colombier 	r->max.x = sr->max.x + delta.x;
2797dd7cddfSDavid du Colombier 	r->max.y = sr->max.y + delta.y;
2807dd7cddfSDavid du Colombier 
2817dd7cddfSDavid du Colombier 	/* move source rectangle so sr->min is in src->r */
2827dd7cddfSDavid du Colombier 	if(src->flags&Frepl) {
2837dd7cddfSDavid du Colombier 		delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
2847dd7cddfSDavid du Colombier 		delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
2857dd7cddfSDavid du Colombier 		sr->min.x += delta.x;
2867dd7cddfSDavid du Colombier 		sr->min.y += delta.y;
2877dd7cddfSDavid du Colombier 		sr->max.x += delta.x;
2887dd7cddfSDavid du Colombier 		sr->max.y += delta.y;
2897dd7cddfSDavid du Colombier 	}
2907dd7cddfSDavid du Colombier 	*p0 = sr->min;
2917dd7cddfSDavid du Colombier 
2927dd7cddfSDavid du Colombier 	/* move mask point so it is in mask->r */
293*8ccd4a63SDavid du Colombier 	*p1 = drawrepl(mask->r, *p1);
2947dd7cddfSDavid du Colombier 	mr->min = *p1;
2957dd7cddfSDavid du Colombier 	mr->max.x = p1->x+Dx(*sr);
2967dd7cddfSDavid du Colombier 	mr->max.y = p1->y+Dy(*sr);
2977dd7cddfSDavid du Colombier 
2987dd7cddfSDavid du Colombier 	assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
2997dd7cddfSDavid du Colombier 	assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
300*8ccd4a63SDavid du Colombier 	assert(ptinrect(*p0, src->r));
301*8ccd4a63SDavid du Colombier 	assert(ptinrect(*p1, mask->r));
302*8ccd4a63SDavid du Colombier 	assert(ptinrect(r->min, dst->r));
3037dd7cddfSDavid du Colombier 
3047dd7cddfSDavid du Colombier 	return 1;
3057dd7cddfSDavid du Colombier }
3067dd7cddfSDavid du Colombier 
3077dd7cddfSDavid du Colombier /*
3087dd7cddfSDavid du Colombier  * Conversion tables.
3097dd7cddfSDavid du Colombier  */
3107dd7cddfSDavid du Colombier static uchar replbit[1+8][256];		/* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
3117dd7cddfSDavid du Colombier 
3127dd7cddfSDavid du Colombier /*
3137dd7cddfSDavid du Colombier  * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
3147dd7cddfSDavid du Colombier  * the X's are where to put the bottom (ones) bit of the n-bit pattern.
3157dd7cddfSDavid du Colombier  * only the top 8 bits of the result are actually used.
3167dd7cddfSDavid du Colombier  * (the lower 8 bits are needed to get bits in the right place
3177dd7cddfSDavid du Colombier  * when n is not a divisor of 8.)
3187dd7cddfSDavid du Colombier  *
3197dd7cddfSDavid du Colombier  * Should check to see if its easier to just refer to replmul than
3207dd7cddfSDavid du Colombier  * use the precomputed values in replbit.  On PCs it may well
3217dd7cddfSDavid du Colombier  * be; on machines with slow multiply instructions it probably isn't.
3227dd7cddfSDavid du Colombier  */
3237dd7cddfSDavid du Colombier #define a ((((((((((((((((0
3247dd7cddfSDavid du Colombier #define X *2+1)
3257dd7cddfSDavid du Colombier #define _ *2)
3267dd7cddfSDavid du Colombier static int replmul[1+8] = {
3277dd7cddfSDavid du Colombier 	0,
3287dd7cddfSDavid du Colombier 	a X X X X X X X X X X X X X X X X,
3297dd7cddfSDavid du Colombier 	a _ X _ X _ X _ X _ X _ X _ X _ X,
3307dd7cddfSDavid du Colombier 	a _ _ X _ _ X _ _ X _ _ X _ _ X _,
3317dd7cddfSDavid du Colombier 	a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
3327dd7cddfSDavid du Colombier 	a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
3337dd7cddfSDavid du Colombier 	a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _,
3347dd7cddfSDavid du Colombier 	a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
3357dd7cddfSDavid du Colombier 	a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
3367dd7cddfSDavid du Colombier };
3377dd7cddfSDavid du Colombier #undef a
3387dd7cddfSDavid du Colombier #undef X
3397dd7cddfSDavid du Colombier #undef _
3407dd7cddfSDavid du Colombier 
3417dd7cddfSDavid du Colombier static void
3427dd7cddfSDavid du Colombier mktables(void)
3437dd7cddfSDavid du Colombier {
344*8ccd4a63SDavid du Colombier 	int i, j, small;
3457dd7cddfSDavid du Colombier 
3467dd7cddfSDavid du Colombier 	if(tablesbuilt)
3477dd7cddfSDavid du Colombier 		return;
3487dd7cddfSDavid du Colombier 
349*8ccd4a63SDavid du Colombier 	fmtinstall('R', Rfmt);
350*8ccd4a63SDavid du Colombier 	fmtinstall('P', Pfmt);
3517dd7cddfSDavid du Colombier 	tablesbuilt = 1;
352*8ccd4a63SDavid du Colombier 
3537dd7cddfSDavid du Colombier 	/* bit replication up to 8 bits */
3547dd7cddfSDavid du Colombier 	for(i=0; i<256; i++){
3557dd7cddfSDavid du Colombier 		for(j=0; j<=8; j++){	/* j <= 8 [sic] */
3567dd7cddfSDavid du Colombier 			small = i & ((1<<j)-1);
3577dd7cddfSDavid du Colombier 			replbit[j][i] = (small*replmul[j])>>8;
3587dd7cddfSDavid du Colombier 		}
3597dd7cddfSDavid du Colombier 	}
3607dd7cddfSDavid du Colombier 
3617dd7cddfSDavid du Colombier }
362*8ccd4a63SDavid du Colombier 
363*8ccd4a63SDavid du Colombier static uchar ones = 0xff;
3647dd7cddfSDavid du Colombier 
3657dd7cddfSDavid du Colombier /*
3667dd7cddfSDavid du Colombier  * General alpha drawing case.  Can handle anything.
3677dd7cddfSDavid du Colombier  */
3687dd7cddfSDavid du Colombier typedef struct	Buffer	Buffer;
3697dd7cddfSDavid du Colombier struct Buffer {
370*8ccd4a63SDavid du Colombier 	/* used by most routines */
3717dd7cddfSDavid du Colombier 	uchar	*red;
3727dd7cddfSDavid du Colombier 	uchar	*grn;
3737dd7cddfSDavid du Colombier 	uchar	*blu;
3747dd7cddfSDavid du Colombier 	uchar	*alpha;
3757dd7cddfSDavid du Colombier 	uchar	*grey;
376*8ccd4a63SDavid du Colombier 	ulong	*rgba;
3777dd7cddfSDavid du Colombier 	int	delta;	/* number of bytes to add to pointer to get next pixel to the right */
378*8ccd4a63SDavid du Colombier 
379*8ccd4a63SDavid du Colombier 	/* used by boolcalc* for mask data */
3807dd7cddfSDavid du Colombier 	uchar	*m;		/* ptr to mask data r.min byte; like p->bytermin */
3817dd7cddfSDavid du Colombier 	int		mskip;	/* no. of left bits to skip in *m */
3827dd7cddfSDavid du Colombier 	uchar	*bm;		/* ptr to mask data img->r.min byte; like p->bytey0s */
3837dd7cddfSDavid du Colombier 	int		bmskip;	/* no. of left bits to skip in *bm */
3847dd7cddfSDavid du Colombier 	uchar	*em;		/* ptr to mask data img->r.max.x byte; like p->bytey0e */
3857dd7cddfSDavid du Colombier 	int		emskip;	/* no. of right bits to skip in *em */
3867dd7cddfSDavid du Colombier };
3877dd7cddfSDavid du Colombier 
3887dd7cddfSDavid du Colombier typedef struct	Param	Param;
389*8ccd4a63SDavid du Colombier typedef Buffer	Readfn(Param*, uchar*, int);
390*8ccd4a63SDavid du Colombier typedef void	Writefn(Param*, uchar*, Buffer);
391*8ccd4a63SDavid du Colombier typedef Buffer	Calcfn(Buffer, Buffer, Buffer, int, int, int);
3927dd7cddfSDavid du Colombier 
3937dd7cddfSDavid du Colombier enum {
3947dd7cddfSDavid du Colombier 	MAXBCACHE = 16
3957dd7cddfSDavid du Colombier };
3967dd7cddfSDavid du Colombier 
3977dd7cddfSDavid du Colombier /* giant rathole to customize functions with */
3987dd7cddfSDavid du Colombier struct Param {
3997dd7cddfSDavid du Colombier 	Readfn	*replcall;
4007dd7cddfSDavid du Colombier 	Readfn	*greymaskcall;
4017dd7cddfSDavid du Colombier 	Readfn	*convreadcall;
4027dd7cddfSDavid du Colombier 	Writefn	*convwritecall;
4037dd7cddfSDavid du Colombier 
4047dd7cddfSDavid du Colombier 	Memimage *img;
4057dd7cddfSDavid du Colombier 	Rectangle	r;
4067dd7cddfSDavid du Colombier 	int	dx;	/* of r */
4077dd7cddfSDavid du Colombier 	int	needbuf;
4087dd7cddfSDavid du Colombier 	int	convgrey;
4097dd7cddfSDavid du Colombier 	int	alphaonly;
4107dd7cddfSDavid du Colombier 
4117dd7cddfSDavid du Colombier 	uchar	*bytey0s;		/* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
4127dd7cddfSDavid du Colombier 	uchar	*bytermin;	/* byteaddr(Pt(r.min.x, img->r.min.y)) */
4137dd7cddfSDavid du Colombier 	uchar	*bytey0e;		/* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
4147dd7cddfSDavid du Colombier 	int		bwidth;
4157dd7cddfSDavid du Colombier 
4167dd7cddfSDavid du Colombier 	int	replcache;	/* if set, cache buffers */
4177dd7cddfSDavid du Colombier 	Buffer	bcache[MAXBCACHE];
4187dd7cddfSDavid du Colombier 	ulong	bfilled;
4197dd7cddfSDavid du Colombier 	uchar	*bufbase;
4207dd7cddfSDavid du Colombier 	int	bufoff;
4217dd7cddfSDavid du Colombier 	int	bufdelta;
4227dd7cddfSDavid du Colombier 
4237dd7cddfSDavid du Colombier 	int	dir;
4247dd7cddfSDavid du Colombier 
4257dd7cddfSDavid du Colombier 	int	convbufoff;
4267dd7cddfSDavid du Colombier 	uchar	*convbuf;
4277dd7cddfSDavid du Colombier 	Param	*convdpar;
4287dd7cddfSDavid du Colombier 	int	convdx;
4297dd7cddfSDavid du Colombier };
4307dd7cddfSDavid du Colombier 
4317dd7cddfSDavid du Colombier static uchar *drawbuf;
4327dd7cddfSDavid du Colombier static int	ndrawbuf;
4337dd7cddfSDavid du Colombier static int	mdrawbuf;
4347dd7cddfSDavid du Colombier static Param spar, mpar, dpar;	/* easier on the stacks */
4357dd7cddfSDavid du Colombier static Readfn	greymaskread, replread, readptr;
4367dd7cddfSDavid du Colombier static Writefn	nullwrite;
437*8ccd4a63SDavid du Colombier static Calcfn	alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
438*8ccd4a63SDavid du Colombier static Calcfn	boolcalc14, boolcalc236789, boolcalc1011;
4397dd7cddfSDavid du Colombier 
4407dd7cddfSDavid du Colombier static Readfn*	readfn(Memimage*);
4417dd7cddfSDavid du Colombier static Readfn*	readalphafn(Memimage*);
4427dd7cddfSDavid du Colombier static Writefn*	writefn(Memimage*);
4437dd7cddfSDavid du Colombier 
4447dd7cddfSDavid du Colombier static Calcfn*	boolcopyfn(Memimage*, Memimage*);
445*8ccd4a63SDavid du Colombier static Readfn*	convfn(Memimage*, Param*, Memimage*, Param*);
446*8ccd4a63SDavid du Colombier 
447*8ccd4a63SDavid du Colombier static Calcfn *alphacalc[Ncomp] =
448*8ccd4a63SDavid du Colombier {
449*8ccd4a63SDavid du Colombier 	alphacalc0,		/* Clear */
450*8ccd4a63SDavid du Colombier 	alphacalc14,		/* DoutS */
451*8ccd4a63SDavid du Colombier 	alphacalc2810,		/* SoutD */
452*8ccd4a63SDavid du Colombier 	alphacalc3679,		/* DxorS */
453*8ccd4a63SDavid du Colombier 	alphacalc14,		/* DinS */
454*8ccd4a63SDavid du Colombier 	alphacalc5,		/* D */
455*8ccd4a63SDavid du Colombier 	alphacalc3679,		/* DatopS */
456*8ccd4a63SDavid du Colombier 	alphacalc3679,		/* DoverS */
457*8ccd4a63SDavid du Colombier 	alphacalc2810,		/* SinD */
458*8ccd4a63SDavid du Colombier 	alphacalc3679,		/* SatopD */
459*8ccd4a63SDavid du Colombier 	alphacalc2810,		/* S */
460*8ccd4a63SDavid du Colombier 	alphacalc11,		/* SoverD */
461*8ccd4a63SDavid du Colombier };
462*8ccd4a63SDavid du Colombier 
463*8ccd4a63SDavid du Colombier static Calcfn *boolcalc[Ncomp] =
464*8ccd4a63SDavid du Colombier {
465*8ccd4a63SDavid du Colombier 	alphacalc0,		/* Clear */
466*8ccd4a63SDavid du Colombier 	boolcalc14,		/* DoutS */
467*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* SoutD */
468*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* DxorS */
469*8ccd4a63SDavid du Colombier 	boolcalc14,		/* DinS */
470*8ccd4a63SDavid du Colombier 	alphacalc5,		/* D */
471*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* DatopS */
472*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* DoverS */
473*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* SinD */
474*8ccd4a63SDavid du Colombier 	boolcalc236789,		/* SatopD */
475*8ccd4a63SDavid du Colombier 	boolcalc1011,		/* S */
476*8ccd4a63SDavid du Colombier 	boolcalc1011,		/* SoverD */
477*8ccd4a63SDavid du Colombier };
4787dd7cddfSDavid du Colombier 
4797dd7cddfSDavid du Colombier static int
4807dd7cddfSDavid du Colombier allocdrawbuf(void)
4817dd7cddfSDavid du Colombier {
4827dd7cddfSDavid du Colombier 	uchar *p;
4837dd7cddfSDavid du Colombier 
4847dd7cddfSDavid du Colombier 	if(ndrawbuf > mdrawbuf){
4857dd7cddfSDavid du Colombier 		p = realloc(drawbuf, ndrawbuf);
4867dd7cddfSDavid du Colombier 		if(p == nil){
4877dd7cddfSDavid du Colombier 			werrstr("memimagedraw out of memory");
4887dd7cddfSDavid du Colombier 			return -1;
4897dd7cddfSDavid du Colombier 		}
4907dd7cddfSDavid du Colombier 		drawbuf = p;
4917dd7cddfSDavid du Colombier 		mdrawbuf = ndrawbuf;
4927dd7cddfSDavid du Colombier 	}
4937dd7cddfSDavid du Colombier 	return 0;
4947dd7cddfSDavid du Colombier }
4957dd7cddfSDavid du Colombier 
4967dd7cddfSDavid du Colombier static Param
4977dd7cddfSDavid du Colombier getparam(Memimage *img, Rectangle r, int convgrey, int needbuf)
4987dd7cddfSDavid du Colombier {
4997dd7cddfSDavid du Colombier 	Param p;
5007dd7cddfSDavid du Colombier 	int nbuf;
5017dd7cddfSDavid du Colombier 
5027dd7cddfSDavid du Colombier 	memset(&p, 0, sizeof p);
5037dd7cddfSDavid du Colombier 
5047dd7cddfSDavid du Colombier 	p.img = img;
5057dd7cddfSDavid du Colombier 	p.r = r;
5067dd7cddfSDavid du Colombier 	p.dx = Dx(r);
5077dd7cddfSDavid du Colombier 	p.needbuf = needbuf;
5087dd7cddfSDavid du Colombier 	p.convgrey = convgrey;
5097dd7cddfSDavid du Colombier 
5107dd7cddfSDavid du Colombier 	assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
5117dd7cddfSDavid du Colombier 
5127dd7cddfSDavid du Colombier 	p.bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
5137dd7cddfSDavid du Colombier 	p.bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
5147dd7cddfSDavid du Colombier 	p.bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
5157dd7cddfSDavid du Colombier 	p.bwidth = sizeof(ulong)*img->width;
5167dd7cddfSDavid du Colombier 
5177dd7cddfSDavid du Colombier 	assert(p.bytey0s <= p.bytermin && p.bytermin <= p.bytey0e);
5187dd7cddfSDavid du Colombier 
5197dd7cddfSDavid du Colombier 	if(p.r.min.x == p.img->r.min.x)
5207dd7cddfSDavid du Colombier 		assert(p.bytermin == p.bytey0s);
5217dd7cddfSDavid du Colombier 
5227dd7cddfSDavid du Colombier 	nbuf = 1;
5237dd7cddfSDavid du Colombier 	if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
5247dd7cddfSDavid du Colombier 		p.replcache = 1;
5257dd7cddfSDavid du Colombier 		nbuf = Dy(img->r);
5267dd7cddfSDavid du Colombier 	}
5277dd7cddfSDavid du Colombier 	p.bufdelta = 4*p.dx;
5287dd7cddfSDavid du Colombier 	p.bufoff = ndrawbuf;
5297dd7cddfSDavid du Colombier 	ndrawbuf += p.bufdelta*nbuf;
5307dd7cddfSDavid du Colombier 
5317dd7cddfSDavid du Colombier 	return p;
5327dd7cddfSDavid du Colombier }
5337dd7cddfSDavid du Colombier 
5347dd7cddfSDavid du Colombier static void
5357dd7cddfSDavid du Colombier clipy(Memimage *img, int *y)
5367dd7cddfSDavid du Colombier {
5377dd7cddfSDavid du Colombier 	int dy;
5387dd7cddfSDavid du Colombier 
5397dd7cddfSDavid du Colombier 	dy = Dy(img->r);
5407dd7cddfSDavid du Colombier 	if(*y == dy)
5417dd7cddfSDavid du Colombier 		*y = 0;
5427dd7cddfSDavid du Colombier 	else if(*y == -1)
5437dd7cddfSDavid du Colombier 		*y = dy-1;
5447dd7cddfSDavid du Colombier 	assert(0 <= *y && *y < dy);
5457dd7cddfSDavid du Colombier }
5467dd7cddfSDavid du Colombier 
5477dd7cddfSDavid du Colombier static void
5487dd7cddfSDavid du Colombier dumpbuf(char *s, Buffer b, int n)
5497dd7cddfSDavid du Colombier {
5507dd7cddfSDavid du Colombier 	int i;
5517dd7cddfSDavid du Colombier 	uchar *p;
5527dd7cddfSDavid du Colombier 
5537dd7cddfSDavid du Colombier 	print("%s", s);
5547dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
5557dd7cddfSDavid du Colombier 		print(" ");
556*8ccd4a63SDavid du Colombier 		if((p=b.grey)){
5577dd7cddfSDavid du Colombier 			print(" k%.2uX", *p);
5587dd7cddfSDavid du Colombier 			b.grey += b.delta;
5597dd7cddfSDavid du Colombier 		}else{
560*8ccd4a63SDavid du Colombier 			if((p=b.red)){
5617dd7cddfSDavid du Colombier 				print(" r%.2uX", *p);
5627dd7cddfSDavid du Colombier 				b.red += b.delta;
5637dd7cddfSDavid du Colombier 			}
564*8ccd4a63SDavid du Colombier 			if((p=b.grn)){
5657dd7cddfSDavid du Colombier 				print(" g%.2uX", *p);
5667dd7cddfSDavid du Colombier 				b.grn += b.delta;
5677dd7cddfSDavid du Colombier 			}
568*8ccd4a63SDavid du Colombier 			if((p=b.blu)){
5697dd7cddfSDavid du Colombier 				print(" b%.2uX", *p);
5707dd7cddfSDavid du Colombier 				b.blu += b.delta;
5717dd7cddfSDavid du Colombier 			}
5727dd7cddfSDavid du Colombier 		}
573*8ccd4a63SDavid du Colombier 		if((p=b.alpha) != &ones){
5747dd7cddfSDavid du Colombier 			print(" α%.2uX", *p);
5757dd7cddfSDavid du Colombier 			b.alpha += b.delta;
5767dd7cddfSDavid du Colombier 		}
5777dd7cddfSDavid du Colombier 	}
5787dd7cddfSDavid du Colombier 	print("\n");
5797dd7cddfSDavid du Colombier }
5807dd7cddfSDavid du Colombier 
5817dd7cddfSDavid du Colombier /*
5827dd7cddfSDavid du Colombier  * For each scan line, we expand the pixels from source, mask, and destination
5837dd7cddfSDavid du Colombier  * into byte-aligned red, green, blue, alpha, and grey channels.  If buffering is not
5847dd7cddfSDavid du Colombier  * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
5857dd7cddfSDavid du Colombier  * the readers need not copy the data: they can simply return pointers to the data.
5867dd7cddfSDavid du Colombier  * If the destination image is grey and the source is not, it is converted using the NTSC
5877dd7cddfSDavid du Colombier  * formula.
5887dd7cddfSDavid du Colombier  *
5897dd7cddfSDavid du Colombier  * Once we have all the channels, we call either rgbcalc or greycalc, depending on
5907dd7cddfSDavid du Colombier  * whether the destination image is color.  This is allowed to overwrite the dst buffer (perhaps
5917dd7cddfSDavid du Colombier  * the actual data, perhaps a copy) with its result.  It should only overwrite the dst buffer
5927dd7cddfSDavid du Colombier  * with the same format (i.e. red bytes with red bytes, etc.)  A new buffer is returned from
5937dd7cddfSDavid du Colombier  * the calculator, and that buffer is passed to a function to write it to the destination.
5947dd7cddfSDavid du Colombier  * If the buffer is already pointing at the destination, the writing function is a no-op.
5957dd7cddfSDavid du Colombier  */
5967dd7cddfSDavid du Colombier #define DBG if(0)
5977dd7cddfSDavid du Colombier static int
5987dd7cddfSDavid du Colombier alphadraw(Memdrawparam *par)
5997dd7cddfSDavid du Colombier {
600*8ccd4a63SDavid du Colombier 	int isgrey, starty, endy, op;
6017dd7cddfSDavid du Colombier 	int needbuf, dsty, srcy, masky;
6027dd7cddfSDavid du Colombier 	int y, dir, dx, dy;
6037dd7cddfSDavid du Colombier 	Buffer bsrc, bdst, bmask;
6047dd7cddfSDavid du Colombier 	Readfn *rdsrc, *rdmask, *rddst;
6057dd7cddfSDavid du Colombier 	Calcfn *calc;
6067dd7cddfSDavid du Colombier 	Writefn *wrdst;
6077dd7cddfSDavid du Colombier 	Memimage *src, *mask, *dst;
6087dd7cddfSDavid du Colombier 	Rectangle r, sr, mr;
6097dd7cddfSDavid du Colombier 
6107dd7cddfSDavid du Colombier 	r = par->r;
6117dd7cddfSDavid du Colombier 	dx = Dx(r);
6127dd7cddfSDavid du Colombier 	dy = Dy(r);
6137dd7cddfSDavid du Colombier 
6147dd7cddfSDavid du Colombier 	ndrawbuf = 0;
6157dd7cddfSDavid du Colombier 
6167dd7cddfSDavid du Colombier 	src = par->src;
6177dd7cddfSDavid du Colombier 	mask = par->mask;
6187dd7cddfSDavid du Colombier 	dst = par->dst;
6197dd7cddfSDavid du Colombier 	sr = par->sr;
6207dd7cddfSDavid du Colombier 	mr = par->mr;
621*8ccd4a63SDavid du Colombier 	op = par->op;
6227dd7cddfSDavid du Colombier 
6237dd7cddfSDavid du Colombier 	isgrey = dst->flags&Fgrey;
6247dd7cddfSDavid du Colombier 
6257dd7cddfSDavid du Colombier 	/*
6267dd7cddfSDavid du Colombier 	 * Buffering when src and dst are the same bitmap is sufficient but not
6277dd7cddfSDavid du Colombier 	 * necessary.  There are stronger conditions we could use.  We could
6287dd7cddfSDavid du Colombier 	 * check to see if the rectangles intersect, and if simply moving in the
6297dd7cddfSDavid du Colombier 	 * correct y direction can avoid the need to buffer.
6307dd7cddfSDavid du Colombier 	 */
6317dd7cddfSDavid du Colombier 	needbuf = (src->data == dst->data);
6327dd7cddfSDavid du Colombier 
6337dd7cddfSDavid du Colombier 	spar = getparam(src, sr, isgrey, needbuf);
6347dd7cddfSDavid du Colombier 	dpar = getparam(dst, r, isgrey, needbuf);
635*8ccd4a63SDavid du Colombier 	mpar = getparam(mask, mr, 0, needbuf);
6367dd7cddfSDavid du Colombier 
6377dd7cddfSDavid du Colombier 	dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
6387dd7cddfSDavid du Colombier 	spar.dir = mpar.dir = dpar.dir = dir;
6397dd7cddfSDavid du Colombier 
6407dd7cddfSDavid du Colombier 	/*
6417dd7cddfSDavid du Colombier 	 * If the mask is purely boolean, we can convert from src to dst format
6427dd7cddfSDavid du Colombier 	 * when we read src, and then just copy it to dst where the mask tells us to.
6437dd7cddfSDavid du Colombier 	 * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
6447dd7cddfSDavid du Colombier 	 *
6457dd7cddfSDavid du Colombier 	 * The computation is accomplished by assigning the function pointers as follows:
6467dd7cddfSDavid du Colombier 	 *	rdsrc - read and convert source into dst format in a buffer
6477dd7cddfSDavid du Colombier 	 * 	rdmask - convert mask to bytes, set pointer to it
6487dd7cddfSDavid du Colombier 	 * 	rddst - fill with pointer to real dst data, but do no reads
6497dd7cddfSDavid du Colombier 	 *	calc - copy src onto dst when mask says to.
6507dd7cddfSDavid du Colombier 	 *	wrdst - do nothing
6517dd7cddfSDavid du Colombier 	 * This is slightly sleazy, since things aren't doing exactly what their names say,
6527dd7cddfSDavid du Colombier 	 * but it avoids a fair amount of code duplication to make this a case here
6537dd7cddfSDavid du Colombier 	 * rather than have a separate booldraw.
6547dd7cddfSDavid du Colombier 	 */
655*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
656*8ccd4a63SDavid du Colombier 	if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
657*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("boolcopy...");
6587dd7cddfSDavid du Colombier 		rdsrc = convfn(dst, &dpar, src, &spar);
6597dd7cddfSDavid du Colombier 		rddst = readptr;
6607dd7cddfSDavid du Colombier 		rdmask = readfn(mask);
6617dd7cddfSDavid du Colombier 		calc = boolcopyfn(dst, mask);
6627dd7cddfSDavid du Colombier 		wrdst = nullwrite;
6637dd7cddfSDavid du Colombier 	}else{
6647dd7cddfSDavid du Colombier 		/* usual alphadraw parameter fetching */
6657dd7cddfSDavid du Colombier 		rdsrc = readfn(src);
6667dd7cddfSDavid du Colombier 		rddst = readfn(dst);
6677dd7cddfSDavid du Colombier 		wrdst = writefn(dst);
668*8ccd4a63SDavid du Colombier 		calc = alphacalc[op];
6697dd7cddfSDavid du Colombier 
6707dd7cddfSDavid du Colombier 		/*
6717dd7cddfSDavid du Colombier 		 * If there is no alpha channel, we'll ask for a grey channel
6727dd7cddfSDavid du Colombier 		 * and pretend it is the alpha.
6737dd7cddfSDavid du Colombier 		 */
6747dd7cddfSDavid du Colombier 		if(mask->flags&Falpha){
6757dd7cddfSDavid du Colombier 			rdmask = readalphafn(mask);
6767dd7cddfSDavid du Colombier 			mpar.alphaonly = 1;
6777dd7cddfSDavid du Colombier 		}else{
6787dd7cddfSDavid du Colombier 			mpar.greymaskcall = readfn(mask);
6797dd7cddfSDavid du Colombier 			mpar.convgrey = 1;
6807dd7cddfSDavid du Colombier 			rdmask = greymaskread;
6817dd7cddfSDavid du Colombier 
6827dd7cddfSDavid du Colombier 			/*
6837dd7cddfSDavid du Colombier 			 * Should really be above, but then boolcopyfns would have
6847dd7cddfSDavid du Colombier 			 * to deal with bit alignment, and I haven't written that.
6857dd7cddfSDavid du Colombier 			 *
6867dd7cddfSDavid du Colombier 			 * This is a common case for things like ellipse drawing.
6877dd7cddfSDavid du Colombier 			 * When there's no alpha involved and the mask is boolean,
6887dd7cddfSDavid du Colombier 			 * we can avoid all the division and multiplication.
6897dd7cddfSDavid du Colombier 			 */
6907dd7cddfSDavid du Colombier 			if(mask->chan == GREY1 && !(src->flags&Falpha))
691*8ccd4a63SDavid du Colombier 				calc = boolcalc[op];
692*8ccd4a63SDavid du Colombier 			else if(op == SoverD && !(src->flags&Falpha))
693*8ccd4a63SDavid du Colombier 				calc = alphacalcS;
6947dd7cddfSDavid du Colombier 		}
6957dd7cddfSDavid du Colombier 	}
6967dd7cddfSDavid du Colombier 
6977dd7cddfSDavid du Colombier 	/*
6987dd7cddfSDavid du Colombier 	 * If the image has a small enough repl rectangle,
6997dd7cddfSDavid du Colombier 	 * we can just read each line once and cache them.
7007dd7cddfSDavid du Colombier 	 */
7017dd7cddfSDavid du Colombier 	if(spar.replcache){
7027dd7cddfSDavid du Colombier 		spar.replcall = rdsrc;
7037dd7cddfSDavid du Colombier 		rdsrc = replread;
7047dd7cddfSDavid du Colombier 	}
7057dd7cddfSDavid du Colombier 	if(mpar.replcache){
7067dd7cddfSDavid du Colombier 		mpar.replcall = rdmask;
7077dd7cddfSDavid du Colombier 		rdmask = replread;
7087dd7cddfSDavid du Colombier 	}
7097dd7cddfSDavid du Colombier 
7107dd7cddfSDavid du Colombier 	if(allocdrawbuf() < 0)
7117dd7cddfSDavid du Colombier 		return 0;
7127dd7cddfSDavid du Colombier 
7137dd7cddfSDavid du Colombier 	/*
7147dd7cddfSDavid du Colombier 	 * Before we were saving only offsets from drawbuf in the parameter
7157dd7cddfSDavid du Colombier 	 * structures; now that drawbuf has been grown to accomodate us,
7167dd7cddfSDavid du Colombier 	 * we can fill in the pointers.
7177dd7cddfSDavid du Colombier 	 */
7187dd7cddfSDavid du Colombier 	spar.bufbase = drawbuf+spar.bufoff;
7197dd7cddfSDavid du Colombier 	mpar.bufbase = drawbuf+mpar.bufoff;
7207dd7cddfSDavid du Colombier 	dpar.bufbase = drawbuf+dpar.bufoff;
7217dd7cddfSDavid du Colombier 	spar.convbuf = drawbuf+spar.convbufoff;
7227dd7cddfSDavid du Colombier 
7237dd7cddfSDavid du Colombier 	if(dir == 1){
7247dd7cddfSDavid du Colombier 		starty = 0;
7257dd7cddfSDavid du Colombier 		endy = dy;
7267dd7cddfSDavid du Colombier 	}else{
7277dd7cddfSDavid du Colombier 		starty = dy-1;
7287dd7cddfSDavid du Colombier 		endy = -1;
7297dd7cddfSDavid du Colombier 	}
7307dd7cddfSDavid du Colombier 
7317dd7cddfSDavid du Colombier 	/*
7327dd7cddfSDavid du Colombier 	 * srcy, masky, and dsty are offsets from the top of their
7337dd7cddfSDavid du Colombier 	 * respective Rectangles.  they need to be contained within
7347dd7cddfSDavid du Colombier 	 * the rectangles, so clipy can keep them there without division.
7357dd7cddfSDavid du Colombier  	 */
7367dd7cddfSDavid du Colombier 	srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
7377dd7cddfSDavid du Colombier 	masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
7387dd7cddfSDavid du Colombier 	dsty = starty + r.min.y - dst->r.min.y;
7397dd7cddfSDavid du Colombier 
7407dd7cddfSDavid du Colombier 	assert(0 <= srcy && srcy < Dy(src->r));
7417dd7cddfSDavid du Colombier 	assert(0 <= masky && masky < Dy(mask->r));
7427dd7cddfSDavid du Colombier 	assert(0 <= dsty && dsty < Dy(dst->r));
7437dd7cddfSDavid du Colombier 
7447dd7cddfSDavid du Colombier 	for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
7457dd7cddfSDavid du Colombier 		clipy(src, &srcy);
7467dd7cddfSDavid du Colombier 		clipy(dst, &dsty);
7477dd7cddfSDavid du Colombier 		clipy(mask, &masky);
7487dd7cddfSDavid du Colombier 
7497dd7cddfSDavid du Colombier 		bsrc = rdsrc(&spar, spar.bufbase, srcy);
7507dd7cddfSDavid du Colombier DBG print("[");
7517dd7cddfSDavid du Colombier 		bmask = rdmask(&mpar, mpar.bufbase, masky);
7527dd7cddfSDavid du Colombier DBG print("]\n");
7537dd7cddfSDavid du Colombier 		bdst = rddst(&dpar, dpar.bufbase, dsty);
7547dd7cddfSDavid du Colombier DBG		dumpbuf("src", bsrc, dx);
7557dd7cddfSDavid du Colombier DBG		dumpbuf("mask", bmask, dx);
7567dd7cddfSDavid du Colombier DBG		dumpbuf("dst", bdst, dx);
757*8ccd4a63SDavid du Colombier 		bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
7587dd7cddfSDavid du Colombier 		wrdst(&dpar, dpar.bytermin+dsty*dpar.bwidth, bdst);
7597dd7cddfSDavid du Colombier 	}
7607dd7cddfSDavid du Colombier 
7617dd7cddfSDavid du Colombier 	return 1;
7627dd7cddfSDavid du Colombier }
7637dd7cddfSDavid du Colombier #undef DBG
7647dd7cddfSDavid du Colombier 
7657dd7cddfSDavid du Colombier static Buffer
766*8ccd4a63SDavid du Colombier alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
767*8ccd4a63SDavid du Colombier {
768*8ccd4a63SDavid du Colombier 	USED(grey);
769*8ccd4a63SDavid du Colombier 	USED(op);
770*8ccd4a63SDavid du Colombier 	memset(bdst.rgba, 0, dx*bdst.delta);
771*8ccd4a63SDavid du Colombier 	return bdst;
772*8ccd4a63SDavid du Colombier }
773*8ccd4a63SDavid du Colombier 
774*8ccd4a63SDavid du Colombier static Buffer
775*8ccd4a63SDavid du Colombier alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
7767dd7cddfSDavid du Colombier {
7777dd7cddfSDavid du Colombier 	Buffer obdst;
778*8ccd4a63SDavid du Colombier 	int fd, sadelta;
779*8ccd4a63SDavid du Colombier 	int i, sa, ma, q;
780*8ccd4a63SDavid du Colombier 	ulong s, t;
7817dd7cddfSDavid du Colombier 
7827dd7cddfSDavid du Colombier 	obdst = bdst;
783*8ccd4a63SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
784*8ccd4a63SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
7857dd7cddfSDavid du Colombier 
7867dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
787*8ccd4a63SDavid du Colombier 		sa = *bsrc.alpha;
7887dd7cddfSDavid du Colombier 		ma = *bmask.alpha;
789*8ccd4a63SDavid du Colombier 		fd = MUL(sa, ma, t);
790*8ccd4a63SDavid du Colombier 		if(op == DoutS)
791*8ccd4a63SDavid du Colombier 			fd = 255-fd;
7927dd7cddfSDavid du Colombier 
7937dd7cddfSDavid du Colombier 		if(grey){
794*8ccd4a63SDavid du Colombier 			*bdst.grey = MUL(fd, *bdst.grey, t);
7957dd7cddfSDavid du Colombier 			bsrc.grey += bsrc.delta;
7967dd7cddfSDavid du Colombier 			bdst.grey += bdst.delta;
7977dd7cddfSDavid du Colombier 		}else{
798*8ccd4a63SDavid du Colombier 			if(q){
799*8ccd4a63SDavid du Colombier 				*bdst.rgba = MUL0123(fd, *bdst.rgba, s, t);
800*8ccd4a63SDavid du Colombier 				bsrc.rgba++;
801*8ccd4a63SDavid du Colombier 				bdst.rgba++;
802*8ccd4a63SDavid du Colombier 				bsrc.alpha += sadelta;
803*8ccd4a63SDavid du Colombier 				bmask.alpha += bmask.delta;
804*8ccd4a63SDavid du Colombier 				continue;
805*8ccd4a63SDavid du Colombier 			}
806*8ccd4a63SDavid du Colombier 			*bdst.red = MUL(fd, *bdst.red, t);
807*8ccd4a63SDavid du Colombier 			*bdst.grn = MUL(fd, *bdst.grn, t);
808*8ccd4a63SDavid du Colombier 			*bdst.blu = MUL(fd, *bdst.blu, t);
8097dd7cddfSDavid du Colombier 			bsrc.red += bsrc.delta;
8107dd7cddfSDavid du Colombier 			bsrc.blu += bsrc.delta;
8117dd7cddfSDavid du Colombier 			bsrc.grn += bsrc.delta;
8127dd7cddfSDavid du Colombier 			bdst.red += bdst.delta;
8137dd7cddfSDavid du Colombier 			bdst.blu += bdst.delta;
8147dd7cddfSDavid du Colombier 			bdst.grn += bdst.delta;
8157dd7cddfSDavid du Colombier 		}
816*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
817*8ccd4a63SDavid du Colombier 			*bdst.alpha = MUL(fd, *bdst.alpha, t);
818*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
819*8ccd4a63SDavid du Colombier 		}
8207dd7cddfSDavid du Colombier 		bmask.alpha += bmask.delta;
821*8ccd4a63SDavid du Colombier 		bsrc.alpha += sadelta;
822*8ccd4a63SDavid du Colombier 	}
823*8ccd4a63SDavid du Colombier 	return obdst;
824*8ccd4a63SDavid du Colombier }
8257dd7cddfSDavid du Colombier 
826*8ccd4a63SDavid du Colombier static Buffer
827*8ccd4a63SDavid du Colombier alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
828*8ccd4a63SDavid du Colombier {
829*8ccd4a63SDavid du Colombier 	Buffer obdst;
830*8ccd4a63SDavid du Colombier 	int fs, sadelta;
831*8ccd4a63SDavid du Colombier 	int i, ma, da, q;
832*8ccd4a63SDavid du Colombier 	ulong s, t;
833*8ccd4a63SDavid du Colombier 
834*8ccd4a63SDavid du Colombier 	obdst = bdst;
835*8ccd4a63SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
836*8ccd4a63SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
837*8ccd4a63SDavid du Colombier 
838*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
839*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
840*8ccd4a63SDavid du Colombier 		da = *bdst.alpha;
841*8ccd4a63SDavid du Colombier 		if(op == SoutD)
842*8ccd4a63SDavid du Colombier 			da = 255-da;
843*8ccd4a63SDavid du Colombier 		fs = ma;
844*8ccd4a63SDavid du Colombier 		if(op != S)
845*8ccd4a63SDavid du Colombier 			fs = MUL(fs, da, t);
846*8ccd4a63SDavid du Colombier 
847*8ccd4a63SDavid du Colombier 		if(grey){
848*8ccd4a63SDavid du Colombier 			*bdst.grey = MUL(fs, *bsrc.grey, t);
849*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
850*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
851*8ccd4a63SDavid du Colombier 		}else{
852*8ccd4a63SDavid du Colombier 			if(q){
853*8ccd4a63SDavid du Colombier 				*bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t);
854*8ccd4a63SDavid du Colombier 				bsrc.rgba++;
855*8ccd4a63SDavid du Colombier 				bdst.rgba++;
856*8ccd4a63SDavid du Colombier 				bmask.alpha += bmask.delta;
857*8ccd4a63SDavid du Colombier 				bdst.alpha += bdst.delta;
858*8ccd4a63SDavid du Colombier 				continue;
859*8ccd4a63SDavid du Colombier 			}
860*8ccd4a63SDavid du Colombier 			*bdst.red = MUL(fs, *bsrc.red, t);
861*8ccd4a63SDavid du Colombier 			*bdst.grn = MUL(fs, *bsrc.grn, t);
862*8ccd4a63SDavid du Colombier 			*bdst.blu = MUL(fs, *bsrc.blu, t);
863*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
864*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
865*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
866*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
867*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
868*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
869*8ccd4a63SDavid du Colombier 		}
870*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
871*8ccd4a63SDavid du Colombier 			*bdst.alpha = MUL(fs, *bsrc.alpha, t);
872*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
873*8ccd4a63SDavid du Colombier 		}
874*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
875*8ccd4a63SDavid du Colombier 		bsrc.alpha += sadelta;
876*8ccd4a63SDavid du Colombier 	}
877*8ccd4a63SDavid du Colombier 	return obdst;
878*8ccd4a63SDavid du Colombier }
879*8ccd4a63SDavid du Colombier 
880*8ccd4a63SDavid du Colombier static Buffer
881*8ccd4a63SDavid du Colombier alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
882*8ccd4a63SDavid du Colombier {
883*8ccd4a63SDavid du Colombier 	Buffer obdst;
884*8ccd4a63SDavid du Colombier 	int fs, fd, sadelta;
885*8ccd4a63SDavid du Colombier 	int i, sa, ma, da, q;
886*8ccd4a63SDavid du Colombier 	ulong s, t, u, v;
887*8ccd4a63SDavid du Colombier 
888*8ccd4a63SDavid du Colombier 	obdst = bdst;
889*8ccd4a63SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
890*8ccd4a63SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
891*8ccd4a63SDavid du Colombier 
892*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
893*8ccd4a63SDavid du Colombier 		sa = *bsrc.alpha;
894*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
895*8ccd4a63SDavid du Colombier 		da = *bdst.alpha;
896*8ccd4a63SDavid du Colombier 		if(op == SatopD)
897*8ccd4a63SDavid du Colombier 			fs = MUL(ma, da, t);
898*8ccd4a63SDavid du Colombier 		else
899*8ccd4a63SDavid du Colombier 			fs = MUL(ma, 255-da, t);
900*8ccd4a63SDavid du Colombier 		if(op == DoverS)
901*8ccd4a63SDavid du Colombier 			fd = 255;
902*8ccd4a63SDavid du Colombier 		else{
903*8ccd4a63SDavid du Colombier 			fd = MUL(sa, ma, t);
904*8ccd4a63SDavid du Colombier 			if(op != DatopS)
905*8ccd4a63SDavid du Colombier 				fd = 255-fd;
906*8ccd4a63SDavid du Colombier 		}
907*8ccd4a63SDavid du Colombier 
908*8ccd4a63SDavid du Colombier 		if(grey){
909*8ccd4a63SDavid du Colombier 			*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
910*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
911*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
912*8ccd4a63SDavid du Colombier 		}else{
913*8ccd4a63SDavid du Colombier 			if(q){
914*8ccd4a63SDavid du Colombier 				*bdst.rgba = MUL0123(fs, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
915*8ccd4a63SDavid du Colombier 				bsrc.rgba++;
916*8ccd4a63SDavid du Colombier 				bdst.rgba++;
917*8ccd4a63SDavid du Colombier 				bsrc.alpha += sadelta;
918*8ccd4a63SDavid du Colombier 				bmask.alpha += bmask.delta;
919*8ccd4a63SDavid du Colombier 				bdst.alpha += bdst.delta;
920*8ccd4a63SDavid du Colombier 				continue;
921*8ccd4a63SDavid du Colombier 			}
922*8ccd4a63SDavid du Colombier 			*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
923*8ccd4a63SDavid du Colombier 			*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
924*8ccd4a63SDavid du Colombier 			*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
925*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
926*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
927*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
928*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
929*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
930*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
931*8ccd4a63SDavid du Colombier 		}
932*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
933*8ccd4a63SDavid du Colombier 			*bdst.alpha = MUL(fs, sa, s)+MUL(fd, da, t);
934*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
935*8ccd4a63SDavid du Colombier 		}
936*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
937*8ccd4a63SDavid du Colombier 		bsrc.alpha += sadelta;
938*8ccd4a63SDavid du Colombier 	}
939*8ccd4a63SDavid du Colombier 	return obdst;
940*8ccd4a63SDavid du Colombier }
941*8ccd4a63SDavid du Colombier 
942*8ccd4a63SDavid du Colombier static Buffer
943*8ccd4a63SDavid du Colombier alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
944*8ccd4a63SDavid du Colombier {
945*8ccd4a63SDavid du Colombier 	USED(dx);
946*8ccd4a63SDavid du Colombier 	USED(grey);
947*8ccd4a63SDavid du Colombier 	USED(op);
948*8ccd4a63SDavid du Colombier 	return bdst;
949*8ccd4a63SDavid du Colombier }
950*8ccd4a63SDavid du Colombier 
951*8ccd4a63SDavid du Colombier static Buffer
952*8ccd4a63SDavid du Colombier alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
953*8ccd4a63SDavid du Colombier {
954*8ccd4a63SDavid du Colombier 	Buffer obdst;
955*8ccd4a63SDavid du Colombier 	int fd, sadelta;
956*8ccd4a63SDavid du Colombier 	int i, sa, ma, q;
957*8ccd4a63SDavid du Colombier 	ulong s, t, u, v;
958*8ccd4a63SDavid du Colombier 
959*8ccd4a63SDavid du Colombier 	USED(op);
960*8ccd4a63SDavid du Colombier 	obdst = bdst;
961*8ccd4a63SDavid du Colombier 	sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
962*8ccd4a63SDavid du Colombier 	q = bsrc.delta == 4 && bdst.delta == 4;
963*8ccd4a63SDavid du Colombier 
964*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
965*8ccd4a63SDavid du Colombier 		sa = *bsrc.alpha;
966*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
967*8ccd4a63SDavid du Colombier 		fd = 255-MUL(sa, ma, t);
968*8ccd4a63SDavid du Colombier 
969*8ccd4a63SDavid du Colombier 		if(grey){
970*8ccd4a63SDavid du Colombier 			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
971*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
972*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
973*8ccd4a63SDavid du Colombier 		}else{
974*8ccd4a63SDavid du Colombier 			if(q){
975*8ccd4a63SDavid du Colombier 				*bdst.rgba = MUL0123(ma, *bsrc.rgba, s, t)+MUL0123(fd, *bdst.rgba, u, v);
976*8ccd4a63SDavid du Colombier 				bsrc.rgba++;
977*8ccd4a63SDavid du Colombier 				bdst.rgba++;
978*8ccd4a63SDavid du Colombier 				bsrc.alpha += sadelta;
979*8ccd4a63SDavid du Colombier 				bmask.alpha += bmask.delta;
980*8ccd4a63SDavid du Colombier 				continue;
981*8ccd4a63SDavid du Colombier 			}
982*8ccd4a63SDavid du Colombier 			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
983*8ccd4a63SDavid du Colombier 			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
984*8ccd4a63SDavid du Colombier 			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
985*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
986*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
987*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
988*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
989*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
990*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
991*8ccd4a63SDavid du Colombier 		}
992*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
993*8ccd4a63SDavid du Colombier 			*bdst.alpha = MUL(ma, sa, s)+MUL(fd, *bdst.alpha, t);
994*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
995*8ccd4a63SDavid du Colombier 		}
996*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
997*8ccd4a63SDavid du Colombier 		bsrc.alpha += sadelta;
998*8ccd4a63SDavid du Colombier 	}
999*8ccd4a63SDavid du Colombier 	return obdst;
1000*8ccd4a63SDavid du Colombier }
1001*8ccd4a63SDavid du Colombier 
1002*8ccd4a63SDavid du Colombier /*
1003*8ccd4a63SDavid du Colombier not used yet
1004*8ccd4a63SDavid du Colombier source and mask alpha 1
1005*8ccd4a63SDavid du Colombier static Buffer
1006*8ccd4a63SDavid du Colombier alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1007*8ccd4a63SDavid du Colombier {
1008*8ccd4a63SDavid du Colombier 	Buffer obdst;
1009*8ccd4a63SDavid du Colombier 	int i;
1010*8ccd4a63SDavid du Colombier 
1011*8ccd4a63SDavid du Colombier 	USED(op);
1012*8ccd4a63SDavid du Colombier 	obdst = bdst;
1013*8ccd4a63SDavid du Colombier 	if(bsrc.delta == bdst.delta){
1014*8ccd4a63SDavid du Colombier 		memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
1015*8ccd4a63SDavid du Colombier 		return obdst;
1016*8ccd4a63SDavid du Colombier 	}
1017*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
1018*8ccd4a63SDavid du Colombier 		if(grey){
1019*8ccd4a63SDavid du Colombier 			*bdst.grey = *bsrc.grey;
1020*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
1021*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
1022*8ccd4a63SDavid du Colombier 		}else{
1023*8ccd4a63SDavid du Colombier 			*bdst.red = *bsrc.red;
1024*8ccd4a63SDavid du Colombier 			*bdst.grn = *bsrc.grn;
1025*8ccd4a63SDavid du Colombier 			*bdst.blu = *bsrc.blu;
1026*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
1027*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
1028*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
1029*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
1030*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
1031*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
1032*8ccd4a63SDavid du Colombier 		}
1033*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
1034*8ccd4a63SDavid du Colombier 			*bdst.alpha = 255;
10357dd7cddfSDavid du Colombier 			bdst.alpha += bdst.delta;
10367dd7cddfSDavid du Colombier 		}
10377dd7cddfSDavid du Colombier 	}
10387dd7cddfSDavid du Colombier 	return obdst;
10397dd7cddfSDavid du Colombier }
1040*8ccd4a63SDavid du Colombier */
10417dd7cddfSDavid du Colombier 
1042*8ccd4a63SDavid du Colombier /* source alpha 1 */
10437dd7cddfSDavid du Colombier static Buffer
1044*8ccd4a63SDavid du Colombier alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
10457dd7cddfSDavid du Colombier {
10467dd7cddfSDavid du Colombier 	Buffer obdst;
1047*8ccd4a63SDavid du Colombier 	int fd;
10487dd7cddfSDavid du Colombier 	int i, ma;
1049*8ccd4a63SDavid du Colombier 	ulong s, t;
10507dd7cddfSDavid du Colombier 
1051*8ccd4a63SDavid du Colombier 	USED(op);
10527dd7cddfSDavid du Colombier 	obdst = bdst;
1053*8ccd4a63SDavid du Colombier 
10547dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
10557dd7cddfSDavid du Colombier 		ma = *bmask.alpha;
1056*8ccd4a63SDavid du Colombier 		fd = 255-ma;
10577dd7cddfSDavid du Colombier 
10587dd7cddfSDavid du Colombier 		if(grey){
1059*8ccd4a63SDavid du Colombier 			*bdst.grey = MUL(ma, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
1060*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
1061*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
1062*8ccd4a63SDavid du Colombier 		}else{
1063*8ccd4a63SDavid du Colombier 			*bdst.red = MUL(ma, *bsrc.red, s)+MUL(fd, *bdst.red, t);
1064*8ccd4a63SDavid du Colombier 			*bdst.grn = MUL(ma, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
1065*8ccd4a63SDavid du Colombier 			*bdst.blu = MUL(ma, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
1066*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
1067*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
1068*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
1069*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
1070*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
1071*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
1072*8ccd4a63SDavid du Colombier 		}
1073*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
1074*8ccd4a63SDavid du Colombier 			*bdst.alpha = ma+MUL(fd, *bdst.alpha, t);
1075*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
1076*8ccd4a63SDavid du Colombier 		}
1077*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
1078*8ccd4a63SDavid du Colombier 	}
1079*8ccd4a63SDavid du Colombier 	return obdst;
1080*8ccd4a63SDavid du Colombier }
1081*8ccd4a63SDavid du Colombier 
1082*8ccd4a63SDavid du Colombier static Buffer
1083*8ccd4a63SDavid du Colombier boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
1084*8ccd4a63SDavid du Colombier {
1085*8ccd4a63SDavid du Colombier 	Buffer obdst;
1086*8ccd4a63SDavid du Colombier 	int i, ma, zero;
1087*8ccd4a63SDavid du Colombier 
1088*8ccd4a63SDavid du Colombier 	obdst = bdst;
1089*8ccd4a63SDavid du Colombier 
1090*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
1091*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
1092*8ccd4a63SDavid du Colombier 		zero = ma ? op == DoutS : op == DinS;
1093*8ccd4a63SDavid du Colombier 
1094*8ccd4a63SDavid du Colombier 		if(grey){
1095*8ccd4a63SDavid du Colombier 			if(zero)
1096*8ccd4a63SDavid du Colombier 				*bdst.grey = 0;
1097*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
1098*8ccd4a63SDavid du Colombier 		}else{
1099*8ccd4a63SDavid du Colombier 			if(zero)
1100*8ccd4a63SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
1101*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
1102*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
1103*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
1104*8ccd4a63SDavid du Colombier 		}
1105*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
1106*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
1107*8ccd4a63SDavid du Colombier 			if(zero)
1108*8ccd4a63SDavid du Colombier 				*bdst.alpha = 0;
1109*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
1110*8ccd4a63SDavid du Colombier 		}
1111*8ccd4a63SDavid du Colombier 	}
1112*8ccd4a63SDavid du Colombier 	return obdst;
1113*8ccd4a63SDavid du Colombier }
1114*8ccd4a63SDavid du Colombier 
1115*8ccd4a63SDavid du Colombier static Buffer
1116*8ccd4a63SDavid du Colombier boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1117*8ccd4a63SDavid du Colombier {
1118*8ccd4a63SDavid du Colombier 	Buffer obdst;
1119*8ccd4a63SDavid du Colombier 	int fs, fd;
1120*8ccd4a63SDavid du Colombier 	int i, ma, da, zero;
1121*8ccd4a63SDavid du Colombier 	ulong s, t;
1122*8ccd4a63SDavid du Colombier 
1123*8ccd4a63SDavid du Colombier 	obdst = bdst;
1124*8ccd4a63SDavid du Colombier 	zero = !(op&1);
1125*8ccd4a63SDavid du Colombier 
1126*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
1127*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
1128*8ccd4a63SDavid du Colombier 		da = *bdst.alpha;
1129*8ccd4a63SDavid du Colombier 		fs = da;
1130*8ccd4a63SDavid du Colombier 		if(op&2)
1131*8ccd4a63SDavid du Colombier 			fs = 255-da;
1132*8ccd4a63SDavid du Colombier 		fd = 0;
1133*8ccd4a63SDavid du Colombier 		if(op&4)
1134*8ccd4a63SDavid du Colombier 			fd = 255;
1135*8ccd4a63SDavid du Colombier 
1136*8ccd4a63SDavid du Colombier 		if(grey){
11377dd7cddfSDavid du Colombier 			if(ma)
1138*8ccd4a63SDavid du Colombier 				*bdst.grey = MUL(fs, *bsrc.grey, s)+MUL(fd, *bdst.grey, t);
1139*8ccd4a63SDavid du Colombier 			else if(zero)
1140*8ccd4a63SDavid du Colombier 				*bdst.grey = 0;
11417dd7cddfSDavid du Colombier 			bsrc.grey += bsrc.delta;
11427dd7cddfSDavid du Colombier 			bdst.grey += bdst.delta;
11437dd7cddfSDavid du Colombier 		}else{
11447dd7cddfSDavid du Colombier 			if(ma){
1145*8ccd4a63SDavid du Colombier 				*bdst.red = MUL(fs, *bsrc.red, s)+MUL(fd, *bdst.red, t);
1146*8ccd4a63SDavid du Colombier 				*bdst.grn = MUL(fs, *bsrc.grn, s)+MUL(fd, *bdst.grn, t);
1147*8ccd4a63SDavid du Colombier 				*bdst.blu = MUL(fs, *bsrc.blu, s)+MUL(fd, *bdst.blu, t);
11487dd7cddfSDavid du Colombier 			}
1149*8ccd4a63SDavid du Colombier 			else if(zero)
1150*8ccd4a63SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
11517dd7cddfSDavid du Colombier 			bsrc.red += bsrc.delta;
11527dd7cddfSDavid du Colombier 			bsrc.blu += bsrc.delta;
11537dd7cddfSDavid du Colombier 			bsrc.grn += bsrc.delta;
11547dd7cddfSDavid du Colombier 			bdst.red += bdst.delta;
11557dd7cddfSDavid du Colombier 			bdst.blu += bdst.delta;
11567dd7cddfSDavid du Colombier 			bdst.grn += bdst.delta;
11577dd7cddfSDavid du Colombier 		}
11587dd7cddfSDavid du Colombier 		bmask.alpha += bmask.delta;
1159*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
11607dd7cddfSDavid du Colombier 			if(ma)
1161*8ccd4a63SDavid du Colombier 				*bdst.alpha = fs+MUL(fd, da, t);
1162*8ccd4a63SDavid du Colombier 			else if(zero)
1163*8ccd4a63SDavid du Colombier 				*bdst.alpha = 0;
11647dd7cddfSDavid du Colombier 			bdst.alpha += bdst.delta;
11657dd7cddfSDavid du Colombier 		}
11667dd7cddfSDavid du Colombier 	}
11677dd7cddfSDavid du Colombier 	return obdst;
11687dd7cddfSDavid du Colombier }
11697dd7cddfSDavid du Colombier 
1170*8ccd4a63SDavid du Colombier static Buffer
1171*8ccd4a63SDavid du Colombier boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1172*8ccd4a63SDavid du Colombier {
1173*8ccd4a63SDavid du Colombier 	Buffer obdst;
1174*8ccd4a63SDavid du Colombier 	int i, ma, zero;
1175*8ccd4a63SDavid du Colombier 
1176*8ccd4a63SDavid du Colombier 	obdst = bdst;
1177*8ccd4a63SDavid du Colombier 	zero = !(op&1);
1178*8ccd4a63SDavid du Colombier 
1179*8ccd4a63SDavid du Colombier 	for(i=0; i<dx; i++){
1180*8ccd4a63SDavid du Colombier 		ma = *bmask.alpha;
1181*8ccd4a63SDavid du Colombier 
1182*8ccd4a63SDavid du Colombier 		if(grey){
1183*8ccd4a63SDavid du Colombier 			if(ma)
1184*8ccd4a63SDavid du Colombier 				*bdst.grey = *bsrc.grey;
1185*8ccd4a63SDavid du Colombier 			else if(zero)
1186*8ccd4a63SDavid du Colombier 				*bdst.grey = 0;
1187*8ccd4a63SDavid du Colombier 			bsrc.grey += bsrc.delta;
1188*8ccd4a63SDavid du Colombier 			bdst.grey += bdst.delta;
1189*8ccd4a63SDavid du Colombier 		}else{
1190*8ccd4a63SDavid du Colombier 			if(ma){
1191*8ccd4a63SDavid du Colombier 				*bdst.red = *bsrc.red;
1192*8ccd4a63SDavid du Colombier 				*bdst.grn = *bsrc.grn;
1193*8ccd4a63SDavid du Colombier 				*bdst.blu = *bsrc.blu;
1194*8ccd4a63SDavid du Colombier 			}
1195*8ccd4a63SDavid du Colombier 			else if(zero)
1196*8ccd4a63SDavid du Colombier 				*bdst.red = *bdst.grn = *bdst.blu = 0;
1197*8ccd4a63SDavid du Colombier 			bsrc.red += bsrc.delta;
1198*8ccd4a63SDavid du Colombier 			bsrc.blu += bsrc.delta;
1199*8ccd4a63SDavid du Colombier 			bsrc.grn += bsrc.delta;
1200*8ccd4a63SDavid du Colombier 			bdst.red += bdst.delta;
1201*8ccd4a63SDavid du Colombier 			bdst.blu += bdst.delta;
1202*8ccd4a63SDavid du Colombier 			bdst.grn += bdst.delta;
1203*8ccd4a63SDavid du Colombier 		}
1204*8ccd4a63SDavid du Colombier 		bmask.alpha += bmask.delta;
1205*8ccd4a63SDavid du Colombier 		if(bdst.alpha != &ones){
1206*8ccd4a63SDavid du Colombier 			if(ma)
1207*8ccd4a63SDavid du Colombier 				*bdst.alpha = 255;
1208*8ccd4a63SDavid du Colombier 			else if(zero)
1209*8ccd4a63SDavid du Colombier 				*bdst.alpha = 0;
1210*8ccd4a63SDavid du Colombier 			bdst.alpha += bdst.delta;
1211*8ccd4a63SDavid du Colombier 		}
1212*8ccd4a63SDavid du Colombier 	}
1213*8ccd4a63SDavid du Colombier 	return obdst;
1214*8ccd4a63SDavid du Colombier }
12157dd7cddfSDavid du Colombier /*
12167dd7cddfSDavid du Colombier  * Replicated cached scan line read.  Call the function listed in the Param,
12177dd7cddfSDavid du Colombier  * but cache the result so that for replicated images we only do the work once.
12187dd7cddfSDavid du Colombier  */
12197dd7cddfSDavid du Colombier static Buffer
1220*8ccd4a63SDavid du Colombier replread(Param *p, uchar *s, int y)
12217dd7cddfSDavid du Colombier {
12227dd7cddfSDavid du Colombier 	Buffer *b;
12237dd7cddfSDavid du Colombier 
1224*8ccd4a63SDavid du Colombier 	USED(s);
12257dd7cddfSDavid du Colombier 	b = &p->bcache[y];
12267dd7cddfSDavid du Colombier 	if((p->bfilled & (1<<y)) == 0){
12277dd7cddfSDavid du Colombier 		p->bfilled |= 1<<y;
12287dd7cddfSDavid du Colombier 		*b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
12297dd7cddfSDavid du Colombier 	}
12307dd7cddfSDavid du Colombier 	return *b;
12317dd7cddfSDavid du Colombier }
12327dd7cddfSDavid du Colombier 
12337dd7cddfSDavid du Colombier /*
12347dd7cddfSDavid du Colombier  * Alpha reading function that simply relabels the grey pointer.
12357dd7cddfSDavid du Colombier  */
12367dd7cddfSDavid du Colombier static Buffer
12377dd7cddfSDavid du Colombier greymaskread(Param *p, uchar *buf, int y)
12387dd7cddfSDavid du Colombier {
12397dd7cddfSDavid du Colombier 	Buffer b;
12407dd7cddfSDavid du Colombier 
12417dd7cddfSDavid du Colombier 	b = p->greymaskcall(p, buf, y);
12427dd7cddfSDavid du Colombier 	b.alpha = b.grey;
12437dd7cddfSDavid du Colombier 	return b;
12447dd7cddfSDavid du Colombier }
12457dd7cddfSDavid du Colombier 
12467dd7cddfSDavid du Colombier #define DBG if(0)
12477dd7cddfSDavid du Colombier static Buffer
12487dd7cddfSDavid du Colombier readnbit(Param *p, uchar *buf, int y)
12497dd7cddfSDavid du Colombier {
12507dd7cddfSDavid du Colombier 	Buffer b;
12517dd7cddfSDavid du Colombier 	Memimage *img;
12527dd7cddfSDavid du Colombier 	uchar *repl, *r, *w, *ow, bits;
12537dd7cddfSDavid du Colombier 	int i, n, sh, depth, x, dx, npack, nbits;
12547dd7cddfSDavid du Colombier 
1255*8ccd4a63SDavid du Colombier 	b.rgba = (ulong*)buf;
12567dd7cddfSDavid du Colombier 	b.grey = w = buf;
12577dd7cddfSDavid du Colombier 	b.red = b.blu = b.grn = w;
1258*8ccd4a63SDavid du Colombier 	b.alpha = &ones;
12597dd7cddfSDavid du Colombier 	b.delta = 1;
12607dd7cddfSDavid du Colombier 
12617dd7cddfSDavid du Colombier 	dx = p->dx;
12627dd7cddfSDavid du Colombier 	img = p->img;
12637dd7cddfSDavid du Colombier 	depth = img->depth;
12647dd7cddfSDavid du Colombier 	repl = &replbit[depth][0];
12657dd7cddfSDavid du Colombier 	npack = 8/depth;
12667dd7cddfSDavid du Colombier 	sh = 8-depth;
12677dd7cddfSDavid du Colombier 
12687dd7cddfSDavid du Colombier 	/* copy from p->r.min.x until end of repl rectangle */
12697dd7cddfSDavid du Colombier 	x = p->r.min.x;
12707dd7cddfSDavid du Colombier 	n = dx;
12717dd7cddfSDavid du Colombier 	if(n > p->img->r.max.x - x)
12727dd7cddfSDavid du Colombier 		n = p->img->r.max.x - x;
12737dd7cddfSDavid du Colombier 
12747dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
12757dd7cddfSDavid du Colombier DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
12767dd7cddfSDavid du Colombier 	bits = *r++;
12777dd7cddfSDavid du Colombier 	nbits = 8;
1278*8ccd4a63SDavid du Colombier 	if((i=x&(npack-1))){
12797dd7cddfSDavid du Colombier DBG print("throwaway %d...", i);
12807dd7cddfSDavid du Colombier 		bits <<= depth*i;
12817dd7cddfSDavid du Colombier 		nbits -= depth*i;
12827dd7cddfSDavid du Colombier 	}
12837dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
12847dd7cddfSDavid du Colombier 		if(nbits == 0){
12857dd7cddfSDavid du Colombier DBG print("(%.2ux)...", *r);
12867dd7cddfSDavid du Colombier 			bits = *r++;
12877dd7cddfSDavid du Colombier 			nbits = 8;
12887dd7cddfSDavid du Colombier 		}
12897dd7cddfSDavid du Colombier 		*w++ = repl[bits>>sh];
12907dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]);
12917dd7cddfSDavid du Colombier 		bits <<= depth;
12927dd7cddfSDavid du Colombier 		nbits -= depth;
12937dd7cddfSDavid du Colombier 	}
12947dd7cddfSDavid du Colombier 	dx -= n;
12957dd7cddfSDavid du Colombier 	if(dx == 0)
12967dd7cddfSDavid du Colombier 		return b;
12977dd7cddfSDavid du Colombier 
12987dd7cddfSDavid du Colombier 	assert(x+i == p->img->r.max.x);
12997dd7cddfSDavid du Colombier 
13007dd7cddfSDavid du Colombier 	/* copy from beginning of repl rectangle until where we were before. */
13017dd7cddfSDavid du Colombier 	x = p->img->r.min.x;
13027dd7cddfSDavid du Colombier 	n = dx;
13037dd7cddfSDavid du Colombier 	if(n > p->r.min.x - x)
13047dd7cddfSDavid du Colombier 		n = p->r.min.x - x;
13057dd7cddfSDavid du Colombier 
13067dd7cddfSDavid du Colombier 	r = p->bytey0s + y*p->bwidth;
13077dd7cddfSDavid du Colombier DBG print("x=%d r=%p...", x, r);
13087dd7cddfSDavid du Colombier 	bits = *r++;
13097dd7cddfSDavid du Colombier 	nbits = 8;
1310*8ccd4a63SDavid du Colombier 	if((i=x&(npack-1))){
13117dd7cddfSDavid du Colombier 		bits <<= depth*i;
13127dd7cddfSDavid du Colombier 		nbits -= depth*i;
13137dd7cddfSDavid du Colombier 	}
13147dd7cddfSDavid du Colombier DBG print("nbits=%d...", nbits);
13157dd7cddfSDavid du Colombier 	for(i=0; i<n; i++){
13167dd7cddfSDavid du Colombier 		if(nbits == 0){
13177dd7cddfSDavid du Colombier 			bits = *r++;
13187dd7cddfSDavid du Colombier 			nbits = 8;
13197dd7cddfSDavid du Colombier 		}
13207dd7cddfSDavid du Colombier 		*w++ = repl[bits>>sh];
13217dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]);
13227dd7cddfSDavid du Colombier 		bits <<= depth;
13237dd7cddfSDavid du Colombier 		nbits -= depth;
13247dd7cddfSDavid du Colombier DBG print("bits %x nbits %d...", bits, nbits);
13257dd7cddfSDavid du Colombier 	}
13267dd7cddfSDavid du Colombier 	dx -= n;
13277dd7cddfSDavid du Colombier 	if(dx == 0)
13287dd7cddfSDavid du Colombier 		return b;
13297dd7cddfSDavid du Colombier 
13307dd7cddfSDavid du Colombier 	assert(dx > 0);
13317dd7cddfSDavid du Colombier 	/* now we have exactly one full scan line: just replicate the buffer itself until we are done */
13327dd7cddfSDavid du Colombier 	ow = buf;
13337dd7cddfSDavid du Colombier 	while(dx--)
13347dd7cddfSDavid du Colombier 		*w++ = *ow++;
13357dd7cddfSDavid du Colombier 
13367dd7cddfSDavid du Colombier 	return b;
13377dd7cddfSDavid du Colombier }
13387dd7cddfSDavid du Colombier #undef DBG
13397dd7cddfSDavid du Colombier 
13407dd7cddfSDavid du Colombier #define DBG if(0)
13417dd7cddfSDavid du Colombier static void
13427dd7cddfSDavid du Colombier writenbit(Param *p, uchar *w, Buffer src)
13437dd7cddfSDavid du Colombier {
13447dd7cddfSDavid du Colombier 	uchar *r;
13457dd7cddfSDavid du Colombier 	ulong bits;
13467dd7cddfSDavid du Colombier 	int i, sh, depth, npack, nbits, x, ex;
13477dd7cddfSDavid du Colombier 
13487dd7cddfSDavid du Colombier 	assert(src.grey != nil && src.delta == 1);
13497dd7cddfSDavid du Colombier 
13507dd7cddfSDavid du Colombier 	x = p->r.min.x;
13517dd7cddfSDavid du Colombier 	ex = x+p->dx;
13527dd7cddfSDavid du Colombier 	depth = p->img->depth;
13537dd7cddfSDavid du Colombier 	npack = 8/depth;
13547dd7cddfSDavid du Colombier 
13557dd7cddfSDavid du Colombier 	i=x&(npack-1);
13567dd7cddfSDavid du Colombier 	bits = i ? (*w >> (8-depth*i)) : 0;
13577dd7cddfSDavid du Colombier 	nbits = depth*i;
13587dd7cddfSDavid du Colombier 	sh = 8-depth;
13597dd7cddfSDavid du Colombier 	r = src.grey;
13607dd7cddfSDavid du Colombier 
13617dd7cddfSDavid du Colombier 	for(; x<ex; x++){
13627dd7cddfSDavid du Colombier 		bits <<= depth;
13637dd7cddfSDavid du Colombier DBG print(" %x", *r);
13647dd7cddfSDavid du Colombier 		bits |= (*r++ >> sh);
13657dd7cddfSDavid du Colombier 		nbits += depth;
13667dd7cddfSDavid du Colombier 		if(nbits == 8){
13677dd7cddfSDavid du Colombier 			*w++ = bits;
13687dd7cddfSDavid du Colombier 			nbits = 0;
13697dd7cddfSDavid du Colombier 		}
13707dd7cddfSDavid du Colombier 	}
13717dd7cddfSDavid du Colombier 
13727dd7cddfSDavid du Colombier 	if(nbits){
13737dd7cddfSDavid du Colombier 		sh = 8-nbits;
13747dd7cddfSDavid du Colombier 		bits <<= sh;
13757dd7cddfSDavid du Colombier 		bits |= *w & ((1<<sh)-1);
13767dd7cddfSDavid du Colombier 		*w = bits;
13777dd7cddfSDavid du Colombier 	}
13787dd7cddfSDavid du Colombier DBG print("\n");
13797dd7cddfSDavid du Colombier 	return;
13807dd7cddfSDavid du Colombier }
13817dd7cddfSDavid du Colombier #undef DBG
13827dd7cddfSDavid du Colombier 
13837dd7cddfSDavid du Colombier static Buffer
13847dd7cddfSDavid du Colombier readcmap(Param *p, uchar *buf, int y)
13857dd7cddfSDavid du Colombier {
13867dd7cddfSDavid du Colombier 	Buffer b;
1387*8ccd4a63SDavid du Colombier 	int a, convgrey, copyalpha, dx, i, m;
13887dd7cddfSDavid du Colombier 	uchar *q, *cmap, *begin, *end, *r, *w;
13897dd7cddfSDavid du Colombier 
13907dd7cddfSDavid du Colombier 	begin = p->bytey0s + y*p->bwidth;
13917dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
13927dd7cddfSDavid du Colombier 	end = p->bytey0e + y*p->bwidth;
13937dd7cddfSDavid du Colombier 	cmap = p->img->cmap->cmap2rgb;
13947dd7cddfSDavid du Colombier 	convgrey = p->convgrey;
1395*8ccd4a63SDavid du Colombier 	copyalpha = (p->img->flags&Falpha) ? 1 : 0;
13967dd7cddfSDavid du Colombier 
13977dd7cddfSDavid du Colombier 	w = buf;
13987dd7cddfSDavid du Colombier 	dx = p->dx;
1399*8ccd4a63SDavid du Colombier 	if(copyalpha){
1400*8ccd4a63SDavid du Colombier 		b.alpha = buf++;
1401*8ccd4a63SDavid du Colombier 		a = p->img->shift[CAlpha]/8;
1402*8ccd4a63SDavid du Colombier 		m = p->img->shift[CMap]/8;
1403*8ccd4a63SDavid du Colombier 		for(i=0; i<dx; i++){
1404*8ccd4a63SDavid du Colombier 			*w++ = r[a];
1405*8ccd4a63SDavid du Colombier 			q = cmap+r[m]*3;
1406*8ccd4a63SDavid du Colombier 			r += 2;
1407*8ccd4a63SDavid du Colombier 			if(r == end)
1408*8ccd4a63SDavid du Colombier 				r = begin;
1409*8ccd4a63SDavid du Colombier 			if(convgrey){
1410*8ccd4a63SDavid du Colombier 				*w++ = RGB2K(q[0], q[1], q[2]);
1411*8ccd4a63SDavid du Colombier 			}else{
1412*8ccd4a63SDavid du Colombier 				*w++ = q[2];	/* blue */
1413*8ccd4a63SDavid du Colombier 				*w++ = q[1];	/* green */
1414*8ccd4a63SDavid du Colombier 				*w++ = q[0];	/* red */
1415*8ccd4a63SDavid du Colombier 			}
1416*8ccd4a63SDavid du Colombier 		}
1417*8ccd4a63SDavid du Colombier 	}else{
1418*8ccd4a63SDavid du Colombier 		b.alpha = &ones;
14197dd7cddfSDavid du Colombier 		for(i=0; i<dx; i++){
14207dd7cddfSDavid du Colombier 			q = cmap+*r++*3;
14217dd7cddfSDavid du Colombier 			if(r == end)
14227dd7cddfSDavid du Colombier 				r = begin;
14237dd7cddfSDavid du Colombier 			if(convgrey){
14247dd7cddfSDavid du Colombier 				*w++ = RGB2K(q[0], q[1], q[2]);
14257dd7cddfSDavid du Colombier 			}else{
14267dd7cddfSDavid du Colombier 				*w++ = q[2];	/* blue */
14277dd7cddfSDavid du Colombier 				*w++ = q[1];	/* green */
14287dd7cddfSDavid du Colombier 				*w++ = q[0];	/* red */
14297dd7cddfSDavid du Colombier 			}
14307dd7cddfSDavid du Colombier 		}
1431*8ccd4a63SDavid du Colombier 	}
1432*8ccd4a63SDavid du Colombier 
1433*8ccd4a63SDavid du Colombier 	b.rgba = (ulong*)(buf-copyalpha);
14347dd7cddfSDavid du Colombier 
14357dd7cddfSDavid du Colombier 	if(convgrey){
14367dd7cddfSDavid du Colombier 		b.grey = buf;
14377dd7cddfSDavid du Colombier 		b.red = b.blu = b.grn = buf;
1438*8ccd4a63SDavid du Colombier 		b.delta = 1+copyalpha;
14397dd7cddfSDavid du Colombier 	}else{
14407dd7cddfSDavid du Colombier 		b.blu = buf;
14417dd7cddfSDavid du Colombier 		b.grn = buf+1;
14427dd7cddfSDavid du Colombier 		b.red = buf+2;
14437dd7cddfSDavid du Colombier 		b.grey = nil;
1444*8ccd4a63SDavid du Colombier 		b.delta = 3+copyalpha;
14457dd7cddfSDavid du Colombier 	}
14467dd7cddfSDavid du Colombier 	return b;
14477dd7cddfSDavid du Colombier }
14487dd7cddfSDavid du Colombier 
14497dd7cddfSDavid du Colombier static void
14507dd7cddfSDavid du Colombier writecmap(Param *p, uchar *w, Buffer src)
14517dd7cddfSDavid du Colombier {
14527dd7cddfSDavid du Colombier 	uchar *cmap, *red, *grn, *blu;
14537dd7cddfSDavid du Colombier 	int i, dx, delta;
14547dd7cddfSDavid du Colombier 
14557dd7cddfSDavid du Colombier 	cmap = p->img->cmap->rgb2cmap;
14567dd7cddfSDavid du Colombier 
14577dd7cddfSDavid du Colombier 	delta = src.delta;
14587dd7cddfSDavid du Colombier 	red= src.red;
14597dd7cddfSDavid du Colombier 	grn = src.grn;
14607dd7cddfSDavid du Colombier 	blu = src.blu;
14617dd7cddfSDavid du Colombier 
14627dd7cddfSDavid du Colombier 	dx = p->dx;
14637dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
14647dd7cddfSDavid du Colombier 		*w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
14657dd7cddfSDavid du Colombier }
14667dd7cddfSDavid du Colombier 
1467*8ccd4a63SDavid du Colombier #define DBG if(0)
14687dd7cddfSDavid du Colombier static Buffer
14697dd7cddfSDavid du Colombier readbyte(Param *p, uchar *buf, int y)
14707dd7cddfSDavid du Colombier {
14717dd7cddfSDavid du Colombier 	Buffer b;
14727dd7cddfSDavid du Colombier 	Memimage *img;
14737dd7cddfSDavid du Colombier 	int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
14747dd7cddfSDavid du Colombier 	uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
14757dd7cddfSDavid du Colombier 	uchar ured, ugrn, ublu;
14767dd7cddfSDavid du Colombier 	ulong u;
14777dd7cddfSDavid du Colombier 
14787dd7cddfSDavid du Colombier 	img = p->img;
14797dd7cddfSDavid du Colombier 	begin = p->bytey0s + y*p->bwidth;
14807dd7cddfSDavid du Colombier 	r = p->bytermin + y*p->bwidth;
14817dd7cddfSDavid du Colombier 	end = p->bytey0e + y*p->bwidth;
14827dd7cddfSDavid du Colombier 
14837dd7cddfSDavid du Colombier 	w = buf;
14847dd7cddfSDavid du Colombier 	dx = p->dx;
14857dd7cddfSDavid du Colombier 	nb = img->depth/8;
14867dd7cddfSDavid du Colombier 
14877dd7cddfSDavid du Colombier 	convgrey = p->convgrey;	/* convert rgb to grey */
14887dd7cddfSDavid du Colombier 	isgrey = img->flags&Fgrey;
14897dd7cddfSDavid du Colombier 	alphaonly = p->alphaonly;
149059cc4ca5SDavid du Colombier 	copyalpha = (img->flags&Falpha) ? 1 : 0;
14917dd7cddfSDavid du Colombier 
1492*8ccd4a63SDavid du Colombier DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
14937dd7cddfSDavid du Colombier 	/* if we can, avoid processing everything */
14947dd7cddfSDavid du Colombier 	if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
14957dd7cddfSDavid du Colombier 		memset(&b, 0, sizeof b);
14967dd7cddfSDavid du Colombier 		if(p->needbuf){
14977dd7cddfSDavid du Colombier 			memmove(buf, r, dx*nb);
14987dd7cddfSDavid du Colombier 			r = buf;
14997dd7cddfSDavid du Colombier 		}
1500*8ccd4a63SDavid du Colombier 		b.rgba = (ulong*)r;
15017dd7cddfSDavid du Colombier 		if(copyalpha)
15027dd7cddfSDavid du Colombier 			b.alpha = r+img->shift[CAlpha]/8;
1503*8ccd4a63SDavid du Colombier 		else
1504*8ccd4a63SDavid du Colombier 			b.alpha = &ones;
15057dd7cddfSDavid du Colombier 		if(isgrey){
15067dd7cddfSDavid du Colombier 			b.grey = r+img->shift[CGrey]/8;
15077dd7cddfSDavid du Colombier 			b.red = b.grn = b.blu = b.grey;
15087dd7cddfSDavid du Colombier 		}else{
15097dd7cddfSDavid du Colombier 			b.red = r+img->shift[CRed]/8;
15107dd7cddfSDavid du Colombier 			b.grn = r+img->shift[CGreen]/8;
15117dd7cddfSDavid du Colombier 			b.blu = r+img->shift[CBlue]/8;
15127dd7cddfSDavid du Colombier 		}
15137dd7cddfSDavid du Colombier 		b.delta = nb;
15147dd7cddfSDavid du Colombier 		return b;
15157dd7cddfSDavid du Colombier 	}
15167dd7cddfSDavid du Colombier 
1517*8ccd4a63SDavid du Colombier DBG print("2\n");
15187dd7cddfSDavid du Colombier 	rrepl = replbit[img->nbits[CRed]];
15197dd7cddfSDavid du Colombier 	grepl = replbit[img->nbits[CGreen]];
15207dd7cddfSDavid du Colombier 	brepl = replbit[img->nbits[CBlue]];
15217dd7cddfSDavid du Colombier 	arepl = replbit[img->nbits[CAlpha]];
15227dd7cddfSDavid du Colombier 	krepl = replbit[img->nbits[CGrey]];
15237dd7cddfSDavid du Colombier 
15247dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
15257dd7cddfSDavid du Colombier 		u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
1526*8ccd4a63SDavid du Colombier 		if(copyalpha) {
15277dd7cddfSDavid du Colombier 			*w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
1528*8ccd4a63SDavid du Colombier DBG print("a %x\n", w[-1]);
1529*8ccd4a63SDavid du Colombier 		}
15307dd7cddfSDavid du Colombier 
15317dd7cddfSDavid du Colombier 		if(isgrey)
15327dd7cddfSDavid du Colombier 			*w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
15337dd7cddfSDavid du Colombier 		else if(!alphaonly){
15347dd7cddfSDavid du Colombier 			ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
15357dd7cddfSDavid du Colombier 			ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
15367dd7cddfSDavid du Colombier 			ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
15377dd7cddfSDavid du Colombier 			if(convgrey){
1538*8ccd4a63SDavid du Colombier DBG print("g %x %x %x\n", ured, ugrn, ublu);
15397dd7cddfSDavid du Colombier 				*w++ = RGB2K(ured, ugrn, ublu);
1540*8ccd4a63SDavid du Colombier DBG print("%x\n", w[-1]);
15417dd7cddfSDavid du Colombier 			}else{
15427dd7cddfSDavid du Colombier 				*w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
15437dd7cddfSDavid du Colombier 				*w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
15447dd7cddfSDavid du Colombier 				*w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
15457dd7cddfSDavid du Colombier 			}
15467dd7cddfSDavid du Colombier 		}
15477dd7cddfSDavid du Colombier 		r += nb;
15487dd7cddfSDavid du Colombier 		if(r == end)
15497dd7cddfSDavid du Colombier 			r = begin;
15507dd7cddfSDavid du Colombier 	}
15517dd7cddfSDavid du Colombier 
1552*8ccd4a63SDavid du Colombier 	b.alpha = copyalpha ? buf : &ones;
1553*8ccd4a63SDavid du Colombier 	b.rgba = (ulong*)buf;
15547dd7cddfSDavid du Colombier 	if(alphaonly){
15557dd7cddfSDavid du Colombier 		b.red = b.grn = b.blu = b.grey = nil;
1556*8ccd4a63SDavid du Colombier 		if(!copyalpha)
1557*8ccd4a63SDavid du Colombier 			b.rgba = nil;
15587dd7cddfSDavid du Colombier 		b.delta = 1;
15597dd7cddfSDavid du Colombier 	}else if(isgrey || convgrey){
15607dd7cddfSDavid du Colombier 		b.grey = buf+copyalpha;
15617dd7cddfSDavid du Colombier 		b.red = b.grn = b.blu = buf+copyalpha;
15627dd7cddfSDavid du Colombier 		b.delta = copyalpha+1;
1563*8ccd4a63SDavid du Colombier DBG print("alpha %x grey %x\n", b.alpha ? *b.alpha : 0xFF, *b.grey);
15647dd7cddfSDavid du Colombier 	}else{
15657dd7cddfSDavid du Colombier 		b.blu = buf+copyalpha;
15667dd7cddfSDavid du Colombier 		b.grn = buf+copyalpha+1;
15677dd7cddfSDavid du Colombier 		b.grey = nil;
15687dd7cddfSDavid du Colombier 		b.red = buf+copyalpha+2;
15697dd7cddfSDavid du Colombier 		b.delta = copyalpha+3;
15707dd7cddfSDavid du Colombier 	}
15717dd7cddfSDavid du Colombier 	return b;
15727dd7cddfSDavid du Colombier }
1573*8ccd4a63SDavid du Colombier #undef DBG
15747dd7cddfSDavid du Colombier 
15757dd7cddfSDavid du Colombier #define DBG if(0)
15767dd7cddfSDavid du Colombier static void
15777dd7cddfSDavid du Colombier writebyte(Param *p, uchar *w, Buffer src)
15787dd7cddfSDavid du Colombier {
15797dd7cddfSDavid du Colombier 	Memimage *img;
15807dd7cddfSDavid du Colombier 	int i, isalpha, isgrey, nb, delta, dx, adelta;
15817dd7cddfSDavid du Colombier 	uchar ff, *red, *grn, *blu, *grey, *alpha;
15827dd7cddfSDavid du Colombier 	ulong u, mask;
15837dd7cddfSDavid du Colombier 
15847dd7cddfSDavid du Colombier 	img = p->img;
15857dd7cddfSDavid du Colombier 
15867dd7cddfSDavid du Colombier 	red = src.red;
15877dd7cddfSDavid du Colombier 	grn = src.grn;
15887dd7cddfSDavid du Colombier 	blu = src.blu;
15897dd7cddfSDavid du Colombier 	alpha = src.alpha;
15907dd7cddfSDavid du Colombier 	delta = src.delta;
15917dd7cddfSDavid du Colombier 	grey = src.grey;
15927dd7cddfSDavid du Colombier 	dx = p->dx;
15937dd7cddfSDavid du Colombier 
15947dd7cddfSDavid du Colombier 	nb = img->depth/8;
15957dd7cddfSDavid du Colombier 	mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
15967dd7cddfSDavid du Colombier 
15977dd7cddfSDavid du Colombier 	isalpha = img->flags&Falpha;
15987dd7cddfSDavid du Colombier 	isgrey = img->flags&Fgrey;
15997dd7cddfSDavid du Colombier 	adelta = src.delta;
16007dd7cddfSDavid du Colombier 
1601*8ccd4a63SDavid du Colombier 	if(isalpha && (alpha == nil || alpha == &ones)){
16027dd7cddfSDavid du Colombier 		ff = 0xFF;
16037dd7cddfSDavid du Colombier 		alpha = &ff;
16047dd7cddfSDavid du Colombier 		adelta = 0;
16057dd7cddfSDavid du Colombier 	}
16067dd7cddfSDavid du Colombier 
16077dd7cddfSDavid du Colombier 	for(i=0; i<dx; i++){
16087dd7cddfSDavid du Colombier 		u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
16097dd7cddfSDavid du Colombier DBG print("u %.8lux...", u);
16107dd7cddfSDavid du Colombier 		u &= mask;
16117dd7cddfSDavid du Colombier DBG print("&mask %.8lux...", u);
16127dd7cddfSDavid du Colombier 		if(isgrey){
16137dd7cddfSDavid du Colombier 			u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
16147dd7cddfSDavid du Colombier DBG print("|grey %.8lux...", u);
16157dd7cddfSDavid du Colombier 			grey += delta;
16167dd7cddfSDavid du Colombier 		}else{
16177dd7cddfSDavid du Colombier 			u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
16187dd7cddfSDavid du Colombier 			u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
16197dd7cddfSDavid du Colombier 			u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
16207dd7cddfSDavid du Colombier 			red += delta;
16217dd7cddfSDavid du Colombier 			grn += delta;
16227dd7cddfSDavid du Colombier 			blu += delta;
16237dd7cddfSDavid du Colombier DBG print("|rgb %.8lux...", u);
16247dd7cddfSDavid du Colombier 		}
16257dd7cddfSDavid du Colombier 
16267dd7cddfSDavid du Colombier 		if(isalpha){
16277dd7cddfSDavid du Colombier 			u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
16287dd7cddfSDavid du Colombier 			alpha += adelta;
16297dd7cddfSDavid du Colombier DBG print("|alpha %.8lux...", u);
16307dd7cddfSDavid du Colombier 		}
16317dd7cddfSDavid du Colombier 
16327dd7cddfSDavid du Colombier 		w[0] = u;
16337dd7cddfSDavid du Colombier 		w[1] = u>>8;
16347dd7cddfSDavid du Colombier 		w[2] = u>>16;
16357dd7cddfSDavid du Colombier 		w[3] = u>>24;
16367dd7cddfSDavid du Colombier 		w += nb;
16377dd7cddfSDavid du Colombier 	}
16387dd7cddfSDavid du Colombier }
16397dd7cddfSDavid du Colombier #undef DBG
16407dd7cddfSDavid du Colombier 
16417dd7cddfSDavid du Colombier static Readfn*
16427dd7cddfSDavid du Colombier readfn(Memimage *img)
16437dd7cddfSDavid du Colombier {
16447dd7cddfSDavid du Colombier 	if(img->depth < 8)
16457dd7cddfSDavid du Colombier 		return readnbit;
1646*8ccd4a63SDavid du Colombier 	if(img->nbits[CMap] == 8)
16477dd7cddfSDavid du Colombier 		return readcmap;
16487dd7cddfSDavid du Colombier 	return readbyte;
16497dd7cddfSDavid du Colombier }
16507dd7cddfSDavid du Colombier 
16517dd7cddfSDavid du Colombier static Readfn*
1652*8ccd4a63SDavid du Colombier readalphafn(Memimage *m)
16537dd7cddfSDavid du Colombier {
1654*8ccd4a63SDavid du Colombier 	USED(m);
16557dd7cddfSDavid du Colombier 	return readbyte;
16567dd7cddfSDavid du Colombier }
16577dd7cddfSDavid du Colombier 
16587dd7cddfSDavid du Colombier static Writefn*
16597dd7cddfSDavid du Colombier writefn(Memimage *img)
16607dd7cddfSDavid du Colombier {
16617dd7cddfSDavid du Colombier 	if(img->depth < 8)
16627dd7cddfSDavid du Colombier 		return writenbit;
16637dd7cddfSDavid du Colombier 	if(img->chan == CMAP8)
16647dd7cddfSDavid du Colombier 		return writecmap;
16657dd7cddfSDavid du Colombier 	return writebyte;
16667dd7cddfSDavid du Colombier }
16677dd7cddfSDavid du Colombier 
16687dd7cddfSDavid du Colombier static void
1669*8ccd4a63SDavid du Colombier nullwrite(Param *p, uchar *s, Buffer b)
16707dd7cddfSDavid du Colombier {
1671*8ccd4a63SDavid du Colombier 	USED(p);
1672*8ccd4a63SDavid du Colombier 	USED(s);
16737dd7cddfSDavid du Colombier }
16747dd7cddfSDavid du Colombier 
16757dd7cddfSDavid du Colombier static Buffer
1676*8ccd4a63SDavid du Colombier readptr(Param *p, uchar *s, int y)
16777dd7cddfSDavid du Colombier {
16787dd7cddfSDavid du Colombier 	Buffer b;
16797dd7cddfSDavid du Colombier 	uchar *q;
16807dd7cddfSDavid du Colombier 
1681*8ccd4a63SDavid du Colombier 	USED(s);
16827dd7cddfSDavid du Colombier 	q = p->bytermin + y*p->bwidth;
16837dd7cddfSDavid du Colombier 	b.red = q;	/* ptr to data */
16847dd7cddfSDavid du Colombier 	b.grn = b.blu = b.grey = b.alpha = nil;
1685*8ccd4a63SDavid du Colombier 	b.rgba = (ulong*)q;
16867dd7cddfSDavid du Colombier 	b.delta = p->img->depth/8;
16877dd7cddfSDavid du Colombier 	return b;
16887dd7cddfSDavid du Colombier }
16897dd7cddfSDavid du Colombier 
16907dd7cddfSDavid du Colombier static Buffer
1691*8ccd4a63SDavid du Colombier boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
16927dd7cddfSDavid du Colombier {
1693*8ccd4a63SDavid du Colombier 	USED(i);
1694*8ccd4a63SDavid du Colombier 	USED(o);
16957dd7cddfSDavid du Colombier 	memmove(bdst.red, bsrc.red, dx*bdst.delta);
16967dd7cddfSDavid du Colombier 	return bdst;
16977dd7cddfSDavid du Colombier }
16987dd7cddfSDavid du Colombier 
16997dd7cddfSDavid du Colombier static Buffer
1700*8ccd4a63SDavid du Colombier boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17017dd7cddfSDavid du Colombier {
17027dd7cddfSDavid du Colombier 	uchar *m, *r, *w, *ew;
17037dd7cddfSDavid du Colombier 
1704*8ccd4a63SDavid du Colombier 	USED(i);
1705*8ccd4a63SDavid du Colombier 	USED(o);
17067dd7cddfSDavid du Colombier 	m = bmask.grey;
17077dd7cddfSDavid du Colombier 	w = bdst.red;
17087dd7cddfSDavid du Colombier 	r = bsrc.red;
17097dd7cddfSDavid du Colombier 	ew = w+dx;
17107dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
17117dd7cddfSDavid du Colombier 		if(*m++)
17127dd7cddfSDavid du Colombier 			*w = *r;
17137dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17147dd7cddfSDavid du Colombier }
17157dd7cddfSDavid du Colombier 
17167dd7cddfSDavid du Colombier static Buffer
1717*8ccd4a63SDavid du Colombier boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17187dd7cddfSDavid du Colombier {
17197dd7cddfSDavid du Colombier 	uchar *m;
17207dd7cddfSDavid du Colombier 	ushort *r, *w, *ew;
17217dd7cddfSDavid du Colombier 
1722*8ccd4a63SDavid du Colombier 	USED(i);
1723*8ccd4a63SDavid du Colombier 	USED(o);
17247dd7cddfSDavid du Colombier 	m = bmask.grey;
17257dd7cddfSDavid du Colombier 	w = (ushort*)bdst.red;
17267dd7cddfSDavid du Colombier 	r = (ushort*)bsrc.red;
17277dd7cddfSDavid du Colombier 	ew = w+dx;
17287dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
17297dd7cddfSDavid du Colombier 		if(*m++)
17307dd7cddfSDavid du Colombier 			*w = *r;
17317dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17327dd7cddfSDavid du Colombier }
17337dd7cddfSDavid du Colombier 
17347dd7cddfSDavid du Colombier static Buffer
1735*8ccd4a63SDavid du Colombier boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17367dd7cddfSDavid du Colombier {
17377dd7cddfSDavid du Colombier 	uchar *m;
17387dd7cddfSDavid du Colombier 	uchar *r, *w, *ew;
17397dd7cddfSDavid du Colombier 
1740*8ccd4a63SDavid du Colombier 	USED(i);
1741*8ccd4a63SDavid du Colombier 	USED(o);
17427dd7cddfSDavid du Colombier 	m = bmask.grey;
17437dd7cddfSDavid du Colombier 	w = bdst.red;
17447dd7cddfSDavid du Colombier 	r = bsrc.red;
17457dd7cddfSDavid du Colombier 	ew = w+dx*3;
17467dd7cddfSDavid du Colombier 	while(w < ew){
17477dd7cddfSDavid du Colombier 		if(*m++){
17487dd7cddfSDavid du Colombier 			*w++ = *r++;
17497dd7cddfSDavid du Colombier 			*w++ = *r++;
17507dd7cddfSDavid du Colombier 			*w++ = *r++;
17517dd7cddfSDavid du Colombier 		}else{
17527dd7cddfSDavid du Colombier 			w += 3;
17537dd7cddfSDavid du Colombier 			r += 3;
17547dd7cddfSDavid du Colombier 		}
17557dd7cddfSDavid du Colombier 	}
17567dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17577dd7cddfSDavid du Colombier }
17587dd7cddfSDavid du Colombier 
17597dd7cddfSDavid du Colombier static Buffer
1760*8ccd4a63SDavid du Colombier boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
17617dd7cddfSDavid du Colombier {
17627dd7cddfSDavid du Colombier 	uchar *m;
17637dd7cddfSDavid du Colombier 	ulong *r, *w, *ew;
17647dd7cddfSDavid du Colombier 
1765*8ccd4a63SDavid du Colombier 	USED(i);
1766*8ccd4a63SDavid du Colombier 	USED(o);
17677dd7cddfSDavid du Colombier 	m = bmask.grey;
17687dd7cddfSDavid du Colombier 	w = (ulong*)bdst.red;
17697dd7cddfSDavid du Colombier 	r = (ulong*)bsrc.red;
17707dd7cddfSDavid du Colombier 	ew = w+dx;
17717dd7cddfSDavid du Colombier 	for(; w < ew; w++,r++)
17727dd7cddfSDavid du Colombier 		if(*m++)
17737dd7cddfSDavid du Colombier 			*w = *r;
17747dd7cddfSDavid du Colombier 	return bdst;	/* not used */
17757dd7cddfSDavid du Colombier }
17767dd7cddfSDavid du Colombier 
17777dd7cddfSDavid du Colombier static Buffer
17787dd7cddfSDavid du Colombier genconv(Param *p, uchar *buf, int y)
17797dd7cddfSDavid du Colombier {
17807dd7cddfSDavid du Colombier 	Buffer b;
17817dd7cddfSDavid du Colombier 	int nb;
17827dd7cddfSDavid du Colombier 	uchar *r, *w, *ew;
17837dd7cddfSDavid du Colombier 
17847dd7cddfSDavid du Colombier 	/* read from source into RGB format in convbuf */
17857dd7cddfSDavid du Colombier 	b = p->convreadcall(p, p->convbuf, y);
17867dd7cddfSDavid du Colombier 
17877dd7cddfSDavid du Colombier 	/* write RGB format into dst format in buf */
17887dd7cddfSDavid du Colombier 	p->convwritecall(p->convdpar, buf, b);
17897dd7cddfSDavid du Colombier 
17907dd7cddfSDavid du Colombier 	if(p->convdx){
17917dd7cddfSDavid du Colombier 		nb = p->convdpar->img->depth/8;
17927dd7cddfSDavid du Colombier 		r = buf;
17937dd7cddfSDavid du Colombier 		w = buf+nb*p->dx;
17947dd7cddfSDavid du Colombier 		ew = buf+nb*p->convdx;
17957dd7cddfSDavid du Colombier 		while(w<ew)
17967dd7cddfSDavid du Colombier 			*w++ = *r++;
17977dd7cddfSDavid du Colombier 	}
17987dd7cddfSDavid du Colombier 
17997dd7cddfSDavid du Colombier 	b.red = buf;
18007dd7cddfSDavid du Colombier 	b.blu = b.grn = b.grey = b.alpha = nil;
1801*8ccd4a63SDavid du Colombier 	b.rgba = (ulong*)buf;
18027dd7cddfSDavid du Colombier 	b.delta = 0;
18037dd7cddfSDavid du Colombier 
18047dd7cddfSDavid du Colombier 	return b;
18057dd7cddfSDavid du Colombier }
18067dd7cddfSDavid du Colombier 
18077dd7cddfSDavid du Colombier static Readfn*
18087dd7cddfSDavid du Colombier convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar)
18097dd7cddfSDavid du Colombier {
18107dd7cddfSDavid du Colombier 	if(dst->chan == src->chan && !(src->flags&Frepl)){
1811*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("readptr...");
18127dd7cddfSDavid du Colombier 		return readptr;
18137dd7cddfSDavid du Colombier 	}
18147dd7cddfSDavid du Colombier 
18157dd7cddfSDavid du Colombier 	if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
18167dd7cddfSDavid du Colombier 		/* cheat because we know the replicated value is exactly the color map entry. */
1817*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("Readnbit...");
18187dd7cddfSDavid du Colombier 		return readnbit;
18197dd7cddfSDavid du Colombier 	}
18207dd7cddfSDavid du Colombier 
18217dd7cddfSDavid du Colombier 	spar->convreadcall = readfn(src);
18227dd7cddfSDavid du Colombier 	spar->convwritecall = writefn(dst);
18237dd7cddfSDavid du Colombier 	spar->convdpar = dpar;
18247dd7cddfSDavid du Colombier 
18257dd7cddfSDavid du Colombier 	/* allocate a conversion buffer */
18267dd7cddfSDavid du Colombier 	spar->convbufoff = ndrawbuf;
18277dd7cddfSDavid du Colombier 	ndrawbuf += spar->dx*4;
18287dd7cddfSDavid du Colombier 
18297dd7cddfSDavid du Colombier 	if(spar->dx > Dx(spar->img->r)){
18307dd7cddfSDavid du Colombier 		spar->convdx = spar->dx;
18317dd7cddfSDavid du Colombier 		spar->dx = Dx(spar->img->r);
18327dd7cddfSDavid du Colombier 	}
18337dd7cddfSDavid du Colombier 
1834*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("genconv...");
18357dd7cddfSDavid du Colombier 	return genconv;
18367dd7cddfSDavid du Colombier }
18377dd7cddfSDavid du Colombier 
18387dd7cddfSDavid du Colombier ulong
18397dd7cddfSDavid du Colombier _pixelbits(Memimage *i, Point pt)
18407dd7cddfSDavid du Colombier {
18417dd7cddfSDavid du Colombier 	uchar *p;
18427dd7cddfSDavid du Colombier 	ulong val;
18437dd7cddfSDavid du Colombier 	int off, bpp, npack;
18447dd7cddfSDavid du Colombier 
18457dd7cddfSDavid du Colombier 	val = 0;
18467dd7cddfSDavid du Colombier 	p = byteaddr(i, pt);
18477dd7cddfSDavid du Colombier 	switch(bpp=i->depth){
18487dd7cddfSDavid du Colombier 	case 1:
18497dd7cddfSDavid du Colombier 	case 2:
18507dd7cddfSDavid du Colombier 	case 4:
18517dd7cddfSDavid du Colombier 		npack = 8/bpp;
18527dd7cddfSDavid du Colombier 		off = pt.x%npack;
18537dd7cddfSDavid du Colombier 		val = p[0] >> bpp*(npack-1-off);
18547dd7cddfSDavid du Colombier 		val &= (1<<bpp)-1;
18557dd7cddfSDavid du Colombier 		break;
18567dd7cddfSDavid du Colombier 	case 8:
18577dd7cddfSDavid du Colombier 		val = p[0];
18587dd7cddfSDavid du Colombier 		break;
18597dd7cddfSDavid du Colombier 	case 16:
18607dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8);
18617dd7cddfSDavid du Colombier 		break;
18627dd7cddfSDavid du Colombier 	case 24:
18637dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8)|(p[2]<<16);
18647dd7cddfSDavid du Colombier 		break;
18657dd7cddfSDavid du Colombier 	case 32:
18667dd7cddfSDavid du Colombier 		val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
18677dd7cddfSDavid du Colombier 		break;
18687dd7cddfSDavid du Colombier 	}
18697dd7cddfSDavid du Colombier 	while(bpp<32){
18707dd7cddfSDavid du Colombier 		val |= val<<bpp;
18717dd7cddfSDavid du Colombier 		bpp *= 2;
18727dd7cddfSDavid du Colombier 	}
18737dd7cddfSDavid du Colombier 	return val;
18747dd7cddfSDavid du Colombier }
18757dd7cddfSDavid du Colombier 
18767dd7cddfSDavid du Colombier static Calcfn*
18777dd7cddfSDavid du Colombier boolcopyfn(Memimage *img, Memimage *mask)
18787dd7cddfSDavid du Colombier {
1879*8ccd4a63SDavid du Colombier 	if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
18807dd7cddfSDavid du Colombier 		return boolmemmove;
18817dd7cddfSDavid du Colombier 
18827dd7cddfSDavid du Colombier 	switch(img->depth){
18837dd7cddfSDavid du Colombier 	case 8:
18847dd7cddfSDavid du Colombier 		return boolcopy8;
18857dd7cddfSDavid du Colombier 	case 16:
18867dd7cddfSDavid du Colombier 		return boolcopy16;
18877dd7cddfSDavid du Colombier 	case 24:
18887dd7cddfSDavid du Colombier 		return boolcopy24;
18897dd7cddfSDavid du Colombier 	case 32:
18907dd7cddfSDavid du Colombier 		return boolcopy32;
18917dd7cddfSDavid du Colombier 	default:
18927dd7cddfSDavid du Colombier 		assert(0 /* boolcopyfn */);
18937dd7cddfSDavid du Colombier 	}
18947dd7cddfSDavid du Colombier 	return nil;
18957dd7cddfSDavid du Colombier }
18967dd7cddfSDavid du Colombier 
18977dd7cddfSDavid du Colombier /*
18987dd7cddfSDavid du Colombier  * Optimized draw for filling and scrolling; uses memset and memmove.
1899*8ccd4a63SDavid du Colombier  *
19007dd7cddfSDavid du Colombier static void
19017dd7cddfSDavid du Colombier memsetb(void *vp, uchar val, int n)
19027dd7cddfSDavid du Colombier {
19037dd7cddfSDavid du Colombier 	uchar *p, *ep;
19047dd7cddfSDavid du Colombier 
19057dd7cddfSDavid du Colombier 	p = vp;
19067dd7cddfSDavid du Colombier 	ep = p+n;
19077dd7cddfSDavid du Colombier 	while(p<ep)
19087dd7cddfSDavid du Colombier 		*p++ = val;
19097dd7cddfSDavid du Colombier }
1910*8ccd4a63SDavid du Colombier */
19117dd7cddfSDavid du Colombier 
19127dd7cddfSDavid du Colombier static void
19137dd7cddfSDavid du Colombier memsets(void *vp, ushort val, int n)
19147dd7cddfSDavid du Colombier {
19157dd7cddfSDavid du Colombier 	ushort *p, *ep;
19167dd7cddfSDavid du Colombier 
19177dd7cddfSDavid du Colombier 	p = vp;
19187dd7cddfSDavid du Colombier 	ep = p+n;
19197dd7cddfSDavid du Colombier 	while(p<ep)
19207dd7cddfSDavid du Colombier 		*p++ = val;
19217dd7cddfSDavid du Colombier }
19227dd7cddfSDavid du Colombier 
19237dd7cddfSDavid du Colombier static void
19247dd7cddfSDavid du Colombier memsetl(void *vp, ulong val, int n)
19257dd7cddfSDavid du Colombier {
19267dd7cddfSDavid du Colombier 	ulong *p, *ep;
19277dd7cddfSDavid du Colombier 
19287dd7cddfSDavid du Colombier 	p = vp;
19297dd7cddfSDavid du Colombier 	ep = p+n;
19307dd7cddfSDavid du Colombier 	while(p<ep)
19317dd7cddfSDavid du Colombier 		*p++ = val;
19327dd7cddfSDavid du Colombier }
19337dd7cddfSDavid du Colombier 
1934*8ccd4a63SDavid du Colombier static void
19357dd7cddfSDavid du Colombier memset24(void *vp, ulong val, int n)
19367dd7cddfSDavid du Colombier {
19377dd7cddfSDavid du Colombier 	uchar *p, *ep;
19387dd7cddfSDavid du Colombier 	uchar a,b,c;
19397dd7cddfSDavid du Colombier 
19407dd7cddfSDavid du Colombier 	p = vp;
19417dd7cddfSDavid du Colombier 	ep = p+3*n;
19427dd7cddfSDavid du Colombier 	a = val;
19437dd7cddfSDavid du Colombier 	b = val>>8;
19447dd7cddfSDavid du Colombier 	c = val>>16;
19457dd7cddfSDavid du Colombier 	while(p<ep){
19467dd7cddfSDavid du Colombier 		*p++ = a;
19477dd7cddfSDavid du Colombier 		*p++ = b;
19487dd7cddfSDavid du Colombier 		*p++ = c;
19497dd7cddfSDavid du Colombier 	}
19507dd7cddfSDavid du Colombier }
19517dd7cddfSDavid du Colombier 
19527dd7cddfSDavid du Colombier ulong
19537dd7cddfSDavid du Colombier _imgtorgba(Memimage *img, ulong val)
19547dd7cddfSDavid du Colombier {
19557dd7cddfSDavid du Colombier 	uchar r, g, b, a;
19567dd7cddfSDavid du Colombier 	int nb, ov, v;
19577dd7cddfSDavid du Colombier 	ulong chan;
19587dd7cddfSDavid du Colombier 	uchar *p;
19597dd7cddfSDavid du Colombier 
19607dd7cddfSDavid du Colombier 	a = 0xFF;
19617dd7cddfSDavid du Colombier 	r = g = b = 0xAA;	/* garbage */
19627dd7cddfSDavid du Colombier 	for(chan=img->chan; chan; chan>>=8){
19637dd7cddfSDavid du Colombier 		nb = NBITS(chan);
19647dd7cddfSDavid du Colombier 		ov = v = val&((1<<nb)-1);
19657dd7cddfSDavid du Colombier 		val >>= nb;
19667dd7cddfSDavid du Colombier 
19677dd7cddfSDavid du Colombier 		while(nb < 8){
19687dd7cddfSDavid du Colombier 			v |= v<<nb;
19697dd7cddfSDavid du Colombier 			nb *= 2;
19707dd7cddfSDavid du Colombier 		}
19717dd7cddfSDavid du Colombier 		v >>= (nb-8);
19727dd7cddfSDavid du Colombier 
19737dd7cddfSDavid du Colombier 		switch(TYPE(chan)){
19747dd7cddfSDavid du Colombier 		case CRed:
19757dd7cddfSDavid du Colombier 			r = v;
19767dd7cddfSDavid du Colombier 			break;
19777dd7cddfSDavid du Colombier 		case CGreen:
19787dd7cddfSDavid du Colombier 			g = v;
19797dd7cddfSDavid du Colombier 			break;
19807dd7cddfSDavid du Colombier 		case CBlue:
19817dd7cddfSDavid du Colombier 			b = v;
19827dd7cddfSDavid du Colombier 			break;
19837dd7cddfSDavid du Colombier 		case CAlpha:
19847dd7cddfSDavid du Colombier 			a = v;
19857dd7cddfSDavid du Colombier 			break;
19867dd7cddfSDavid du Colombier 		case CGrey:
19877dd7cddfSDavid du Colombier 			r = g = b = v;
19887dd7cddfSDavid du Colombier 			break;
19897dd7cddfSDavid du Colombier 		case CMap:
19907dd7cddfSDavid du Colombier 			p = img->cmap->cmap2rgb+3*ov;
19917dd7cddfSDavid du Colombier 			r = *p++;
19927dd7cddfSDavid du Colombier 			g = *p++;
19937dd7cddfSDavid du Colombier 			b = *p;
19947dd7cddfSDavid du Colombier 			break;
19957dd7cddfSDavid du Colombier 		}
19967dd7cddfSDavid du Colombier 	}
19977dd7cddfSDavid du Colombier 	return (r<<24)|(g<<16)|(b<<8)|a;
19987dd7cddfSDavid du Colombier }
19997dd7cddfSDavid du Colombier 
20007dd7cddfSDavid du Colombier ulong
20017dd7cddfSDavid du Colombier _rgbatoimg(Memimage *img, ulong rgba)
20027dd7cddfSDavid du Colombier {
20037dd7cddfSDavid du Colombier 	ulong chan;
20047dd7cddfSDavid du Colombier 	int d, nb;
20057dd7cddfSDavid du Colombier 	ulong v;
20067dd7cddfSDavid du Colombier 	uchar *p, r, g, b, a, m;
20077dd7cddfSDavid du Colombier 
20087dd7cddfSDavid du Colombier 	v = 0;
20097dd7cddfSDavid du Colombier 	r = rgba>>24;
20107dd7cddfSDavid du Colombier 	g = rgba>>16;
20117dd7cddfSDavid du Colombier 	b = rgba>>8;
20127dd7cddfSDavid du Colombier 	a = rgba;
20137dd7cddfSDavid du Colombier 	d = 0;
20147dd7cddfSDavid du Colombier 	for(chan=img->chan; chan; chan>>=8){
20157dd7cddfSDavid du Colombier 		nb = NBITS(chan);
20167dd7cddfSDavid du Colombier 		switch(TYPE(chan)){
20177dd7cddfSDavid du Colombier 		case CRed:
20187dd7cddfSDavid du Colombier 			v |= (r>>(8-nb))<<d;
20197dd7cddfSDavid du Colombier 			break;
20207dd7cddfSDavid du Colombier 		case CGreen:
20217dd7cddfSDavid du Colombier 			v |= (g>>(8-nb))<<d;
20227dd7cddfSDavid du Colombier 			break;
20237dd7cddfSDavid du Colombier 		case CBlue:
20247dd7cddfSDavid du Colombier 			v |= (b>>(8-nb))<<d;
20257dd7cddfSDavid du Colombier 			break;
20267dd7cddfSDavid du Colombier 		case CAlpha:
20277dd7cddfSDavid du Colombier 			v |= (a>>(8-nb))<<d;
20287dd7cddfSDavid du Colombier 			break;
20297dd7cddfSDavid du Colombier 		case CMap:
20307dd7cddfSDavid du Colombier 			p = img->cmap->rgb2cmap;
20317dd7cddfSDavid du Colombier 			m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
203259cc4ca5SDavid du Colombier 			v |= (m>>(8-nb))<<d;
20337dd7cddfSDavid du Colombier 			break;
20347dd7cddfSDavid du Colombier 		case CGrey:
20357dd7cddfSDavid du Colombier 			m = RGB2K(r,g,b);
203659cc4ca5SDavid du Colombier 			v |= (m>>(8-nb))<<d;
20377dd7cddfSDavid du Colombier 			break;
20387dd7cddfSDavid du Colombier 		}
20397dd7cddfSDavid du Colombier 		d += nb;
20407dd7cddfSDavid du Colombier 	}
2041*8ccd4a63SDavid du Colombier //	print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
20427dd7cddfSDavid du Colombier 	return v;
20437dd7cddfSDavid du Colombier }
20447dd7cddfSDavid du Colombier 
2045*8ccd4a63SDavid du Colombier #define DBG if(0)
20467dd7cddfSDavid du Colombier static int
20477dd7cddfSDavid du Colombier memoptdraw(Memdrawparam *par)
20487dd7cddfSDavid du Colombier {
2049*8ccd4a63SDavid du Colombier 	int m, y, dy, dx, op;
20507dd7cddfSDavid du Colombier 	ulong v;
20517dd7cddfSDavid du Colombier 	Memimage *src;
20527dd7cddfSDavid du Colombier 	Memimage *dst;
20537dd7cddfSDavid du Colombier 
20547dd7cddfSDavid du Colombier 	dx = Dx(par->r);
20557dd7cddfSDavid du Colombier 	dy = Dy(par->r);
20567dd7cddfSDavid du Colombier 	src = par->src;
20577dd7cddfSDavid du Colombier 	dst = par->dst;
2058*8ccd4a63SDavid du Colombier 	op = par->op;
20597dd7cddfSDavid du Colombier 
2060*8ccd4a63SDavid du Colombier DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
20617dd7cddfSDavid du Colombier 	/*
20627dd7cddfSDavid du Colombier 	 * If we have an opaque mask and source is one opaque pixel we can convert to the
20637dd7cddfSDavid du Colombier 	 * destination format and just replicate with memset.
20647dd7cddfSDavid du Colombier 	 */
20657dd7cddfSDavid du Colombier 	m = Simplesrc|Simplemask|Fullmask;
2066*8ccd4a63SDavid du Colombier 	if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
20677dd7cddfSDavid du Colombier 		uchar *dp, p[4];
206859cc4ca5SDavid du Colombier 		int d, dwid, ppb, np, nb;
20697dd7cddfSDavid du Colombier 		uchar lm, rm;
20707dd7cddfSDavid du Colombier 
2071*8ccd4a63SDavid du Colombier DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
20727dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
20737dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
20747dd7cddfSDavid du Colombier 		v = par->sdval;
2075*8ccd4a63SDavid du Colombier DBG print("sdval %lud, depth %d\n", v, dst->depth);
20767dd7cddfSDavid du Colombier 		switch(dst->depth){
20777dd7cddfSDavid du Colombier 		case 1:
20787dd7cddfSDavid du Colombier 		case 2:
20797dd7cddfSDavid du Colombier 		case 4:
208059cc4ca5SDavid du Colombier 			for(d=dst->depth; d<8; d*=2)
208159cc4ca5SDavid du Colombier 				v |= (v<<d);
20827dd7cddfSDavid du Colombier 			ppb = 8/dst->depth;	/* pixels per byte */
20837dd7cddfSDavid du Colombier 			m = ppb-1;
20847dd7cddfSDavid du Colombier 			/* left edge */
20857dd7cddfSDavid du Colombier 			np = par->r.min.x&m;		/* no. pixels unused on left side of word */
20867dd7cddfSDavid du Colombier 			dx -= (ppb-np);
20877dd7cddfSDavid du Colombier 			nb = 8 - np * dst->depth;		/* no. bits used on right side of word */
20887dd7cddfSDavid du Colombier 			lm = (1<<nb)-1;
2089*8ccd4a63SDavid 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);
20907dd7cddfSDavid du Colombier 
20917dd7cddfSDavid du Colombier 			/* right edge */
20927dd7cddfSDavid du Colombier 			np = par->r.max.x&m;	/* no. pixels used on left side of word */
20937dd7cddfSDavid du Colombier 			dx -= np;
20947dd7cddfSDavid du Colombier 			nb = 8 - np * dst->depth;		/* no. bits unused on right side of word */
20957dd7cddfSDavid du Colombier 			rm = ~((1<<nb)-1);
2096*8ccd4a63SDavid 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);
20977dd7cddfSDavid du Colombier 
2098*8ccd4a63SDavid du Colombier DBG print("dx %d Dx %d\n", dx, Dx(par->r));
20997dd7cddfSDavid du Colombier 			/* lm, rm are masks that are 1 where we should touch the bits */
21007dd7cddfSDavid du Colombier 			if(dx < 0){	/* just one byte */
21017dd7cddfSDavid du Colombier 				lm &= rm;
21027dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid)
21037dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & lm;
21047dd7cddfSDavid du Colombier 			}else if(dx == 0){	/* no full bytes */
21057dd7cddfSDavid du Colombier 				if(lm)
21067dd7cddfSDavid du Colombier 					dwid--;
21077dd7cddfSDavid du Colombier 
21087dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid){
21097dd7cddfSDavid du Colombier 					if(lm){
2110*8ccd4a63SDavid du Colombier DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
21117dd7cddfSDavid du Colombier 						*dp ^= (v ^ *dp) & lm;
21127dd7cddfSDavid du Colombier 						dp++;
21137dd7cddfSDavid du Colombier 					}
21147dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & rm;
21157dd7cddfSDavid du Colombier 				}
21167dd7cddfSDavid du Colombier 			}else{		/* full bytes in middle */
21177dd7cddfSDavid du Colombier 				dx /= ppb;
21187dd7cddfSDavid du Colombier 				if(lm)
21197dd7cddfSDavid du Colombier 					dwid--;
21207dd7cddfSDavid du Colombier 				dwid -= dx;
21217dd7cddfSDavid du Colombier 
21227dd7cddfSDavid du Colombier 				for(y=0; y<dy; y++, dp+=dwid){
21237dd7cddfSDavid du Colombier 					if(lm){
21247dd7cddfSDavid du Colombier 						*dp ^= (v ^ *dp) & lm;
21257dd7cddfSDavid du Colombier 						dp++;
21267dd7cddfSDavid du Colombier 					}
21277dd7cddfSDavid du Colombier 					memset(dp, v, dx);
21287dd7cddfSDavid du Colombier 					dp += dx;
21297dd7cddfSDavid du Colombier 					*dp ^= (v ^ *dp) & rm;
21307dd7cddfSDavid du Colombier 				}
21317dd7cddfSDavid du Colombier 			}
21327dd7cddfSDavid du Colombier 			return 1;
21337dd7cddfSDavid du Colombier 		case 8:
21347dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21357dd7cddfSDavid du Colombier 				memset(dp, v, dx);
21367dd7cddfSDavid du Colombier 			return 1;
21377dd7cddfSDavid du Colombier 		case 16:
21387dd7cddfSDavid du Colombier 			p[0] = v;		/* make little endian */
21397dd7cddfSDavid du Colombier 			p[1] = v>>8;
21407dd7cddfSDavid du Colombier 			v = *(ushort*)p;
2141*8ccd4a63SDavid du Colombier DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
2142*8ccd4a63SDavid du Colombier 	dp, dx, dy, dwid);
21437dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21447dd7cddfSDavid du Colombier 				memsets(dp, v, dx);
21457dd7cddfSDavid du Colombier 			return 1;
21467dd7cddfSDavid du Colombier 		case 24:
21477dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21487dd7cddfSDavid du Colombier 				memset24(dp, v, dx);
21497dd7cddfSDavid du Colombier 			return 1;
21507dd7cddfSDavid du Colombier 		case 32:
21517dd7cddfSDavid du Colombier 			p[0] = v;		/* make little endian */
21527dd7cddfSDavid du Colombier 			p[1] = v>>8;
21537dd7cddfSDavid du Colombier 			p[2] = v>>16;
21547dd7cddfSDavid du Colombier 			p[3] = v>>24;
21557dd7cddfSDavid du Colombier 			v = *(ulong*)p;
21567dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid)
21577dd7cddfSDavid du Colombier 				memsetl(dp, v, dx);
21587dd7cddfSDavid du Colombier 			return 1;
21597dd7cddfSDavid du Colombier 		default:
21607dd7cddfSDavid du Colombier 			assert(0 /* bad dest depth in memoptdraw */);
21617dd7cddfSDavid du Colombier 		}
21627dd7cddfSDavid du Colombier 	}
21637dd7cddfSDavid du Colombier 
21647dd7cddfSDavid du Colombier 	/*
21657dd7cddfSDavid du Colombier 	 * If no source alpha, an opaque mask, we can just copy the
21667dd7cddfSDavid du Colombier 	 * source onto the destination.  If the channels are the same and
21677dd7cddfSDavid du Colombier 	 * the source is not replicated, memmove suffices.
21687dd7cddfSDavid du Colombier 	 */
21697dd7cddfSDavid du Colombier 	m = Simplemask|Fullmask;
21707dd7cddfSDavid du Colombier 	if((par->state&(m|Replsrc))==m && src->depth >= 8
2171*8ccd4a63SDavid du Colombier 	&& src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){
21727dd7cddfSDavid du Colombier 		uchar *sp, *dp;
21737dd7cddfSDavid du Colombier 		long swid, dwid, nb;
21747dd7cddfSDavid du Colombier 		int dir;
21757dd7cddfSDavid du Colombier 
21767dd7cddfSDavid du Colombier 		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
21777dd7cddfSDavid du Colombier 			dir = -1;
21787dd7cddfSDavid du Colombier 		else
21797dd7cddfSDavid du Colombier 			dir = 1;
21807dd7cddfSDavid du Colombier 
21817dd7cddfSDavid du Colombier 		swid = src->width*sizeof(ulong);
21827dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
21837dd7cddfSDavid du Colombier 		sp = byteaddr(src, par->sr.min);
21847dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
21857dd7cddfSDavid du Colombier 		if(dir == -1){
21867dd7cddfSDavid du Colombier 			sp += (dy-1)*swid;
21877dd7cddfSDavid du Colombier 			dp += (dy-1)*dwid;
21887dd7cddfSDavid du Colombier 			swid = -swid;
21897dd7cddfSDavid du Colombier 			dwid = -dwid;
21907dd7cddfSDavid du Colombier 		}
21917dd7cddfSDavid du Colombier 		nb = (dx*src->depth)/8;
21927dd7cddfSDavid du Colombier 		for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
21937dd7cddfSDavid du Colombier 			memmove(dp, sp, nb);
21947dd7cddfSDavid du Colombier 		return 1;
21957dd7cddfSDavid du Colombier 	}
21967dd7cddfSDavid du Colombier 
21977dd7cddfSDavid du Colombier 	/*
21987dd7cddfSDavid du Colombier 	 * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
21997dd7cddfSDavid du Colombier 	 * they're all bit aligned, we can just use bit operators.  This happens
22007dd7cddfSDavid du Colombier 	 * when we're manipulating boolean masks, e.g. in the arc code.
22017dd7cddfSDavid du Colombier 	 */
22027dd7cddfSDavid du Colombier 	if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0
22037dd7cddfSDavid du Colombier 	&& dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1
22047dd7cddfSDavid du Colombier 	&& (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
22057dd7cddfSDavid du Colombier 		uchar *sp, *dp, *mp;
22067dd7cddfSDavid du Colombier 		uchar lm, rm;
22077dd7cddfSDavid du Colombier 		long swid, dwid, mwid;
22087dd7cddfSDavid du Colombier 		int i, x, dir;
22097dd7cddfSDavid du Colombier 
22107dd7cddfSDavid du Colombier 		sp = byteaddr(src, par->sr.min);
22117dd7cddfSDavid du Colombier 		dp = byteaddr(dst, par->r.min);
22127dd7cddfSDavid du Colombier 		mp = byteaddr(par->mask, par->mr.min);
22137dd7cddfSDavid du Colombier 		swid = src->width*sizeof(ulong);
22147dd7cddfSDavid du Colombier 		dwid = dst->width*sizeof(ulong);
22157dd7cddfSDavid du Colombier 		mwid = par->mask->width*sizeof(ulong);
22167dd7cddfSDavid du Colombier 
22177dd7cddfSDavid du Colombier 		if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
22187dd7cddfSDavid du Colombier 			dir = -1;
22197dd7cddfSDavid du Colombier 		}else
22207dd7cddfSDavid du Colombier 			dir = 1;
22217dd7cddfSDavid du Colombier 
22227dd7cddfSDavid du Colombier 		lm = 0xFF>>(par->r.min.x&7);
22237dd7cddfSDavid du Colombier 		rm = 0xFF<<(8-(par->r.max.x&7));
22247dd7cddfSDavid du Colombier 		dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
22257dd7cddfSDavid du Colombier 
22267dd7cddfSDavid du Colombier 		if(dx < 0){	/* one byte wide */
22277dd7cddfSDavid du Colombier 			lm &= rm;
22287dd7cddfSDavid du Colombier 			if(dir == -1){
22297dd7cddfSDavid du Colombier 				dp += dwid*(dy-1);
22307dd7cddfSDavid du Colombier 				sp += swid*(dy-1);
22317dd7cddfSDavid du Colombier 				mp += mwid*(dy-1);
22327dd7cddfSDavid du Colombier 				dwid = -dwid;
22337dd7cddfSDavid du Colombier 				swid = -swid;
22347dd7cddfSDavid du Colombier 				mwid = -mwid;
22357dd7cddfSDavid du Colombier 			}
22367dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++){
22377dd7cddfSDavid du Colombier 				*dp ^= (*dp ^ *sp) & *mp & lm;
22387dd7cddfSDavid du Colombier 				dp += dwid;
22397dd7cddfSDavid du Colombier 				sp += swid;
22407dd7cddfSDavid du Colombier 				mp += mwid;
22417dd7cddfSDavid du Colombier 			}
22427dd7cddfSDavid du Colombier 			return 1;
22437dd7cddfSDavid du Colombier 		}
22447dd7cddfSDavid du Colombier 
22457dd7cddfSDavid du Colombier 		dx /= 8;
22467dd7cddfSDavid du Colombier 		if(dir == 1){
22477dd7cddfSDavid du Colombier 			i = (lm!=0)+dx+(rm!=0);
22487dd7cddfSDavid du Colombier 			mwid -= i;
22497dd7cddfSDavid du Colombier 			swid -= i;
22507dd7cddfSDavid du Colombier 			dwid -= i;
22517dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
22527dd7cddfSDavid du Colombier 				if(lm){
22537dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++ & lm;
22547dd7cddfSDavid du Colombier 					dp++;
22557dd7cddfSDavid du Colombier 				}
22567dd7cddfSDavid du Colombier 				for(x=0; x<dx; x++){
22577dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++;
22587dd7cddfSDavid du Colombier 					dp++;
22597dd7cddfSDavid du Colombier 				}
22607dd7cddfSDavid du Colombier 				if(rm){
22617dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp++) & *mp++ & rm;
22627dd7cddfSDavid du Colombier 					dp++;
22637dd7cddfSDavid du Colombier 				}
22647dd7cddfSDavid du Colombier 			}
22657dd7cddfSDavid du Colombier 			return 1;
22667dd7cddfSDavid du Colombier 		}else{
22677dd7cddfSDavid du Colombier 		/* dir == -1 */
22687dd7cddfSDavid du Colombier 			i = (lm!=0)+dx+(rm!=0);
22697dd7cddfSDavid du Colombier 			dp += dwid*(dy-1)+i-1;
22707dd7cddfSDavid du Colombier 			sp += swid*(dy-1)+i-1;
22717dd7cddfSDavid du Colombier 			mp += mwid*(dy-1)+i-1;
22727dd7cddfSDavid du Colombier 			dwid = -dwid+i;
22737dd7cddfSDavid du Colombier 			swid = -swid+i;
22747dd7cddfSDavid du Colombier 			mwid = -mwid+i;
22757dd7cddfSDavid du Colombier 			for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
22767dd7cddfSDavid du Colombier 				if(rm){
22777dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp-- & rm;
22787dd7cddfSDavid du Colombier 					dp--;
22797dd7cddfSDavid du Colombier 				}
22807dd7cddfSDavid du Colombier 				for(x=0; x<dx; x++){
22817dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp--;
22827dd7cddfSDavid du Colombier 					dp--;
22837dd7cddfSDavid du Colombier 				}
22847dd7cddfSDavid du Colombier 				if(lm){
22857dd7cddfSDavid du Colombier 					*dp ^= (*dp ^ *sp--) & *mp-- & lm;
22867dd7cddfSDavid du Colombier 					dp--;
22877dd7cddfSDavid du Colombier 				}
22887dd7cddfSDavid du Colombier 			}
22897dd7cddfSDavid du Colombier 		}
22907dd7cddfSDavid du Colombier 		return 1;
22917dd7cddfSDavid du Colombier 	}
22927dd7cddfSDavid du Colombier 	return 0;
22937dd7cddfSDavid du Colombier }
2294*8ccd4a63SDavid du Colombier #undef DBG
22957dd7cddfSDavid du Colombier 
22967dd7cddfSDavid du Colombier /*
22977dd7cddfSDavid du Colombier  * Boolean character drawing.
22987dd7cddfSDavid du Colombier  * Solid opaque color through a 1-bit greyscale mask.
22997dd7cddfSDavid du Colombier  */
23007dd7cddfSDavid du Colombier #define DBG if(0)
23017dd7cddfSDavid du Colombier static int
23027dd7cddfSDavid du Colombier chardraw(Memdrawparam *par)
23037dd7cddfSDavid du Colombier {
23047dd7cddfSDavid du Colombier 	ulong bits;
2305*8ccd4a63SDavid du Colombier 	int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
23067dd7cddfSDavid du Colombier 	ulong v, maskwid, dstwid;
23077dd7cddfSDavid du Colombier 	uchar *wp, *rp, *q, *wc;
23087dd7cddfSDavid du Colombier 	ushort *ws;
23097dd7cddfSDavid du Colombier 	ulong *wl;
23107dd7cddfSDavid du Colombier 	uchar sp[4];
23117dd7cddfSDavid du Colombier 	Rectangle r, mr;
23127dd7cddfSDavid du Colombier 	Memimage *mask, *src, *dst;
23137dd7cddfSDavid du Colombier 
23147dd7cddfSDavid 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",
23157dd7cddfSDavid du Colombier 		par->mask->flags, par->mask->depth, par->src->flags,
23167dd7cddfSDavid du Colombier 		Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
23177dd7cddfSDavid du Colombier 
23187dd7cddfSDavid du Colombier 	mask = par->mask;
23197dd7cddfSDavid du Colombier 	src = par->src;
23207dd7cddfSDavid du Colombier 	dst = par->dst;
23217dd7cddfSDavid du Colombier 	r = par->r;
23227dd7cddfSDavid du Colombier 	mr = par->mr;
2323*8ccd4a63SDavid du Colombier 	op = par->op;
23247dd7cddfSDavid du Colombier 
23257dd7cddfSDavid du Colombier 	if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc)
2326*8ccd4a63SDavid du Colombier 	|| mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data
2327*8ccd4a63SDavid du Colombier 	|| op != SoverD)
23287dd7cddfSDavid du Colombier 		return 0;
23297dd7cddfSDavid du Colombier 
2330*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("chardraw...");
2331*8ccd4a63SDavid du Colombier 
23327dd7cddfSDavid du Colombier 	depth = mask->depth;
23337dd7cddfSDavid du Colombier 	maskwid = mask->width*sizeof(ulong);
23347dd7cddfSDavid du Colombier 	rp = byteaddr(mask, mr.min);
23357dd7cddfSDavid du Colombier 	npack = 8/depth;
23367dd7cddfSDavid du Colombier 	bsh = (mr.min.x % npack) * depth;
23377dd7cddfSDavid du Colombier 
23387dd7cddfSDavid du Colombier 	wp = byteaddr(dst, r.min);
23397dd7cddfSDavid du Colombier 	dstwid = dst->width*sizeof(ulong);
23407dd7cddfSDavid du Colombier DBG print("bsh %d\n", bsh);
23417dd7cddfSDavid du Colombier 	dy = Dy(r);
23427dd7cddfSDavid du Colombier 	dx = Dx(r);
23437dd7cddfSDavid du Colombier 
23447dd7cddfSDavid du Colombier 	ddepth = dst->depth;
23457dd7cddfSDavid du Colombier 
23467dd7cddfSDavid du Colombier 	/*
23477dd7cddfSDavid du Colombier 	 * for loop counts from bsh to bsh+dx
23487dd7cddfSDavid du Colombier 	 *
23497dd7cddfSDavid du Colombier 	 * we want the bottom bits to be the amount
23507dd7cddfSDavid du Colombier 	 * to shift the pixels down, so for n≡0 (mod 8) we want
23517dd7cddfSDavid du Colombier 	 * bottom bits 7.  for n≡1, 6, etc.
23527dd7cddfSDavid du Colombier 	 * the bits come from -n-1.
23537dd7cddfSDavid du Colombier 	 */
23547dd7cddfSDavid du Colombier 
23557dd7cddfSDavid du Colombier 	bx = -bsh-1;
23567dd7cddfSDavid du Colombier 	ex = -bsh-1-dx;
2357*8ccd4a63SDavid du Colombier 	bits = 0;
23587dd7cddfSDavid du Colombier 	v = par->sdval;
23597dd7cddfSDavid du Colombier 
23607dd7cddfSDavid du Colombier 	/* make little endian */
23617dd7cddfSDavid du Colombier 	sp[0] = v;
23627dd7cddfSDavid du Colombier 	sp[1] = v>>8;
23637dd7cddfSDavid du Colombier 	sp[2] = v>>16;
23647dd7cddfSDavid du Colombier 	sp[3] = v>>24;
23657dd7cddfSDavid du Colombier 
2366*8ccd4a63SDavid du Colombier //print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
23677dd7cddfSDavid du Colombier 	for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
23687dd7cddfSDavid du Colombier 		q = rp;
23697dd7cddfSDavid du Colombier 		if(bsh)
23707dd7cddfSDavid du Colombier 			bits = *q++;
23717dd7cddfSDavid du Colombier 		switch(ddepth){
23727dd7cddfSDavid du Colombier 		case 8:
2373*8ccd4a63SDavid du Colombier //if(drawdebug) iprint("8loop...");
23747dd7cddfSDavid du Colombier 			wc = wp;
23757dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wc++){
23767dd7cddfSDavid du Colombier 				i = x&7;
23777dd7cddfSDavid du Colombier 				if(i == 8-1)
23787dd7cddfSDavid du Colombier 					bits = *q++;
23797dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
23807dd7cddfSDavid du Colombier 				if((bits>>i)&1)
23817dd7cddfSDavid du Colombier 					*wc = v;
23827dd7cddfSDavid du Colombier 			}
23837dd7cddfSDavid du Colombier 			break;
23847dd7cddfSDavid du Colombier 		case 16:
23857dd7cddfSDavid du Colombier 			ws = (ushort*)wp;
23867dd7cddfSDavid du Colombier 			v = *(ushort*)sp;
23877dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, ws++){
23887dd7cddfSDavid du Colombier 				i = x&7;
23897dd7cddfSDavid du Colombier 				if(i == 8-1)
23907dd7cddfSDavid du Colombier 					bits = *q++;
23917dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
23927dd7cddfSDavid du Colombier 				if((bits>>i)&1)
23937dd7cddfSDavid du Colombier 					*ws = v;
23947dd7cddfSDavid du Colombier 			}
23957dd7cddfSDavid du Colombier 			break;
23967dd7cddfSDavid du Colombier 		case 24:
23977dd7cddfSDavid du Colombier 			wc = wp;
23987dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wc+=3){
23997dd7cddfSDavid du Colombier 				i = x&7;
24007dd7cddfSDavid du Colombier 				if(i == 8-1)
24017dd7cddfSDavid du Colombier 					bits = *q++;
24027dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i);
24037dd7cddfSDavid du Colombier 				if((bits>>i)&1){
24047dd7cddfSDavid du Colombier 					wc[0] = sp[0];
24057dd7cddfSDavid du Colombier 					wc[1] = sp[1];
24067dd7cddfSDavid du Colombier 					wc[2] = sp[2];
24077dd7cddfSDavid du Colombier 				}
24087dd7cddfSDavid du Colombier 			}
24097dd7cddfSDavid du Colombier 			break;
24107dd7cddfSDavid du Colombier 		case 32:
24117dd7cddfSDavid du Colombier 			wl = (ulong*)wp;
24127dd7cddfSDavid du Colombier 			v = *(ulong*)sp;
24137dd7cddfSDavid du Colombier 			for(x=bx; x>ex; x--, wl++){
24147dd7cddfSDavid du Colombier 				i = x&7;
24157dd7cddfSDavid du Colombier 				if(i == 8-1)
24167dd7cddfSDavid du Colombier 					bits = *q++;
24177dd7cddfSDavid du Colombier DBG iprint("bits %lux sh %d...", bits, i);
24187dd7cddfSDavid du Colombier 				if((bits>>i)&1)
24197dd7cddfSDavid du Colombier 					*wl = v;
24207dd7cddfSDavid du Colombier 			}
24217dd7cddfSDavid du Colombier 			break;
24227dd7cddfSDavid du Colombier 		}
24237dd7cddfSDavid du Colombier 	}
24247dd7cddfSDavid du Colombier 
24257dd7cddfSDavid du Colombier DBG print("\n");
24267dd7cddfSDavid du Colombier 	return 1;
24277dd7cddfSDavid du Colombier }
24287dd7cddfSDavid du Colombier #undef DBG
24297dd7cddfSDavid du Colombier 
2430*8ccd4a63SDavid du Colombier 
2431*8ccd4a63SDavid du Colombier /*
2432*8ccd4a63SDavid du Colombier  * Fill entire byte with replicated (if necessary) copy of source pixel,
2433*8ccd4a63SDavid du Colombier  * assuming destination ldepth is >= source ldepth.
2434*8ccd4a63SDavid du Colombier  *
2435*8ccd4a63SDavid du Colombier  * This code is just plain wrong for >8bpp.
2436*8ccd4a63SDavid du Colombier  *
2437*8ccd4a63SDavid du Colombier ulong
2438*8ccd4a63SDavid du Colombier membyteval(Memimage *src)
2439*8ccd4a63SDavid du Colombier {
2440*8ccd4a63SDavid du Colombier 	int i, val, bpp;
2441*8ccd4a63SDavid du Colombier 	uchar uc;
2442*8ccd4a63SDavid du Colombier 
2443*8ccd4a63SDavid du Colombier 	unloadmemimage(src, src->r, &uc, 1);
2444*8ccd4a63SDavid du Colombier 	bpp = src->depth;
2445*8ccd4a63SDavid du Colombier 	uc <<= (src->r.min.x&(7/src->depth))*src->depth;
2446*8ccd4a63SDavid du Colombier 	uc &= ~(0xFF>>bpp);
2447*8ccd4a63SDavid du Colombier 	// pixel value is now in high part of byte. repeat throughout byte
2448*8ccd4a63SDavid du Colombier 	val = uc;
2449*8ccd4a63SDavid du Colombier 	for(i=bpp; i<8; i<<=1)
2450*8ccd4a63SDavid du Colombier 		val |= val>>i;
2451*8ccd4a63SDavid du Colombier 	return val;
2452*8ccd4a63SDavid du Colombier }
2453*8ccd4a63SDavid du Colombier  *
2454*8ccd4a63SDavid du Colombier  */
2455*8ccd4a63SDavid du Colombier 
245659cc4ca5SDavid du Colombier void
245759cc4ca5SDavid du Colombier _memfillcolor(Memimage *i, ulong val)
245859cc4ca5SDavid du Colombier {
245959cc4ca5SDavid du Colombier 	ulong bits;
246059cc4ca5SDavid du Colombier 	int d, y;
2461*8ccd4a63SDavid du Colombier 	uchar p[4];
246259cc4ca5SDavid du Colombier 
246359cc4ca5SDavid du Colombier 	if(val == DNofill)
246459cc4ca5SDavid du Colombier 		return;
246559cc4ca5SDavid du Colombier 
246659cc4ca5SDavid du Colombier 	bits = _rgbatoimg(i, val);
246759cc4ca5SDavid du Colombier 	switch(i->depth){
246859cc4ca5SDavid du Colombier 	case 24:	/* 24-bit images suck */
246959cc4ca5SDavid du Colombier 		for(y=i->r.min.y; y<i->r.max.y; y++)
247059cc4ca5SDavid du Colombier 			memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
247159cc4ca5SDavid du Colombier 		break;
247259cc4ca5SDavid du Colombier 	default:	/* 1, 2, 4, 8, 16, 32 */
247359cc4ca5SDavid du Colombier 		for(d=i->depth; d<32; d*=2)
247459cc4ca5SDavid du Colombier 			bits = (bits << d) | bits;
2475*8ccd4a63SDavid du Colombier 		p[0] = bits;		/* make little endian */
2476*8ccd4a63SDavid du Colombier 		p[1] = bits>>8;
2477*8ccd4a63SDavid du Colombier 		p[2] = bits>>16;
2478*8ccd4a63SDavid du Colombier 		p[3] = bits>>24;
2479*8ccd4a63SDavid du Colombier 		bits = *(ulong*)p;
248059cc4ca5SDavid du Colombier 		memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));
248159cc4ca5SDavid du Colombier 		break;
248259cc4ca5SDavid du Colombier 	}
248359cc4ca5SDavid du Colombier }
2484*8ccd4a63SDavid du Colombier 
2485