#include <pool.h>
extern Pool* imagmem;
-int drawdebug;
/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
#define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
static ulong rgbatoimg(Memimage*, ulong);
static ulong pixelbits(Memimage*, Point);
-#define DBG if(0)
void
memimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
{
if(mask == nil)
mask = memopaque;
-DBG print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);
-
- if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
-// if(drawdebug)
-// iprint("empty clipped rectangle\n");
+ if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0)
return;
- }
- if(op < Clear || op > SoverD){
-// if(drawdebug)
-// iprint("op out of range: %d\n", op);
+ if(op < Clear || op > SoverD)
return;
- }
par.op = op;
par.dst = dst;
par.state |= Simplesrc;
par.srgba = imgtorgba(src, par.sval);
par.sdval = rgbatoimg(dst, par.srgba);
- if((par.srgba&0xFF) == 0 && (op&DoutS)){
-// if (drawdebug) iprint("fill with transparent source\n");
+ if((par.srgba&0xFF) == 0 && (op&DoutS))
return; /* no-op successfully handled */
- }
}
}
par.state |= Replmask;
if(Dx(mask->r)==1 && Dy(mask->r)==1){
par.mval = pixelbits(mask, mask->r.min);
- if(par.mval == 0 && (op&DoutS)){
-// if(drawdebug) iprint("fill with zero mask\n");
+ if(par.mval == 0 && (op&DoutS))
return; /* no-op successfully handled */
- }
par.state |= Simplemask;
if(par.mval == ~0)
par.state |= Fullmask;
}
}
-// if(drawdebug)
-// iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);
-DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
-
/*
* Now that we've clipped the parameters down to be consistent, we
* simply try sub-drawing routines in order until we find one that was able
* which checks to see if there is anything it can help with.
* There could be an if around this checking to see if dst is in video memory.
*/
-DBG print("test hwdraw\n");
- if(hwdraw(&par)){
-//if(drawdebug) iprint("hw handled\n");
-DBG print("hwdraw handled\n");
+ if(hwdraw(&par))
return;
- }
+
/*
* Optimizations using memmove and memset.
*/
-DBG print("test memoptdraw\n");
- if(memoptdraw(&par)){
-//if(drawdebug) iprint("memopt handled\n");
-DBG print("memopt handled\n");
+ if(memoptdraw(&par))
return;
- }
/*
* Character drawing.
* Solid source color being painted through a boolean mask onto a high res image.
*/
-DBG print("test chardraw\n");
- if(chardraw(&par)){
-//if(drawdebug) iprint("chardraw handled\n");
-DBG print("chardraw handled\n");
+ if(chardraw(&par))
return;
- }
/*
* General calculation-laden case that does alpha for each pixel.
*/
-DBG print("do alphadraw\n");
alphadraw(&par);
-//if(drawdebug) iprint("alphadraw handled\n");
-DBG print("alphadraw handled\n");
}
-#undef DBG
/*
int convdx;
};
-static uchar *drawbuf;
-static int ndrawbuf;
-static int mdrawbuf;
static Readfn greymaskread, replread, readptr;
static Writefn nullwrite;
static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
static Calcfn* boolcopyfn(Memimage*, Memimage*);
static Readfn* convfn(Memimage*, Param*, Memimage*, Param*, int*);
-static Readfn* ptrfn(Memimage*);
static Calcfn *alphacalc[Ncomp] =
{
assert(0 <= *y && *y < dy);
}
-static void
-dumpbuf(char *s, Buffer b, int n)
-{
- int i;
- uchar *p;
-
- print("%s", s);
- for(i=0; i<n; i++){
- print(" ");
- if(p=b.grey){
- print(" k%.2uX", *p);
- b.grey += b.delta;
- }else{
- if(p=b.red){
- print(" r%.2uX", *p);
- b.red += b.delta;
- }
- if(p=b.grn){
- print(" g%.2uX", *p);
- b.grn += b.delta;
- }
- if(p=b.blu){
- print(" b%.2uX", *p);
- b.blu += b.delta;
- }
- }
- if((p=b.alpha) != &ones){
- print(" α%.2uX", *p);
- b.alpha += b.delta;
- }
- }
- print("\n");
-}
-
/*
* For each scan line, we expand the pixels from source, mask, and destination
* into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not
* the calculator, and that buffer is passed to a function to write it to the destination.
* If the buffer is already pointing at the destination, the writing function is a no-op.
*/
-#define DBG if(0)
static int
alphadraw(Memdrawparam *par)
{
* but it avoids a fair amount of code duplication to make this a case here
* rather than have a separate booldraw.
*/
-//if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth);
if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
-//if(drawdebug) iprint("boolcopy...");
rdsrc = convfn(dst, &z->dpar, src, &z->spar, &ndrawbuf);
rddst = readptr;
rdmask = readfn(mask);
clipy(mask, &masky);
bsrc = rdsrc(&z->spar, z->spar.bufbase, srcy);
-DBG print("[");
bmask = rdmask(&z->mpar, z->mpar.bufbase, masky);
-DBG print("]\n");
bdst = rddst(&z->dpar, z->dpar.bufbase, dsty);
-DBG dumpbuf("src", bsrc, dx);
-DBG dumpbuf("mask", bmask, dx);
-DBG dumpbuf("dst", bdst, dx);
bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
wrdst(&z->dpar, z->dpar.bytermin+dsty*z->dpar.bwidth, bdst);
}
z->inuse = 0;
return 1;
}
-#undef DBG
static Buffer
alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
return b;
}
-#define DBG if(0)
static Buffer
readnbit(Param *p, uchar *buf, int y)
{
n = p->img->r.max.x - x;
r = p->bytermin + y*p->bwidth;
-DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
bits = *r++;
nbits = 8;
if(i=x&(npack-1)){
-DBG print("throwaway %d...", i);
bits <<= depth*i;
nbits -= depth*i;
}
for(i=0; i<n; i++){
if(nbits == 0){
-DBG print("(%.2ux)...", *r);
bits = *r++;
nbits = 8;
}
*w++ = repl[bits>>sh];
-DBG print("bit %x...", repl[bits>>sh]);
bits <<= depth;
nbits -= depth;
}
n = p->r.min.x - x;
r = p->bytey0s + y*p->bwidth;
-DBG print("x=%d r=%p...", x, r);
bits = *r++;
nbits = 8;
if(i=x&(npack-1)){
bits <<= depth*i;
nbits -= depth*i;
}
-DBG print("nbits=%d...", nbits);
for(i=0; i<n; i++){
if(nbits == 0){
bits = *r++;
nbits = 8;
}
*w++ = repl[bits>>sh];
-DBG print("bit %x...", repl[bits>>sh]);
bits <<= depth;
nbits -= depth;
-DBG print("bits %x nbits %d...", bits, nbits);
}
dx -= n;
if(dx == 0)
return b;
}
-#undef DBG
-#define DBG if(0)
static void
writenbit(Param *p, uchar *w, Buffer src)
{
for(; x<ex; x++){
bits <<= depth;
-DBG print(" %x", *r);
bits |= (*r++ >> sh);
nbits += depth;
if(nbits == 8){
bits |= *w & ((1<<sh)-1);
*w = bits;
}
-DBG print("\n");
return;
}
-#undef DBG
static Buffer
readcmap(Param *p, uchar *buf, int y)
}
}
-#define DBG if(0)
static Buffer
readbyte(Param *p, uchar *buf, int y)
{
alphaonly = p->alphaonly;
copyalpha = (img->flags&Falpha) != 0;
-DBG print("copyalpha %d alphaonly %d convgrey %d isgrey %d\n", copyalpha, alphaonly, convgrey, isgrey);
/* if we can, avoid processing everything */
if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
memset(&b, 0, sizeof b);
return b;
}
-DBG print("2\n");
rrepl = replbit[img->nbits[CRed]];
grepl = replbit[img->nbits[CGreen]];
brepl = replbit[img->nbits[CBlue]];
u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
if(copyalpha) {
*w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
-DBG print("a %x\n", w[-1]);
}
if(isgrey)
ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
if(convgrey){
-DBG print("g %x %x %x\n", ured, ugrn, ublu);
*w++ = RGB2K(ured, ugrn, ublu);
-DBG print("%x\n", w[-1]);
}else{
w[0] = ublu;
w[1] = ugrn;
b.grey = buf+copyalpha;
b.red = b.grn = b.blu = buf+copyalpha;
b.delta = copyalpha+1;
-DBG print("alpha %x grey %x\n", *b.alpha, *b.grey);
}else{
b.blu = buf+copyalpha;
b.grn = buf+copyalpha+1;
}
return b;
}
-#undef DBG
-#define DBG if(0)
static void
writebyte(Param *p, uchar *w, Buffer src)
{
mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
for(i=0; i<dx; i++){
u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
-DBG print("u %.8lux...", u);
u &= mask;
-DBG print("&mask %.8lux...", u);
if(isgrey){
u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
-DBG print("|grey %.8lux...", u);
grey += delta;
}else{
u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
red += delta;
grn += delta;
blu += delta;
-DBG print("|rgb %.8lux...", u);
}
if(isalpha){
u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
alpha += adelta;
-DBG print("|alpha %.8lux...", u);
}
w[0] = u;
w += nb;
}
}
-#undef DBG
static Readfn*
readfn(Memimage *img)
static Readfn*
convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar, int *ndrawbuf)
{
- if(dst->chan == src->chan && !(src->flags&Frepl)){
-//if(drawdebug) iprint("readptr...");
+ if(dst->chan == src->chan && !(src->flags&Frepl))
return readptr;
- }
if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
/* cheat because we know the replicated value is exactly the color map entry. */
-//if(drawdebug) iprint("Readnbit...");
return readnbit;
}
spar->dx = Dx(spar->img->r);
}
-//if(drawdebug) iprint("genconv...");
return genconv;
}
}
d += nb;
}
-// print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v);
return v;
}
-#define DBG if(0)
static int
memoptdraw(Memdrawparam *par)
{
dst = par->dst;
op = par->op;
-DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
/*
* If we have an opaque mask and source is one opaque pixel we can convert to the
* destination format and just replicate with memset.
int d, dwid, ppb, np, nb;
uchar *dp, lm, rm;
-DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
dwid = dst->width*sizeof(ulong);
dp = byteaddr(dst, par->r.min);
v = par->sdval;
-DBG print("sdval %lud, depth %d\n", v, dst->depth);
switch(dst->depth){
case 1:
case 2:
dx -= (ppb-np);
nb = 8 - np * dst->depth; /* no. bits used on right side of word */
lm = (1<<nb)-1;
-DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m);
/* right edge */
np = par->r.max.x&m; /* no. pixels used on left side of word */
dx -= np;
nb = 8 - np * dst->depth; /* no. bits unused on right side of word */
rm = ~((1<<nb)-1);
-DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m);
-DBG print("dx %d Dx %d\n", dx, Dx(par->r));
/* lm, rm are masks that are 1 where we should touch the bits */
if(dx < 0){ /* just one byte */
lm &= rm;
for(y=0; y<dy; y++, dp+=dwid){
if(lm){
-DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
*dp ^= (v ^ *dp) & lm;
dp++;
}
}
return 0;
}
-#undef DBG
/*
* Boolean character drawing.
* Solid opaque color through a 1-bit greyscale mask.
*/
-#define DBG if(0)
static int
chardraw(Memdrawparam *par)
{
Rectangle r, mr;
Memimage *mask, *src, *dst;
-if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n",
- par->mask->flags, par->mask->depth, par->src->flags,
- Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
-
mask = par->mask;
src = par->src;
dst = par->dst;
|| op != SoverD)
return 0;
-//if(drawdebug) iprint("chardraw...");
-
depth = mask->depth;
maskwid = mask->width*sizeof(ulong);
rp = byteaddr(mask, mr.min);
wp = byteaddr(dst, r.min);
dstwid = dst->width*sizeof(ulong);
-DBG print("bsh %d\n", bsh);
dy = Dy(r);
dx = Dx(r);
sp[2] = v>>16;
sp[3] = v>>24;
-//print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]);
for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
q = rp;
if(bsh)
bits = *q++;
switch(ddepth){
case 8:
-//if(drawdebug) iprint("8loop...");
wc = wp;
for(x=bx; x>ex; x--, wc++){
i = x&7;
if(i == 8-1)
bits = *q++;
-DBG print("bits %lux sh %d...", bits, i);
if((bits>>i)&1)
*wc = v;
}
i = x&7;
if(i == 8-1)
bits = *q++;
-DBG print("bits %lux sh %d...", bits, i);
if((bits>>i)&1)
*ws = v;
}
i = x&7;
if(i == 8-1)
bits = *q++;
-DBG print("bits %lux sh %d...", bits, i);
if((bits>>i)&1){
wc[0] = sp[0];
wc[1] = sp[1];
i = x&7;
if(i == 8-1)
bits = *q++;
-DBG iprint("bits %lux sh %d...", bits, i);
if((bits>>i)&1)
*wl = v;
}
break;
}
}
-
-DBG print("\n");
return 1;
}
-#undef DBG
-
-/*
- * Fill entire byte with replicated (if necessary) copy of source pixel,
- * assuming destination ldepth is >= source ldepth.
- *
- * This code is just plain wrong for >8bpp.
- *
-ulong
-membyteval(Memimage *src)
-{
- int i, val, bpp;
- uchar uc;
-
- unloadmemimage(src, src->r, &uc, 1);
- bpp = src->depth;
- uc <<= (src->r.min.x&(7/src->depth))*src->depth;
- uc &= ~(0xFF>>bpp);
- /* pixel value is now in high part of byte. repeat throughout byte
- val = uc;
- for(i=bpp; i<8; i<<=1)
- val |= val>>i;
- return val;
-}
- *
- */
void
memfillcolor(Memimage *i, ulong val)