Warning: Attempt to read property "date" on null in /usr/local/www/websvn.planix.org/blame.php on line 247

Warning: Attempt to read property "msg" on null in /usr/local/www/websvn.planix.org/blame.php on line 247
WebSVN – planix.SVN – Blame – /os/branches/feature_fixcpp/sys/src/libmemdraw/drawtest.c – Rev 2

Subversion Repositories planix.SVN

Rev

Go to most recent revision | Details | Last modification | View Log | RSS feed

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