17dd7cddfSDavid du Colombier #include <u.h>
27dd7cddfSDavid du Colombier #include <libc.h>
37dd7cddfSDavid du Colombier #include <bio.h>
47dd7cddfSDavid du Colombier #include <draw.h>
57dd7cddfSDavid du Colombier #include <memdraw.h>
67dd7cddfSDavid du Colombier
77dd7cddfSDavid du Colombier #define DBG if(0)
87dd7cddfSDavid du Colombier #define RGB2K(r,g,b) ((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000)
97dd7cddfSDavid du Colombier
107dd7cddfSDavid du Colombier /*
117dd7cddfSDavid du Colombier * This program tests the 'memimagedraw' primitive stochastically.
127dd7cddfSDavid du Colombier * It tests the combination aspects of it thoroughly, but since the
137dd7cddfSDavid du Colombier * three images it uses are disjoint, it makes no check of the
147dd7cddfSDavid du Colombier * correct behavior when images overlap. That is, however, much
157dd7cddfSDavid du Colombier * easier to get right and to test.
167dd7cddfSDavid du Colombier */
177dd7cddfSDavid du Colombier
187dd7cddfSDavid du Colombier void drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point);
197dd7cddfSDavid du Colombier void verifyone(void);
207dd7cddfSDavid du Colombier void verifyline(void);
217dd7cddfSDavid du Colombier void verifyrect(void);
227dd7cddfSDavid du Colombier void verifyrectrepl(int, int);
237dd7cddfSDavid du Colombier void putpixel(Memimage *img, Point pt, ulong nv);
247dd7cddfSDavid du Colombier ulong rgbatopix(uchar, uchar, uchar, uchar);
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier char *dchan, *schan, *mchan;
277dd7cddfSDavid du Colombier int dbpp, sbpp, mbpp;
287dd7cddfSDavid du Colombier
297dd7cddfSDavid du Colombier int drawdebug=0;
307dd7cddfSDavid du Colombier int seed;
317dd7cddfSDavid du Colombier int niters = 100;
327dd7cddfSDavid du Colombier int dbpp; /* bits per pixel in destination */
337dd7cddfSDavid du Colombier int sbpp; /* bits per pixel in src */
347dd7cddfSDavid du Colombier int mbpp; /* bits per pixel in mask */
357dd7cddfSDavid du Colombier int dpm; /* pixel mask at high part of byte, in destination */
367dd7cddfSDavid du Colombier int nbytes; /* in destination */
377dd7cddfSDavid du Colombier
387dd7cddfSDavid du Colombier int Xrange = 64;
397dd7cddfSDavid du Colombier int Yrange = 8;
407dd7cddfSDavid du Colombier
417dd7cddfSDavid du Colombier Memimage *dst;
427dd7cddfSDavid du Colombier Memimage *src;
437dd7cddfSDavid du Colombier Memimage *mask;
447dd7cddfSDavid du Colombier Memimage *stmp;
457dd7cddfSDavid du Colombier Memimage *mtmp;
467dd7cddfSDavid du Colombier Memimage *ones;
477dd7cddfSDavid du Colombier uchar *dstbits;
487dd7cddfSDavid du Colombier uchar *srcbits;
497dd7cddfSDavid du Colombier uchar *maskbits;
507dd7cddfSDavid du Colombier ulong *savedstbits;
517dd7cddfSDavid du Colombier
527dd7cddfSDavid du Colombier void
rdb(void)537dd7cddfSDavid du Colombier rdb(void)
547dd7cddfSDavid du Colombier {
557dd7cddfSDavid du Colombier }
567dd7cddfSDavid du Colombier
577dd7cddfSDavid du Colombier int
iprint(char * fmt,...)587dd7cddfSDavid du Colombier iprint(char *fmt, ...)
597dd7cddfSDavid du Colombier {
607dd7cddfSDavid du Colombier int n;
617dd7cddfSDavid du Colombier va_list va;
627dd7cddfSDavid du Colombier char buf[1024];
637dd7cddfSDavid du Colombier
647dd7cddfSDavid du Colombier va_start(va, fmt);
65*2ffcfecaSDavid du Colombier n = vseprint(buf, buf+sizeof buf, fmt, va) - buf;
667dd7cddfSDavid du Colombier va_end(va);
677dd7cddfSDavid du Colombier
687dd7cddfSDavid du Colombier write(1,buf,n);
697dd7cddfSDavid du Colombier return 1;
707dd7cddfSDavid du Colombier }
717dd7cddfSDavid du Colombier
727dd7cddfSDavid du Colombier void
main(int argc,char * argv[])737dd7cddfSDavid du Colombier main(int argc, char *argv[])
747dd7cddfSDavid du Colombier {
757dd7cddfSDavid du Colombier memimageinit();
767dd7cddfSDavid du Colombier seed = time(0);
777dd7cddfSDavid du Colombier
787dd7cddfSDavid du Colombier ARGBEGIN{
797dd7cddfSDavid du Colombier case 'x':
807dd7cddfSDavid du Colombier Xrange = atoi(ARGF());
817dd7cddfSDavid du Colombier break;
827dd7cddfSDavid du Colombier case 'y':
837dd7cddfSDavid du Colombier Yrange = atoi(ARGF());
847dd7cddfSDavid du Colombier break;
857dd7cddfSDavid du Colombier case 'n':
867dd7cddfSDavid du Colombier niters = atoi(ARGF());
877dd7cddfSDavid du Colombier break;
887dd7cddfSDavid du Colombier case 's':
897dd7cddfSDavid du Colombier seed = atoi(ARGF());
907dd7cddfSDavid du Colombier break;
917dd7cddfSDavid du Colombier }ARGEND
927dd7cddfSDavid du Colombier
937dd7cddfSDavid du Colombier dchan = "r8g8b8";
947dd7cddfSDavid du Colombier schan = "r8g8b8";
957dd7cddfSDavid du Colombier mchan = "r8g8b8";
967dd7cddfSDavid du Colombier switch(argc){
977dd7cddfSDavid du Colombier case 3: mchan = argv[2];
987dd7cddfSDavid du Colombier case 2: schan = argv[1];
997dd7cddfSDavid du Colombier case 1: dchan = argv[0];
1007dd7cddfSDavid du Colombier case 0: break;
1017dd7cddfSDavid du Colombier default: goto Usage;
1027dd7cddfSDavid du Colombier Usage:
1037dd7cddfSDavid du Colombier fprint(2, "usage: dtest [dchan [schan [mchan]]]\n");
1047dd7cddfSDavid du Colombier exits("usage");
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
107*2ffcfecaSDavid du Colombier // fmtinstall('b', numbconv); /* binary! */
1087dd7cddfSDavid du Colombier
1097dd7cddfSDavid du Colombier fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan);
1107dd7cddfSDavid du Colombier srand(seed);
1117dd7cddfSDavid du Colombier
1127dd7cddfSDavid du Colombier dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan));
1137dd7cddfSDavid du Colombier src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
1147dd7cddfSDavid du Colombier mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
1157dd7cddfSDavid du Colombier stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan));
1167dd7cddfSDavid du Colombier mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
1177dd7cddfSDavid du Colombier ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan));
1187dd7cddfSDavid du Colombier // print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan);
1197dd7cddfSDavid du Colombier if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) {
1207dd7cddfSDavid du Colombier Alloc:
1217dd7cddfSDavid du Colombier fprint(2, "dtest: allocation failed: %r\n");
1227dd7cddfSDavid du Colombier exits("alloc");
1237dd7cddfSDavid du Colombier }
1247dd7cddfSDavid du Colombier nbytes = (4*Xrange+4)*Yrange;
1257dd7cddfSDavid du Colombier srcbits = malloc(nbytes);
1267dd7cddfSDavid du Colombier dstbits = malloc(nbytes);
1277dd7cddfSDavid du Colombier maskbits = malloc(nbytes);
1287dd7cddfSDavid du Colombier savedstbits = malloc(nbytes);
1297dd7cddfSDavid du Colombier if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0)
1307dd7cddfSDavid du Colombier goto Alloc;
1317dd7cddfSDavid du Colombier dbpp = dst->depth;
1327dd7cddfSDavid du Colombier sbpp = src->depth;
1337dd7cddfSDavid du Colombier mbpp = mask->depth;
1347dd7cddfSDavid du Colombier dpm = 0xFF ^ (0xFF>>dbpp);
1357dd7cddfSDavid du Colombier memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange);
1367dd7cddfSDavid du Colombier
1377dd7cddfSDavid du Colombier
1387dd7cddfSDavid du Colombier fprint(2, "dtest: verify single pixel operation\n");
1397dd7cddfSDavid du Colombier verifyone();
1407dd7cddfSDavid du Colombier
1417dd7cddfSDavid du Colombier fprint(2, "dtest: verify full line non-replicated\n");
1427dd7cddfSDavid du Colombier verifyline();
1437dd7cddfSDavid du Colombier
1447dd7cddfSDavid du Colombier fprint(2, "dtest: verify full rectangle non-replicated\n");
1457dd7cddfSDavid du Colombier verifyrect();
1467dd7cddfSDavid du Colombier
1477dd7cddfSDavid du Colombier fprint(2, "dtest: verify full rectangle source replicated\n");
1487dd7cddfSDavid du Colombier verifyrectrepl(1, 0);
1497dd7cddfSDavid du Colombier
1507dd7cddfSDavid du Colombier fprint(2, "dtest: verify full rectangle mask replicated\n");
1517dd7cddfSDavid du Colombier verifyrectrepl(0, 1);
1527dd7cddfSDavid du Colombier
1537dd7cddfSDavid du Colombier fprint(2, "dtest: verify full rectangle source and mask replicated\n");
1547dd7cddfSDavid du Colombier verifyrectrepl(1, 1);
1557dd7cddfSDavid du Colombier
1567dd7cddfSDavid du Colombier exits(0);
1577dd7cddfSDavid du Colombier }
1587dd7cddfSDavid du Colombier
1597dd7cddfSDavid du Colombier /*
1607dd7cddfSDavid du Colombier * Dump out an ASCII representation of an image. The label specifies
1617dd7cddfSDavid du Colombier * a list of characters to put at various points in the picture.
1627dd7cddfSDavid du Colombier */
1637dd7cddfSDavid du Colombier static void
Bprintr5g6b5(Biobuf * bio,char *,ulong v)1647dd7cddfSDavid du Colombier Bprintr5g6b5(Biobuf *bio, char*, ulong v)
1657dd7cddfSDavid du Colombier {
1667dd7cddfSDavid du Colombier int r,g,b;
1677dd7cddfSDavid du Colombier r = (v>>11)&31;
1687dd7cddfSDavid du Colombier g = (v>>5)&63;
1697dd7cddfSDavid du Colombier b = v&31;
1707dd7cddfSDavid du Colombier Bprint(bio, "%.2x%.2x%.2x", r,g,b);
1717dd7cddfSDavid du Colombier }
1727dd7cddfSDavid du Colombier
1737dd7cddfSDavid du Colombier static void
Bprintr5g5b5a1(Biobuf * bio,char *,ulong v)1747dd7cddfSDavid du Colombier Bprintr5g5b5a1(Biobuf *bio, char*, ulong v)
1757dd7cddfSDavid du Colombier {
1767dd7cddfSDavid du Colombier int r,g,b,a;
1777dd7cddfSDavid du Colombier r = (v>>11)&31;
1787dd7cddfSDavid du Colombier g = (v>>6)&31;
1797dd7cddfSDavid du Colombier b = (v>>1)&31;
1807dd7cddfSDavid du Colombier a = v&1;
1817dd7cddfSDavid du Colombier Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a);
1827dd7cddfSDavid du Colombier }
1837dd7cddfSDavid du Colombier
1847dd7cddfSDavid du Colombier void
dumpimage(char * name,Memimage * img,void * vdata,Point labelpt)1857dd7cddfSDavid du Colombier dumpimage(char *name, Memimage *img, void *vdata, Point labelpt)
1867dd7cddfSDavid du Colombier {
1877dd7cddfSDavid du Colombier Biobuf b;
1887dd7cddfSDavid du Colombier uchar *data;
1897dd7cddfSDavid du Colombier uchar *p;
1907dd7cddfSDavid du Colombier char *arg;
1917dd7cddfSDavid du Colombier void (*fmt)(Biobuf*, char*, ulong);
1927dd7cddfSDavid du Colombier int npr, x, y, nb, bpp;
1937dd7cddfSDavid du Colombier ulong v, mask;
1947dd7cddfSDavid du Colombier Rectangle r;
1957dd7cddfSDavid du Colombier
1967dd7cddfSDavid du Colombier fmt = nil;
1977dd7cddfSDavid du Colombier arg = nil;
1987dd7cddfSDavid du Colombier switch(img->depth){
1997dd7cddfSDavid du Colombier case 1:
2007dd7cddfSDavid du Colombier case 2:
2017dd7cddfSDavid du Colombier case 4:
2027dd7cddfSDavid du Colombier fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
2037dd7cddfSDavid du Colombier arg = "%.1ux";
2047dd7cddfSDavid du Colombier break;
2057dd7cddfSDavid du Colombier case 8:
2067dd7cddfSDavid du Colombier fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
2077dd7cddfSDavid du Colombier arg = "%.2ux";
2087dd7cddfSDavid du Colombier break;
2097dd7cddfSDavid du Colombier case 16:
2107dd7cddfSDavid du Colombier arg = nil;
2117dd7cddfSDavid du Colombier if(img->chan == RGB16)
2127dd7cddfSDavid du Colombier fmt = Bprintr5g6b5;
2137dd7cddfSDavid du Colombier else{
2147dd7cddfSDavid du Colombier fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
2157dd7cddfSDavid du Colombier arg = "%.4ux";
2167dd7cddfSDavid du Colombier }
2177dd7cddfSDavid du Colombier break;
2187dd7cddfSDavid du Colombier case 24:
2197dd7cddfSDavid du Colombier fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
2207dd7cddfSDavid du Colombier arg = "%.6lux";
2217dd7cddfSDavid du Colombier break;
2227dd7cddfSDavid du Colombier case 32:
2237dd7cddfSDavid du Colombier fmt = (void(*)(Biobuf*,char*,ulong))Bprint;
2247dd7cddfSDavid du Colombier arg = "%.8lux";
2257dd7cddfSDavid du Colombier break;
2267dd7cddfSDavid du Colombier }
2277dd7cddfSDavid du Colombier if(fmt == nil){
2287dd7cddfSDavid du Colombier fprint(2, "bad format\n");
2297dd7cddfSDavid du Colombier abort();
2307dd7cddfSDavid du Colombier }
2317dd7cddfSDavid du Colombier
2327dd7cddfSDavid du Colombier r = img->r;
2337dd7cddfSDavid du Colombier Binit(&b, 2, OWRITE);
2347dd7cddfSDavid du Colombier data = vdata;
2357dd7cddfSDavid du Colombier bpp = img->depth;
2367dd7cddfSDavid du Colombier Bprint(&b, "%s\t%d\tr %R clipr %R repl %d data %p *%P\n", name, r.min.x, r, img->clipr, (img->flags&Frepl) ? 1 : 0, vdata, labelpt);
2377dd7cddfSDavid du Colombier mask = (1ULL<<bpp)-1;
2387dd7cddfSDavid du Colombier // for(y=r.min.y; y<r.max.y; y++){
2397dd7cddfSDavid du Colombier for(y=0; y<Yrange; y++){
2407dd7cddfSDavid du Colombier nb = 0;
2417dd7cddfSDavid du Colombier v = 0;
2427dd7cddfSDavid du Colombier p = data+(byteaddr(img, Pt(0,y))-(uchar*)img->data->bdata);
2437dd7cddfSDavid du Colombier Bprint(&b, "%-4d\t", y);
2447dd7cddfSDavid du Colombier // for(x=r.min.x; x<r.max.x; x++){
2457dd7cddfSDavid du Colombier for(x=0; x<Xrange; x++){
2467dd7cddfSDavid du Colombier if(x==0)
2477dd7cddfSDavid du Colombier Bprint(&b, "\t");
2487dd7cddfSDavid du Colombier
2497dd7cddfSDavid du Colombier if(x != 0 && (x%8)==0)
2507dd7cddfSDavid du Colombier Bprint(&b, " ");
2517dd7cddfSDavid du Colombier
2527dd7cddfSDavid du Colombier npr = 0;
2537dd7cddfSDavid du Colombier if(x==labelpt.x && y==labelpt.y){
2547dd7cddfSDavid du Colombier Bprint(&b, "*");
2557dd7cddfSDavid du Colombier npr++;
2567dd7cddfSDavid du Colombier }
2577dd7cddfSDavid du Colombier if(npr == 0)
2587dd7cddfSDavid du Colombier Bprint(&b, " ");
2597dd7cddfSDavid du Colombier
2607dd7cddfSDavid du Colombier while(nb < bpp){
2617dd7cddfSDavid du Colombier v &= (1<<nb)-1;
2627dd7cddfSDavid du Colombier v |= (ulong)(*p++) << nb;
2637dd7cddfSDavid du Colombier nb += 8;
2647dd7cddfSDavid du Colombier }
2657dd7cddfSDavid du Colombier nb -= bpp;
2667dd7cddfSDavid du Colombier // print("bpp %d v %.8lux mask %.8lux nb %d\n", bpp, v, mask, nb);
2677dd7cddfSDavid du Colombier fmt(&b, arg, (v>>nb)&mask);
2687dd7cddfSDavid du Colombier }
2697dd7cddfSDavid du Colombier Bprint(&b, "\n");
2707dd7cddfSDavid du Colombier }
2717dd7cddfSDavid du Colombier Bterm(&b);
2727dd7cddfSDavid du Colombier }
2737dd7cddfSDavid du Colombier
2747dd7cddfSDavid du Colombier /*
2757dd7cddfSDavid du Colombier * Verify that the destination pixel has the specified value.
2767dd7cddfSDavid du Colombier * The value is in the high bits of v, suitably masked, but must
2777dd7cddfSDavid du Colombier * be extracted from the destination Memimage.
2787dd7cddfSDavid du Colombier */
2797dd7cddfSDavid du Colombier void
checkone(Point p,Point sp,Point mp)2807dd7cddfSDavid du Colombier checkone(Point p, Point sp, Point mp)
2817dd7cddfSDavid du Colombier {
2827dd7cddfSDavid du Colombier int delta;
2837dd7cddfSDavid du Colombier uchar *dp, *sdp;
2847dd7cddfSDavid du Colombier
2857dd7cddfSDavid du Colombier delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata;
2867dd7cddfSDavid du Colombier dp = (uchar*)dst->data->bdata+delta;
2877dd7cddfSDavid du Colombier sdp = (uchar*)savedstbits+delta;
2887dd7cddfSDavid du Colombier
2897dd7cddfSDavid du Colombier if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) {
2907dd7cddfSDavid du Colombier fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp);
2917dd7cddfSDavid du Colombier fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n",
2927dd7cddfSDavid du Colombier dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]);
2937dd7cddfSDavid du Colombier fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp));
2947dd7cddfSDavid du Colombier dumpimage("src", src, src->data->bdata, sp);
2957dd7cddfSDavid du Colombier dumpimage("mask", mask, mask->data->bdata, mp);
2967dd7cddfSDavid du Colombier dumpimage("origdst", dst, dstbits, p);
2977dd7cddfSDavid du Colombier dumpimage("dst", dst, dst->data->bdata, p);
2987dd7cddfSDavid du Colombier dumpimage("gooddst", dst, savedstbits, p);
2997dd7cddfSDavid du Colombier abort();
3007dd7cddfSDavid du Colombier }
3017dd7cddfSDavid du Colombier }
3027dd7cddfSDavid du Colombier
3037dd7cddfSDavid du Colombier /*
3047dd7cddfSDavid du Colombier * Verify that the destination line has the same value as the saved line.
3057dd7cddfSDavid du Colombier */
3067dd7cddfSDavid du Colombier #define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y
3077dd7cddfSDavid du Colombier void
checkline(Rectangle r,Point sp,Point mp,int y,Memimage * stmp,Memimage * mtmp)3087dd7cddfSDavid du Colombier checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp)
3097dd7cddfSDavid du Colombier {
3107dd7cddfSDavid du Colombier ulong *dp;
3117dd7cddfSDavid du Colombier int nb;
3127dd7cddfSDavid du Colombier ulong *saved;
3137dd7cddfSDavid du Colombier
3147dd7cddfSDavid du Colombier dp = wordaddr(dst, Pt(0, y));
3157dd7cddfSDavid du Colombier saved = savedstbits + y*dst->width;
3167dd7cddfSDavid du Colombier if(dst->depth < 8)
3177dd7cddfSDavid du Colombier nb = Xrange/(8/dst->depth);
3187dd7cddfSDavid du Colombier else
3197dd7cddfSDavid du Colombier nb = Xrange*(dst->depth/8);
3207dd7cddfSDavid du Colombier if(memcmp(dp, saved, nb) != 0){
3217dd7cddfSDavid du Colombier fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp);
3227dd7cddfSDavid du Colombier fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp);
3237dd7cddfSDavid du Colombier dumpimage("src", src, src->data->bdata, sp);
3247dd7cddfSDavid du Colombier if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp);
3257dd7cddfSDavid du Colombier dumpimage("mask", mask, mask->data->bdata, mp);
3267dd7cddfSDavid du Colombier if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp);
3277dd7cddfSDavid du Colombier dumpimage("origdst", dst, dstbits, r.min);
3287dd7cddfSDavid du Colombier dumpimage("dst", dst, dst->data->bdata, r.min);
3297dd7cddfSDavid du Colombier dumpimage("gooddst", dst, savedstbits, r.min);
3307dd7cddfSDavid du Colombier abort();
3317dd7cddfSDavid du Colombier }
3327dd7cddfSDavid du Colombier }
3337dd7cddfSDavid du Colombier
3347dd7cddfSDavid du Colombier /*
3357dd7cddfSDavid du Colombier * Fill the bits of an image with random data.
3367dd7cddfSDavid du Colombier * The Memimage parameter is used only to make sure
3377dd7cddfSDavid du Colombier * the data is well formatted: only ucbits is written.
3387dd7cddfSDavid du Colombier */
3397dd7cddfSDavid du Colombier void
fill(Memimage * img,uchar * ucbits)3407dd7cddfSDavid du Colombier fill(Memimage *img, uchar *ucbits)
3417dd7cddfSDavid du Colombier {
3427dd7cddfSDavid du Colombier int i, x, y;
3437dd7cddfSDavid du Colombier ushort *up;
3447dd7cddfSDavid du Colombier uchar alpha, r, g, b;
3457dd7cddfSDavid du Colombier void *data;
3467dd7cddfSDavid du Colombier
3477dd7cddfSDavid du Colombier if((img->flags&Falpha) == 0){
3487dd7cddfSDavid du Colombier up = (ushort*)ucbits;
3497dd7cddfSDavid du Colombier for(i=0; i<nbytes/2; i++)
3507dd7cddfSDavid du Colombier *up++ = lrand() >> 7;
3517dd7cddfSDavid du Colombier if(i+i != nbytes)
3527dd7cddfSDavid du Colombier *(uchar*)up = lrand() >> 7;
3537dd7cddfSDavid du Colombier }else{
3547dd7cddfSDavid du Colombier data = img->data->bdata;
3557dd7cddfSDavid du Colombier img->data->bdata = ucbits;
3567dd7cddfSDavid du Colombier
3577dd7cddfSDavid du Colombier for(x=img->r.min.x; x<img->r.max.x; x++)
3587dd7cddfSDavid du Colombier for(y=img->r.min.y; y<img->r.max.y; y++){
3597dd7cddfSDavid du Colombier alpha = rand() >> 4;
3607dd7cddfSDavid du Colombier r = rand()%(alpha+1);
3617dd7cddfSDavid du Colombier g = rand()%(alpha+1);
3627dd7cddfSDavid du Colombier b = rand()%(alpha+1);
3637dd7cddfSDavid du Colombier putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha));
3647dd7cddfSDavid du Colombier }
3657dd7cddfSDavid du Colombier img->data->bdata = data;
3667dd7cddfSDavid du Colombier }
3677dd7cddfSDavid du Colombier
3687dd7cddfSDavid du Colombier }
3697dd7cddfSDavid du Colombier
3707dd7cddfSDavid du Colombier /*
3717dd7cddfSDavid du Colombier * Mask is preset; do the rest
3727dd7cddfSDavid du Colombier */
3737dd7cddfSDavid du Colombier void
verifyonemask(void)3747dd7cddfSDavid du Colombier verifyonemask(void)
3757dd7cddfSDavid du Colombier {
3767dd7cddfSDavid du Colombier Point dp, sp, mp;
3777dd7cddfSDavid du Colombier
3787dd7cddfSDavid du Colombier fill(dst, dstbits);
3797dd7cddfSDavid du Colombier fill(src, srcbits);
3807dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
3817dd7cddfSDavid du Colombier memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
3827dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
3837dd7cddfSDavid du Colombier
3847dd7cddfSDavid du Colombier dp.x = nrand(Xrange);
3857dd7cddfSDavid du Colombier dp.y = nrand(Yrange);
3867dd7cddfSDavid du Colombier
3877dd7cddfSDavid du Colombier sp.x = nrand(Xrange);
3887dd7cddfSDavid du Colombier sp.y = nrand(Yrange);
3897dd7cddfSDavid du Colombier
3907dd7cddfSDavid du Colombier mp.x = nrand(Xrange);
3917dd7cddfSDavid du Colombier mp.y = nrand(Yrange);
3927dd7cddfSDavid du Colombier
3937dd7cddfSDavid du Colombier drawonepixel(dst, dp, src, sp, mask, mp);
3947dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
3957dd7cddfSDavid du Colombier memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
3967dd7cddfSDavid du Colombier
3977dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
3986b6b9ac8SDavid du Colombier memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD);
3997dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
4007dd7cddfSDavid du Colombier
4017dd7cddfSDavid du Colombier checkone(dp, sp, mp);
4027dd7cddfSDavid du Colombier }
4037dd7cddfSDavid du Colombier
4047dd7cddfSDavid du Colombier void
verifyone(void)4057dd7cddfSDavid du Colombier verifyone(void)
4067dd7cddfSDavid du Colombier {
4077dd7cddfSDavid du Colombier int i;
4087dd7cddfSDavid du Colombier
4097dd7cddfSDavid du Colombier /* mask all zeros */
4107dd7cddfSDavid du Colombier memset(maskbits, 0, nbytes);
4117dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
4127dd7cddfSDavid du Colombier verifyonemask();
4137dd7cddfSDavid du Colombier
4147dd7cddfSDavid du Colombier /* mask all ones */
4157dd7cddfSDavid du Colombier memset(maskbits, 0xFF, nbytes);
4167dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
4177dd7cddfSDavid du Colombier verifyonemask();
4187dd7cddfSDavid du Colombier
4197dd7cddfSDavid du Colombier /* random mask */
4207dd7cddfSDavid du Colombier for(i=0; i<niters; i++){
4217dd7cddfSDavid du Colombier fill(mask, maskbits);
4227dd7cddfSDavid du Colombier verifyonemask();
4237dd7cddfSDavid du Colombier }
4247dd7cddfSDavid du Colombier }
4257dd7cddfSDavid du Colombier
4267dd7cddfSDavid du Colombier /*
4277dd7cddfSDavid du Colombier * Mask is preset; do the rest
4287dd7cddfSDavid du Colombier */
4297dd7cddfSDavid du Colombier void
verifylinemask(void)4307dd7cddfSDavid du Colombier verifylinemask(void)
4317dd7cddfSDavid du Colombier {
4327dd7cddfSDavid du Colombier Point sp, mp, tp, up;
4337dd7cddfSDavid du Colombier Rectangle dr;
4347dd7cddfSDavid du Colombier int x;
4357dd7cddfSDavid du Colombier
4367dd7cddfSDavid du Colombier fill(dst, dstbits);
4377dd7cddfSDavid du Colombier fill(src, srcbits);
4387dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
4397dd7cddfSDavid du Colombier memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
4407dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
4417dd7cddfSDavid du Colombier
4427dd7cddfSDavid du Colombier dr.min.x = nrand(Xrange-1);
4437dd7cddfSDavid du Colombier dr.min.y = nrand(Yrange-1);
4447dd7cddfSDavid du Colombier dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
4457dd7cddfSDavid du Colombier dr.max.y = dr.min.y + 1;
4467dd7cddfSDavid du Colombier
4477dd7cddfSDavid du Colombier sp.x = nrand(Xrange);
4487dd7cddfSDavid du Colombier sp.y = nrand(Yrange);
4497dd7cddfSDavid du Colombier
4507dd7cddfSDavid du Colombier mp.x = nrand(Xrange);
4517dd7cddfSDavid du Colombier mp.y = nrand(Yrange);
4527dd7cddfSDavid du Colombier
4537dd7cddfSDavid du Colombier tp = sp;
4547dd7cddfSDavid du Colombier up = mp;
4557dd7cddfSDavid du Colombier for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
4566b6b9ac8SDavid du Colombier memimagedraw(dst, Rect(x, dr.min.y, x+1, dr.min.y+1), src, tp, mask, up, SoverD);
4577dd7cddfSDavid du Colombier memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
4587dd7cddfSDavid du Colombier
4597dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
4607dd7cddfSDavid du Colombier
4616b6b9ac8SDavid du Colombier memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
4627dd7cddfSDavid du Colombier checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil);
4637dd7cddfSDavid du Colombier }
4647dd7cddfSDavid du Colombier
4657dd7cddfSDavid du Colombier void
verifyline(void)4667dd7cddfSDavid du Colombier verifyline(void)
4677dd7cddfSDavid du Colombier {
4687dd7cddfSDavid du Colombier int i;
4697dd7cddfSDavid du Colombier
4707dd7cddfSDavid du Colombier /* mask all ones */
4717dd7cddfSDavid du Colombier memset(maskbits, 0xFF, nbytes);
4727dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
4737dd7cddfSDavid du Colombier verifylinemask();
4747dd7cddfSDavid du Colombier
4757dd7cddfSDavid du Colombier /* mask all zeros */
4767dd7cddfSDavid du Colombier memset(maskbits, 0, nbytes);
4777dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
4787dd7cddfSDavid du Colombier verifylinemask();
4797dd7cddfSDavid du Colombier
4807dd7cddfSDavid du Colombier /* random mask */
4817dd7cddfSDavid du Colombier for(i=0; i<niters; i++){
4827dd7cddfSDavid du Colombier fill(mask, maskbits);
4837dd7cddfSDavid du Colombier verifylinemask();
4847dd7cddfSDavid du Colombier }
4857dd7cddfSDavid du Colombier }
4867dd7cddfSDavid du Colombier
4877dd7cddfSDavid du Colombier /*
4887dd7cddfSDavid du Colombier * Mask is preset; do the rest
4897dd7cddfSDavid du Colombier */
4907dd7cddfSDavid du Colombier void
verifyrectmask(void)4917dd7cddfSDavid du Colombier verifyrectmask(void)
4927dd7cddfSDavid du Colombier {
4937dd7cddfSDavid du Colombier Point sp, mp, tp, up;
4947dd7cddfSDavid du Colombier Rectangle dr;
4957dd7cddfSDavid du Colombier int x, y;
4967dd7cddfSDavid du Colombier
4977dd7cddfSDavid du Colombier fill(dst, dstbits);
4987dd7cddfSDavid du Colombier fill(src, srcbits);
4997dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
5007dd7cddfSDavid du Colombier memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
5017dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
5027dd7cddfSDavid du Colombier
5037dd7cddfSDavid du Colombier dr.min.x = nrand(Xrange-1);
5047dd7cddfSDavid du Colombier dr.min.y = nrand(Yrange-1);
5057dd7cddfSDavid du Colombier dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x);
5067dd7cddfSDavid du Colombier dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y);
5077dd7cddfSDavid du Colombier
5087dd7cddfSDavid du Colombier sp.x = nrand(Xrange);
5097dd7cddfSDavid du Colombier sp.y = nrand(Yrange);
5107dd7cddfSDavid du Colombier
5117dd7cddfSDavid du Colombier mp.x = nrand(Xrange);
5127dd7cddfSDavid du Colombier mp.y = nrand(Yrange);
5137dd7cddfSDavid du Colombier
5147dd7cddfSDavid du Colombier tp = sp;
5157dd7cddfSDavid du Colombier up = mp;
5167dd7cddfSDavid du Colombier for(y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++){
5177dd7cddfSDavid du Colombier for(x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
5186b6b9ac8SDavid du Colombier memimagedraw(dst, Rect(x, y, x+1, y+1), src, tp, mask, up, SoverD);
5197dd7cddfSDavid du Colombier tp.x = sp.x;
5207dd7cddfSDavid du Colombier up.x = mp.x;
5217dd7cddfSDavid du Colombier }
5227dd7cddfSDavid du Colombier memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
5237dd7cddfSDavid du Colombier
5247dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
5257dd7cddfSDavid du Colombier
5266b6b9ac8SDavid du Colombier memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
5277dd7cddfSDavid du Colombier for(y=0; y<Yrange; y++)
5287dd7cddfSDavid du Colombier checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, nil, nil);
5297dd7cddfSDavid du Colombier }
5307dd7cddfSDavid du Colombier
5317dd7cddfSDavid du Colombier void
verifyrect(void)5327dd7cddfSDavid du Colombier verifyrect(void)
5337dd7cddfSDavid du Colombier {
5347dd7cddfSDavid du Colombier int i;
5357dd7cddfSDavid du Colombier
5367dd7cddfSDavid du Colombier /* mask all zeros */
5377dd7cddfSDavid du Colombier memset(maskbits, 0, nbytes);
5387dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
5397dd7cddfSDavid du Colombier verifyrectmask();
5407dd7cddfSDavid du Colombier
5417dd7cddfSDavid du Colombier /* mask all ones */
5427dd7cddfSDavid du Colombier memset(maskbits, 0xFF, nbytes);
5437dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
5447dd7cddfSDavid du Colombier verifyrectmask();
5457dd7cddfSDavid du Colombier
5467dd7cddfSDavid du Colombier /* random mask */
5477dd7cddfSDavid du Colombier for(i=0; i<niters; i++){
5487dd7cddfSDavid du Colombier fill(mask, maskbits);
5497dd7cddfSDavid du Colombier verifyrectmask();
5507dd7cddfSDavid du Colombier }
5517dd7cddfSDavid du Colombier }
5527dd7cddfSDavid du Colombier
5537dd7cddfSDavid du Colombier Rectangle
randrect(void)5547dd7cddfSDavid du Colombier randrect(void)
5557dd7cddfSDavid du Colombier {
5567dd7cddfSDavid du Colombier Rectangle r;
5577dd7cddfSDavid du Colombier
5587dd7cddfSDavid du Colombier r.min.x = nrand(Xrange-1);
5597dd7cddfSDavid du Colombier r.min.y = nrand(Yrange-1);
5607dd7cddfSDavid du Colombier r.max.x = r.min.x + 1 + nrand(Xrange-1-r.min.x);
5617dd7cddfSDavid du Colombier r.max.y = r.min.y + 1 + nrand(Yrange-1-r.min.y);
5627dd7cddfSDavid du Colombier return r;
5637dd7cddfSDavid du Colombier }
5647dd7cddfSDavid du Colombier
5657dd7cddfSDavid du Colombier /*
5667dd7cddfSDavid du Colombier * Return coordinate corresponding to x withing range [minx, maxx)
5677dd7cddfSDavid du Colombier */
5687dd7cddfSDavid du Colombier int
tilexy(int minx,int maxx,int x)5697dd7cddfSDavid du Colombier tilexy(int minx, int maxx, int x)
5707dd7cddfSDavid du Colombier {
5717dd7cddfSDavid du Colombier int sx;
5727dd7cddfSDavid du Colombier
5737dd7cddfSDavid du Colombier sx = (x-minx) % (maxx-minx);
5747dd7cddfSDavid du Colombier if(sx < 0)
5757dd7cddfSDavid du Colombier sx += maxx-minx;
5767dd7cddfSDavid du Colombier return sx+minx;
5777dd7cddfSDavid du Colombier }
5787dd7cddfSDavid du Colombier
5797dd7cddfSDavid du Colombier void
replicate(Memimage * i,Memimage * tmp)5807dd7cddfSDavid du Colombier replicate(Memimage *i, Memimage *tmp)
5817dd7cddfSDavid du Colombier {
5827dd7cddfSDavid du Colombier Rectangle r, r1;
5837dd7cddfSDavid du Colombier int x, y, nb;
5847dd7cddfSDavid du Colombier
5857dd7cddfSDavid du Colombier /* choose the replication window (i->r) */
5867dd7cddfSDavid du Colombier r.min.x = nrand(Xrange-1);
5877dd7cddfSDavid du Colombier r.min.y = nrand(Yrange-1);
5887dd7cddfSDavid du Colombier /* make it trivial more often than pure chance allows */
5897dd7cddfSDavid du Colombier switch(lrand()&0){
5907dd7cddfSDavid du Colombier case 1:
5917dd7cddfSDavid du Colombier r.max.x = r.min.x + 2;
5927dd7cddfSDavid du Colombier r.max.y = r.min.y + 2;
5937dd7cddfSDavid du Colombier if(r.max.x < Xrange && r.max.y < Yrange)
5947dd7cddfSDavid du Colombier break;
5957dd7cddfSDavid du Colombier /* fall through */
5967dd7cddfSDavid du Colombier case 0:
5977dd7cddfSDavid du Colombier r.max.x = r.min.x + 1;
5987dd7cddfSDavid du Colombier r.max.y = r.min.y + 1;
5997dd7cddfSDavid du Colombier break;
6007dd7cddfSDavid du Colombier default:
6017dd7cddfSDavid du Colombier if(r.min.x+3 >= Xrange)
6027dd7cddfSDavid du Colombier r.max.x = Xrange;
6037dd7cddfSDavid du Colombier else
6047dd7cddfSDavid du Colombier r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3));
6057dd7cddfSDavid du Colombier
6067dd7cddfSDavid du Colombier if(r.min.y+3 >= Yrange)
6077dd7cddfSDavid du Colombier r.max.y = Yrange;
6087dd7cddfSDavid du Colombier else
6097dd7cddfSDavid du Colombier r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3));
6107dd7cddfSDavid du Colombier }
6117dd7cddfSDavid du Colombier assert(r.min.x >= 0);
6127dd7cddfSDavid du Colombier assert(r.max.x <= Xrange);
6137dd7cddfSDavid du Colombier assert(r.min.y >= 0);
6147dd7cddfSDavid du Colombier assert(r.max.y <= Yrange);
6157dd7cddfSDavid du Colombier /* copy from i to tmp so we have just the replicated bits */
6167dd7cddfSDavid du Colombier nb = tmp->width*sizeof(ulong)*Yrange;
6177dd7cddfSDavid du Colombier memset(tmp->data->bdata, 0, nb);
6186b6b9ac8SDavid du Colombier memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD);
6197dd7cddfSDavid du Colombier memmove(i->data->bdata, tmp->data->bdata, nb);
6207dd7cddfSDavid du Colombier /* i is now a non-replicated instance of the replication */
6217dd7cddfSDavid du Colombier /* replicate it by hand through tmp */
6227dd7cddfSDavid du Colombier memset(tmp->data->bdata, 0, nb);
6237dd7cddfSDavid du Colombier x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x);
6247dd7cddfSDavid du Colombier for(; x<Xrange; x+=Dx(r)){
6257dd7cddfSDavid du Colombier y = -(tilexy(r.min.y, r.max.y, 0)-r.min.y);
6267dd7cddfSDavid du Colombier for(; y<Yrange; y+=Dy(r)){
6277dd7cddfSDavid du Colombier /* set r1 to instance of tile by translation */
6287dd7cddfSDavid du Colombier r1.min.x = x;
6297dd7cddfSDavid du Colombier r1.min.y = y;
6307dd7cddfSDavid du Colombier r1.max.x = r1.min.x+Dx(r);
6317dd7cddfSDavid du Colombier r1.max.y = r1.min.y+Dy(r);
6326b6b9ac8SDavid du Colombier memimagedraw(tmp, r1, i, r.min, ones, r.min, SoverD);
6337dd7cddfSDavid du Colombier }
6347dd7cddfSDavid du Colombier }
6357dd7cddfSDavid du Colombier i->flags |= Frepl;
6367dd7cddfSDavid du Colombier i->r = r;
6377dd7cddfSDavid du Colombier i->clipr = randrect();
6387dd7cddfSDavid du Colombier // fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y,
6397dd7cddfSDavid du Colombier // i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y);
6407dd7cddfSDavid du Colombier tmp->clipr = i->clipr;
6417dd7cddfSDavid du Colombier }
6427dd7cddfSDavid du Colombier
6437dd7cddfSDavid du Colombier /*
6447dd7cddfSDavid du Colombier * Mask is preset; do the rest
6457dd7cddfSDavid du Colombier */
6467dd7cddfSDavid du Colombier void
verifyrectmaskrepl(int srcrepl,int maskrepl)6477dd7cddfSDavid du Colombier verifyrectmaskrepl(int srcrepl, int maskrepl)
6487dd7cddfSDavid du Colombier {
6497dd7cddfSDavid du Colombier Point sp, mp, tp, up;
6507dd7cddfSDavid du Colombier Rectangle dr;
6517dd7cddfSDavid du Colombier int x, y;
6527dd7cddfSDavid du Colombier Memimage *s, *m;
6537dd7cddfSDavid du Colombier
6547dd7cddfSDavid du Colombier // print("verfrect %d %d\n", srcrepl, maskrepl);
6557dd7cddfSDavid du Colombier src->flags &= ~Frepl;
6567dd7cddfSDavid du Colombier src->r = Rect(0, 0, Xrange, Yrange);
6577dd7cddfSDavid du Colombier src->clipr = src->r;
6587dd7cddfSDavid du Colombier stmp->flags &= ~Frepl;
6597dd7cddfSDavid du Colombier stmp->r = Rect(0, 0, Xrange, Yrange);
6607dd7cddfSDavid du Colombier stmp->clipr = src->r;
6617dd7cddfSDavid du Colombier mask->flags &= ~Frepl;
6627dd7cddfSDavid du Colombier mask->r = Rect(0, 0, Xrange, Yrange);
6637dd7cddfSDavid du Colombier mask->clipr = mask->r;
6647dd7cddfSDavid du Colombier mtmp->flags &= ~Frepl;
6657dd7cddfSDavid du Colombier mtmp->r = Rect(0, 0, Xrange, Yrange);
6667dd7cddfSDavid du Colombier mtmp->clipr = mask->r;
6677dd7cddfSDavid du Colombier
6687dd7cddfSDavid du Colombier fill(dst, dstbits);
6697dd7cddfSDavid du Colombier fill(src, srcbits);
6707dd7cddfSDavid du Colombier
6717dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
6727dd7cddfSDavid du Colombier memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange);
6737dd7cddfSDavid du Colombier memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange);
6747dd7cddfSDavid du Colombier
6757dd7cddfSDavid du Colombier if(srcrepl){
6767dd7cddfSDavid du Colombier replicate(src, stmp);
6777dd7cddfSDavid du Colombier s = stmp;
6787dd7cddfSDavid du Colombier }else
6797dd7cddfSDavid du Colombier s = src;
6807dd7cddfSDavid du Colombier if(maskrepl){
6817dd7cddfSDavid du Colombier replicate(mask, mtmp);
6827dd7cddfSDavid du Colombier m = mtmp;
6837dd7cddfSDavid du Colombier }else
6847dd7cddfSDavid du Colombier m = mask;
6857dd7cddfSDavid du Colombier
6867dd7cddfSDavid du Colombier dr = randrect();
6877dd7cddfSDavid du Colombier
6887dd7cddfSDavid du Colombier sp.x = nrand(Xrange);
6897dd7cddfSDavid du Colombier sp.y = nrand(Yrange);
6907dd7cddfSDavid du Colombier
6917dd7cddfSDavid du Colombier mp.x = nrand(Xrange);
6927dd7cddfSDavid du Colombier mp.y = nrand(Yrange);
6937dd7cddfSDavid du Colombier
6947dd7cddfSDavid du Colombier DBG print("smalldraws\n");
6957dd7cddfSDavid du Colombier for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; y<dr.max.y && tp.y<Yrange && up.y<Yrange; y++,tp.y++,up.y++)
6967dd7cddfSDavid du Colombier for(tp.x=sp.x,up.x=mp.x,x=dr.min.x; x<dr.max.x && tp.x<Xrange && up.x<Xrange; x++,tp.x++,up.x++)
6976b6b9ac8SDavid du Colombier memimagedraw(dst, Rect(x, y, x+1, y+1), s, tp, m, up, SoverD);
6987dd7cddfSDavid du Colombier memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange);
6997dd7cddfSDavid du Colombier
7007dd7cddfSDavid du Colombier memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange);
7017dd7cddfSDavid du Colombier
7027dd7cddfSDavid du Colombier DBG print("bigdraw\n");
7036b6b9ac8SDavid du Colombier memimagedraw(dst, dr, src, sp, mask, mp, SoverD);
7047dd7cddfSDavid du Colombier for(y=0; y<Yrange; y++)
7057dd7cddfSDavid du Colombier checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil);
7067dd7cddfSDavid du Colombier }
7077dd7cddfSDavid du Colombier
7087dd7cddfSDavid du Colombier void
verifyrectrepl(int srcrepl,int maskrepl)7097dd7cddfSDavid du Colombier verifyrectrepl(int srcrepl, int maskrepl)
7107dd7cddfSDavid du Colombier {
7117dd7cddfSDavid du Colombier int i;
7127dd7cddfSDavid du Colombier
7137dd7cddfSDavid du Colombier /* mask all ones */
7147dd7cddfSDavid du Colombier memset(maskbits, 0xFF, nbytes);
7157dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
7167dd7cddfSDavid du Colombier verifyrectmaskrepl(srcrepl, maskrepl);
7177dd7cddfSDavid du Colombier
7187dd7cddfSDavid du Colombier /* mask all zeros */
7197dd7cddfSDavid du Colombier memset(maskbits, 0, nbytes);
7207dd7cddfSDavid du Colombier for(i=0; i<niters; i++)
7217dd7cddfSDavid du Colombier verifyrectmaskrepl(srcrepl, maskrepl);
7227dd7cddfSDavid du Colombier
7237dd7cddfSDavid du Colombier /* random mask */
7247dd7cddfSDavid du Colombier for(i=0; i<niters; i++){
7257dd7cddfSDavid du Colombier fill(mask, maskbits);
7267dd7cddfSDavid du Colombier verifyrectmaskrepl(srcrepl, maskrepl);
7277dd7cddfSDavid du Colombier }
7287dd7cddfSDavid du Colombier }
7297dd7cddfSDavid du Colombier
7307dd7cddfSDavid du Colombier /*
7317dd7cddfSDavid du Colombier * Trivial draw implementation.
7327dd7cddfSDavid du Colombier * Color values are passed around as ulongs containing ααRRGGBB
7337dd7cddfSDavid du Colombier */
7347dd7cddfSDavid du Colombier
7357dd7cddfSDavid du Colombier /*
7367dd7cddfSDavid du Colombier * Convert v, which is nhave bits wide, into its nwant bits wide equivalent.
7377dd7cddfSDavid du Colombier * Replicates to widen the value, truncates to narrow it.
7387dd7cddfSDavid du Colombier */
7397dd7cddfSDavid du Colombier ulong
replbits(ulong v,int nhave,int nwant)7407dd7cddfSDavid du Colombier replbits(ulong v, int nhave, int nwant)
7417dd7cddfSDavid du Colombier {
7427dd7cddfSDavid du Colombier v &= (1<<nhave)-1;
7437dd7cddfSDavid du Colombier for(; nhave<nwant; nhave*=2)
7447dd7cddfSDavid du Colombier v |= v<<nhave;
7457dd7cddfSDavid du Colombier v >>= (nhave-nwant);
7467dd7cddfSDavid du Colombier return v & ((1<<nwant)-1);
7477dd7cddfSDavid du Colombier }
7487dd7cddfSDavid du Colombier
7497dd7cddfSDavid du Colombier /*
7507dd7cddfSDavid du Colombier * Decode a pixel into the uchar* values.
7517dd7cddfSDavid du Colombier */
7527dd7cddfSDavid du Colombier void
pixtorgba(ulong v,uchar * r,uchar * g,uchar * b,uchar * a)7537dd7cddfSDavid du Colombier pixtorgba(ulong v, uchar *r, uchar *g, uchar *b, uchar *a)
7547dd7cddfSDavid du Colombier {
7557dd7cddfSDavid du Colombier *a = v>>24;
7567dd7cddfSDavid du Colombier *r = v>>16;
7577dd7cddfSDavid du Colombier *g = v>>8;
7587dd7cddfSDavid du Colombier *b = v;
7597dd7cddfSDavid du Colombier }
7607dd7cddfSDavid du Colombier
7617dd7cddfSDavid du Colombier /*
7627dd7cddfSDavid du Colombier * Convert uchar channels into ulong pixel.
7637dd7cddfSDavid du Colombier */
7647dd7cddfSDavid du Colombier ulong
rgbatopix(uchar r,uchar g,uchar b,uchar a)7657dd7cddfSDavid du Colombier rgbatopix(uchar r, uchar g, uchar b, uchar a)
7667dd7cddfSDavid du Colombier {
7677dd7cddfSDavid du Colombier return (a<<24)|(r<<16)|(g<<8)|b;
7687dd7cddfSDavid du Colombier }
7697dd7cddfSDavid du Colombier
7707dd7cddfSDavid du Colombier /*
7717dd7cddfSDavid du Colombier * Retrieve the pixel value at pt in the image.
7727dd7cddfSDavid du Colombier */
7737dd7cddfSDavid du Colombier ulong
getpixel(Memimage * img,Point pt)7747dd7cddfSDavid du Colombier getpixel(Memimage *img, Point pt)
7757dd7cddfSDavid du Colombier {
7767dd7cddfSDavid du Colombier uchar r, g, b, a, *p;
7777dd7cddfSDavid du Colombier int nbits, npack, bpp;
7787dd7cddfSDavid du Colombier ulong v, c, rbits, bits;
7797dd7cddfSDavid du Colombier
7807dd7cddfSDavid du Colombier r = g = b = 0;
7817dd7cddfSDavid du Colombier a = ~0; /* default alpha is full */
7827dd7cddfSDavid du Colombier
7837dd7cddfSDavid du Colombier p = byteaddr(img, pt);
7847dd7cddfSDavid du Colombier v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
7857dd7cddfSDavid du Colombier bpp = img->depth;
7867dd7cddfSDavid du Colombier if(bpp<8){
7877dd7cddfSDavid du Colombier /*
7887dd7cddfSDavid du Colombier * Sub-byte greyscale pixels.
7897dd7cddfSDavid du Colombier *
7907dd7cddfSDavid du Colombier * We want to throw away the top pt.x%npack pixels and then use the next bpp bits
7917dd7cddfSDavid du Colombier * in the bottom byte of v. This madness is due to having big endian bits
7927dd7cddfSDavid du Colombier * but little endian bytes.
7937dd7cddfSDavid du Colombier */
7947dd7cddfSDavid du Colombier npack = 8/bpp;
7957dd7cddfSDavid du Colombier v >>= 8 - bpp*(pt.x%npack+1);
7967dd7cddfSDavid du Colombier v &= (1<<bpp)-1;
7977dd7cddfSDavid du Colombier r = g = b = replbits(v, bpp, 8);
7987dd7cddfSDavid du Colombier }else{
7997dd7cddfSDavid du Colombier /*
8007dd7cddfSDavid du Colombier * General case. We need to parse the channel descriptor and do what it says.
8017dd7cddfSDavid du Colombier * In all channels but the color map, we replicate to 8 bits because that's the
8027dd7cddfSDavid du Colombier * precision that all calculations are done at.
8037dd7cddfSDavid du Colombier *
8047dd7cddfSDavid du Colombier * In the case of the color map, we leave the bits alone, in case a color map
8057dd7cddfSDavid du Colombier * with less than 8 bits of index is used. This is currently disallowed, so it's
8067dd7cddfSDavid du Colombier * sort of silly.
8077dd7cddfSDavid du Colombier */
8087dd7cddfSDavid du Colombier
8097dd7cddfSDavid du Colombier for(c=img->chan; c; c>>=8){
8107dd7cddfSDavid du Colombier nbits = NBITS(c);
8117dd7cddfSDavid du Colombier bits = v & ((1<<nbits)-1);
8127dd7cddfSDavid du Colombier rbits = replbits(bits, nbits, 8);
8137dd7cddfSDavid du Colombier v >>= nbits;
8147dd7cddfSDavid du Colombier switch(TYPE(c)){
8157dd7cddfSDavid du Colombier case CRed:
8167dd7cddfSDavid du Colombier r = rbits;
8177dd7cddfSDavid du Colombier break;
8187dd7cddfSDavid du Colombier case CGreen:
8197dd7cddfSDavid du Colombier g = rbits;
8207dd7cddfSDavid du Colombier break;
8217dd7cddfSDavid du Colombier case CBlue:
8227dd7cddfSDavid du Colombier b = rbits;
8237dd7cddfSDavid du Colombier break;
8247dd7cddfSDavid du Colombier case CGrey:
8257dd7cddfSDavid du Colombier r = g = b = rbits;
8267dd7cddfSDavid du Colombier break;
8277dd7cddfSDavid du Colombier case CAlpha:
8287dd7cddfSDavid du Colombier a = rbits;
8297dd7cddfSDavid du Colombier break;
8307dd7cddfSDavid du Colombier case CMap:
8317dd7cddfSDavid du Colombier p = img->cmap->cmap2rgb + 3*bits;
8327dd7cddfSDavid du Colombier r = p[0];
8337dd7cddfSDavid du Colombier g = p[1];
8347dd7cddfSDavid du Colombier b = p[2];
8357dd7cddfSDavid du Colombier break;
8367dd7cddfSDavid du Colombier case CIgnore:
8377dd7cddfSDavid du Colombier break;
8387dd7cddfSDavid du Colombier default:
8397dd7cddfSDavid du Colombier fprint(2, "unknown channel type %lud\n", TYPE(c));
8407dd7cddfSDavid du Colombier abort();
8417dd7cddfSDavid du Colombier }
8427dd7cddfSDavid du Colombier }
8437dd7cddfSDavid du Colombier }
8447dd7cddfSDavid du Colombier return rgbatopix(r, g, b, a);
8457dd7cddfSDavid du Colombier }
8467dd7cddfSDavid du Colombier
8477dd7cddfSDavid du Colombier /*
8487dd7cddfSDavid du Colombier * Return the greyscale equivalent of a pixel.
8497dd7cddfSDavid du Colombier */
8507dd7cddfSDavid du Colombier uchar
getgrey(Memimage * img,Point pt)8517dd7cddfSDavid du Colombier getgrey(Memimage *img, Point pt)
8527dd7cddfSDavid du Colombier {
8537dd7cddfSDavid du Colombier uchar r, g, b, a;
8547dd7cddfSDavid du Colombier pixtorgba(getpixel(img, pt), &r, &g, &b, &a);
8557dd7cddfSDavid du Colombier return RGB2K(r, g, b);
8567dd7cddfSDavid du Colombier }
8577dd7cddfSDavid du Colombier
8587dd7cddfSDavid du Colombier /*
8597dd7cddfSDavid du Colombier * Return the value at pt in image, if image is interpreted
8607dd7cddfSDavid du Colombier * as a mask. This means the alpha channel if present, else
8617dd7cddfSDavid du Colombier * the greyscale or its computed equivalent.
8627dd7cddfSDavid du Colombier */
8637dd7cddfSDavid du Colombier uchar
getmask(Memimage * img,Point pt)8647dd7cddfSDavid du Colombier getmask(Memimage *img, Point pt)
8657dd7cddfSDavid du Colombier {
8667dd7cddfSDavid du Colombier if(img->flags&Falpha)
8677dd7cddfSDavid du Colombier return getpixel(img, pt)>>24;
8687dd7cddfSDavid du Colombier else
8697dd7cddfSDavid du Colombier return getgrey(img, pt);
8707dd7cddfSDavid du Colombier }
8717dd7cddfSDavid du Colombier #undef DBG
8727dd7cddfSDavid du Colombier
8737dd7cddfSDavid du Colombier #define DBG if(0)
8747dd7cddfSDavid du Colombier /*
8757dd7cddfSDavid du Colombier * Write a pixel to img at point pt.
8767dd7cddfSDavid du Colombier *
8777dd7cddfSDavid du Colombier * We do this by reading a 32-bit little endian
8787dd7cddfSDavid du Colombier * value from p and then writing it back
8797dd7cddfSDavid du Colombier * after tweaking the appropriate bits. Because
8807dd7cddfSDavid du Colombier * the data is little endian, we don't have to worry
8817dd7cddfSDavid du Colombier * about what the actual depth is, as long as it is
8827dd7cddfSDavid du Colombier * less than 32 bits.
8837dd7cddfSDavid du Colombier */
8847dd7cddfSDavid du Colombier void
putpixel(Memimage * img,Point pt,ulong nv)8857dd7cddfSDavid du Colombier putpixel(Memimage *img, Point pt, ulong nv)
8867dd7cddfSDavid du Colombier {
8877dd7cddfSDavid du Colombier uchar r, g, b, a, *p, *q;
8887dd7cddfSDavid du Colombier ulong c, mask, bits, v;
8897dd7cddfSDavid du Colombier int bpp, sh, npack, nbits;
8907dd7cddfSDavid du Colombier
8917dd7cddfSDavid du Colombier pixtorgba(nv, &r, &g, &b, &a);
8927dd7cddfSDavid du Colombier
8937dd7cddfSDavid du Colombier p = byteaddr(img, pt);
8947dd7cddfSDavid du Colombier v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
8957dd7cddfSDavid du Colombier bpp = img->depth;
8967dd7cddfSDavid du Colombier DBG print("v %.8lux...", v);
8977dd7cddfSDavid du Colombier if(bpp < 8){
8987dd7cddfSDavid du Colombier /*
8997dd7cddfSDavid du Colombier * Sub-byte greyscale pixels. We need to skip the leftmost pt.x%npack pixels,
9007dd7cddfSDavid du Colombier * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels.
9017dd7cddfSDavid du Colombier */
9027dd7cddfSDavid du Colombier npack = 8/bpp;
9037dd7cddfSDavid du Colombier sh = bpp*(npack - pt.x%npack - 1);
9047dd7cddfSDavid du Colombier bits = RGB2K(r,g,b);
9057dd7cddfSDavid du Colombier DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp));
9067dd7cddfSDavid du Colombier bits = replbits(bits, 8, bpp);
9077dd7cddfSDavid du Colombier mask = (1<<bpp)-1;
9087dd7cddfSDavid du Colombier DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
9097dd7cddfSDavid du Colombier mask <<= sh;
9107dd7cddfSDavid du Colombier bits <<= sh;
9117dd7cddfSDavid du Colombier DBG print("(%lux & %lux) | (%lux & %lux)", v, ~mask, bits, mask);
9127dd7cddfSDavid du Colombier v = (v & ~mask) | (bits & mask);
9137dd7cddfSDavid du Colombier } else {
9147dd7cddfSDavid du Colombier /*
9157dd7cddfSDavid du Colombier * General case. We need to parse the channel descriptor again.
9167dd7cddfSDavid du Colombier */
9177dd7cddfSDavid du Colombier sh = 0;
9187dd7cddfSDavid du Colombier for(c=img->chan; c; c>>=8){
9197dd7cddfSDavid du Colombier nbits = NBITS(c);
9207dd7cddfSDavid du Colombier switch(TYPE(c)){
9217dd7cddfSDavid du Colombier case CRed:
9227dd7cddfSDavid du Colombier bits = r;
9237dd7cddfSDavid du Colombier break;
9247dd7cddfSDavid du Colombier case CGreen:
9257dd7cddfSDavid du Colombier bits = g;
9267dd7cddfSDavid du Colombier break;
9277dd7cddfSDavid du Colombier case CBlue:
9287dd7cddfSDavid du Colombier bits = b;
9297dd7cddfSDavid du Colombier break;
9307dd7cddfSDavid du Colombier case CGrey:
9317dd7cddfSDavid du Colombier bits = RGB2K(r, g, b);
9327dd7cddfSDavid du Colombier break;
9337dd7cddfSDavid du Colombier case CAlpha:
9347dd7cddfSDavid du Colombier bits = a;
9357dd7cddfSDavid du Colombier break;
9367dd7cddfSDavid du Colombier case CIgnore:
9377dd7cddfSDavid du Colombier bits = 0;
9387dd7cddfSDavid du Colombier break;
9397dd7cddfSDavid du Colombier case CMap:
9407dd7cddfSDavid du Colombier q = img->cmap->rgb2cmap;
9417dd7cddfSDavid du Colombier bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)];
9427dd7cddfSDavid du Colombier break;
9437dd7cddfSDavid du Colombier default:
9447dd7cddfSDavid du Colombier SET(bits);
9457dd7cddfSDavid du Colombier fprint(2, "unknown channel type %lud\n", TYPE(c));
9467dd7cddfSDavid du Colombier abort();
9477dd7cddfSDavid du Colombier }
9487dd7cddfSDavid du Colombier
9497dd7cddfSDavid du Colombier DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits));
9507dd7cddfSDavid du Colombier if(TYPE(c) != CMap)
9517dd7cddfSDavid du Colombier bits = replbits(bits, 8, nbits);
9527dd7cddfSDavid du Colombier mask = (1<<nbits)-1;
9537dd7cddfSDavid du Colombier DBG print("bits %lux mask %lux sh %d...", bits, mask, sh);
9547dd7cddfSDavid du Colombier bits <<= sh;
9557dd7cddfSDavid du Colombier mask <<= sh;
9567dd7cddfSDavid du Colombier v = (v & ~mask) | (bits & mask);
9577dd7cddfSDavid du Colombier sh += nbits;
9587dd7cddfSDavid du Colombier }
9597dd7cddfSDavid du Colombier }
9607dd7cddfSDavid du Colombier DBG print("v %.8lux\n", v);
9617dd7cddfSDavid du Colombier p[0] = v;
9627dd7cddfSDavid du Colombier p[1] = v>>8;
9637dd7cddfSDavid du Colombier p[2] = v>>16;
9647dd7cddfSDavid du Colombier p[3] = v>>24;
9657dd7cddfSDavid du Colombier }
9667dd7cddfSDavid du Colombier #undef DBG
9677dd7cddfSDavid du Colombier
9687dd7cddfSDavid du Colombier #define DBG if(0)
9697dd7cddfSDavid du Colombier void
drawonepixel(Memimage * dst,Point dp,Memimage * src,Point sp,Memimage * mask,Point mp)9707dd7cddfSDavid du Colombier drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp)
9717dd7cddfSDavid du Colombier {
9727dd7cddfSDavid du Colombier uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk;
9737dd7cddfSDavid du Colombier
9747dd7cddfSDavid du Colombier pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da);
9757dd7cddfSDavid du Colombier pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa);
9767dd7cddfSDavid du Colombier m = getmask(mask, mp);
9777dd7cddfSDavid du Colombier M = 255-(sa*m)/255;
9787dd7cddfSDavid du Colombier
9797dd7cddfSDavid du Colombier DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m);
9807dd7cddfSDavid du Colombier if(dst->flags&Fgrey){
9817dd7cddfSDavid du Colombier /*
9827dd7cddfSDavid du Colombier * We need to do the conversion to grey before the alpha calculation
9837dd7cddfSDavid du Colombier * because the draw operator does this, and we need to be operating
9847dd7cddfSDavid du Colombier * at the same precision so we get exactly the same answers.
9857dd7cddfSDavid du Colombier */
9867dd7cddfSDavid du Colombier sk = RGB2K(sr, sg, sb);
9877dd7cddfSDavid du Colombier dk = RGB2K(dr, dg, db);
9887dd7cddfSDavid du Colombier dk = (sk*m + dk*M)/255;
9897dd7cddfSDavid du Colombier dr = dg = db = dk;
9907dd7cddfSDavid du Colombier da = (sa*m + da*M)/255;
9917dd7cddfSDavid du Colombier }else{
9927dd7cddfSDavid du Colombier /*
9937dd7cddfSDavid du Colombier * True color alpha calculation treats all channels (including alpha)
9947dd7cddfSDavid du Colombier * the same. It might have been nice to use an array, but oh well.
9957dd7cddfSDavid du Colombier */
9967dd7cddfSDavid du Colombier dr = (sr*m + dr*M)/255;
9977dd7cddfSDavid du Colombier dg = (sg*m + dg*M)/255;
9987dd7cddfSDavid du Colombier db = (sb*m + db*M)/255;
9997dd7cddfSDavid du Colombier da = (sa*m + da*M)/255;
10007dd7cddfSDavid du Colombier }
10017dd7cddfSDavid du Colombier
10027dd7cddfSDavid du Colombier DBG print("%x %x %x %x\n", dr,dg,db,da);
10037dd7cddfSDavid du Colombier putpixel(dst, dp, rgbatopix(dr, dg, db, da));
10047dd7cddfSDavid du Colombier }
1005