From e5888a1ffdae813d7575f5fb02275c6bb07e5199 Mon Sep 17 00:00:00 2001 From: Taru Karttunen Date: Wed, 30 Mar 2011 15:46:40 +0300 Subject: Import sources from 2011-03-30 iso image --- sys/src/libmemdraw/drawtest.c | 1004 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1004 insertions(+) create mode 100755 sys/src/libmemdraw/drawtest.c (limited to 'sys/src/libmemdraw/drawtest.c') diff --git a/sys/src/libmemdraw/drawtest.c b/sys/src/libmemdraw/drawtest.c new file mode 100755 index 000000000..df9dd0123 --- /dev/null +++ b/sys/src/libmemdraw/drawtest.c @@ -0,0 +1,1004 @@ +#include +#include +#include +#include +#include + +#define DBG if(0) +#define RGB2K(r,g,b) ((299*((ulong)(r))+587*((ulong)(g))+114*((ulong)(b)))/1000) + +/* + * This program tests the 'memimagedraw' primitive stochastically. + * It tests the combination aspects of it thoroughly, but since the + * three images it uses are disjoint, it makes no check of the + * correct behavior when images overlap. That is, however, much + * easier to get right and to test. + */ + +void drawonepixel(Memimage*, Point, Memimage*, Point, Memimage*, Point); +void verifyone(void); +void verifyline(void); +void verifyrect(void); +void verifyrectrepl(int, int); +void putpixel(Memimage *img, Point pt, ulong nv); +ulong rgbatopix(uchar, uchar, uchar, uchar); + +char *dchan, *schan, *mchan; +int dbpp, sbpp, mbpp; + +int drawdebug=0; +int seed; +int niters = 100; +int dbpp; /* bits per pixel in destination */ +int sbpp; /* bits per pixel in src */ +int mbpp; /* bits per pixel in mask */ +int dpm; /* pixel mask at high part of byte, in destination */ +int nbytes; /* in destination */ + +int Xrange = 64; +int Yrange = 8; + +Memimage *dst; +Memimage *src; +Memimage *mask; +Memimage *stmp; +Memimage *mtmp; +Memimage *ones; +uchar *dstbits; +uchar *srcbits; +uchar *maskbits; +ulong *savedstbits; + +void +rdb(void) +{ +} + +int +iprint(char *fmt, ...) +{ + int n; + va_list va; + char buf[1024]; + + va_start(va, fmt); + n = vseprint(buf, buf+sizeof buf, fmt, va) - buf; + va_end(va); + + write(1,buf,n); + return 1; +} + +void +main(int argc, char *argv[]) +{ + memimageinit(); + seed = time(0); + + ARGBEGIN{ + case 'x': + Xrange = atoi(ARGF()); + break; + case 'y': + Yrange = atoi(ARGF()); + break; + case 'n': + niters = atoi(ARGF()); + break; + case 's': + seed = atoi(ARGF()); + break; + }ARGEND + + dchan = "r8g8b8"; + schan = "r8g8b8"; + mchan = "r8g8b8"; + switch(argc){ + case 3: mchan = argv[2]; + case 2: schan = argv[1]; + case 1: dchan = argv[0]; + case 0: break; + default: goto Usage; + Usage: + fprint(2, "usage: dtest [dchan [schan [mchan]]]\n"); + exits("usage"); + } + +// fmtinstall('b', numbconv); /* binary! */ + + fprint(2, "%s -x %d -y %d -s 0x%x %s %s %s\n", argv0, Xrange, Yrange, seed, dchan, schan, mchan); + srand(seed); + + dst = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(dchan)); + src = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan)); + mask = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); + stmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(schan)); + mtmp = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); + ones = allocmemimage(Rect(0, 0, Xrange, Yrange), strtochan(mchan)); +// print("chan %lux %lux %lux %lux %lux %lux\n", dst->chan, src->chan, mask->chan, stmp->chan, mtmp->chan, ones->chan); + if(dst==0 || src==0 || mask==0 || mtmp==0 || ones==0) { + Alloc: + fprint(2, "dtest: allocation failed: %r\n"); + exits("alloc"); + } + nbytes = (4*Xrange+4)*Yrange; + srcbits = malloc(nbytes); + dstbits = malloc(nbytes); + maskbits = malloc(nbytes); + savedstbits = malloc(nbytes); + if(dstbits==0 || srcbits==0 || maskbits==0 || savedstbits==0) + goto Alloc; + dbpp = dst->depth; + sbpp = src->depth; + mbpp = mask->depth; + dpm = 0xFF ^ (0xFF>>dbpp); + memset(ones->data->bdata, 0xFF, ones->width*sizeof(ulong)*Yrange); + + + fprint(2, "dtest: verify single pixel operation\n"); + verifyone(); + + fprint(2, "dtest: verify full line non-replicated\n"); + verifyline(); + + fprint(2, "dtest: verify full rectangle non-replicated\n"); + verifyrect(); + + fprint(2, "dtest: verify full rectangle source replicated\n"); + verifyrectrepl(1, 0); + + fprint(2, "dtest: verify full rectangle mask replicated\n"); + verifyrectrepl(0, 1); + + fprint(2, "dtest: verify full rectangle source and mask replicated\n"); + verifyrectrepl(1, 1); + + exits(0); +} + +/* + * Dump out an ASCII representation of an image. The label specifies + * a list of characters to put at various points in the picture. + */ +static void +Bprintr5g6b5(Biobuf *bio, char*, ulong v) +{ + int r,g,b; + r = (v>>11)&31; + g = (v>>5)&63; + b = v&31; + Bprint(bio, "%.2x%.2x%.2x", r,g,b); +} + +static void +Bprintr5g5b5a1(Biobuf *bio, char*, ulong v) +{ + int r,g,b,a; + r = (v>>11)&31; + g = (v>>6)&31; + b = (v>>1)&31; + a = v&1; + Bprint(bio, "%.2x%.2x%.2x%.2x", r,g,b,a); +} + +void +dumpimage(char *name, Memimage *img, void *vdata, Point labelpt) +{ + Biobuf b; + uchar *data; + uchar *p; + char *arg; + void (*fmt)(Biobuf*, char*, ulong); + int npr, x, y, nb, bpp; + ulong v, mask; + Rectangle r; + + fmt = nil; + arg = nil; + switch(img->depth){ + case 1: + case 2: + case 4: + fmt = (void(*)(Biobuf*,char*,ulong))Bprint; + arg = "%.1ux"; + break; + case 8: + fmt = (void(*)(Biobuf*,char*,ulong))Bprint; + arg = "%.2ux"; + break; + case 16: + arg = nil; + if(img->chan == RGB16) + fmt = Bprintr5g6b5; + else{ + fmt = (void(*)(Biobuf*,char*,ulong))Bprint; + arg = "%.4ux"; + } + break; + case 24: + fmt = (void(*)(Biobuf*,char*,ulong))Bprint; + arg = "%.6lux"; + break; + case 32: + fmt = (void(*)(Biobuf*,char*,ulong))Bprint; + arg = "%.8lux"; + break; + } + if(fmt == nil){ + fprint(2, "bad format\n"); + abort(); + } + + r = img->r; + Binit(&b, 2, OWRITE); + data = vdata; + bpp = img->depth; + 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); + mask = (1ULL<data->bdata); + Bprint(&b, "%-4d\t", y); +// for(x=r.min.x; x>nb)&mask); + } + Bprint(&b, "\n"); + } + Bterm(&b); +} + +/* + * Verify that the destination pixel has the specified value. + * The value is in the high bits of v, suitably masked, but must + * be extracted from the destination Memimage. + */ +void +checkone(Point p, Point sp, Point mp) +{ + int delta; + uchar *dp, *sdp; + + delta = (uchar*)byteaddr(dst, p)-(uchar*)dst->data->bdata; + dp = (uchar*)dst->data->bdata+delta; + sdp = (uchar*)savedstbits+delta; + + if(memcmp(dp, sdp, (dst->depth+7)/8) != 0) { + fprint(2, "dtest: one bad pixel drawing at dst %P from source %P mask %P\n", p, sp, mp); + fprint(2, " %.2ux %.2ux %.2ux %.2ux should be %.2ux %.2ux %.2ux %.2ux\n", + dp[0], dp[1], dp[2], dp[3], sdp[0], sdp[1], sdp[2], sdp[3]); + fprint(2, "addresses dst %p src %p mask %p\n", dp, byteaddr(src, sp), byteaddr(mask, mp)); + dumpimage("src", src, src->data->bdata, sp); + dumpimage("mask", mask, mask->data->bdata, mp); + dumpimage("origdst", dst, dstbits, p); + dumpimage("dst", dst, dst->data->bdata, p); + dumpimage("gooddst", dst, savedstbits, p); + abort(); + } +} + +/* + * Verify that the destination line has the same value as the saved line. + */ +#define RECTPTS(r) (r).min.x, (r).min.y, (r).max.x, (r).max.y +void +checkline(Rectangle r, Point sp, Point mp, int y, Memimage *stmp, Memimage *mtmp) +{ + ulong *dp; + int nb; + ulong *saved; + + dp = wordaddr(dst, Pt(0, y)); + saved = savedstbits + y*dst->width; + if(dst->depth < 8) + nb = Xrange/(8/dst->depth); + else + nb = Xrange*(dst->depth/8); + if(memcmp(dp, saved, nb) != 0){ + fprint(2, "dtest: bad line at y=%d; saved %p dp %p\n", y, saved, dp); + fprint(2, "draw dst %R src %P mask %P\n", r, sp, mp); + dumpimage("src", src, src->data->bdata, sp); + if(stmp) dumpimage("stmp", stmp, stmp->data->bdata, sp); + dumpimage("mask", mask, mask->data->bdata, mp); + if(mtmp) dumpimage("mtmp", mtmp, mtmp->data->bdata, mp); + dumpimage("origdst", dst, dstbits, r.min); + dumpimage("dst", dst, dst->data->bdata, r.min); + dumpimage("gooddst", dst, savedstbits, r.min); + abort(); + } +} + +/* + * Fill the bits of an image with random data. + * The Memimage parameter is used only to make sure + * the data is well formatted: only ucbits is written. + */ +void +fill(Memimage *img, uchar *ucbits) +{ + int i, x, y; + ushort *up; + uchar alpha, r, g, b; + void *data; + + if((img->flags&Falpha) == 0){ + up = (ushort*)ucbits; + for(i=0; i> 7; + if(i+i != nbytes) + *(uchar*)up = lrand() >> 7; + }else{ + data = img->data->bdata; + img->data->bdata = ucbits; + + for(x=img->r.min.x; xr.max.x; x++) + for(y=img->r.min.y; yr.max.y; y++){ + alpha = rand() >> 4; + r = rand()%(alpha+1); + g = rand()%(alpha+1); + b = rand()%(alpha+1); + putpixel(img, Pt(x,y), rgbatopix(r,g,b,alpha)); + } + img->data->bdata = data; + } + +} + +/* + * Mask is preset; do the rest + */ +void +verifyonemask(void) +{ + Point dp, sp, mp; + + fill(dst, dstbits); + fill(src, srcbits); + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + + dp.x = nrand(Xrange); + dp.y = nrand(Yrange); + + sp.x = nrand(Xrange); + sp.y = nrand(Yrange); + + mp.x = nrand(Xrange); + mp.y = nrand(Yrange); + + drawonepixel(dst, dp, src, sp, mask, mp); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + memmove(savedstbits, dst->data->bdata, dst->width*sizeof(ulong)*Yrange); + + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + memimagedraw(dst, Rect(dp.x, dp.y, dp.x+1, dp.y+1), src, sp, mask, mp, SoverD); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + + checkone(dp, sp, mp); +} + +void +verifyone(void) +{ + int i; + + /* mask all zeros */ + memset(maskbits, 0, nbytes); + for(i=0; idata->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + + dr.min.x = nrand(Xrange-1); + dr.min.y = nrand(Yrange-1); + dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x); + dr.max.y = dr.min.y + 1; + + sp.x = nrand(Xrange); + sp.y = nrand(Yrange); + + mp.x = nrand(Xrange); + mp.y = nrand(Yrange); + + tp = sp; + up = mp; + for(x=dr.min.x; xdata->bdata, dst->width*sizeof(ulong)*Yrange); + + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + + memimagedraw(dst, dr, src, sp, mask, mp, SoverD); + checkline(dr, drawrepl(src->r, sp), drawrepl(mask->r, mp), dr.min.y, nil, nil); +} + +void +verifyline(void) +{ + int i; + + /* mask all ones */ + memset(maskbits, 0xFF, nbytes); + for(i=0; idata->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + + dr.min.x = nrand(Xrange-1); + dr.min.y = nrand(Yrange-1); + dr.max.x = dr.min.x + 1 + nrand(Xrange-1-dr.min.x); + dr.max.y = dr.min.y + 1 + nrand(Yrange-1-dr.min.y); + + sp.x = nrand(Xrange); + sp.y = nrand(Yrange); + + mp.x = nrand(Xrange); + mp.y = nrand(Yrange); + + tp = sp; + up = mp; + for(y=dr.min.y; ydata->bdata, dst->width*sizeof(ulong)*Yrange); + + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + + memimagedraw(dst, dr, src, sp, mask, mp, SoverD); + for(y=0; yr, sp), drawrepl(mask->r, mp), y, nil, nil); +} + +void +verifyrect(void) +{ + int i; + + /* mask all zeros */ + memset(maskbits, 0, nbytes); + for(i=0; ir) */ + r.min.x = nrand(Xrange-1); + r.min.y = nrand(Yrange-1); + /* make it trivial more often than pure chance allows */ + switch(lrand()&0){ + case 1: + r.max.x = r.min.x + 2; + r.max.y = r.min.y + 2; + if(r.max.x < Xrange && r.max.y < Yrange) + break; + /* fall through */ + case 0: + r.max.x = r.min.x + 1; + r.max.y = r.min.y + 1; + break; + default: + if(r.min.x+3 >= Xrange) + r.max.x = Xrange; + else + r.max.x = r.min.x+3 + nrand(Xrange-(r.min.x+3)); + + if(r.min.y+3 >= Yrange) + r.max.y = Yrange; + else + r.max.y = r.min.y+3 + nrand(Yrange-(r.min.y+3)); + } + assert(r.min.x >= 0); + assert(r.max.x <= Xrange); + assert(r.min.y >= 0); + assert(r.max.y <= Yrange); + /* copy from i to tmp so we have just the replicated bits */ + nb = tmp->width*sizeof(ulong)*Yrange; + memset(tmp->data->bdata, 0, nb); + memimagedraw(tmp, r, i, r.min, ones, r.min, SoverD); + memmove(i->data->bdata, tmp->data->bdata, nb); + /* i is now a non-replicated instance of the replication */ + /* replicate it by hand through tmp */ + memset(tmp->data->bdata, 0, nb); + x = -(tilexy(r.min.x, r.max.x, 0)-r.min.x); + for(; xflags |= Frepl; + i->r = r; + i->clipr = randrect(); +// fprint(2, "replicate [[%d %d] [%d %d]] [[%d %d][%d %d]]\n", r.min.x, r.min.y, r.max.x, r.max.y, +// i->clipr.min.x, i->clipr.min.y, i->clipr.max.x, i->clipr.max.y); + tmp->clipr = i->clipr; +} + +/* + * Mask is preset; do the rest + */ +void +verifyrectmaskrepl(int srcrepl, int maskrepl) +{ + Point sp, mp, tp, up; + Rectangle dr; + int x, y; + Memimage *s, *m; + +// print("verfrect %d %d\n", srcrepl, maskrepl); + src->flags &= ~Frepl; + src->r = Rect(0, 0, Xrange, Yrange); + src->clipr = src->r; + stmp->flags &= ~Frepl; + stmp->r = Rect(0, 0, Xrange, Yrange); + stmp->clipr = src->r; + mask->flags &= ~Frepl; + mask->r = Rect(0, 0, Xrange, Yrange); + mask->clipr = mask->r; + mtmp->flags &= ~Frepl; + mtmp->r = Rect(0, 0, Xrange, Yrange); + mtmp->clipr = mask->r; + + fill(dst, dstbits); + fill(src, srcbits); + + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + memmove(src->data->bdata, srcbits, src->width*sizeof(ulong)*Yrange); + memmove(mask->data->bdata, maskbits, mask->width*sizeof(ulong)*Yrange); + + if(srcrepl){ + replicate(src, stmp); + s = stmp; + }else + s = src; + if(maskrepl){ + replicate(mask, mtmp); + m = mtmp; + }else + m = mask; + + dr = randrect(); + + sp.x = nrand(Xrange); + sp.y = nrand(Yrange); + + mp.x = nrand(Xrange); + mp.y = nrand(Yrange); + +DBG print("smalldraws\n"); + for(tp.y=sp.y,up.y=mp.y,y=dr.min.y; ydata->bdata, dst->width*sizeof(ulong)*Yrange); + + memmove(dst->data->bdata, dstbits, dst->width*sizeof(ulong)*Yrange); + +DBG print("bigdraw\n"); + memimagedraw(dst, dr, src, sp, mask, mp, SoverD); + for(y=0; yr, sp), drawrepl(mask->r, mp), y, srcrepl?stmp:nil, maskrepl?mtmp:nil); +} + +void +verifyrectrepl(int srcrepl, int maskrepl) +{ + int i; + + /* mask all ones */ + memset(maskbits, 0xFF, nbytes); + for(i=0; i>= (nhave-nwant); + return v & ((1<>24; + *r = v>>16; + *g = v>>8; + *b = v; +} + +/* + * Convert uchar channels into ulong pixel. + */ +ulong +rgbatopix(uchar r, uchar g, uchar b, uchar a) +{ + return (a<<24)|(r<<16)|(g<<8)|b; +} + +/* + * Retrieve the pixel value at pt in the image. + */ +ulong +getpixel(Memimage *img, Point pt) +{ + uchar r, g, b, a, *p; + int nbits, npack, bpp; + ulong v, c, rbits, bits; + + r = g = b = 0; + a = ~0; /* default alpha is full */ + + p = byteaddr(img, pt); + v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); + bpp = img->depth; + if(bpp<8){ + /* + * Sub-byte greyscale pixels. + * + * We want to throw away the top pt.x%npack pixels and then use the next bpp bits + * in the bottom byte of v. This madness is due to having big endian bits + * but little endian bytes. + */ + npack = 8/bpp; + v >>= 8 - bpp*(pt.x%npack+1); + v &= (1<chan; c; c>>=8){ + nbits = NBITS(c); + bits = v & ((1<>= nbits; + switch(TYPE(c)){ + case CRed: + r = rbits; + break; + case CGreen: + g = rbits; + break; + case CBlue: + b = rbits; + break; + case CGrey: + r = g = b = rbits; + break; + case CAlpha: + a = rbits; + break; + case CMap: + p = img->cmap->cmap2rgb + 3*bits; + r = p[0]; + g = p[1]; + b = p[2]; + break; + case CIgnore: + break; + default: + fprint(2, "unknown channel type %lud\n", TYPE(c)); + abort(); + } + } + } + return rgbatopix(r, g, b, a); +} + +/* + * Return the greyscale equivalent of a pixel. + */ +uchar +getgrey(Memimage *img, Point pt) +{ + uchar r, g, b, a; + pixtorgba(getpixel(img, pt), &r, &g, &b, &a); + return RGB2K(r, g, b); +} + +/* + * Return the value at pt in image, if image is interpreted + * as a mask. This means the alpha channel if present, else + * the greyscale or its computed equivalent. + */ +uchar +getmask(Memimage *img, Point pt) +{ + if(img->flags&Falpha) + return getpixel(img, pt)>>24; + else + return getgrey(img, pt); +} +#undef DBG + +#define DBG if(0) +/* + * Write a pixel to img at point pt. + * + * We do this by reading a 32-bit little endian + * value from p and then writing it back + * after tweaking the appropriate bits. Because + * the data is little endian, we don't have to worry + * about what the actual depth is, as long as it is + * less than 32 bits. + */ +void +putpixel(Memimage *img, Point pt, ulong nv) +{ + uchar r, g, b, a, *p, *q; + ulong c, mask, bits, v; + int bpp, sh, npack, nbits; + + pixtorgba(nv, &r, &g, &b, &a); + + p = byteaddr(img, pt); + v = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); + bpp = img->depth; +DBG print("v %.8lux...", v); + if(bpp < 8){ + /* + * Sub-byte greyscale pixels. We need to skip the leftmost pt.x%npack pixels, + * which is equivalent to skipping the rightmost npack - pt.x%npack - 1 pixels. + */ + npack = 8/bpp; + sh = bpp*(npack - pt.x%npack - 1); + bits = RGB2K(r,g,b); +DBG print("repl %lux 8 %d = %lux...", bits, bpp, replbits(bits, 8, bpp)); + bits = replbits(bits, 8, bpp); + mask = (1<chan; c; c>>=8){ + nbits = NBITS(c); + switch(TYPE(c)){ + case CRed: + bits = r; + break; + case CGreen: + bits = g; + break; + case CBlue: + bits = b; + break; + case CGrey: + bits = RGB2K(r, g, b); + break; + case CAlpha: + bits = a; + break; + case CIgnore: + bits = 0; + break; + case CMap: + q = img->cmap->rgb2cmap; + bits = q[(r>>4)*16*16+(g>>4)*16+(b>>4)]; + break; + default: + SET(bits); + fprint(2, "unknown channel type %lud\n", TYPE(c)); + abort(); + } + +DBG print("repl %lux 8 %d = %lux...", bits, nbits, replbits(bits, 8, nbits)); + if(TYPE(c) != CMap) + bits = replbits(bits, 8, nbits); + mask = (1<>8; + p[2] = v>>16; + p[3] = v>>24; +} +#undef DBG + +#define DBG if(0) +void +drawonepixel(Memimage *dst, Point dp, Memimage *src, Point sp, Memimage *mask, Point mp) +{ + uchar m, M, sr, sg, sb, sa, sk, dr, dg, db, da, dk; + + pixtorgba(getpixel(dst, dp), &dr, &dg, &db, &da); + pixtorgba(getpixel(src, sp), &sr, &sg, &sb, &sa); + m = getmask(mask, mp); + M = 255-(sa*m)/255; + +DBG print("dst %x %x %x %x src %x %x %x %x m %x = ", dr,dg,db,da, sr,sg,sb,sa, m); + if(dst->flags&Fgrey){ + /* + * We need to do the conversion to grey before the alpha calculation + * because the draw operator does this, and we need to be operating + * at the same precision so we get exactly the same answers. + */ + sk = RGB2K(sr, sg, sb); + dk = RGB2K(dr, dg, db); + dk = (sk*m + dk*M)/255; + dr = dg = db = dk; + da = (sa*m + da*M)/255; + }else{ + /* + * True color alpha calculation treats all channels (including alpha) + * the same. It might have been nice to use an array, but oh well. + */ + dr = (sr*m + dr*M)/255; + dg = (sg*m + dg*M)/255; + db = (sb*m + db*M)/255; + da = (sa*m + da*M)/255; + } + +DBG print("%x %x %x %x\n", dr,dg,db,da); + putpixel(dst, dp, rgbatopix(dr, dg, db, da)); +} -- cgit v1.2.3