xref: /plan9/sys/src/cmd/unix/drawterm/libmemdraw/drawtest.c (revision 8ccd4a6360d974db7bd7bbd4f37e7018419ea908)
1*8ccd4a63SDavid du Colombier #include <u.h>
2*8ccd4a63SDavid du Colombier #include <libc.h>
3*8ccd4a63SDavid du Colombier #include <bio.h>
4*8ccd4a63SDavid du Colombier #include <draw.h>
5*8ccd4a63SDavid du Colombier #include <memdraw.h>
6*8ccd4a63SDavid du Colombier 
7*8ccd4a63SDavid du Colombier #define DBG if(0)
8*8ccd4a63SDavid du Colombier #define RGB2K(r,g,b)	((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000)
9*8ccd4a63SDavid du Colombier 
10*8ccd4a63SDavid du Colombier /*
11*8ccd4a63SDavid du Colombier  * This program tests the 'memimagedraw' primitive stochastically.
12*8ccd4a63SDavid du Colombier  * It tests the combination aspects of it thoroughly, but since the
13*8ccd4a63SDavid du Colombier  * three images it uses are disjoint, it makes no check of the
14*8ccd4a63SDavid du Colombier  * correct behavior when images overlap.  That is, however, much
15*8ccd4a63SDavid du Colombier  * easier to get right and to test.
16*8ccd4a63SDavid du Colombier  */
17*8ccd4a63SDavid du Colombier 
18*8ccd4a63SDavid du Colombier void	drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point);
19*8ccd4a63SDavid du Colombier void	verifyone(void);
20*8ccd4a63SDavid du Colombier void	verifyline(void);
21*8ccd4a63SDavid du Colombier void	verifyrect(void);
22*8ccd4a63SDavid du Colombier void	verifyrectrepl(int, int);
23*8ccd4a63SDavid du Colombier void putpixel(Memimage *img, Point pt, ulong nv);
24*8ccd4a63SDavid du Colombier ulong rgbatopix(uchar, uchar, uchar, uchar);
25*8ccd4a63SDavid du Colombier 
26*8ccd4a63SDavid du Colombier char *dchan, *schan, *mchan;
27*8ccd4a63SDavid du Colombier int dbpp, sbpp, mbpp;
28*8ccd4a63SDavid du Colombier 
29*8ccd4a63SDavid du Colombier int drawdebug=0;
30*8ccd4a63SDavid du Colombier int	seed;
31*8ccd4a63SDavid du Colombier int	niters = 100;
32*8ccd4a63SDavid du Colombier int	dbpp;	/* bits per pixel in destination */
33*8ccd4a63SDavid du Colombier int	sbpp;	/* bits per pixel in src */
34*8ccd4a63SDavid du Colombier int	mbpp;	/* bits per pixel in mask */
35*8ccd4a63SDavid du Colombier int	dpm;	/* pixel mask at high part of byte, in destination */
36*8ccd4a63SDavid du Colombier int	nbytes;	/* in destination */
37*8ccd4a63SDavid du Colombier 
38*8ccd4a63SDavid du Colombier int	Xrange	= 64;
39*8ccd4a63SDavid du Colombier int	Yrange	= 8;
40*8ccd4a63SDavid du Colombier 
41*8ccd4a63SDavid du Colombier Memimage	*dst;
42*8ccd4a63SDavid du Colombier Memimage	*src;
43*8ccd4a63SDavid du Colombier Memimage	*mask;
44*8ccd4a63SDavid du Colombier Memimage	*stmp;
45*8ccd4a63SDavid du Colombier Memimage	*mtmp;
46*8ccd4a63SDavid du Colombier Memimage	*ones;
47*8ccd4a63SDavid du Colombier uchar	*dstbits;
48*8ccd4a63SDavid du Colombier uchar	*srcbits;
49*8ccd4a63SDavid du Colombier uchar	*maskbits;
50*8ccd4a63SDavid du Colombier ulong	*savedstbits;
51*8ccd4a63SDavid du Colombier 
52*8ccd4a63SDavid du Colombier void
rdb(void)53*8ccd4a63SDavid du Colombier rdb(void)
54*8ccd4a63SDavid du Colombier {
55*8ccd4a63SDavid du Colombier }
56*8ccd4a63SDavid du Colombier 
57*8ccd4a63SDavid du Colombier int
iprint(char * fmt,...)58*8ccd4a63SDavid du Colombier iprint(char *fmt, ...)
59*8ccd4a63SDavid du Colombier {
60*8ccd4a63SDavid du Colombier 	int n;
61*8ccd4a63SDavid du Colombier 	va_list va;
62*8ccd4a63SDavid du Colombier 	char buf[1024];
63*8ccd4a63SDavid du Colombier 
64*8ccd4a63SDavid du Colombier 	va_start(va, fmt);
65*8ccd4a63SDavid du Colombier 	n = doprint(buf, buf+sizeof buf, fmt, va) - buf;
66*8ccd4a63SDavid du Colombier 	va_end(va);
67*8ccd4a63SDavid du Colombier 
68*8ccd4a63SDavid du Colombier 	write(1,buf,n);
69*8ccd4a63SDavid du Colombier 	return 1;
70*8ccd4a63SDavid du Colombier }
71*8ccd4a63SDavid du Colombier 
72*8ccd4a63SDavid du Colombier void
main(int argc,char * argv[])73*8ccd4a63SDavid du Colombier main(int argc, char *argv[])
74*8ccd4a63SDavid du Colombier {
75*8ccd4a63SDavid du Colombier 	memimageinit();
76*8ccd4a63SDavid du Colombier 	seed = time(0);
77*8ccd4a63SDavid du Colombier 
78*8ccd4a63SDavid du Colombier 	ARGBEGIN{
79*8ccd4a63SDavid du Colombier 	case 'x':
80*8ccd4a63SDavid du Colombier 		Xrange = atoi(ARGF());
81*8ccd4a63SDavid du Colombier 		break;
82*8ccd4a63SDavid du Colombier 	case 'y':
83*8ccd4a63SDavid du Colombier 		Yrange = atoi(ARGF());
84*8ccd4a63SDavid du Colombier 		break;
85*8ccd4a63SDavid du Colombier 	case 'n':
86*8ccd4a63SDavid du Colombier 		niters = atoi(ARGF());
87*8ccd4a63SDavid du Colombier 		break;
88*8ccd4a63SDavid du Colombier 	case 's':
89*8ccd4a63SDavid du Colombier 		seed = atoi(ARGF());
90*8ccd4a63SDavid du Colombier 		break;
91*8ccd4a63SDavid du Colombier 	}ARGEND
92*8ccd4a63SDavid du Colombier 
93*8ccd4a63SDavid du Colombier 	dchan = "r8g8b8";
94*8ccd4a63SDavid du Colombier 	schan = "r8g8b8";
95*8ccd4a63SDavid du Colombier 	mchan = "r8g8b8";
96*8ccd4a63SDavid du Colombier 	switch(argc){
97*8ccd4a63SDavid du Colombier 	case 3:	mchan = argv[2];
98*8ccd4a63SDavid du Colombier 	case 2:	schan = argv[1];
99*8ccd4a63SDavid du Colombier 	case 1:	dchan = argv[0];
100*8ccd4a63SDavid du Colombier 	case 0:	break;
101*8ccd4a63SDavid du Colombier 	default:	goto Usage;
102*8ccd4a63SDavid du Colombier 	Usage:
103*8ccd4a63SDavid du Colombier 		fprint(2, "usage: dtest [dchan [schan [mchan]]]\n");
104*8ccd4a63SDavid du Colombier 		exits("usage");
105*8ccd4a63SDavid du Colombier 	}
106*8ccd4a63SDavid du Colombier 
107*8ccd4a63SDavid du Colombier 	fmtinstall('b', numbconv);	/* binary! */
108*8ccd4a63SDavid du Colombier 
109*8ccd4a63SDavid du Colombier 	fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan);
110*8ccd4a63SDavid du Colombier 	srand(seed);
111*8ccd4a63SDavid du Colombier 
112*8ccd4a63SDavid du Colombier 	dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan));
113*8ccd4a63SDavid du Colombier 	src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
114*8ccd4a63SDavid du Colombier 	mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
115*8ccd4a63SDavid du Colombier 	stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
116*8ccd4a63SDavid du Colombier 	mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
117*8ccd4a63SDavid du Colombier 	ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
118*8ccd4a63SDavid du Colombier //	print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan);
119*8ccd4a63SDavid du Colombier 	if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) {
120*8ccd4a63SDavid du Colombier 	Alloc:
121*8ccd4a63SDavid du Colombier 		fprint(2, "dtest: allocation failed: %r\n");
122*8ccd4a63SDavid du Colombier 		exits("alloc");
123*8ccd4a63SDavid du Colombier 	}
124*8ccd4a63SDavid du Colombier 	nbytes = (4*Xrange+4)*Yrange;
125*8ccd4a63SDavid du Colombier 	srcbits = malloc(nbytes);
126*8ccd4a63SDavid du Colombier 	dstbits = malloc(nbytes);
127*8ccd4a63SDavid du Colombier 	maskbits = malloc(nbytes);
128*8ccd4a63SDavid du Colombier 	savedstbits = malloc(nbytes);
129*8ccd4a63SDavid du Colombier 	if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0)
130*8ccd4a63SDavid du Colombier 		goto Alloc;
131*8ccd4a63SDavid du Colombier 	dbpp = dst->depth;
132*8ccd4a63SDavid du Colombier 	sbpp = src->depth;
133*8ccd4a63SDavid du Colombier 	mbpp = mask->depth;
134*8ccd4a63SDavid du Colombier 	dpm = 0xFF ^ (0xFF>>dbpp);
135*8ccd4a63SDavid du Colombier 	memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange);
136*8ccd4a63SDavid du Colombier 
137*8ccd4a63SDavid du Colombier 
138*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify single pixel operation\n");
139*8ccd4a63SDavid du Colombier 	verifyone();
140*8ccd4a63SDavid du Colombier 
141*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify full line non-replicated\n");
142*8ccd4a63SDavid du Colombier 	verifyline();
143*8ccd4a63SDavid du Colombier 
144*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify full rectangle non-replicated\n");
145*8ccd4a63SDavid du Colombier 	verifyrect();
146*8ccd4a63SDavid du Colombier 
147*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify full rectangle source replicated\n");
148*8ccd4a63SDavid du Colombier 	verifyrectrepl(1, 0);
149*8ccd4a63SDavid du Colombier 
150*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify full rectangle mask replicated\n");
151*8ccd4a63SDavid du Colombier 	verifyrectrepl(0, 1);
152*8ccd4a63SDavid du Colombier 
153*8ccd4a63SDavid du Colombier 	fprint(2, "dtest: verify full rectangle source and mask replicated\n");
154*8ccd4a63SDavid du Colombier 	verifyrectrepl(1, 1);
155*8ccd4a63SDavid du Colombier 
156*8ccd4a63SDavid du Colombier 	exits(0);
157*8ccd4a63SDavid du Colombier }
158*8ccd4a63SDavid du Colombier 
159*8ccd4a63SDavid du Colombier /*
160*8ccd4a63SDavid du Colombier  * Dump out an ASCII representation of an image.  The label specifies
161*8ccd4a63SDavid du Colombier  * a list of characters to put at various points in the picture.
162*8ccd4a63SDavid du Colombier  */
163*8ccd4a63SDavid du Colombier static void
Bprintr5g6b5(Biobuf * bio,char *,ulong v)164*8ccd4a63SDavid du Colombier Bprintr5g6b5(Biobuf *bio, char*, ulong v)
165*8ccd4a63SDavid du Colombier {
166*8ccd4a63SDavid du Colombier 	int r,g,b;
167*8ccd4a63SDavid du Colombier 	r = (v>>11)&31;
168*8ccd4a63SDavid du Colombier 	g = (v>>5)&63;
169*8ccd4a63SDavid du Colombier 	b = v&31;
170*8ccd4a63SDavid du Colombier 	Bprint(bio, "%.2x%.2x%.2x", r,g,b);
171*8ccd4a63SDavid du Colombier }
172*8ccd4a63SDavid du Colombier 
173*8ccd4a63SDavid du Colombier static void
Bprintr5g5b5a1(Biobuf * bio,char *,ulong v)174*8ccd4a63SDavid du Colombier Bprintr5g5b5a1(Biobuf *bio, char*, ulong v)
175*8ccd4a63SDavid du Colombier {
176*8ccd4a63SDavid du Colombier 	int r,g,b,a;
177*8ccd4a63SDavid du Colombier 	r = (v>>11)&31;
178*8ccd4a63SDavid du Colombier 	g = (v>>6)&31;
179*8ccd4a63SDavid du Colombier 	b = (v>>1)&31;
180*8ccd4a63SDavid du Colombier 	a = v&1;
181*8ccd4a63SDavid du Colombier 	Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a);
182*8ccd4a63SDavid du Colombier }
183*8ccd4a63SDavid du Colombier 
184*8ccd4a63SDavid du Colombier void
dumpimage(char * name,Memimage * img,void * vdata,Point labelpt)185*8ccd4a63SDavid du Colombier dumpimage(char *name, Memimage *img, void *vdata, Point labelpt)
186*8ccd4a63SDavid du Colombier {
187*8ccd4a63SDavid du Colombier 	Biobuf b;
188*8ccd4a63SDavid du Colombier 	uchar *data;
189*8ccd4a63SDavid du Colombier 	uchar *p;
190*8ccd4a63SDavid du Colombier 	char *arg;
191*8ccd4a63SDavid du Colombier 	void (*fmt)(Biobuf*, char*, ulong);
192*8ccd4a63SDavid du Colombier 	int npr, x, y, nb, bpp;
193*8ccd4a63SDavid du Colombier 	ulong v, mask;
194*8ccd4a63SDavid du Colombier 	Rectangle r;
195*8ccd4a63SDavid du Colombier 
196*8ccd4a63SDavid du Colombier 	fmt = nil;
197*8ccd4a63SDavid du Colombier 	arg = nil;
198*8ccd4a63SDavid du Colombier 	switch(img->depth){
199*8ccd4a63SDavid du Colombier 	case 1:
200*8ccd4a63SDavid du Colombier 	case 2:
201*8ccd4a63SDavid du Colombier 	case 4:
202*8ccd4a63SDavid du Colombier 		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
203*8ccd4a63SDavid du Colombier 		arg = "%.1ux";
204*8ccd4a63SDavid du Colombier 		break;
205*8ccd4a63SDavid du Colombier 	case 8:
206*8ccd4a63SDavid du Colombier 		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
207*8ccd4a63SDavid du Colombier 		arg = "%.2ux";
208*8ccd4a63SDavid du Colombier 		break;
209*8ccd4a63SDavid du Colombier 	case 16:
210*8ccd4a63SDavid du Colombier 		arg = nil;
211*8ccd4a63SDavid du Colombier 		if(img->chan == RGB16)
212*8ccd4a63SDavid du Colombier 			fmt = Bprintr5g6b5;
213*8ccd4a63SDavid du Colombier 		else{
214*8ccd4a63SDavid du Colombier 			fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
215*8ccd4a63SDavid du Colombier 			arg = "%.4ux";
216*8ccd4a63SDavid du Colombier 		}
217*8ccd4a63SDavid du Colombier 		break;
218*8ccd4a63SDavid du Colombier 	case 24:
219*8ccd4a63SDavid du Colombier 		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
220*8ccd4a63SDavid du Colombier 		arg = "%.6lux";
221*8ccd4a63SDavid du Colombier 		break;
222*8ccd4a63SDavid du Colombier 	case 32:
223*8ccd4a63SDavid du Colombier 		fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
224*8ccd4a63SDavid du Colombier 		arg = "%.8lux";
225*8ccd4a63SDavid du Colombier 		break;
226*8ccd4a63SDavid du Colombier 	}
227*8ccd4a63SDavid du Colombier 	if(fmt == nil){
228*8ccd4a63SDavid du Colombier 		fprint(2, "bad format\n");
229*8ccd4a63SDavid du Colombier 		abort();
230*8ccd4a63SDavid du Colombier 	}
231*8ccd4a63SDavid du Colombier 
232*8ccd4a63SDavid du Colombier 	r  = img->r;
233*8ccd4a63SDavid du Colombier 	Binit(&b, 2, OWRITE);
234*8ccd4a63SDavid du Colombier 	data = vdata;
235*8ccd4a63SDavid du Colombier 	bpp = img->depth;
236*8ccd4a63SDavid du Colombier 	Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt);
237*8ccd4a63SDavid du Colombier 	mask = (1ULL<<bpp)-1;
238*8ccd4a63SDavid du Colombier //	for(y=r.min.y; y<r.max.y; y++){
239*8ccd4a63SDavid du Colombier 	for(y=0; y<Yrange; y++){
240*8ccd4a63SDavid du Colombier 		nb = 0;
241*8ccd4a63SDavid du Colombier 		v = 0;
242*8ccd4a63SDavid du Colombier 		p = data+(byteaddr(img, Pt(0,y))-(uchar*)img->data->bdata);
243*8ccd4a63SDavid du Colombier 		Bprint(&b, "%-4d\t", y);
244*8ccd4a63SDavid du Colombier //		for(x=r.min.x; x<r.max.x; x++){
245*8ccd4a63SDavid du Colombier 		for(x=0; x<Xrange; x++){
246*8ccd4a63SDavid du Colombier 			if(x==0)
247*8ccd4a63SDavid du Colombier 				Bprint(&b, "\t");
248*8ccd4a63SDavid du Colombier 
249*8ccd4a63SDavid du Colombier 			if(x != 0 && (x%8)==0)
250*8ccd4a63SDavid du Colombier 				Bprint(&b, " ");
251*8ccd4a63SDavid du Colombier 
252*8ccd4a63SDavid du Colombier 			npr = 0;
253*8ccd4a63SDavid du Colombier 			if(x==labelpt.x && y==labelpt.y){
254*8ccd4a63SDavid du Colombier 				Bprint(&b, "*");
255*8ccd4a63SDavid du Colombier 				npr++;
256*8ccd4a63SDavid du Colombier 			}
257*8ccd4a63SDavid du Colombier 			if(npr == 0)
258*8ccd4a63SDavid du Colombier 				Bprint(&b, " ");
259*8ccd4a63SDavid du Colombier 
260*8ccd4a63SDavid du Colombier 			while(nb < bpp){
261*8ccd4a63SDavid du Colombier 				v &= (1<<nb)-1;
262*8ccd4a63SDavid du Colombier 				v |= (ulong)(*p++) << nb;
263*8ccd4a63SDavid du Colombier 				nb += 8;
264*8ccd4a63SDavid du Colombier 			}
265*8ccd4a63SDavid du Colombier 			nb -= bpp;
266*8ccd4a63SDavid du Colombier //			print("bpp %d v %.8lux mask %.8lux nb %d\n", bpp, v, mask, nb);
267*8ccd4a63SDavid du Colombier 			fmt(&b, arg, (v>>nb)&mask);
268*8ccd4a63SDavid du Colombier 		}
269*8ccd4a63SDavid du Colombier 		Bprint(&b, "\n");
270*8ccd4a63SDavid du Colombier 	}
271*8ccd4a63SDavid du Colombier 	Bterm(&b);
272*8ccd4a63SDavid du Colombier }
273*8ccd4a63SDavid du Colombier 
274*8ccd4a63SDavid du Colombier /*
275*8ccd4a63SDavid du Colombier  * Verify that the destination pixel has the specified value.
276*8ccd4a63SDavid du Colombier  * The value is in the high bits of v, suitably masked, but must
277*8ccd4a63SDavid du Colombier  * be extracted from the destination Memimage.
278*8ccd4a63SDavid du Colombier  */
279*8ccd4a63SDavid du Colombier void
checkone(Point p,Point sp,Point mp)280*8ccd4a63SDavid du Colombier checkone(Point p, Point sp, Point mp)
281*8ccd4a63SDavid du Colombier {
282*8ccd4a63SDavid du Colombier 	int delta;
283*8ccd4a63SDavid du Colombier 	uchar *dp, *sdp;
284*8ccd4a63SDavid du Colombier 
285*8ccd4a63SDavid du Colombier 	delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata;
286*8ccd4a63SDavid du Colombier 	dp = (uchar*)dst->data->bdata+delta;
287*8ccd4a63SDavid du Colombier 	sdp = (uchar*)savedstbits+delta;
288*8ccd4a63SDavid du Colombier 
289*8ccd4a63SDavid du Colombier 	if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) {
290*8ccd4a63SDavid du Colombier 		fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp);
291*8ccd4a63SDavid du Colombier 		fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n",
292*8ccd4a63SDavid du Colombier 			dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]);
293*8ccd4a63SDavid du Colombier 		fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp));
294*8ccd4a63SDavid du Colombier 		dumpimage("src", src, src->data->bdata, sp);
295*8ccd4a63SDavid du Colombier 		dumpimage("mask", mask, mask->data->bdata, mp);
296*8ccd4a63SDavid du Colombier 		dumpimage("origdst", dst, dstbits, p);
297*8ccd4a63SDavid du Colombier 		dumpimage("dst", dst, dst->data->bdata, p);
298*8ccd4a63SDavid du Colombier 		dumpimage("gooddst", dst, savedstbits, p);
299*8ccd4a63SDavid du Colombier 		abort();
300*8ccd4a63SDavid du Colombier 	}
301*8ccd4a63SDavid du Colombier }
302*8ccd4a63SDavid du Colombier 
303*8ccd4a63SDavid du Colombier /*
304*8ccd4a63SDavid du Colombier  * Verify that the destination line has the same value as the saved line.
305*8ccd4a63SDavid du Colombier  */
306*8ccd4a63SDavid du Colombier #define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
307*8ccd4a63SDavid du Colombier void
checkline(Rectangle r,Point sp,Point mp,int y,Memimage * stmp,Memimage * mtmp)308*8ccd4a63SDavid du Colombier checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp)
309*8ccd4a63SDavid du Colombier {
310*8ccd4a63SDavid du Colombier 	ulong *dp;
311*8ccd4a63SDavid du Colombier 	int nb;
312*8ccd4a63SDavid du Colombier 	ulong *saved;
313*8ccd4a63SDavid du Colombier 
314*8ccd4a63SDavid du Colombier 	dp = wordaddr(dst, Pt(0, y));
315*8ccd4a63SDavid du Colombier 	saved = savedstbits + y*dst->width;
316*8ccd4a63SDavid du Colombier 	if(dst->depth < 8)
317*8ccd4a63SDavid du Colombier 		nb = Xrange/(8/dst->depth);
318*8ccd4a63SDavid du Colombier 	else
319*8ccd4a63SDavid du Colombier 		nb = Xrange*(dst->depth/8);
320*8ccd4a63SDavid du Colombier 	if(memcmp(dp, saved, nb) != 0){
321*8ccd4a63SDavid du Colombier 		fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp);
322*8ccd4a63SDavid du Colombier 		fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp);
323*8ccd4a63SDavid du Colombier 		dumpimage("src", src, src->data->bdata, sp);
324*8ccd4a63SDavid du Colombier 		if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp);
325*8ccd4a63SDavid du Colombier 		dumpimage("mask", mask, mask->data->bdata, mp);
326*8ccd4a63SDavid du Colombier 		if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp);
327*8ccd4a63SDavid du Colombier 		dumpimage("origdst", dst, dstbits, r.min);
328*8ccd4a63SDavid du Colombier 		dumpimage("dst", dst, dst->data->bdata, r.min);
329*8ccd4a63SDavid du Colombier 		dumpimage("gooddst", dst, savedstbits, r.min);
330*8ccd4a63SDavid du Colombier 		abort();
331*8ccd4a63SDavid du Colombier 	}
332*8ccd4a63SDavid du Colombier }
333*8ccd4a63SDavid du Colombier 
334*8ccd4a63SDavid du Colombier /*
335*8ccd4a63SDavid du Colombier  * Fill the bits of an image with random data.
336*8ccd4a63SDavid du Colombier  * The Memimage parameter is used only to make sure
337*8ccd4a63SDavid du Colombier  * the data is well formatted: only ucbits is written.
338*8ccd4a63SDavid du Colombier  */
339*8ccd4a63SDavid du Colombier void
fill(Memimage * img,uchar * ucbits)340*8ccd4a63SDavid du Colombier fill(Memimage *img, uchar *ucbits)
341*8ccd4a63SDavid du Colombier {
342*8ccd4a63SDavid du Colombier 	int i, x, y;
343*8ccd4a63SDavid du Colombier 	ushort *up;
344*8ccd4a63SDavid du Colombier 	uchar alpha, r, g, b;
345*8ccd4a63SDavid du Colombier 	void *data;
346*8ccd4a63SDavid du Colombier 
347*8ccd4a63SDavid du Colombier 	if((img->flags&Falpha) == 0){
348*8ccd4a63SDavid du Colombier 		up = (ushort*)ucbits;
349*8ccd4a63SDavid du Colombier 		for(i=0; i<nbytes/2; i++)
350*8ccd4a63SDavid du Colombier 			*up++ = lrand() >> 7;
351*8ccd4a63SDavid du Colombier 		if(i+i != nbytes)
352*8ccd4a63SDavid du Colombier 			*(uchar*)up = lrand() >> 7;
353*8ccd4a63SDavid du Colombier 	}else{
354*8ccd4a63SDavid du Colombier 		data = img->data->bdata;
355*8ccd4a63SDavid du Colombier 		img->data->bdata = ucbits;
356*8ccd4a63SDavid du Colombier 
357*8ccd4a63SDavid du Colombier 		for(x=img->r.min.x; x<img->r.max.x; x++)
358*8ccd4a63SDavid du Colombier 		for(y=img->r.min.y; y<img->r.max.y; y++){
359*8ccd4a63SDavid du Colombier 			alpha = rand() >> 4;
360*8ccd4a63SDavid du Colombier 			r = rand()%(alpha+1);
361*8ccd4a63SDavid du Colombier 			g = rand()%(alpha+1);
362*8ccd4a63SDavid du Colombier 			b = rand()%(alpha+1);
363*8ccd4a63SDavid du Colombier 			putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha));
364*8ccd4a63SDavid du Colombier 		}
365*8ccd4a63SDavid du Colombier 		img->data->bdata = data;
366*8ccd4a63SDavid du Colombier 	}
367*8ccd4a63SDavid du Colombier 
368*8ccd4a63SDavid du Colombier }
369*8ccd4a63SDavid du Colombier 
370*8ccd4a63SDavid du Colombier /*
371*8ccd4a63SDavid du Colombier  * Mask is preset; do the rest
372*8ccd4a63SDavid du Colombier  */
373*8ccd4a63SDavid du Colombier void
verifyonemask(void)374*8ccd4a63SDavid du Colombier verifyonemask(void)
375*8ccd4a63SDavid du Colombier {
376*8ccd4a63SDavid du Colombier 	Point dp, sp, mp;
377*8ccd4a63SDavid du Colombier 
378*8ccd4a63SDavid du Colombier 	fill(dst, dstbits);
379*8ccd4a63SDavid du Colombier 	fill(src, srcbits);
380*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
381*8ccd4a63SDavid du Colombier 	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
382*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
383*8ccd4a63SDavid du Colombier 
384*8ccd4a63SDavid du Colombier 	dp.x = nrand(Xrange);
385*8ccd4a63SDavid du Colombier 	dp.y = nrand(Yrange);
386*8ccd4a63SDavid du Colombier 
387*8ccd4a63SDavid du Colombier 	sp.x = nrand(Xrange);
388*8ccd4a63SDavid du Colombier 	sp.y = nrand(Yrange);
389*8ccd4a63SDavid du Colombier 
390*8ccd4a63SDavid du Colombier 	mp.x = nrand(Xrange);
391*8ccd4a63SDavid du Colombier 	mp.y = nrand(Yrange);
392*8ccd4a63SDavid du Colombier 
393*8ccd4a63SDavid du Colombier 	drawonepixel(dst, dp, src, sp, mask, mp);
394*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
395*8ccd4a63SDavid du Colombier 	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
396*8ccd4a63SDavid du Colombier 
397*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
398*8ccd4a63SDavid du Colombier 	memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD);
399*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
400*8ccd4a63SDavid du Colombier 
401*8ccd4a63SDavid du Colombier 	checkone(dp, sp, mp);
402*8ccd4a63SDavid du Colombier }
403*8ccd4a63SDavid du Colombier 
404*8ccd4a63SDavid du Colombier void
verifyone(void)405*8ccd4a63SDavid du Colombier verifyone(void)
406*8ccd4a63SDavid du Colombier {
407*8ccd4a63SDavid du Colombier 	int i;
408*8ccd4a63SDavid du Colombier 
409*8ccd4a63SDavid du Colombier 	/* mask all zeros */
410*8ccd4a63SDavid du Colombier 	memset(maskbits, 0, nbytes);
411*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
412*8ccd4a63SDavid du Colombier 		verifyonemask();
413*8ccd4a63SDavid du Colombier 
414*8ccd4a63SDavid du Colombier 	/* mask all ones */
415*8ccd4a63SDavid du Colombier 	memset(maskbits, 0xFF, nbytes);
416*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
417*8ccd4a63SDavid du Colombier 		verifyonemask();
418*8ccd4a63SDavid du Colombier 
419*8ccd4a63SDavid du Colombier 	/* random mask */
420*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++){
421*8ccd4a63SDavid du Colombier 		fill(mask, maskbits);
422*8ccd4a63SDavid du Colombier 		verifyonemask();
423*8ccd4a63SDavid du Colombier 	}
424*8ccd4a63SDavid du Colombier }
425*8ccd4a63SDavid du Colombier 
426*8ccd4a63SDavid du Colombier /*
427*8ccd4a63SDavid du Colombier  * Mask is preset; do the rest
428*8ccd4a63SDavid du Colombier  */
429*8ccd4a63SDavid du Colombier void
verifylinemask(void)430*8ccd4a63SDavid du Colombier verifylinemask(void)
431*8ccd4a63SDavid du Colombier {
432*8ccd4a63SDavid du Colombier 	Point sp, mp, tp, up;
433*8ccd4a63SDavid du Colombier 	Rectangle dr;
434*8ccd4a63SDavid du Colombier 	int x;
435*8ccd4a63SDavid du Colombier 
436*8ccd4a63SDavid du Colombier 	fill(dst, dstbits);
437*8ccd4a63SDavid du Colombier 	fill(src, srcbits);
438*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
439*8ccd4a63SDavid du Colombier 	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
440*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
441*8ccd4a63SDavid du Colombier 
442*8ccd4a63SDavid du Colombier 	dr.min.x = nrand(Xrange-1);
443*8ccd4a63SDavid du Colombier 	dr.min.y = nrand(Yrange-1);
444*8ccd4a63SDavid du Colombier 	dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
445*8ccd4a63SDavid du Colombier 	dr.max.y = dr.min.y + 1;
446*8ccd4a63SDavid du Colombier 
447*8ccd4a63SDavid du Colombier 	sp.x = nrand(Xrange);
448*8ccd4a63SDavid du Colombier 	sp.y = nrand(Yrange);
449*8ccd4a63SDavid du Colombier 
450*8ccd4a63SDavid du Colombier 	mp.x = nrand(Xrange);
451*8ccd4a63SDavid du Colombier 	mp.y = nrand(Yrange);
452*8ccd4a63SDavid du Colombier 
453*8ccd4a63SDavid du Colombier 	tp = sp;
454*8ccd4a63SDavid du Colombier 	up = mp;
455*8ccd4a63SDavid du Colombier 	for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
456*8ccd4a63SDavid du Colombier 		memimagedraw(dst, Rect(x, dr.min.y, x+1, dr.min.y+1), src, tp, mask, up, SoverD);
457*8ccd4a63SDavid du Colombier 	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
458*8ccd4a63SDavid du Colombier 
459*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
460*8ccd4a63SDavid du Colombier 
461*8ccd4a63SDavid du Colombier 	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
462*8ccd4a63SDavid du Colombier 	checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil);
463*8ccd4a63SDavid du Colombier }
464*8ccd4a63SDavid du Colombier 
465*8ccd4a63SDavid du Colombier void
verifyline(void)466*8ccd4a63SDavid du Colombier verifyline(void)
467*8ccd4a63SDavid du Colombier {
468*8ccd4a63SDavid du Colombier 	int i;
469*8ccd4a63SDavid du Colombier 
470*8ccd4a63SDavid du Colombier 	/* mask all ones */
471*8ccd4a63SDavid du Colombier 	memset(maskbits, 0xFF, nbytes);
472*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
473*8ccd4a63SDavid du Colombier 		verifylinemask();
474*8ccd4a63SDavid du Colombier 
475*8ccd4a63SDavid du Colombier 	/* mask all zeros */
476*8ccd4a63SDavid du Colombier 	memset(maskbits, 0, nbytes);
477*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
478*8ccd4a63SDavid du Colombier 		verifylinemask();
479*8ccd4a63SDavid du Colombier 
480*8ccd4a63SDavid du Colombier 	/* random mask */
481*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++){
482*8ccd4a63SDavid du Colombier 		fill(mask, maskbits);
483*8ccd4a63SDavid du Colombier 		verifylinemask();
484*8ccd4a63SDavid du Colombier 	}
485*8ccd4a63SDavid du Colombier }
486*8ccd4a63SDavid du Colombier 
487*8ccd4a63SDavid du Colombier /*
488*8ccd4a63SDavid du Colombier  * Mask is preset; do the rest
489*8ccd4a63SDavid du Colombier  */
490*8ccd4a63SDavid du Colombier void
verifyrectmask(void)491*8ccd4a63SDavid du Colombier verifyrectmask(void)
492*8ccd4a63SDavid du Colombier {
493*8ccd4a63SDavid du Colombier 	Point sp, mp, tp, up;
494*8ccd4a63SDavid du Colombier 	Rectangle dr;
495*8ccd4a63SDavid du Colombier 	int x, y;
496*8ccd4a63SDavid du Colombier 
497*8ccd4a63SDavid du Colombier 	fill(dst, dstbits);
498*8ccd4a63SDavid du Colombier 	fill(src, srcbits);
499*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
500*8ccd4a63SDavid du Colombier 	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
501*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
502*8ccd4a63SDavid du Colombier 
503*8ccd4a63SDavid du Colombier 	dr.min.x = nrand(Xrange-1);
504*8ccd4a63SDavid du Colombier 	dr.min.y = nrand(Yrange-1);
505*8ccd4a63SDavid du Colombier 	dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
506*8ccd4a63SDavid du Colombier 	dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y);
507*8ccd4a63SDavid du Colombier 
508*8ccd4a63SDavid du Colombier 	sp.x = nrand(Xrange);
509*8ccd4a63SDavid du Colombier 	sp.y = nrand(Yrange);
510*8ccd4a63SDavid du Colombier 
511*8ccd4a63SDavid du Colombier 	mp.x = nrand(Xrange);
512*8ccd4a63SDavid du Colombier 	mp.y = nrand(Yrange);
513*8ccd4a63SDavid du Colombier 
514*8ccd4a63SDavid du Colombier 	tp = sp;
515*8ccd4a63SDavid du Colombier 	up = mp;
516*8ccd4a63SDavid du Colombier 	for(y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++){
517*8ccd4a63SDavid du Colombier 		for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
518*8ccd4a63SDavid du Colombier 			memimagedraw(dst, Rect(x, y, x+1, y+1), src, tp, mask, up, SoverD);
519*8ccd4a63SDavid du Colombier 		tp.x = sp.x;
520*8ccd4a63SDavid du Colombier 		up.x = mp.x;
521*8ccd4a63SDavid du Colombier 	}
522*8ccd4a63SDavid du Colombier 	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
523*8ccd4a63SDavid du Colombier 
524*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
525*8ccd4a63SDavid du Colombier 
526*8ccd4a63SDavid du Colombier 	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
527*8ccd4a63SDavid du Colombier 	for(y=0; y<Yrange; y++)
528*8ccd4a63SDavid du Colombier 		checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, nil, nil);
529*8ccd4a63SDavid du Colombier }
530*8ccd4a63SDavid du Colombier 
531*8ccd4a63SDavid du Colombier void
verifyrect(void)532*8ccd4a63SDavid du Colombier verifyrect(void)
533*8ccd4a63SDavid du Colombier {
534*8ccd4a63SDavid du Colombier 	int i;
535*8ccd4a63SDavid du Colombier 
536*8ccd4a63SDavid du Colombier 	/* mask all zeros */
537*8ccd4a63SDavid du Colombier 	memset(maskbits, 0, nbytes);
538*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
539*8ccd4a63SDavid du Colombier 		verifyrectmask();
540*8ccd4a63SDavid du Colombier 
541*8ccd4a63SDavid du Colombier 	/* mask all ones */
542*8ccd4a63SDavid du Colombier 	memset(maskbits, 0xFF, nbytes);
543*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
544*8ccd4a63SDavid du Colombier 		verifyrectmask();
545*8ccd4a63SDavid du Colombier 
546*8ccd4a63SDavid du Colombier 	/* random mask */
547*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++){
548*8ccd4a63SDavid du Colombier 		fill(mask, maskbits);
549*8ccd4a63SDavid du Colombier 		verifyrectmask();
550*8ccd4a63SDavid du Colombier 	}
551*8ccd4a63SDavid du Colombier }
552*8ccd4a63SDavid du Colombier 
553*8ccd4a63SDavid du Colombier Rectangle
randrect(void)554*8ccd4a63SDavid du Colombier randrect(void)
555*8ccd4a63SDavid du Colombier {
556*8ccd4a63SDavid du Colombier 	Rectangle r;
557*8ccd4a63SDavid du Colombier 
558*8ccd4a63SDavid du Colombier 	r.min.x = nrand(Xrange-1);
559*8ccd4a63SDavid du Colombier 	r.min.y = nrand(Yrange-1);
560*8ccd4a63SDavid du Colombier 	r.max.x = r.min.x + 1 + nrand(Xrange-1-r.min.x);
561*8ccd4a63SDavid du Colombier 	r.max.y = r.min.y + 1 + nrand(Yrange-1-r.min.y);
562*8ccd4a63SDavid du Colombier 	return r;
563*8ccd4a63SDavid du Colombier }
564*8ccd4a63SDavid du Colombier 
565*8ccd4a63SDavid du Colombier /*
566*8ccd4a63SDavid du Colombier  * Return coordinate corresponding to x withing range [minx, maxx)
567*8ccd4a63SDavid du Colombier  */
568*8ccd4a63SDavid du Colombier int
tilexy(int minx,int maxx,int x)569*8ccd4a63SDavid du Colombier tilexy(int minx, int maxx, int x)
570*8ccd4a63SDavid du Colombier {
571*8ccd4a63SDavid du Colombier 	int sx;
572*8ccd4a63SDavid du Colombier 
573*8ccd4a63SDavid du Colombier 	sx = (x-minx) % (maxx-minx);
574*8ccd4a63SDavid du Colombier 	if(sx < 0)
575*8ccd4a63SDavid du Colombier 		sx += maxx-minx;
576*8ccd4a63SDavid du Colombier 	return sx+minx;
577*8ccd4a63SDavid du Colombier }
578*8ccd4a63SDavid du Colombier 
579*8ccd4a63SDavid du Colombier void
replicate(Memimage * i,Memimage * tmp)580*8ccd4a63SDavid du Colombier replicate(Memimage *i, Memimage *tmp)
581*8ccd4a63SDavid du Colombier {
582*8ccd4a63SDavid du Colombier 	Rectangle r, r1;
583*8ccd4a63SDavid du Colombier 	int x, y, nb;
584*8ccd4a63SDavid du Colombier 
585*8ccd4a63SDavid du Colombier 	/* choose the replication window (i->r) */
586*8ccd4a63SDavid du Colombier 	r.min.x = nrand(Xrange-1);
587*8ccd4a63SDavid du Colombier 	r.min.y = nrand(Yrange-1);
588*8ccd4a63SDavid du Colombier 	/* make it trivial more often than pure chance allows */
589*8ccd4a63SDavid du Colombier 	switch(lrand()&0){
590*8ccd4a63SDavid du Colombier 	case 1:
591*8ccd4a63SDavid du Colombier 		r.max.x = r.min.x + 2;
592*8ccd4a63SDavid du Colombier 		r.max.y = r.min.y + 2;
593*8ccd4a63SDavid du Colombier 		if(r.max.x < Xrange && r.max.y < Yrange)
594*8ccd4a63SDavid du Colombier 			break;
595*8ccd4a63SDavid du Colombier 		/* fall through */
596*8ccd4a63SDavid du Colombier 	case 0:
597*8ccd4a63SDavid du Colombier 		r.max.x = r.min.x + 1;
598*8ccd4a63SDavid du Colombier 		r.max.y = r.min.y + 1;
599*8ccd4a63SDavid du Colombier 		break;
600*8ccd4a63SDavid du Colombier 	default:
601*8ccd4a63SDavid du Colombier 		if(r.min.x+3 >= Xrange)
602*8ccd4a63SDavid du Colombier 			r.max.x = Xrange;
603*8ccd4a63SDavid du Colombier 		else
604*8ccd4a63SDavid du Colombier 			r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3));
605*8ccd4a63SDavid du Colombier 
606*8ccd4a63SDavid du Colombier 		if(r.min.y+3 >= Yrange)
607*8ccd4a63SDavid du Colombier 			r.max.y = Yrange;
608*8ccd4a63SDavid du Colombier 		else
609*8ccd4a63SDavid du Colombier 			r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3));
610*8ccd4a63SDavid du Colombier 	}
611*8ccd4a63SDavid du Colombier 	assert(r.min.x >= 0);
612*8ccd4a63SDavid du Colombier 	assert(r.max.x <= Xrange);
613*8ccd4a63SDavid du Colombier 	assert(r.min.y >= 0);
614*8ccd4a63SDavid du Colombier 	assert(r.max.y <= Yrange);
615*8ccd4a63SDavid du Colombier 	/* copy from i to tmp so we have just the replicated bits */
616*8ccd4a63SDavid du Colombier 	nb = tmp->width*sizeof(ulong)*Yrange;
617*8ccd4a63SDavid du Colombier 	memset(tmp->data->bdata, 0, nb);
618*8ccd4a63SDavid du Colombier 	memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD);
619*8ccd4a63SDavid du Colombier 	memmove(i->data->bdata, tmp->data->bdata, nb);
620*8ccd4a63SDavid du Colombier 	/* i is now a non-replicated instance of the replication */
621*8ccd4a63SDavid du Colombier 	/* replicate it by hand through tmp */
622*8ccd4a63SDavid du Colombier 	memset(tmp->data->bdata, 0, nb);
623*8ccd4a63SDavid du Colombier 	x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x);
624*8ccd4a63SDavid du Colombier 	for(; x<Xrange; x+=Dx(r)){
625*8ccd4a63SDavid du Colombier 		y = -(tilexy(r.min.y, r.max.y, 0)-r.min.y);
626*8ccd4a63SDavid du Colombier 		for(; y<Yrange; y+=Dy(r)){
627*8ccd4a63SDavid du Colombier 			/* set r1 to instance of tile by translation */
628*8ccd4a63SDavid du Colombier 			r1.min.x = x;
629*8ccd4a63SDavid du Colombier 			r1.min.y = y;
630*8ccd4a63SDavid du Colombier 			r1.max.x = r1.min.x+Dx(r);
631*8ccd4a63SDavid du Colombier 			r1.max.y = r1.min.y+Dy(r);
632*8ccd4a63SDavid du Colombier 			memimagedraw(tmp, r1, i, r.min, ones, r.min, SoverD);
633*8ccd4a63SDavid du Colombier 		}
634*8ccd4a63SDavid du Colombier 	}
635*8ccd4a63SDavid du Colombier 	i->flags |= Frepl;
636*8ccd4a63SDavid du Colombier 	i->r = r;
637*8ccd4a63SDavid du Colombier 	i->clipr = randrect();
638*8ccd4a63SDavid du Colombier //	fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y,
639*8ccd4a63SDavid du Colombier //		i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
640*8ccd4a63SDavid du Colombier 	tmp->clipr = i->clipr;
641*8ccd4a63SDavid du Colombier }
642*8ccd4a63SDavid du Colombier 
643*8ccd4a63SDavid du Colombier /*
644*8ccd4a63SDavid du Colombier  * Mask is preset; do the rest
645*8ccd4a63SDavid du Colombier  */
646*8ccd4a63SDavid du Colombier void
verifyrectmaskrepl(int srcrepl,int maskrepl)647*8ccd4a63SDavid du Colombier verifyrectmaskrepl(int srcrepl, int maskrepl)
648*8ccd4a63SDavid du Colombier {
649*8ccd4a63SDavid du Colombier 	Point sp, mp, tp, up;
650*8ccd4a63SDavid du Colombier 	Rectangle dr;
651*8ccd4a63SDavid du Colombier 	int x, y;
652*8ccd4a63SDavid du Colombier 	Memimage *s, *m;
653*8ccd4a63SDavid du Colombier 
654*8ccd4a63SDavid du Colombier //	print("verfrect %d %d\n", srcrepl, maskrepl);
655*8ccd4a63SDavid du Colombier 	src->flags &= ~Frepl;
656*8ccd4a63SDavid du Colombier 	src->r = Rect(0, 0, Xrange, Yrange);
657*8ccd4a63SDavid du Colombier 	src->clipr = src->r;
658*8ccd4a63SDavid du Colombier 	stmp->flags &= ~Frepl;
659*8ccd4a63SDavid du Colombier 	stmp->r = Rect(0, 0, Xrange, Yrange);
660*8ccd4a63SDavid du Colombier 	stmp->clipr = src->r;
661*8ccd4a63SDavid du Colombier 	mask->flags &= ~Frepl;
662*8ccd4a63SDavid du Colombier 	mask->r = Rect(0, 0, Xrange, Yrange);
663*8ccd4a63SDavid du Colombier 	mask->clipr = mask->r;
664*8ccd4a63SDavid du Colombier 	mtmp->flags &= ~Frepl;
665*8ccd4a63SDavid du Colombier 	mtmp->r = Rect(0, 0, Xrange, Yrange);
666*8ccd4a63SDavid du Colombier 	mtmp->clipr = mask->r;
667*8ccd4a63SDavid du Colombier 
668*8ccd4a63SDavid du Colombier 	fill(dst, dstbits);
669*8ccd4a63SDavid du Colombier 	fill(src, srcbits);
670*8ccd4a63SDavid du Colombier 
671*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
672*8ccd4a63SDavid du Colombier 	memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
673*8ccd4a63SDavid du Colombier 	memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
674*8ccd4a63SDavid du Colombier 
675*8ccd4a63SDavid du Colombier 	if(srcrepl){
676*8ccd4a63SDavid du Colombier 		replicate(src, stmp);
677*8ccd4a63SDavid du Colombier 		s = stmp;
678*8ccd4a63SDavid du Colombier 	}else
679*8ccd4a63SDavid du Colombier 		s = src;
680*8ccd4a63SDavid du Colombier 	if(maskrepl){
681*8ccd4a63SDavid du Colombier 		replicate(mask, mtmp);
682*8ccd4a63SDavid du Colombier 		m = mtmp;
683*8ccd4a63SDavid du Colombier 	}else
684*8ccd4a63SDavid du Colombier 		m = mask;
685*8ccd4a63SDavid du Colombier 
686*8ccd4a63SDavid du Colombier 	dr = randrect();
687*8ccd4a63SDavid du Colombier 
688*8ccd4a63SDavid du Colombier 	sp.x = nrand(Xrange);
689*8ccd4a63SDavid du Colombier 	sp.y = nrand(Yrange);
690*8ccd4a63SDavid du Colombier 
691*8ccd4a63SDavid du Colombier 	mp.x = nrand(Xrange);
692*8ccd4a63SDavid du Colombier 	mp.y = nrand(Yrange);
693*8ccd4a63SDavid du Colombier 
694*8ccd4a63SDavid du Colombier DBG	print("smalldraws\n");
695*8ccd4a63SDavid du Colombier 	for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++)
696*8ccd4a63SDavid du Colombier 		for(tp.x=sp.x,up.x=mp.x,x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
697*8ccd4a63SDavid du Colombier 			memimagedraw(dst, Rect(x, y, x+1, y+1), s, tp, m, up, SoverD);
698*8ccd4a63SDavid du Colombier 	memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
699*8ccd4a63SDavid du Colombier 
700*8ccd4a63SDavid du Colombier 	memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
701*8ccd4a63SDavid du Colombier 
702*8ccd4a63SDavid du Colombier DBG	print("bigdraw\n");
703*8ccd4a63SDavid du Colombier 	memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
704*8ccd4a63SDavid du Colombier 	for(y=0; y<Yrange; y++)
705*8ccd4a63SDavid du Colombier 		checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil);
706*8ccd4a63SDavid du Colombier }
707*8ccd4a63SDavid du Colombier 
708*8ccd4a63SDavid du Colombier void
verifyrectrepl(int srcrepl,int maskrepl)709*8ccd4a63SDavid du Colombier verifyrectrepl(int srcrepl, int maskrepl)
710*8ccd4a63SDavid du Colombier {
711*8ccd4a63SDavid du Colombier 	int i;
712*8ccd4a63SDavid du Colombier 
713*8ccd4a63SDavid du Colombier 	/* mask all ones */
714*8ccd4a63SDavid du Colombier 	memset(maskbits, 0xFF, nbytes);
715*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
716*8ccd4a63SDavid du Colombier 		verifyrectmaskrepl(srcrepl, maskrepl);
717*8ccd4a63SDavid du Colombier 
718*8ccd4a63SDavid du Colombier 	/* mask all zeros */
719*8ccd4a63SDavid du Colombier 	memset(maskbits, 0, nbytes);
720*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++)
721*8ccd4a63SDavid du Colombier 		verifyrectmaskrepl(srcrepl, maskrepl);
722*8ccd4a63SDavid du Colombier 
723*8ccd4a63SDavid du Colombier 	/* random mask */
724*8ccd4a63SDavid du Colombier 	for(i=0; i<niters; i++){
725*8ccd4a63SDavid du Colombier 		fill(mask, maskbits);
726*8ccd4a63SDavid du Colombier 		verifyrectmaskrepl(srcrepl, maskrepl);
727*8ccd4a63SDavid du Colombier 	}
728*8ccd4a63SDavid du Colombier }
729*8ccd4a63SDavid du Colombier 
730*8ccd4a63SDavid du Colombier /*
731*8ccd4a63SDavid du Colombier  * Trivial draw implementation.
732*8ccd4a63SDavid du Colombier  * Color values are passed around as ulongs containing ααRRGGBB
733*8ccd4a63SDavid du Colombier  */
734*8ccd4a63SDavid du Colombier 
735*8ccd4a63SDavid du Colombier /*
736*8ccd4a63SDavid du Colombier  * Convert v, which is nhave bits wide, into its nwant bits wide equivalent.
737*8ccd4a63SDavid du Colombier  * Replicates to widen the value, truncates to narrow it.
738*8ccd4a63SDavid du Colombier  */
739*8ccd4a63SDavid du Colombier ulong
replbits(ulong v,int nhave,int nwant)740*8ccd4a63SDavid du Colombier replbits(ulong v, int nhave, int nwant)
741*8ccd4a63SDavid du Colombier {
742*8ccd4a63SDavid du Colombier 	v &= (1<<nhave)-1;
743*8ccd4a63SDavid du Colombier 	for(; nhave<nwant; nhave*=2)
744*8ccd4a63SDavid du Colombier 		v |= v<<nhave;
745*8ccd4a63SDavid du Colombier 	v >>= (nhave-nwant);
746*8ccd4a63SDavid du Colombier 	return v & ((1<<nwant)-1);
747*8ccd4a63SDavid du Colombier }
748*8ccd4a63SDavid du Colombier 
749*8ccd4a63SDavid du Colombier /*
750*8ccd4a63SDavid du Colombier  * Decode a pixel into the uchar* values.
751*8ccd4a63SDavid du Colombier  */
752*8ccd4a63SDavid du Colombier void
pixtorgba(ulong v,uchar * r,uchar * g,uchar * b,uchar * a)753*8ccd4a63SDavid du Colombier pixtorgba(ulong v, uchar *r, uchar *g, uchar *b, uchar *a)
754*8ccd4a63SDavid du Colombier {
755*8ccd4a63SDavid du Colombier 	*a = v>>24;
756*8ccd4a63SDavid du Colombier 	*r = v>>16;
757*8ccd4a63SDavid du Colombier 	*g = v>>8;
758*8ccd4a63SDavid du Colombier 	*b = v;
759*8ccd4a63SDavid du Colombier }
760*8ccd4a63SDavid du Colombier 
761*8ccd4a63SDavid du Colombier /*
762*8ccd4a63SDavid du Colombier  * Convert uchar channels into ulong pixel.
763*8ccd4a63SDavid du Colombier  */
764*8ccd4a63SDavid du Colombier ulong
rgbatopix(uchar r,uchar g,uchar b,uchar a)765*8ccd4a63SDavid du Colombier rgbatopix(uchar r, uchar g, uchar b, uchar a)
766*8ccd4a63SDavid du Colombier {
767*8ccd4a63SDavid du Colombier 	return (a<<24)|(r<<16)|(g<<8)|b;
768*8ccd4a63SDavid du Colombier }
769*8ccd4a63SDavid du Colombier 
770*8ccd4a63SDavid du Colombier /*
771*8ccd4a63SDavid du Colombier  * Retrieve the pixel value at pt in the image.
772*8ccd4a63SDavid du Colombier  */
773*8ccd4a63SDavid du Colombier ulong
getpixel(Memimage * img,Point pt)774*8ccd4a63SDavid du Colombier getpixel(Memimage *img, Point pt)
775*8ccd4a63SDavid du Colombier {
776*8ccd4a63SDavid du Colombier 	uchar r, g, b, a, *p;
777*8ccd4a63SDavid du Colombier 	int nbits, npack, bpp;
778*8ccd4a63SDavid du Colombier 	ulong v, c, rbits, bits;
779*8ccd4a63SDavid du Colombier 
780*8ccd4a63SDavid du Colombier 	r = g = b = 0;
781*8ccd4a63SDavid du Colombier 	a = ~0;	/* default alpha is full */
782*8ccd4a63SDavid du Colombier 
783*8ccd4a63SDavid du Colombier 	p = byteaddr(img, pt);
784*8ccd4a63SDavid du Colombier 	v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
785*8ccd4a63SDavid du Colombier 	bpp = img->depth;
786*8ccd4a63SDavid du Colombier 	if(bpp<8){
787*8ccd4a63SDavid du Colombier 		/*
788*8ccd4a63SDavid du Colombier 		 * Sub-byte greyscale pixels.
789*8ccd4a63SDavid du Colombier 		 *
790*8ccd4a63SDavid du Colombier 		 * We want to throw away the top pt.x%npack pixels and then use the next bpp bits
791*8ccd4a63SDavid du Colombier 		 * in the bottom byte of v.  This madness is due to having big endian bits
792*8ccd4a63SDavid du Colombier 		 * but little endian bytes.
793*8ccd4a63SDavid du Colombier 		 */
794*8ccd4a63SDavid du Colombier 		npack = 8/bpp;
795*8ccd4a63SDavid du Colombier 		v >>= 8 - bpp*(pt.x%npack+1);
796*8ccd4a63SDavid du Colombier 		v &= (1<<bpp)-1;
797*8ccd4a63SDavid du Colombier 		r = g = b = replbits(v, bpp, 8);
798*8ccd4a63SDavid du Colombier 	}else{
799*8ccd4a63SDavid du Colombier 		/*
800*8ccd4a63SDavid du Colombier 		 * General case.  We need to parse the channel descriptor and do what it says.
801*8ccd4a63SDavid du Colombier 		 * In all channels but the color map, we replicate to 8 bits because that's the
802*8ccd4a63SDavid du Colombier 		 * precision that all calculations are done at.
803*8ccd4a63SDavid du Colombier 		 *
804*8ccd4a63SDavid du Colombier 		 * In the case of the color map, we leave the bits alone, in case a color map
805*8ccd4a63SDavid du Colombier 		 * with less than 8 bits of index is used.  This is currently disallowed, so it's
806*8ccd4a63SDavid du Colombier 		 * sort of silly.
807*8ccd4a63SDavid du Colombier 		 */
808*8ccd4a63SDavid du Colombier 
809*8ccd4a63SDavid du Colombier 		for(c=img->chan; c; c>>=8){
810*8ccd4a63SDavid du Colombier 			nbits = NBITS(c);
811*8ccd4a63SDavid du Colombier 			bits = v & ((1<<nbits)-1);
812*8ccd4a63SDavid du Colombier 			rbits = replbits(bits, nbits, 8);
813*8ccd4a63SDavid du Colombier 			v >>= nbits;
814*8ccd4a63SDavid du Colombier 			switch(TYPE(c)){
815*8ccd4a63SDavid du Colombier 			case CRed:
816*8ccd4a63SDavid du Colombier 				r = rbits;
817*8ccd4a63SDavid du Colombier 				break;
818*8ccd4a63SDavid du Colombier 			case CGreen:
819*8ccd4a63SDavid du Colombier 				g = rbits;
820*8ccd4a63SDavid du Colombier 				break;
821*8ccd4a63SDavid du Colombier 			case CBlue:
822*8ccd4a63SDavid du Colombier 				b = rbits;
823*8ccd4a63SDavid du Colombier 				break;
824*8ccd4a63SDavid du Colombier 			case CGrey:
825*8ccd4a63SDavid du Colombier 				r = g = b = rbits;
826*8ccd4a63SDavid du Colombier 				break;
827*8ccd4a63SDavid du Colombier 			case CAlpha:
828*8ccd4a63SDavid du Colombier 				a = rbits;
829*8ccd4a63SDavid du Colombier 				break;
830*8ccd4a63SDavid du Colombier 			case CMap:
831*8ccd4a63SDavid du Colombier 				p = img->cmap->cmap2rgb + 3*bits;
832*8ccd4a63SDavid du Colombier 				r = p[0];
833*8ccd4a63SDavid du Colombier 				g = p[1];
834*8ccd4a63SDavid du Colombier 				b = p[2];
835*8ccd4a63SDavid du Colombier 				break;
836*8ccd4a63SDavid du Colombier 			case CIgnore:
837*8ccd4a63SDavid du Colombier 				break;
838*8ccd4a63SDavid du Colombier 			default:
839*8ccd4a63SDavid du Colombier 				fprint(2, "unknown channel type %lud\n", TYPE(c));
840*8ccd4a63SDavid du Colombier 				abort();
841*8ccd4a63SDavid du Colombier 			}
842*8ccd4a63SDavid du Colombier 		}
843*8ccd4a63SDavid du Colombier 	}
844*8ccd4a63SDavid du Colombier 	return rgbatopix(r, g, b, a);
845*8ccd4a63SDavid du Colombier }
846*8ccd4a63SDavid du Colombier 
847*8ccd4a63SDavid du Colombier /*
848*8ccd4a63SDavid du Colombier  * Return the greyscale equivalent of a pixel.
849*8ccd4a63SDavid du Colombier  */
850*8ccd4a63SDavid du Colombier uchar
getgrey(Memimage * img,Point pt)851*8ccd4a63SDavid du Colombier getgrey(Memimage *img, Point pt)
852*8ccd4a63SDavid du Colombier {
853*8ccd4a63SDavid du Colombier 	uchar r, g, b, a;
854*8ccd4a63SDavid du Colombier 	pixtorgba(getpixel(img, pt), &r, &g, &b, &a);
855*8ccd4a63SDavid du Colombier 	return RGB2K(r, g, b);
856*8ccd4a63SDavid du Colombier }
857*8ccd4a63SDavid du Colombier 
858*8ccd4a63SDavid du Colombier /*
859*8ccd4a63SDavid du Colombier  * Return the value at pt in image, if image is interpreted
860*8ccd4a63SDavid du Colombier  * as a mask.  This means the alpha channel if present, else
861*8ccd4a63SDavid du Colombier  * the greyscale or its computed equivalent.
862*8ccd4a63SDavid du Colombier  */
863*8ccd4a63SDavid du Colombier uchar
getmask(Memimage * img,Point pt)864*8ccd4a63SDavid du Colombier getmask(Memimage *img, Point pt)
865*8ccd4a63SDavid du Colombier {
866*8ccd4a63SDavid du Colombier 	if(img->flags&Falpha)
867*8ccd4a63SDavid du Colombier 		return getpixel(img, pt)>>24;
868*8ccd4a63SDavid du Colombier 	else
869*8ccd4a63SDavid du Colombier 		return getgrey(img, pt);
870*8ccd4a63SDavid du Colombier }
871*8ccd4a63SDavid du Colombier #undef DBG
872*8ccd4a63SDavid du Colombier 
873*8ccd4a63SDavid du Colombier #define DBG if(0)
874*8ccd4a63SDavid du Colombier /*
875*8ccd4a63SDavid du Colombier  * Write a pixel to img at point pt.
876*8ccd4a63SDavid du Colombier  *
877*8ccd4a63SDavid du Colombier  * We do this by reading a 32-bit little endian
878*8ccd4a63SDavid du Colombier  * value from p and then writing it back
879*8ccd4a63SDavid du Colombier  * after tweaking the appropriate bits.  Because
880*8ccd4a63SDavid du Colombier  * the data is little endian, we don't have to worry
881*8ccd4a63SDavid du Colombier  * about what the actual depth is, as long as it is
882*8ccd4a63SDavid du Colombier  * less than 32 bits.
883*8ccd4a63SDavid du Colombier  */
884*8ccd4a63SDavid du Colombier void
putpixel(Memimage * img,Point pt,ulong nv)885*8ccd4a63SDavid du Colombier putpixel(Memimage *img, Point pt, ulong nv)
886*8ccd4a63SDavid du Colombier {
887*8ccd4a63SDavid du Colombier 	uchar r, g, b, a, *p, *q;
888*8ccd4a63SDavid du Colombier 	ulong c, mask, bits, v;
889*8ccd4a63SDavid du Colombier 	int bpp, sh, npack, nbits;
890*8ccd4a63SDavid du Colombier 
891*8ccd4a63SDavid du Colombier 	pixtorgba(nv, &r, &g, &b, &a);
892*8ccd4a63SDavid du Colombier 
893*8ccd4a63SDavid du Colombier 	p = byteaddr(img, pt);
894*8ccd4a63SDavid du Colombier 	v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
895*8ccd4a63SDavid du Colombier 	bpp = img->depth;
896*8ccd4a63SDavid du Colombier DBG print("v %.8lux...", v);
897*8ccd4a63SDavid du Colombier 	if(bpp < 8){
898*8ccd4a63SDavid du Colombier 		/*
899*8ccd4a63SDavid du Colombier 		 * Sub-byte greyscale pixels.  We need to skip the leftmost pt.x%npack pixels,
900*8ccd4a63SDavid du Colombier 		 * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels.
901*8ccd4a63SDavid du Colombier 		 */
902*8ccd4a63SDavid du Colombier 		npack = 8/bpp;
903*8ccd4a63SDavid du Colombier 		sh = bpp*(npack - pt.x%npack - 1);
904*8ccd4a63SDavid du Colombier 		bits = RGB2K(r,g,b);
905*8ccd4a63SDavid du Colombier DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp));
906*8ccd4a63SDavid du Colombier 		bits = replbits(bits, 8, bpp);
907*8ccd4a63SDavid du Colombier 		mask = (1<<bpp)-1;
908*8ccd4a63SDavid du Colombier DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
909*8ccd4a63SDavid du Colombier 		mask <<= sh;
910*8ccd4a63SDavid du Colombier 		bits <<= sh;
911*8ccd4a63SDavid du Colombier DBG print("(%lux & %lux) | (%lux & %lux)", v, ~mask, bits, mask);
912*8ccd4a63SDavid du Colombier 		v = (v & ~mask) | (bits & mask);
913*8ccd4a63SDavid du Colombier 	} else {
914*8ccd4a63SDavid du Colombier 		/*
915*8ccd4a63SDavid du Colombier 		 * General case.  We need to parse the channel descriptor again.
916*8ccd4a63SDavid du Colombier 		 */
917*8ccd4a63SDavid du Colombier 		sh = 0;
918*8ccd4a63SDavid du Colombier 		for(c=img->chan; c; c>>=8){
919*8ccd4a63SDavid du Colombier 			nbits = NBITS(c);
920*8ccd4a63SDavid du Colombier 			switch(TYPE(c)){
921*8ccd4a63SDavid du Colombier 			case CRed:
922*8ccd4a63SDavid du Colombier 				bits = r;
923*8ccd4a63SDavid du Colombier 				break;
924*8ccd4a63SDavid du Colombier 			case CGreen:
925*8ccd4a63SDavid du Colombier 				bits = g;
926*8ccd4a63SDavid du Colombier 				break;
927*8ccd4a63SDavid du Colombier 			case CBlue:
928*8ccd4a63SDavid du Colombier 				bits = b;
929*8ccd4a63SDavid du Colombier 				break;
930*8ccd4a63SDavid du Colombier 			case CGrey:
931*8ccd4a63SDavid du Colombier 				bits = RGB2K(r, g, b);
932*8ccd4a63SDavid du Colombier 				break;
933*8ccd4a63SDavid du Colombier 			case CAlpha:
934*8ccd4a63SDavid du Colombier 				bits = a;
935*8ccd4a63SDavid du Colombier 				break;
936*8ccd4a63SDavid du Colombier 			case CIgnore:
937*8ccd4a63SDavid du Colombier 				bits = 0;
938*8ccd4a63SDavid du Colombier 				break;
939*8ccd4a63SDavid du Colombier 			case CMap:
940*8ccd4a63SDavid du Colombier 				q = img->cmap->rgb2cmap;
941*8ccd4a63SDavid du Colombier 				bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)];
942*8ccd4a63SDavid du Colombier 				break;
943*8ccd4a63SDavid du Colombier 			default:
944*8ccd4a63SDavid du Colombier 				SET(bits);
945*8ccd4a63SDavid du Colombier 				fprint(2, "unknown channel type %lud\n", TYPE(c));
946*8ccd4a63SDavid du Colombier 				abort();
947*8ccd4a63SDavid du Colombier 			}
948*8ccd4a63SDavid du Colombier 
949*8ccd4a63SDavid du Colombier DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits));
950*8ccd4a63SDavid du Colombier 			if(TYPE(c) != CMap)
951*8ccd4a63SDavid du Colombier 				bits = replbits(bits, 8, nbits);
952*8ccd4a63SDavid du Colombier 			mask = (1<<nbits)-1;
953*8ccd4a63SDavid du Colombier DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
954*8ccd4a63SDavid du Colombier 			bits <<= sh;
955*8ccd4a63SDavid du Colombier 			mask <<= sh;
956*8ccd4a63SDavid du Colombier 			v = (v & ~mask) | (bits & mask);
957*8ccd4a63SDavid du Colombier 			sh += nbits;
958*8ccd4a63SDavid du Colombier 		}
959*8ccd4a63SDavid du Colombier 	}
960*8ccd4a63SDavid du Colombier DBG print("v %.8lux\n", v);
961*8ccd4a63SDavid du Colombier 	p[0] = v;
962*8ccd4a63SDavid du Colombier 	p[1] = v>>8;
963*8ccd4a63SDavid du Colombier 	p[2] = v>>16;
964*8ccd4a63SDavid du Colombier 	p[3] = v>>24;
965*8ccd4a63SDavid du Colombier }
966*8ccd4a63SDavid du Colombier #undef DBG
967*8ccd4a63SDavid du Colombier 
968*8ccd4a63SDavid du Colombier #define DBG if(0)
969*8ccd4a63SDavid du Colombier void
drawonepixel(Memimage * dst,Point dp,Memimage * src,Point sp,Memimage * mask,Point mp)970*8ccd4a63SDavid du Colombier drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp)
971*8ccd4a63SDavid du Colombier {
972*8ccd4a63SDavid du Colombier 	uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk;
973*8ccd4a63SDavid du Colombier 
974*8ccd4a63SDavid du Colombier 	pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da);
975*8ccd4a63SDavid du Colombier 	pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa);
976*8ccd4a63SDavid du Colombier 	m = getmask(mask, mp);
977*8ccd4a63SDavid du Colombier 	M = 255-(sa*m)/255;
978*8ccd4a63SDavid du Colombier 
979*8ccd4a63SDavid du Colombier DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m);
980*8ccd4a63SDavid du Colombier 	if(dst->flags&Fgrey){
981*8ccd4a63SDavid du Colombier 		/*
982*8ccd4a63SDavid du Colombier 		 * We need to do the conversion to grey before the alpha calculation
983*8ccd4a63SDavid du Colombier 		 * because the draw operator does this, and we need to be operating
984*8ccd4a63SDavid du Colombier 		 * at the same precision so we get exactly the same answers.
985*8ccd4a63SDavid du Colombier 		 */
986*8ccd4a63SDavid du Colombier 		sk = RGB2K(sr, sg, sb);
987*8ccd4a63SDavid du Colombier 		dk = RGB2K(dr, dg, db);
988*8ccd4a63SDavid du Colombier 		dk = (sk*m + dk*M)/255;
989*8ccd4a63SDavid du Colombier 		dr = dg = db = dk;
990*8ccd4a63SDavid du Colombier 		da = (sa*m + da*M)/255;
991*8ccd4a63SDavid du Colombier 	}else{
992*8ccd4a63SDavid du Colombier 		/*
993*8ccd4a63SDavid du Colombier 		 * True color alpha calculation treats all channels (including alpha)
994*8ccd4a63SDavid du Colombier 		 * the same.  It might have been nice to use an array, but oh well.
995*8ccd4a63SDavid du Colombier 		 */
996*8ccd4a63SDavid du Colombier 		dr = (sr*m + dr*M)/255;
997*8ccd4a63SDavid du Colombier 		dg = (sg*m + dg*M)/255;
998*8ccd4a63SDavid du Colombier 		db = (sb*m + db*M)/255;
999*8ccd4a63SDavid du Colombier 		da = (sa*m + da*M)/255;
1000*8ccd4a63SDavid du Colombier 	}
1001*8ccd4a63SDavid du Colombier 
1002*8ccd4a63SDavid du Colombier DBG print("%x %x %x %x\n", dr,dg,db,da);
1003*8ccd4a63SDavid du Colombier 	putpixel(dst, dp, rgbatopix(dr, dg, db, da));
1004*8ccd4a63SDavid du Colombier }
1005