7 static int tablesbuilt;
9 /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */
10 #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19)
13 * For 16-bit values, x / 255 == (t = x+1, (t+(t>>8)) >> 8).
14 * We add another 127 to round to the nearest value rather
17 * CALCxy does x bytewise calculations on y input images (x=1,4; y=1,2).
18 * CALC2x does two parallel 16-bit calculations on y input images (y=1,2).
20 #define CALC11(a, v, tmp) \
21 (tmp=(a)*(v)+128, (tmp+(tmp>>8))>>8)
23 #define CALC12(a1, v1, a2, v2, tmp) \
24 (tmp=(a1)*(v1)+(a2)*(v2)+128, (tmp+(tmp>>8))>>8)
28 #define CALC21(a, vvuu, tmp) \
29 (tmp=(a)*(vvuu)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK)
31 #define CALC41(a, rgba, tmp1, tmp2) \
32 (CALC21(a, rgba & MASK, tmp1) | \
33 (CALC21(a, (rgba>>8)&MASK, tmp2)<<8))
35 #define CALC22(a1, vvuu1, a2, vvuu2, tmp) \
36 (tmp=(a1)*(vvuu1)+(a2)*(vvuu2)+0x00800080, ((tmp+((tmp>>8)&MASK))>>8)&MASK)
38 #define CALC42(a1, rgba1, a2, rgba2, tmp1, tmp2) \
39 (CALC22(a1, rgba1 & MASK, a2, rgba2 & MASK, tmp1) | \
40 (CALC22(a1, (rgba1>>8) & MASK, a2, (rgba2>>8) & MASK, tmp2)<<8))
42 static void mktables(void);
43 typedef int Subdraw(Memdrawparam*);
44 static Subdraw chardraw, alphadraw, memoptdraw;
46 static Memimage* memones;
47 static Memimage* memzeros;
50 Memimage *memtransparent;
58 static int didinit = 0;
68 fmtinstall('R', Rfmt);
69 fmtinstall('P', Pfmt);
70 fmtinstall('b', __ifmt);
72 memones = allocmemimage(Rect(0,0,1,1), GREY1);
73 memones->flags |= Frepl;
74 memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
75 *byteaddr(memones, ZP) = ~0;
77 memzeros = allocmemimage(Rect(0,0,1,1), GREY1);
78 memzeros->flags |= Frepl;
79 memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);
80 *byteaddr(memzeros, ZP) = 0;
82 if(memones == nil || memzeros == nil)
83 assert(0 /*cannot initialize memimage library */); /* RSC BUG */
88 memtransparent = memzeros;
91 u32int _imgtorgba(Memimage*, u32int);
92 u32int _rgbatoimg(Memimage*, u32int);
93 u32int _pixelbits(Memimage*, Point);
95 #define DBG if(drawdebug)
96 static Memdrawparam par;
99 _memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op)
104 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);
106 if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){
108 /* iprint("empty clipped rectangle\n"); */
112 if(op < Clear || op > SoverD){
114 /* iprint("op out of range: %d\n", op); */
122 /* par.sr set by drawclip */
124 /* par.mr set by drawclip */
127 if(src->flags&Frepl){
128 par.state |= Replsrc;
129 if(Dx(src->r)==1 && Dy(src->r)==1){
130 par.sval = pixelbits(src, src->r.min);
131 par.state |= Simplesrc;
132 par.srgba = _imgtorgba(src, par.sval);
133 par.sdval = _rgbatoimg(dst, par.srgba);
134 if((par.srgba&0xFF) == 0 && (op&DoutS)){
135 /* if (drawdebug) iprint("fill with transparent source\n"); */
136 return nil; /* no-op successfully handled */
138 if((par.srgba&0xFF) == 0xFF)
139 par.state |= Fullsrc;
143 if(mask->flags & Frepl){
144 par.state |= Replmask;
145 if(Dx(mask->r)==1 && Dy(mask->r)==1){
146 par.mval = pixelbits(mask, mask->r.min);
147 if(par.mval == 0 && (op&DoutS)){
148 /* if(drawdebug) iprint("fill with zero mask\n"); */
149 return nil; /* no-op successfully handled */
151 par.state |= Simplemask;
153 par.state |= Fullmask;
154 par.mrgba = _imgtorgba(mask, par.mval);
159 /* iprint("dr %R sr %R mr %R...", r, par.sr, par.mr); */
160 DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);
166 _memimagedraw(Memdrawparam *par)
169 * Now that we've clipped the parameters down to be consistent, we
170 * simply try sub-drawing routines in order until we find one that was able
171 * to handle us. If the sub-drawing routine returns zero, it means it was
172 * unable to satisfy the request, so we do not return.
176 * Hardware support. Each video driver provides this function,
177 * which checks to see if there is anything it can help with.
178 * There could be an if around this checking to see if dst is in video memory.
180 DBG print("test hwdraw\n");
182 /*if(drawdebug) iprint("hw handled\n"); */
183 DBG print("hwdraw handled\n");
187 * Optimizations using memmove and memset.
189 DBG print("test memoptdraw\n");
191 /*if(drawdebug) iprint("memopt handled\n"); */
192 DBG print("memopt handled\n");
198 * Solid source color being painted through a boolean mask onto a high res image.
200 DBG print("test chardraw\n");
202 /*if(drawdebug) iprint("chardraw handled\n"); */
203 DBG print("chardraw handled\n");
208 * General calculation-laden case that does alpha for each pixel.
210 DBG print("do alphadraw\n");
212 /*if(drawdebug) iprint("alphadraw handled\n"); */
213 DBG print("alphadraw handled\n");
218 * Clip the destination rectangle further based on the properties of the
219 * source and mask rectangles. Once the destination rectangle is properly
220 * clipped, adjust the source and mask rectangles to be the same size.
221 * Then if source or mask is replicated, move its clipped rectangle
222 * so that its minimum point falls within the repl rectangle.
224 * Return zero if the final rectangle is null.
227 drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr)
233 if(r->min.x>=r->max.x || r->min.y>=r->max.y)
235 splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);
236 /* clip to destination */
238 if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))
240 /* move mask point */
241 p1->x += r->min.x-rmin.x;
242 p1->y += r->min.y-rmin.y;
243 /* move source point */
244 p0->x += r->min.x-rmin.x;
245 p0->y += r->min.y-rmin.y;
246 /* map destination rectangle into source */
248 sr->max.x = p0->x+Dx(*r);
249 sr->max.y = p0->y+Dy(*r);
250 /* sr is r in source coordinates; clip to source */
251 if(!(src->flags&Frepl) && !rectclip(sr, src->r))
253 if(!rectclip(sr, src->clipr))
255 /* compute and clip rectangle in mask */
257 /* move mask point with source */
258 p1->x += sr->min.x-p0->x;
259 p1->y += sr->min.y-p0->y;
261 mr->max.x = p1->x+Dx(*sr);
262 mr->max.y = p1->y+Dy(*sr);
264 /* mr is now rectangle in mask; clip it */
265 if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))
267 if(!rectclip(mr, mask->clipr))
269 /* reflect any clips back to source */
270 sr->min.x += mr->min.x-omr.min.x;
271 sr->min.y += mr->min.y-omr.min.y;
272 sr->max.x += mr->max.x-omr.max.x;
273 sr->max.y += mr->max.y-omr.max.y;
276 if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))
278 if(!rectclip(sr, mask->clipr))
283 /* move source clipping back to destination */
284 delta.x = r->min.x - p0->x;
285 delta.y = r->min.y - p0->y;
286 r->min.x = sr->min.x + delta.x;
287 r->min.y = sr->min.y + delta.y;
288 r->max.x = sr->max.x + delta.x;
289 r->max.y = sr->max.y + delta.y;
291 /* move source rectangle so sr->min is in src->r */
292 if(src->flags&Frepl) {
293 delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;
294 delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;
295 sr->min.x += delta.x;
296 sr->min.y += delta.y;
297 sr->max.x += delta.x;
298 sr->max.y += delta.y;
302 /* move mask point so it is in mask->r */
303 *p1 = drawrepl(mask->r, *p1);
305 mr->max.x = p1->x+Dx(*sr);
306 mr->max.y = p1->y+Dy(*sr);
308 assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));
309 assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));
310 assert(ptinrect(*p0, src->r));
311 assert(ptinrect(*p1, mask->r));
312 assert(ptinrect(r->min, dst->r));
320 static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */
321 static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */
322 static uchar conv28[256][4]; /* ... */
323 static uchar conv48[256][2];
326 * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8.
327 * the X's are where to put the bottom (ones) bit of the n-bit pattern.
328 * only the top 8 bits of the result are actually used.
329 * (the lower 8 bits are needed to get bits in the right place
330 * when n is not a divisor of 8.)
332 * Should check to see if its easier to just refer to replmul than
333 * use the precomputed values in replbit. On PCs it may well
334 * be; on machines with slow multiply instructions it probably isn't.
336 #define a ((((((((((((((((0
339 static int replmul[1+8] = {
341 a X X X X X X X X X X X X X X X X,
342 a _ X _ X _ X _ X _ X _ X _ X _ X,
343 a _ _ X _ _ X _ _ X _ _ X _ _ X _,
344 a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,
345 a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,
346 a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _,
347 a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,
348 a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,
357 int i, j, mask, sh, small;
362 fmtinstall('R', Rfmt);
363 fmtinstall('P', Pfmt);
366 /* bit replication up to 8 bits */
367 for(i=0; i<256; i++){
368 for(j=0; j<=8; j++){ /* j <= 8 [sic] */
369 small = i & ((1<<j)-1);
370 replbit[j][i] = (small*replmul[j])>>8;
374 /* bit unpacking up to 8 bits, only powers of 2 */
375 for(i=0; i<256; i++){
376 for(j=0, sh=7, mask=1; j<8; j++, sh--)
377 conv18[i][j] = replbit[1][(i>>sh)&mask];
379 for(j=0, sh=6, mask=3; j<4; j++, sh-=2)
380 conv28[i][j] = replbit[2][(i>>sh)&mask];
382 for(j=0, sh=4, mask=15; j<2; j++, sh-=4)
383 conv48[i][j] = replbit[4][(i>>sh)&mask];
387 static uchar ones = 0xff;
390 * General alpha drawing case. Can handle anything.
392 typedef struct Buffer Buffer;
394 /* used by most routines */
401 int delta; /* number of bytes to add to pointer to get next pixel to the right */
403 /* used by boolcalc* for mask data */
404 uchar *m; /* ptr to mask data r.min byte; like p->bytermin */
405 int mskip; /* no. of left bits to skip in *m */
406 uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */
407 int bmskip; /* no. of left bits to skip in *bm */
408 uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */
409 int emskip; /* no. of right bits to skip in *em */
412 typedef struct Param Param;
413 typedef Buffer Readfn(Param*, uchar*, int);
414 typedef void Writefn(Param*, uchar*, Buffer);
415 typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int, int);
421 /* giant rathole to customize functions with */
424 Readfn *greymaskcall;
425 Readfn *convreadcall;
426 Writefn *convwritecall;
435 uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */
436 uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */
437 uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */
440 int replcache; /* if set, cache buffers */
441 Buffer bcache[MAXBCACHE];
455 static uchar *drawbuf;
458 static Param spar, mpar, dpar; /* easier on the stacks */
459 static Readfn greymaskread, replread, readptr;
460 static Writefn nullwrite;
461 static Calcfn alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;
462 static Calcfn boolcalc14, boolcalc236789, boolcalc1011;
464 static Readfn* readfn(Memimage*);
465 static Readfn* readalphafn(Memimage*);
466 static Writefn* writefn(Memimage*);
468 static Calcfn* boolcopyfn(Memimage*, Memimage*);
469 static Readfn* convfn(Memimage*, Param*, Memimage*, Param*);
471 static Calcfn *alphacalc[Ncomp] =
473 alphacalc0, /* Clear */
474 alphacalc14, /* DoutS */
475 alphacalc2810, /* SoutD */
476 alphacalc3679, /* DxorS */
477 alphacalc14, /* DinS */
479 alphacalc3679, /* DatopS */
480 alphacalc3679, /* DoverS */
481 alphacalc2810, /* SinD */
482 alphacalc3679, /* SatopD */
483 alphacalc2810, /* S */
484 alphacalc11, /* SoverD */
487 static Calcfn *boolcalc[Ncomp] =
489 alphacalc0, /* Clear */
490 boolcalc14, /* DoutS */
491 boolcalc236789, /* SoutD */
492 boolcalc236789, /* DxorS */
493 boolcalc14, /* DinS */
495 boolcalc236789, /* DatopS */
496 boolcalc236789, /* DoverS */
497 boolcalc236789, /* SinD */
498 boolcalc236789, /* SatopD */
499 boolcalc1011, /* S */
500 boolcalc1011, /* SoverD */
508 if(ndrawbuf > mdrawbuf){
509 p = realloc(drawbuf, ndrawbuf);
511 werrstr("memimagedraw out of memory");
521 getparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf)
525 memset(p, 0, sizeof *p);
530 p->needbuf = needbuf;
531 p->convgrey = convgrey;
533 assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);
535 p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));
536 p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));
537 p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));
538 p->bwidth = sizeof(u32int)*img->width;
540 assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);
542 if(p->r.min.x == p->img->r.min.x)
543 assert(p->bytermin == p->bytey0s);
546 if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){
550 p->bufdelta = 4*p->dx;
551 p->bufoff = ndrawbuf;
552 ndrawbuf += p->bufdelta*nbuf;
556 clipy(Memimage *img, int *y)
565 assert(0 <= *y && *y < dy);
569 dumpbuf(char *s, Buffer b, int n)
578 print(" k%.2uX", *p);
582 print(" r%.2uX", *p);
586 print(" g%.2uX", *p);
590 print(" b%.2uX", *p);
594 if((p=b.alpha) != &ones){
595 print(" α%.2uX", *p);
603 * For each scan line, we expand the pixels from source, mask, and destination
604 * into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not
605 * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32),
606 * the readers need not copy the data: they can simply return pointers to the data.
607 * If the destination image is grey and the source is not, it is converted using the NTSC
610 * Once we have all the channels, we call either rgbcalc or greycalc, depending on
611 * whether the destination image is color. This is allowed to overwrite the dst buffer (perhaps
612 * the actual data, perhaps a copy) with its result. It should only overwrite the dst buffer
613 * with the same format (i.e. red bytes with red bytes, etc.) A new buffer is returned from
614 * the calculator, and that buffer is passed to a function to write it to the destination.
615 * If the buffer is already pointing at the destination, the writing function is a no-op.
617 #define DBG if(drawdebug)
619 alphadraw(Memdrawparam *par)
621 int isgrey, starty, endy, op;
622 int needbuf, dsty, srcy, masky;
624 Buffer bsrc, bdst, bmask;
625 Readfn *rdsrc, *rdmask, *rddst;
628 Memimage *src, *mask, *dst;
632 print("alphadraw %R\n", par->r);
646 isgrey = dst->flags&Fgrey;
649 * Buffering when src and dst are the same bitmap is sufficient but not
650 * necessary. There are stronger conditions we could use. We could
651 * check to see if the rectangles intersect, and if simply moving in the
652 * correct y direction can avoid the need to buffer.
654 needbuf = (src->data == dst->data);
656 getparam(&spar, src, sr, isgrey, needbuf);
657 getparam(&dpar, dst, r, isgrey, needbuf);
658 getparam(&mpar, mask, mr, 0, needbuf);
660 dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1;
661 spar.dir = mpar.dir = dpar.dir = dir;
664 * If the mask is purely boolean, we can convert from src to dst format
665 * when we read src, and then just copy it to dst where the mask tells us to.
666 * This requires a boolean (1-bit grey) mask and lack of a source alpha channel.
668 * The computation is accomplished by assigning the function pointers as follows:
669 * rdsrc - read and convert source into dst format in a buffer
670 * rdmask - convert mask to bytes, set pointer to it
671 * rddst - fill with pointer to real dst data, but do no reads
672 * calc - copy src onto dst when mask says to.
674 * This is slightly sleazy, since things aren't doing exactly what their names say,
675 * but it avoids a fair amount of code duplication to make this a case here
676 * rather than have a separate booldraw.
678 /*if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth); */
679 if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8 && op == SoverD){
680 /*if(drawdebug) iprint("boolcopy..."); */
681 rdsrc = convfn(dst, &dpar, src, &spar);
683 rdmask = readfn(mask);
684 calc = boolcopyfn(dst, mask);
687 /* usual alphadraw parameter fetching */
690 wrdst = writefn(dst);
691 calc = alphacalc[op];
694 * If there is no alpha channel, we'll ask for a grey channel
695 * and pretend it is the alpha.
697 if(mask->flags&Falpha){
698 rdmask = readalphafn(mask);
701 mpar.greymaskcall = readfn(mask);
703 rdmask = greymaskread;
706 * Should really be above, but then boolcopyfns would have
707 * to deal with bit alignment, and I haven't written that.
709 * This is a common case for things like ellipse drawing.
710 * When there's no alpha involved and the mask is boolean,
711 * we can avoid all the division and multiplication.
713 if(mask->chan == GREY1 && !(src->flags&Falpha))
715 else if(op == SoverD && !(src->flags&Falpha))
721 * If the image has a small enough repl rectangle,
722 * we can just read each line once and cache them.
725 spar.replcall = rdsrc;
729 mpar.replcall = rdmask;
733 if(allocdrawbuf() < 0)
737 * Before we were saving only offsets from drawbuf in the parameter
738 * structures; now that drawbuf has been grown to accomodate us,
739 * we can fill in the pointers.
741 spar.bufbase = drawbuf+spar.bufoff;
742 mpar.bufbase = drawbuf+mpar.bufoff;
743 dpar.bufbase = drawbuf+dpar.bufoff;
744 spar.convbuf = drawbuf+spar.convbufoff;
755 * srcy, masky, and dsty are offsets from the top of their
756 * respective Rectangles. they need to be contained within
757 * the rectangles, so clipy can keep them there without division.
759 srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r);
760 masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r);
761 dsty = starty + r.min.y - dst->r.min.y;
763 assert(0 <= srcy && srcy < Dy(src->r));
764 assert(0 <= masky && masky < Dy(mask->r));
765 assert(0 <= dsty && dsty < Dy(dst->r));
768 print("alphadraw: rdsrc=%p rdmask=%p rddst=%p calc=%p wrdst=%p\n",
769 rdsrc, rdmask, rddst, calc, wrdst);
770 for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){
775 bsrc = rdsrc(&spar, spar.bufbase, srcy);
777 bmask = rdmask(&mpar, mpar.bufbase, masky);
779 bdst = rddst(&dpar, dpar.bufbase, dsty);
780 DBG dumpbuf("src", bsrc, dx);
781 DBG dumpbuf("mask", bmask, dx);
782 DBG dumpbuf("dst", bdst, dx);
783 bdst = calc(bdst, bsrc, bmask, dx, isgrey, op);
784 DBG dumpbuf("bdst", bdst, dx);
785 wrdst(&dpar, dpar.bytermin+dsty*dpar.bwidth, bdst);
793 alphacalc0(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
797 memset(bdst.rgba, 0, dx*bdst.delta);
802 * Do the channels in the buffers match enough
803 * that we can do word-at-a-time operations
807 chanmatch(Buffer *bdst, Buffer *bsrc)
812 * first, r, g, b must be in the same place
815 drgb = (uchar*)bdst->rgba;
816 srgb = (uchar*)bsrc->rgba;
817 if(bdst->red - drgb != bsrc->red - srgb
818 || bdst->blu - drgb != bsrc->blu - srgb
819 || bdst->grn - drgb != bsrc->grn - srgb)
823 * that implies alpha is in the same place,
824 * if it is there at all (it might be == &ones).
825 * if the destination is &ones, we can scribble
826 * over the rgba slot just fine.
828 if(bdst->alpha == &ones)
832 * if the destination is not ones but the src is,
833 * then the simultaneous calculation will use
834 * bogus bytes from the src's rgba. no good.
836 if(bsrc->alpha == &ones)
840 * otherwise, alphas are in the same place.
846 alphacalc14(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
854 sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
855 q = bsrc.delta == 4 && bdst.delta == 4 && chanmatch(&bdst, &bsrc);
860 fd = CALC11(sa, ma, t);
865 *bdst.grey = CALC11(fd, *bdst.grey, t);
866 bsrc.grey += bsrc.delta;
867 bdst.grey += bdst.delta;
870 *bdst.rgba = CALC41(fd, *bdst.rgba, t, t1);
873 bsrc.alpha += sadelta;
874 bmask.alpha += bmask.delta;
877 *bdst.red = CALC11(fd, *bdst.red, t);
878 *bdst.grn = CALC11(fd, *bdst.grn, t);
879 *bdst.blu = CALC11(fd, *bdst.blu, t);
880 bsrc.red += bsrc.delta;
881 bsrc.blu += bsrc.delta;
882 bsrc.grn += bsrc.delta;
883 bdst.red += bdst.delta;
884 bdst.blu += bdst.delta;
885 bdst.grn += bdst.delta;
887 if(bdst.alpha != &ones){
888 *bdst.alpha = CALC11(fd, *bdst.alpha, t);
889 bdst.alpha += bdst.delta;
891 bmask.alpha += bmask.delta;
892 bsrc.alpha += sadelta;
898 alphacalc2810(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
906 sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
907 q = bsrc.delta == 4 && bdst.delta == 4 && chanmatch(&bdst, &bsrc);
916 fs = CALC11(fs, da, t);
919 *bdst.grey = CALC11(fs, *bsrc.grey, t);
920 bsrc.grey += bsrc.delta;
921 bdst.grey += bdst.delta;
924 *bdst.rgba = CALC41(fs, *bsrc.rgba, t, t1);
927 bmask.alpha += bmask.delta;
928 bdst.alpha += bdst.delta;
931 *bdst.red = CALC11(fs, *bsrc.red, t);
932 *bdst.grn = CALC11(fs, *bsrc.grn, t);
933 *bdst.blu = CALC11(fs, *bsrc.blu, t);
934 bsrc.red += bsrc.delta;
935 bsrc.blu += bsrc.delta;
936 bsrc.grn += bsrc.delta;
937 bdst.red += bdst.delta;
938 bdst.blu += bdst.delta;
939 bdst.grn += bdst.delta;
941 if(bdst.alpha != &ones){
942 *bdst.alpha = CALC11(fs, *bsrc.alpha, t);
943 bdst.alpha += bdst.delta;
945 bmask.alpha += bmask.delta;
946 bsrc.alpha += sadelta;
952 alphacalc3679(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
956 int i, sa, ma, da, q;
960 sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
961 q = bsrc.delta == 4 && bdst.delta == 4 && chanmatch(&bdst, &bsrc);
968 fs = CALC11(ma, da, t);
970 fs = CALC11(ma, 255-da, t);
974 fd = CALC11(sa, ma, t);
980 *bdst.grey = CALC12(fs, *bsrc.grey, fd, *bdst.grey, t);
981 bsrc.grey += bsrc.delta;
982 bdst.grey += bdst.delta;
985 *bdst.rgba = CALC42(fs, *bsrc.rgba, fd, *bdst.rgba, t, t1);
988 bsrc.alpha += sadelta;
989 bmask.alpha += bmask.delta;
990 bdst.alpha += bdst.delta;
993 *bdst.red = CALC12(fs, *bsrc.red, fd, *bdst.red, t);
994 *bdst.grn = CALC12(fs, *bsrc.grn, fd, *bdst.grn, t);
995 *bdst.blu = CALC12(fs, *bsrc.blu, fd, *bdst.blu, t);
996 bsrc.red += bsrc.delta;
997 bsrc.blu += bsrc.delta;
998 bsrc.grn += bsrc.delta;
999 bdst.red += bdst.delta;
1000 bdst.blu += bdst.delta;
1001 bdst.grn += bdst.delta;
1003 if(bdst.alpha != &ones){
1004 *bdst.alpha = CALC12(fs, sa, fd, da, t);
1005 bdst.alpha += bdst.delta;
1007 bmask.alpha += bmask.delta;
1008 bsrc.alpha += sadelta;
1014 alphacalc5(Buffer bdst, Buffer b1, Buffer b2, int dx, int grey, int op)
1023 alphacalc11(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1032 sadelta = bsrc.alpha == &ones ? 0 : bsrc.delta;
1033 q = bsrc.delta == 4 && bdst.delta == 4 && chanmatch(&bdst, &bsrc);
1035 for(i=0; i<dx; i++){
1038 fd = 255-CALC11(sa, ma, t);
1041 *bdst.grey = CALC12(ma, *bsrc.grey, fd, *bdst.grey, t);
1042 bsrc.grey += bsrc.delta;
1043 bdst.grey += bdst.delta;
1046 *bdst.rgba = CALC42(ma, *bsrc.rgba, fd, *bdst.rgba, t, t1);
1049 bsrc.alpha += sadelta;
1050 bmask.alpha += bmask.delta;
1053 *bdst.red = CALC12(ma, *bsrc.red, fd, *bdst.red, t);
1054 *bdst.grn = CALC12(ma, *bsrc.grn, fd, *bdst.grn, t);
1055 *bdst.blu = CALC12(ma, *bsrc.blu, fd, *bdst.blu, t);
1056 bsrc.red += bsrc.delta;
1057 bsrc.blu += bsrc.delta;
1058 bsrc.grn += bsrc.delta;
1059 bdst.red += bdst.delta;
1060 bdst.blu += bdst.delta;
1061 bdst.grn += bdst.delta;
1063 if(bdst.alpha != &ones){
1064 *bdst.alpha = CALC12(ma, sa, fd, *bdst.alpha, t);
1065 bdst.alpha += bdst.delta;
1067 bmask.alpha += bmask.delta;
1068 bsrc.alpha += sadelta;
1075 source and mask alpha 1
1077 alphacalcS0(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1084 if(bsrc.delta == bdst.delta){
1085 memmove(bdst.rgba, bsrc.rgba, dx*bdst.delta);
1088 for(i=0; i<dx; i++){
1090 *bdst.grey = *bsrc.grey;
1091 bsrc.grey += bsrc.delta;
1092 bdst.grey += bdst.delta;
1094 *bdst.red = *bsrc.red;
1095 *bdst.grn = *bsrc.grn;
1096 *bdst.blu = *bsrc.blu;
1097 bsrc.red += bsrc.delta;
1098 bsrc.blu += bsrc.delta;
1099 bsrc.grn += bsrc.delta;
1100 bdst.red += bdst.delta;
1101 bdst.blu += bdst.delta;
1102 bdst.grn += bdst.delta;
1104 if(bdst.alpha != &ones){
1106 bdst.alpha += bdst.delta;
1113 /* source alpha 1 */
1115 alphacalcS(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1125 for(i=0; i<dx; i++){
1130 *bdst.grey = CALC12(ma, *bsrc.grey, fd, *bdst.grey, t);
1131 bsrc.grey += bsrc.delta;
1132 bdst.grey += bdst.delta;
1134 *bdst.red = CALC12(ma, *bsrc.red, fd, *bdst.red, t);
1135 *bdst.grn = CALC12(ma, *bsrc.grn, fd, *bdst.grn, t);
1136 *bdst.blu = CALC12(ma, *bsrc.blu, fd, *bdst.blu, t);
1137 bsrc.red += bsrc.delta;
1138 bsrc.blu += bsrc.delta;
1139 bsrc.grn += bsrc.delta;
1140 bdst.red += bdst.delta;
1141 bdst.blu += bdst.delta;
1142 bdst.grn += bdst.delta;
1144 if(bdst.alpha != &ones){
1145 *bdst.alpha = ma+CALC11(fd, *bdst.alpha, t);
1146 bdst.alpha += bdst.delta;
1148 bmask.alpha += bmask.delta;
1154 boolcalc14(Buffer bdst, Buffer b1, Buffer bmask, int dx, int grey, int op)
1161 for(i=0; i<dx; i++){
1163 zero = ma ? op == DoutS : op == DinS;
1168 bdst.grey += bdst.delta;
1171 *bdst.red = *bdst.grn = *bdst.blu = 0;
1172 bdst.red += bdst.delta;
1173 bdst.blu += bdst.delta;
1174 bdst.grn += bdst.delta;
1176 bmask.alpha += bmask.delta;
1177 if(bdst.alpha != &ones){
1180 bdst.alpha += bdst.delta;
1187 boolcalc236789(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1191 int i, ma, da, zero;
1197 for(i=0; i<dx; i++){
1209 *bdst.grey = CALC12(fs, *bsrc.grey, fd, *bdst.grey, t);
1212 bsrc.grey += bsrc.delta;
1213 bdst.grey += bdst.delta;
1216 *bdst.red = CALC12(fs, *bsrc.red, fd, *bdst.red, t);
1217 *bdst.grn = CALC12(fs, *bsrc.grn, fd, *bdst.grn, t);
1218 *bdst.blu = CALC12(fs, *bsrc.blu, fd, *bdst.blu, t);
1221 *bdst.red = *bdst.grn = *bdst.blu = 0;
1222 bsrc.red += bsrc.delta;
1223 bsrc.blu += bsrc.delta;
1224 bsrc.grn += bsrc.delta;
1225 bdst.red += bdst.delta;
1226 bdst.blu += bdst.delta;
1227 bdst.grn += bdst.delta;
1229 bmask.alpha += bmask.delta;
1230 if(bdst.alpha != &ones){
1232 *bdst.alpha = fs+CALC11(fd, da, t);
1235 bdst.alpha += bdst.delta;
1242 boolcalc1011(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey, int op)
1250 for(i=0; i<dx; i++){
1255 *bdst.grey = *bsrc.grey;
1258 bsrc.grey += bsrc.delta;
1259 bdst.grey += bdst.delta;
1262 *bdst.red = *bsrc.red;
1263 *bdst.grn = *bsrc.grn;
1264 *bdst.blu = *bsrc.blu;
1267 *bdst.red = *bdst.grn = *bdst.blu = 0;
1268 bsrc.red += bsrc.delta;
1269 bsrc.blu += bsrc.delta;
1270 bsrc.grn += bsrc.delta;
1271 bdst.red += bdst.delta;
1272 bdst.blu += bdst.delta;
1273 bdst.grn += bdst.delta;
1275 bmask.alpha += bmask.delta;
1276 if(bdst.alpha != &ones){
1281 bdst.alpha += bdst.delta;
1287 * Replicated cached scan line read. Call the function listed in the Param,
1288 * but cache the result so that for replicated images we only do the work once.
1291 replread(Param *p, uchar *s, int y)
1297 if((p->bfilled & (1<<y)) == 0){
1299 *b = p->replcall(p, p->bufbase+y*p->bufdelta, y);
1305 * Alpha reading function that simply relabels the grey pointer.
1308 greymaskread(Param *p, uchar *buf, int y)
1312 b = p->greymaskcall(p, buf, y);
1319 readnbit(Param *p, uchar *buf, int y)
1323 uchar *repl, *r, *w, *ow, bits;
1324 int i, n, sh, depth, x, dx, npack, nbits;
1326 memset(&b, 0, sizeof b);
1327 b.rgba = (u32int*)buf;
1329 b.red = b.blu = b.grn = w;
1336 repl = &replbit[depth][0];
1340 /* copy from p->r.min.x until end of repl rectangle */
1343 if(n > p->img->r.max.x - x)
1344 n = p->img->r.max.x - x;
1346 r = p->bytermin + y*p->bwidth;
1347 DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n);
1351 DBG print("throwaway %d...", i);
1357 DBG print("(%.2ux)...", *r);
1361 *w++ = repl[bits>>sh];
1362 DBG print("bit %x...", repl[bits>>sh]);
1370 assert(x+i == p->img->r.max.x);
1372 /* copy from beginning of repl rectangle until where we were before. */
1373 x = p->img->r.min.x;
1375 if(n > p->r.min.x - x)
1378 r = p->bytey0s + y*p->bwidth;
1379 DBG print("x=%d r=%p...", x, r);
1386 DBG print("nbits=%d...", nbits);
1392 *w++ = repl[bits>>sh];
1393 DBG print("bit %x...", repl[bits>>sh]);
1396 DBG print("bits %x nbits %d...", bits, nbits);
1403 /* now we have exactly one full scan line: just replicate the buffer itself until we are done */
1414 writenbit(Param *p, uchar *w, Buffer src)
1418 int i, sh, depth, npack, nbits, x, ex;
1420 assert(src.grey != nil && src.delta == 1);
1424 depth = p->img->depth;
1428 bits = i ? (*w >> (8-depth*i)) : 0;
1435 DBG print(" %x", *r);
1436 bits |= (*r++ >> sh);
1447 bits |= *w & ((1<<sh)-1);
1456 readcmap(Param *p, uchar *buf, int y)
1459 int a, convgrey, copyalpha, dx, i, m;
1460 uchar *q, *cmap, *begin, *end, *r, *w;
1462 memset(&b, 0, sizeof b);
1463 begin = p->bytey0s + y*p->bwidth;
1464 r = p->bytermin + y*p->bwidth;
1465 end = p->bytey0e + y*p->bwidth;
1466 cmap = p->img->cmap->cmap2rgb;
1467 convgrey = p->convgrey;
1468 copyalpha = (p->img->flags&Falpha) ? 1 : 0;
1474 a = p->img->shift[CAlpha]/8;
1475 m = p->img->shift[CMap]/8;
1476 for(i=0; i<dx; i++){
1483 *w++ = RGB2K(q[0], q[1], q[2]);
1485 *w++ = q[2]; /* blue */
1486 *w++ = q[1]; /* green */
1487 *w++ = q[0]; /* red */
1492 for(i=0; i<dx; i++){
1497 *w++ = RGB2K(q[0], q[1], q[2]);
1499 *w++ = q[2]; /* blue */
1500 *w++ = q[1]; /* green */
1501 *w++ = q[0]; /* red */
1506 b.rgba = (u32int*)(buf-copyalpha);
1510 b.red = b.blu = b.grn = buf;
1511 b.delta = 1+copyalpha;
1517 b.delta = 3+copyalpha;
1523 writecmap(Param *p, uchar *w, Buffer src)
1525 uchar *cmap, *red, *grn, *blu;
1528 cmap = p->img->cmap->rgb2cmap;
1536 for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta)
1537 *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)];
1540 #define DBG if(drawdebug)
1542 readbyte(Param *p, uchar *buf, int y)
1546 int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb;
1547 uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl;
1548 uchar ured, ugrn, ublu;
1552 begin = p->bytey0s + y*p->bwidth;
1553 r = p->bytermin + y*p->bwidth;
1554 end = p->bytey0e + y*p->bwidth;
1560 convgrey = p->convgrey; /* convert rgb to grey */
1561 isgrey = img->flags&Fgrey;
1562 alphaonly = p->alphaonly;
1563 copyalpha = (img->flags&Falpha) ? 1 : 0;
1565 /* if we can, avoid processing everything */
1566 if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){
1567 memset(&b, 0, sizeof b);
1569 memmove(buf, r, dx*nb);
1572 b.rgba = (u32int*)r;
1574 b.alpha = r+img->shift[CAlpha]/8;
1578 b.grey = r+img->shift[CGrey]/8;
1579 b.red = b.grn = b.blu = b.grey;
1581 b.red = r+img->shift[CRed]/8;
1582 b.grn = r+img->shift[CGreen]/8;
1583 b.blu = r+img->shift[CBlue]/8;
1589 rrepl = replbit[img->nbits[CRed]];
1590 grepl = replbit[img->nbits[CGreen]];
1591 brepl = replbit[img->nbits[CBlue]];
1592 arepl = replbit[img->nbits[CAlpha]];
1593 krepl = replbit[img->nbits[CGrey]];
1595 for(i=0; i<dx; i++){
1596 u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24);
1598 *w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]];
1601 *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]];
1602 else if(!alphaonly){
1603 ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
1604 ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
1605 ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
1607 *w++ = RGB2K(ured, ugrn, ublu);
1609 *w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]];
1610 *w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]];
1611 *w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]];
1619 b.alpha = copyalpha ? buf : &ones;
1620 b.rgba = (u32int*)buf;
1622 b.red = b.grn = b.blu = b.grey = nil;
1626 }else if(isgrey || convgrey){
1627 b.grey = buf+copyalpha;
1628 b.red = b.grn = b.blu = buf+copyalpha;
1629 b.delta = copyalpha+1;
1631 b.blu = buf+copyalpha;
1632 b.grn = buf+copyalpha+1;
1634 b.red = buf+copyalpha+2;
1635 b.delta = copyalpha+3;
1641 #define DBG if(drawdebug)
1643 writebyte(Param *p, uchar *w, Buffer src)
1646 int i, isalpha, isgrey, nb, delta, dx, adelta;
1647 uchar ff, *red, *grn, *blu, *grey, *alpha;
1661 mask = (nb==4) ? 0 : ~((1<<img->depth)-1);
1663 isalpha = img->flags&Falpha;
1664 isgrey = img->flags&Fgrey;
1667 if(isalpha && (alpha == nil || alpha == &ones)){
1673 for(i=0; i<dx; i++){
1674 u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24);
1675 DBG print("u %.8lux...", u);
1677 DBG print("&mask %.8lux...", u);
1679 u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey];
1680 DBG print("|grey %.8lux...", u);
1683 u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed];
1684 u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen];
1685 u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue];
1689 DBG print("|rgb %.8lux...", u);
1693 u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha];
1695 DBG print("|alpha %.8lux...", u);
1702 DBG print("write back %.8lux...", u);
1709 readfn(Memimage *img)
1713 if(img->nbits[CMap] == 8)
1719 readalphafn(Memimage *m)
1726 writefn(Memimage *img)
1730 if(img->chan == CMAP8)
1736 nullwrite(Param *p, uchar *s, Buffer b)
1743 readptr(Param *p, uchar *s, int y)
1749 memset(&b, 0, sizeof b);
1750 q = p->bytermin + y*p->bwidth;
1751 b.red = q; /* ptr to data */
1752 b.grn = b.blu = b.grey = b.alpha = nil;
1753 b.rgba = (u32int*)q;
1754 b.delta = p->img->depth/8;
1759 boolmemmove(Buffer bdst, Buffer bsrc, Buffer b1, int dx, int i, int o)
1763 memmove(bdst.red, bsrc.red, dx*bdst.delta);
1768 boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
1770 uchar *m, *r, *w, *ew;
1778 for(; w < ew; w++,r++)
1781 return bdst; /* not used */
1785 boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
1793 w = (ushort*)bdst.red;
1794 r = (ushort*)bsrc.red;
1796 for(; w < ew; w++,r++)
1799 return bdst; /* not used */
1803 boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
1824 return bdst; /* not used */
1828 boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int i, int o)
1836 w = (u32int*)bdst.red;
1837 r = (u32int*)bsrc.red;
1839 for(; w < ew; w++,r++)
1842 return bdst; /* not used */
1846 genconv(Param *p, uchar *buf, int y)
1852 /* read from source into RGB format in convbuf */
1853 b = p->convreadcall(p, p->convbuf, y);
1855 /* write RGB format into dst format in buf */
1856 p->convwritecall(p->convdpar, buf, b);
1859 nb = p->convdpar->img->depth/8;
1862 ew = buf+nb*p->convdx;
1868 b.blu = b.grn = b.grey = b.alpha = nil;
1869 b.rgba = (u32int*)buf;
1876 convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar)
1878 if(dst->chan == src->chan && !(src->flags&Frepl)){
1879 /*if(drawdebug) iprint("readptr..."); */
1883 if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){
1884 /* cheat because we know the replicated value is exactly the color map entry. */
1885 /*if(drawdebug) iprint("Readnbit..."); */
1889 spar->convreadcall = readfn(src);
1890 spar->convwritecall = writefn(dst);
1891 spar->convdpar = dpar;
1893 /* allocate a conversion buffer */
1894 spar->convbufoff = ndrawbuf;
1895 ndrawbuf += spar->dx*4;
1897 if(spar->dx > Dx(spar->img->r)){
1898 spar->convdx = spar->dx;
1899 spar->dx = Dx(spar->img->r);
1902 /*if(drawdebug) iprint("genconv..."); */
1907 * Do NOT call this directly. pixelbits is a wrapper
1908 * around this that fetches the bits from the X server
1912 _pixelbits(Memimage *i, Point pt)
1916 int off, bpp, npack;
1919 p = byteaddr(i, pt);
1920 switch(bpp=i->depth){
1926 val = p[0] >> bpp*(npack-1-off);
1933 val = p[0]|(p[1]<<8);
1936 val = p[0]|(p[1]<<8)|(p[2]<<16);
1939 val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24);
1950 boolcopyfn(Memimage *img, Memimage *mask)
1952 if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0)
1965 assert(0 /* boolcopyfn */);
1971 * Optimized draw for filling and scrolling; uses memset and memmove.
1974 memsets(void *vp, ushort val, int n)
1985 memsetl(void *vp, u32int val, int n)
1996 memset24(void *vp, u32int val, int n)
2014 _imgtorgba(Memimage *img, u32int val)
2022 r = g = b = 0xAA; /* garbage */
2023 for(chan=img->chan; chan; chan>>=8){
2025 ov = v = val&((1<<nb)-1);
2051 p = img->cmap->cmap2rgb+3*ov;
2058 return (r<<24)|(g<<16)|(b<<8)|a;
2062 _rgbatoimg(Memimage *img, u32int rgba)
2067 uchar *p, r, g, b, a, m;
2075 for(chan=img->chan; chan; chan>>=8){
2079 v |= (r>>(8-nb))<<d;
2082 v |= (g>>(8-nb))<<d;
2085 v |= (b>>(8-nb))<<d;
2088 v |= (a>>(8-nb))<<d;
2091 p = img->cmap->rgb2cmap;
2092 m = p[(r>>4)*256+(g>>4)*16+(b>>4)];
2093 v |= (m>>(8-nb))<<d;
2097 v |= (m>>(8-nb))<<d;
2102 /* print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v); */
2108 memoptdraw(Memdrawparam *par)
2110 int m, y, dy, dx, op;
2122 DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth);
2124 * If we have an opaque mask and source is one opaque pixel we can convert to the
2125 * destination format and just replicate with memset.
2127 m = Simplesrc|Simplemask|Fullmask;
2128 if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){
2130 int d, dwid, ppb, np, nb;
2133 DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata);
2134 dwid = dst->width*sizeof(u32int);
2135 dp = byteaddr(dst, par->r.min);
2137 DBG print("sdval %lud, depth %d\n", v, dst->depth);
2142 for(d=dst->depth; d<8; d*=2)
2144 ppb = 8/dst->depth; /* pixels per byte */
2147 np = par->r.min.x&m; /* no. pixels unused on left side of word */
2149 nb = 8 - np * dst->depth; /* no. bits used on right side of word */
2151 DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m);
2154 np = par->r.max.x&m; /* no. pixels used on left side of word */
2156 nb = 8 - np * dst->depth; /* no. bits unused on right side of word */
2158 DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m);
2160 DBG print("dx %d Dx %d\n", dx, Dx(par->r));
2161 /* lm, rm are masks that are 1 where we should touch the bits */
2162 if(dx < 0){ /* just one byte */
2164 for(y=0; y<dy; y++, dp+=dwid)
2165 *dp ^= (v ^ *dp) & lm;
2166 }else if(dx == 0){ /* no full bytes */
2170 for(y=0; y<dy; y++, dp+=dwid){
2172 DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm);
2173 *dp ^= (v ^ *dp) & lm;
2176 *dp ^= (v ^ *dp) & rm;
2178 }else{ /* full bytes in middle */
2184 for(y=0; y<dy; y++, dp+=dwid){
2186 *dp ^= (v ^ *dp) & lm;
2191 *dp ^= (v ^ *dp) & rm;
2196 for(y=0; y<dy; y++, dp+=dwid)
2200 p[0] = v; /* make little endian */
2202 memmove(&u16, p, 2);
2204 DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n",
2206 for(y=0; y<dy; y++, dp+=dwid)
2210 for(y=0; y<dy; y++, dp+=dwid)
2211 memset24(dp, v, dx);
2214 p[0] = v; /* make little endian */
2219 for(y=0; y<dy; y++, dp+=dwid)
2223 assert(0 /* bad dest depth in memoptdraw */);
2228 * If no source alpha, an opaque mask, we can just copy the
2229 * source onto the destination. If the channels are the same and
2230 * the source is not replicated, memmove suffices.
2232 m = Simplemask|Fullmask;
2233 if((par->state&(m|Replsrc))==m && src->depth >= 8
2234 && src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){
2236 long swid, dwid, nb;
2239 if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min))
2244 swid = src->width*sizeof(u32int);
2245 dwid = dst->width*sizeof(u32int);
2246 sp = byteaddr(src, par->sr.min);
2247 dp = byteaddr(dst, par->r.min);
2254 nb = (dx*src->depth)/8;
2255 for(y=0; y<dy; y++, sp+=swid, dp+=dwid)
2256 memmove(dp, sp, nb);
2261 * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and
2262 * they're all bit aligned, we can just use bit operators. This happens
2263 * when we're manipulating boolean masks, e.g. in the arc code.
2265 if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0
2266 && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1
2267 && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){
2268 uchar *sp, *dp, *mp;
2270 long swid, dwid, mwid;
2273 sp = byteaddr(src, par->sr.min);
2274 dp = byteaddr(dst, par->r.min);
2275 mp = byteaddr(par->mask, par->mr.min);
2276 swid = src->width*sizeof(u32int);
2277 dwid = dst->width*sizeof(u32int);
2278 mwid = par->mask->width*sizeof(u32int);
2280 if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){
2285 lm = 0xFF>>(par->r.min.x&7);
2286 rm = 0xFF<<(8-(par->r.max.x&7));
2287 dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7);
2289 if(dx < 0){ /* one byte wide */
2299 for(y=0; y<dy; y++){
2300 *dp ^= (*dp ^ *sp) & *mp & lm;
2310 i = (lm!=0)+dx+(rm!=0);
2314 for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
2316 *dp ^= (*dp ^ *sp++) & *mp++ & lm;
2319 for(x=0; x<dx; x++){
2320 *dp ^= (*dp ^ *sp++) & *mp++;
2324 *dp ^= (*dp ^ *sp++) & *mp++ & rm;
2331 i = (lm!=0)+dx+(rm!=0);
2332 dp += dwid*(dy-1)+i-1;
2333 sp += swid*(dy-1)+i-1;
2334 mp += mwid*(dy-1)+i-1;
2338 for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){
2340 *dp ^= (*dp ^ *sp--) & *mp-- & rm;
2343 for(x=0; x<dx; x++){
2344 *dp ^= (*dp ^ *sp--) & *mp--;
2348 *dp ^= (*dp ^ *sp--) & *mp-- & lm;
2360 * Boolean character drawing.
2361 * Solid opaque color through a 1-bit greyscale mask.
2365 chardraw(Memdrawparam *par)
2368 int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op;
2369 u32int v, maskwid, dstwid;
2370 uchar *wp, *rp, *q, *wc;
2375 Memimage *mask, *src, *dst;
2377 // black box to hide pointer conversions from gcc.
2378 // we'll see how long this works.
2384 if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n",
2385 par->mask->flags, par->mask->depth, par->src->flags,
2386 Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data);
2395 if((par->state&(Replsrc|Simplesrc|Fullsrc|Replmask)) != (Replsrc|Simplesrc|Fullsrc)
2396 || mask->depth != 1 || dst->depth<8 || dst->data==src->data
2400 /*if(drawdebug) iprint("chardraw..."); */
2402 depth = mask->depth;
2403 maskwid = mask->width*sizeof(u32int);
2404 rp = byteaddr(mask, mr.min);
2406 bsh = (mr.min.x % npack) * depth;
2408 wp = byteaddr(dst, r.min);
2409 dstwid = dst->width*sizeof(u32int);
2410 DBG print("bsh %d\n", bsh);
2414 ddepth = dst->depth;
2417 * for loop counts from bsh to bsh+dx
2419 * we want the bottom bits to be the amount
2420 * to shift the pixels down, so for n≡0 (mod 8) we want
2421 * bottom bits 7. for n≡1, 6, etc.
2422 * the bits come from -n-1.
2430 /* make little endian */
2436 /*print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]); */
2437 for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){
2443 /*if(drawdebug) iprint("8loop..."); */
2445 for(x=bx; x>ex; x--, wc++){
2449 DBG print("bits %lux sh %d...", bits, i);
2455 gcc_black_box.u8 = wp;
2456 ws = gcc_black_box.u16;
2457 gcc_black_box.u8 = sp;
2458 v = *gcc_black_box.u16;
2459 for(x=bx; x>ex; x--, ws++){
2463 DBG print("bits %lux sh %d...", bits, i);
2470 for(x=bx; x>ex; x--, wc+=3){
2474 DBG print("bits %lux sh %d...", bits, i);
2483 gcc_black_box.u8 = wp;
2484 wl = gcc_black_box.u32;
2485 gcc_black_box.u8 = sp;
2486 v = *gcc_black_box.u32;
2487 for(x=bx; x>ex; x--, wl++){
2491 DBG iprint("bits %lux sh %d...", bits, i);
2506 * Fill entire byte with replicated (if necessary) copy of source pixel,
2507 * assuming destination ldepth is >= source ldepth.
2509 * This code is just plain wrong for >8bpp.
2512 membyteval(Memimage *src)
2517 unloadmemimage(src, src->r, &uc, 1);
2519 uc <<= (src->r.min.x&(7/src->depth))*src->depth;
2521 * pixel value is now in high part of byte. repeat throughout byte
2523 for(i=bpp; i<8; i<<=1)
2531 _memfillcolor(Memimage *i, u32int val)
2540 bits = _rgbatoimg(i, val);
2542 case 24: /* 24-bit images suck */
2543 for(y=i->r.min.y; y<i->r.max.y; y++)
2544 memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r));
2546 default: /* 1, 2, 4, 8, 16, 32 */
2547 for(d=i->depth; d<32; d*=2)
2548 bits = (bits << d) | bits;
2549 p[0] = bits; /* make little endian */
2553 memmove(&bits, p, 4);
2554 memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r));