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