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