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