1*7dd7cddfSDavid du Colombier #include "../lib9.h" 2*7dd7cddfSDavid du Colombier 3*7dd7cddfSDavid du Colombier #include "../libdraw/draw.h" 4*7dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h" 5*7dd7cddfSDavid du Colombier 6*7dd7cddfSDavid du Colombier /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ 7*7dd7cddfSDavid du Colombier #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) 8*7dd7cddfSDavid du Colombier 9*7dd7cddfSDavid du Colombier /* 10*7dd7cddfSDavid du Colombier * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation. 11*7dd7cddfSDavid du Colombier * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation. 12*7dd7cddfSDavid du Colombier * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole. 13*7dd7cddfSDavid du Colombier */ 14*7dd7cddfSDavid du Colombier /* #define DIV255(x) (((x)*257+256)>>16) */ 15*7dd7cddfSDavid du Colombier #define DIV255(x) ((((x)+1)*257)>>16) 16*7dd7cddfSDavid du Colombier /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */ 17*7dd7cddfSDavid du Colombier 18*7dd7cddfSDavid du Colombier static void mktables(void); 19*7dd7cddfSDavid du Colombier typedef int Subdraw(Memdrawparam*); 20*7dd7cddfSDavid du Colombier static Subdraw chardraw, alphadraw, memoptdraw; 21*7dd7cddfSDavid du Colombier 22*7dd7cddfSDavid du Colombier static Memimage* memones; 23*7dd7cddfSDavid du Colombier static Memimage* memzeros; 24*7dd7cddfSDavid du Colombier Memimage *memwhite; 25*7dd7cddfSDavid du Colombier Memimage *memblack; 26*7dd7cddfSDavid du Colombier Memimage *memtransparent; 27*7dd7cddfSDavid du Colombier Memimage *memopaque; 28*7dd7cddfSDavid du Colombier 29*7dd7cddfSDavid du Colombier int 30*7dd7cddfSDavid du Colombier Rconv(va_list *o, Fconv *f) 31*7dd7cddfSDavid du Colombier { 32*7dd7cddfSDavid du Colombier Rectangle r; 33*7dd7cddfSDavid du Colombier char buf[128]; 34*7dd7cddfSDavid du Colombier 35*7dd7cddfSDavid du Colombier r = va_arg(*o, Rectangle); 36*7dd7cddfSDavid du Colombier sprint(buf, "%P %P", r.min, r.max); 37*7dd7cddfSDavid du Colombier strconv(buf, f); 38*7dd7cddfSDavid du Colombier return sizeof r; 39*7dd7cddfSDavid du Colombier } 40*7dd7cddfSDavid du Colombier 41*7dd7cddfSDavid du Colombier int 42*7dd7cddfSDavid du Colombier Pconv(va_list *o, Fconv *f) 43*7dd7cddfSDavid du Colombier { 44*7dd7cddfSDavid du Colombier Point p; 45*7dd7cddfSDavid du Colombier char buf[64]; 46*7dd7cddfSDavid du Colombier 47*7dd7cddfSDavid du Colombier p = va_arg(*o, Point); 48*7dd7cddfSDavid du Colombier sprint(buf, "[%d %d]", p.x, p.y); 49*7dd7cddfSDavid du Colombier strconv(buf, f); 50*7dd7cddfSDavid du Colombier return sizeof p; 51*7dd7cddfSDavid du Colombier } 52*7dd7cddfSDavid du Colombier 53*7dd7cddfSDavid du Colombier void 54*7dd7cddfSDavid du Colombier _memimageinit(void) 55*7dd7cddfSDavid du Colombier { 56*7dd7cddfSDavid du Colombier static int didinit = 0; 57*7dd7cddfSDavid du Colombier 58*7dd7cddfSDavid du Colombier if(didinit) 59*7dd7cddfSDavid du Colombier return; 60*7dd7cddfSDavid du Colombier 61*7dd7cddfSDavid du Colombier didinit = 1; 62*7dd7cddfSDavid du Colombier 63*7dd7cddfSDavid du Colombier fmtinstall('R', Rconv); 64*7dd7cddfSDavid du Colombier fmtinstall('P', Pconv); 65*7dd7cddfSDavid du Colombier 66*7dd7cddfSDavid du Colombier mktables(); 67*7dd7cddfSDavid du Colombier memmkcmap(); 68*7dd7cddfSDavid du Colombier 69*7dd7cddfSDavid du Colombier memones = allocmemimage(Rect(0,0,1,1), GREY1); 70*7dd7cddfSDavid du Colombier memones->flags |= Frepl; 71*7dd7cddfSDavid du Colombier memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); 72*7dd7cddfSDavid du Colombier *byteaddr(memones, ZP) = ~0; 73*7dd7cddfSDavid du Colombier 74*7dd7cddfSDavid du Colombier memzeros = allocmemimage(Rect(0,0,1,1), GREY1); 75*7dd7cddfSDavid du Colombier memzeros->flags |= Frepl; 76*7dd7cddfSDavid du Colombier memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); 77*7dd7cddfSDavid du Colombier *byteaddr(memzeros, ZP) = 0; 78*7dd7cddfSDavid du Colombier 79*7dd7cddfSDavid du Colombier if(memones == nil || memzeros == nil) 80*7dd7cddfSDavid du Colombier assert(0 /*cannot initialize memimage library */); /* RSC BUG */ 81*7dd7cddfSDavid du Colombier 82*7dd7cddfSDavid du Colombier memwhite = memones; 83*7dd7cddfSDavid du Colombier memblack = memzeros; 84*7dd7cddfSDavid du Colombier memopaque = memones; 85*7dd7cddfSDavid du Colombier memtransparent = memzeros; 86*7dd7cddfSDavid du Colombier } 87*7dd7cddfSDavid du Colombier 88*7dd7cddfSDavid du Colombier int 89*7dd7cddfSDavid du Colombier drawreplxy(int min, int max, int x) 90*7dd7cddfSDavid du Colombier { 91*7dd7cddfSDavid du Colombier int sx; 92*7dd7cddfSDavid du Colombier 93*7dd7cddfSDavid du Colombier sx = (x-min)%(max-min); 94*7dd7cddfSDavid du Colombier if(sx < 0) 95*7dd7cddfSDavid du Colombier sx += max-min; 96*7dd7cddfSDavid du Colombier return sx+min; 97*7dd7cddfSDavid du Colombier } 98*7dd7cddfSDavid du Colombier 99*7dd7cddfSDavid du Colombier Point 100*7dd7cddfSDavid du Colombier drawrepl(Rectangle r, Point p) 101*7dd7cddfSDavid du Colombier { 102*7dd7cddfSDavid du Colombier p.x = drawreplxy(r.min.x, r.max.x, p.x); 103*7dd7cddfSDavid du Colombier p.y = drawreplxy(r.min.y, r.max.y, p.y); 104*7dd7cddfSDavid du Colombier return p; 105*7dd7cddfSDavid du Colombier } 106*7dd7cddfSDavid du Colombier 107*7dd7cddfSDavid du Colombier #define DBG if(0) 108*7dd7cddfSDavid du Colombier static Memdrawparam par; /* sleazily left for the X implementation */ 109*7dd7cddfSDavid du Colombier Memdrawparam* 110*7dd7cddfSDavid du Colombier _memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1) 111*7dd7cddfSDavid du Colombier { 112*7dd7cddfSDavid du Colombier static int n = 0; 113*7dd7cddfSDavid du Colombier 114*7dd7cddfSDavid du Colombier if(mask == nil) 115*7dd7cddfSDavid du Colombier mask = memopaque; 116*7dd7cddfSDavid du Colombier 117*7dd7cddfSDavid du Colombier if(drawdebug) 118*7dd7cddfSDavid du Colombier iprint("memimagedraw %p/%luX %R %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, src, src->chan, p0, mask, mask->chan, p1); 119*7dd7cddfSDavid du Colombier 120*7dd7cddfSDavid du Colombier if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){ 121*7dd7cddfSDavid du Colombier if(drawdebug) 122*7dd7cddfSDavid du Colombier iprint("empty clipped rectangle\n"); 123*7dd7cddfSDavid du Colombier return nil; 124*7dd7cddfSDavid du Colombier } 125*7dd7cddfSDavid du Colombier 126*7dd7cddfSDavid du Colombier par.dst = dst; 127*7dd7cddfSDavid du Colombier par.r = r; 128*7dd7cddfSDavid du Colombier par.src = src; 129*7dd7cddfSDavid du Colombier /* par.sr set by drawclip */ 130*7dd7cddfSDavid du Colombier par.mask = mask; 131*7dd7cddfSDavid du Colombier /* par.mr set by drawclip */ 132*7dd7cddfSDavid du Colombier 133*7dd7cddfSDavid du Colombier par.state = 0; 134*7dd7cddfSDavid du Colombier if(src->flags&Frepl){ 135*7dd7cddfSDavid du Colombier par.state |= Replsrc; 136*7dd7cddfSDavid du Colombier if(Dx(src->r)==1 && Dy(src->r)==1){ 137*7dd7cddfSDavid du Colombier par.sval = pixelbits(src, src->r.min); 138*7dd7cddfSDavid du Colombier par.state |= Simplesrc; 139*7dd7cddfSDavid du Colombier par.srgba = _imgtorgba(src, par.sval); 140*7dd7cddfSDavid du Colombier par.sdval = _rgbatoimg(dst, par.srgba); 141*7dd7cddfSDavid du Colombier } 142*7dd7cddfSDavid du Colombier } 143*7dd7cddfSDavid du Colombier 144*7dd7cddfSDavid du Colombier if(mask->flags & Frepl){ 145*7dd7cddfSDavid du Colombier par.state |= Replmask; 146*7dd7cddfSDavid du Colombier if(Dx(mask->r)==1 && Dy(mask->r)==1){ 147*7dd7cddfSDavid du Colombier par.mval = pixelbits(mask, mask->r.min); 148*7dd7cddfSDavid du Colombier if(par.mval == 0){ 149*7dd7cddfSDavid du Colombier if(drawdebug) iprint("fill with zero mask\n"); 150*7dd7cddfSDavid du Colombier return nil; /* no-op successfully handled */ 151*7dd7cddfSDavid du Colombier } 152*7dd7cddfSDavid du Colombier par.state |= Simplemask; 153*7dd7cddfSDavid du Colombier if(par.mval == ~0) 154*7dd7cddfSDavid du Colombier par.state |= Fullmask; 155*7dd7cddfSDavid du Colombier par.mrgba = _imgtorgba(mask, par.mval); 156*7dd7cddfSDavid du Colombier } 157*7dd7cddfSDavid du Colombier } 158*7dd7cddfSDavid du Colombier 159*7dd7cddfSDavid du Colombier if(drawdebug) 160*7dd7cddfSDavid du Colombier iprint("dr %R sr %R mr %R...", r, par.sr, par.mr); 161*7dd7cddfSDavid du Colombier DBG print("draw dr %R sr %R mr %R\n", r, par.sr, par.mr); 162*7dd7cddfSDavid du Colombier 163*7dd7cddfSDavid du Colombier return ∥ 164*7dd7cddfSDavid du Colombier } 165*7dd7cddfSDavid du Colombier 166*7dd7cddfSDavid du Colombier void 167*7dd7cddfSDavid du Colombier _memimagedraw(Memdrawparam *par) 168*7dd7cddfSDavid du Colombier { 169*7dd7cddfSDavid du Colombier if(par == nil) 170*7dd7cddfSDavid du Colombier return; 171*7dd7cddfSDavid du Colombier 172*7dd7cddfSDavid du Colombier /* 173*7dd7cddfSDavid du Colombier * Now that we've clipped the parameters down to be consistent, we 174*7dd7cddfSDavid du Colombier * simply try sub-drawing routines in order until we find one that was able 175*7dd7cddfSDavid du Colombier * to handle us. If the sub-drawing routine returns zero, it means it was 176*7dd7cddfSDavid du Colombier * unable to satisfy the request, so we do not return. 177*7dd7cddfSDavid du Colombier */ 178*7dd7cddfSDavid du Colombier 179*7dd7cddfSDavid du Colombier /* 180*7dd7cddfSDavid du Colombier * Hardware support. Each video driver provides this function, 181*7dd7cddfSDavid du Colombier * which checks to see if there is anything it can help with. 182*7dd7cddfSDavid du Colombier * There could be an if around this checking to see if dst is in video memory. 183*7dd7cddfSDavid du Colombier */ 184*7dd7cddfSDavid du Colombier if(hwdraw(par)) 185*7dd7cddfSDavid du Colombier { 186*7dd7cddfSDavid du Colombier if(drawdebug) iprint("hw handled\n"); 187*7dd7cddfSDavid du Colombier return; 188*7dd7cddfSDavid du Colombier } 189*7dd7cddfSDavid du Colombier /* 190*7dd7cddfSDavid du Colombier * Optimizations using memmove and memset. 191*7dd7cddfSDavid du Colombier */ 192*7dd7cddfSDavid du Colombier if(memoptdraw(par)){ 193*7dd7cddfSDavid du Colombier if(drawdebug) iprint("memopt handled\n"); 194*7dd7cddfSDavid du Colombier { 195*7dd7cddfSDavid du Colombier return; 196*7dd7cddfSDavid du Colombier } 197*7dd7cddfSDavid du Colombier } 198*7dd7cddfSDavid du Colombier 199*7dd7cddfSDavid du Colombier /* 200*7dd7cddfSDavid du Colombier * Character drawing. 201*7dd7cddfSDavid du Colombier * Solid source color being painted through a boolean mask onto a high res image. 202*7dd7cddfSDavid du Colombier */ 203*7dd7cddfSDavid du Colombier if(chardraw(par)){ 204*7dd7cddfSDavid du Colombier if(drawdebug) iprint("chardraw handled\n"); 205*7dd7cddfSDavid du Colombier return; 206*7dd7cddfSDavid du Colombier } 207*7dd7cddfSDavid du Colombier 208*7dd7cddfSDavid du Colombier /* 209*7dd7cddfSDavid du Colombier * General calculation-laden case that does alpha for each pixel. 210*7dd7cddfSDavid du Colombier */ 211*7dd7cddfSDavid du Colombier alphadraw(par); 212*7dd7cddfSDavid du Colombier if(drawdebug) iprint("alphadraw handled\n"); 213*7dd7cddfSDavid du Colombier return; 214*7dd7cddfSDavid du Colombier } 215*7dd7cddfSDavid du Colombier #undef DBG 216*7dd7cddfSDavid du Colombier 217*7dd7cddfSDavid du Colombier /* 218*7dd7cddfSDavid du Colombier * Clip the destination rectangle further based on the properties of the 219*7dd7cddfSDavid du Colombier * source and mask rectangles. Once the destination rectangle is properly 220*7dd7cddfSDavid du Colombier * clipped, adjust the source and mask rectangles to be the same size. 221*7dd7cddfSDavid du Colombier * Then if source or mask is replicated, move its clipped rectangle 222*7dd7cddfSDavid du Colombier * so that its minimum point falls within the repl rectangle. 223*7dd7cddfSDavid du Colombier * 224*7dd7cddfSDavid du Colombier * Return zero if the final rectangle is null. 225*7dd7cddfSDavid du Colombier */ 226*7dd7cddfSDavid du Colombier int 227*7dd7cddfSDavid du Colombier drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) 228*7dd7cddfSDavid du Colombier { 229*7dd7cddfSDavid du Colombier Point rmin, delta; 230*7dd7cddfSDavid du Colombier int splitcoords; 231*7dd7cddfSDavid du Colombier Rectangle omr; 232*7dd7cddfSDavid du Colombier Point p; 233*7dd7cddfSDavid du Colombier 234*7dd7cddfSDavid du Colombier if(r->min.x>=r->max.x || r->min.y>=r->max.y) 235*7dd7cddfSDavid du Colombier return 0; 236*7dd7cddfSDavid du Colombier splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); 237*7dd7cddfSDavid du Colombier /* clip to destination */ 238*7dd7cddfSDavid du Colombier rmin = r->min; 239*7dd7cddfSDavid du Colombier if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) 240*7dd7cddfSDavid du Colombier return 0; 241*7dd7cddfSDavid du Colombier /* move mask point */ 242*7dd7cddfSDavid du Colombier p1->x += r->min.x-rmin.x; 243*7dd7cddfSDavid du Colombier p1->y += r->min.y-rmin.y; 244*7dd7cddfSDavid du Colombier /* move source point */ 245*7dd7cddfSDavid du Colombier p0->x += r->min.x-rmin.x; 246*7dd7cddfSDavid du Colombier p0->y += r->min.y-rmin.y; 247*7dd7cddfSDavid du Colombier /* map destination rectangle into source */ 248*7dd7cddfSDavid du Colombier sr->min = *p0; 249*7dd7cddfSDavid du Colombier sr->max.x = p0->x+Dx(*r); 250*7dd7cddfSDavid du Colombier sr->max.y = p0->y+Dy(*r); 251*7dd7cddfSDavid du Colombier /* sr is r in source coordinates; clip to source */ 252*7dd7cddfSDavid du Colombier if(!(src->flags&Frepl) && !rectclip(sr, src->r)) 253*7dd7cddfSDavid du Colombier return 0; 254*7dd7cddfSDavid du Colombier if(!rectclip(sr, src->clipr)) 255*7dd7cddfSDavid du Colombier return 0; 256*7dd7cddfSDavid du Colombier /* compute and clip rectangle in mask */ 257*7dd7cddfSDavid du Colombier if(splitcoords){ 258*7dd7cddfSDavid du Colombier /* move mask point with source */ 259*7dd7cddfSDavid du Colombier p1->x += sr->min.x-p0->x; 260*7dd7cddfSDavid du Colombier p1->y += sr->min.y-p0->y; 261*7dd7cddfSDavid du Colombier mr->min = *p1; 262*7dd7cddfSDavid du Colombier mr->max.x = p1->x+Dx(*sr); 263*7dd7cddfSDavid du Colombier mr->max.y = p1->y+Dy(*sr); 264*7dd7cddfSDavid du Colombier omr = *mr; 265*7dd7cddfSDavid du Colombier /* mr is now rectangle in mask; clip it */ 266*7dd7cddfSDavid du Colombier if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) 267*7dd7cddfSDavid du Colombier return 0; 268*7dd7cddfSDavid du Colombier if(!rectclip(mr, mask->clipr)) 269*7dd7cddfSDavid du Colombier return 0; 270*7dd7cddfSDavid du Colombier /* reflect any clips back to source */ 271*7dd7cddfSDavid du Colombier sr->min.x += mr->min.x-omr.min.x; 272*7dd7cddfSDavid du Colombier sr->min.y += mr->min.y-omr.min.y; 273*7dd7cddfSDavid du Colombier sr->max.x += mr->max.x-omr.max.x; 274*7dd7cddfSDavid du Colombier sr->max.y += mr->max.y-omr.max.y; 275*7dd7cddfSDavid du Colombier *p1 = mr->min; 276*7dd7cddfSDavid du Colombier }else{ 277*7dd7cddfSDavid du Colombier if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) 278*7dd7cddfSDavid du Colombier return 0; 279*7dd7cddfSDavid du Colombier if(!rectclip(sr, mask->clipr)) 280*7dd7cddfSDavid du Colombier return 0; 281*7dd7cddfSDavid du Colombier *p1 = sr->min; 282*7dd7cddfSDavid du Colombier } 283*7dd7cddfSDavid du Colombier 284*7dd7cddfSDavid du Colombier /* move source clipping back to destination */ 285*7dd7cddfSDavid du Colombier delta.x = r->min.x - p0->x; 286*7dd7cddfSDavid du Colombier delta.y = r->min.y - p0->y; 287*7dd7cddfSDavid du Colombier r->min.x = sr->min.x + delta.x; 288*7dd7cddfSDavid du Colombier r->min.y = sr->min.y + delta.y; 289*7dd7cddfSDavid du Colombier r->max.x = sr->max.x + delta.x; 290*7dd7cddfSDavid du Colombier r->max.y = sr->max.y + delta.y; 291*7dd7cddfSDavid du Colombier 292*7dd7cddfSDavid du Colombier /* move source rectangle so sr->min is in src->r */ 293*7dd7cddfSDavid du Colombier if(src->flags&Frepl) { 294*7dd7cddfSDavid du Colombier delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; 295*7dd7cddfSDavid du Colombier delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; 296*7dd7cddfSDavid du Colombier sr->min.x += delta.x; 297*7dd7cddfSDavid du Colombier sr->min.y += delta.y; 298*7dd7cddfSDavid du Colombier sr->max.x += delta.x; 299*7dd7cddfSDavid du Colombier sr->max.y += delta.y; 300*7dd7cddfSDavid du Colombier } 301*7dd7cddfSDavid du Colombier *p0 = sr->min; 302*7dd7cddfSDavid du Colombier 303*7dd7cddfSDavid du Colombier /* move mask point so it is in mask->r */ 304*7dd7cddfSDavid du Colombier /* use temporary point p to avoid warnings about unaligned volatiles on digital unix */ 305*7dd7cddfSDavid du Colombier p = *p1; 306*7dd7cddfSDavid du Colombier p = drawrepl(mask->r, p); 307*7dd7cddfSDavid du Colombier *p1 = p; 308*7dd7cddfSDavid du Colombier mr->min = *p1; 309*7dd7cddfSDavid du Colombier mr->max.x = p1->x+Dx(*sr); 310*7dd7cddfSDavid du Colombier mr->max.y = p1->y+Dy(*sr); 311*7dd7cddfSDavid du Colombier 312*7dd7cddfSDavid du Colombier assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); 313*7dd7cddfSDavid du Colombier assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); 314*7dd7cddfSDavid du Colombier assert((p=*p0, ptinrect(p, src->r))); 315*7dd7cddfSDavid du Colombier assert((p=*p1, ptinrect(p, mask->r))); 316*7dd7cddfSDavid du Colombier assert((p=r->min, ptinrect(p, dst->r))); 317*7dd7cddfSDavid du Colombier 318*7dd7cddfSDavid du Colombier return 1; 319*7dd7cddfSDavid du Colombier } 320*7dd7cddfSDavid du Colombier 321*7dd7cddfSDavid du Colombier /* 322*7dd7cddfSDavid du Colombier * Conversion tables. 323*7dd7cddfSDavid du Colombier */ 324*7dd7cddfSDavid du Colombier static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */ 325*7dd7cddfSDavid du Colombier static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */ 326*7dd7cddfSDavid du Colombier static uchar conv28[256][4]; /* ... */ 327*7dd7cddfSDavid du Colombier static uchar conv48[256][2]; 328*7dd7cddfSDavid du Colombier static int tablesbuilt; 329*7dd7cddfSDavid du Colombier 330*7dd7cddfSDavid du Colombier /* 331*7dd7cddfSDavid du Colombier * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. 332*7dd7cddfSDavid du Colombier * the X's are where to put the bottom (ones) bit of the n-bit pattern. 333*7dd7cddfSDavid du Colombier * only the top 8 bits of the result are actually used. 334*7dd7cddfSDavid du Colombier * (the lower 8 bits are needed to get bits in the right place 335*7dd7cddfSDavid du Colombier * when n is not a divisor of 8.) 336*7dd7cddfSDavid du Colombier * 337*7dd7cddfSDavid du Colombier * Should check to see if its easier to just refer to replmul than 338*7dd7cddfSDavid du Colombier * use the precomputed values in replbit. On PCs it may well 339*7dd7cddfSDavid du Colombier * be; on machines with slow multiply instructions it probably isn't. 340*7dd7cddfSDavid du Colombier */ 341*7dd7cddfSDavid du Colombier #define a ((((((((((((((((0 342*7dd7cddfSDavid du Colombier #define X *2+1) 343*7dd7cddfSDavid du Colombier #define _ *2) 344*7dd7cddfSDavid du Colombier static int replmul[1+8] = { 345*7dd7cddfSDavid du Colombier 0, 346*7dd7cddfSDavid du Colombier a X X X X X X X X X X X X X X X X, 347*7dd7cddfSDavid du Colombier a _ X _ X _ X _ X _ X _ X _ X _ X, 348*7dd7cddfSDavid du Colombier a _ _ X _ _ X _ _ X _ _ X _ _ X _, 349*7dd7cddfSDavid du Colombier a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, 350*7dd7cddfSDavid du Colombier a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, 351*7dd7cddfSDavid du Colombier a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, 352*7dd7cddfSDavid du Colombier a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, 353*7dd7cddfSDavid du Colombier a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X, 354*7dd7cddfSDavid du Colombier }; 355*7dd7cddfSDavid du Colombier #undef a 356*7dd7cddfSDavid du Colombier #undef X 357*7dd7cddfSDavid du Colombier #undef _ 358*7dd7cddfSDavid du Colombier 359*7dd7cddfSDavid du Colombier static void 360*7dd7cddfSDavid du Colombier mktables(void) 361*7dd7cddfSDavid du Colombier { 362*7dd7cddfSDavid du Colombier int i, j, mask, sh, small; 363*7dd7cddfSDavid du Colombier 364*7dd7cddfSDavid du Colombier if(tablesbuilt) 365*7dd7cddfSDavid du Colombier return; 366*7dd7cddfSDavid du Colombier 367*7dd7cddfSDavid du Colombier tablesbuilt = 1; 368*7dd7cddfSDavid du Colombier /* bit replication up to 8 bits */ 369*7dd7cddfSDavid du Colombier for(i=0; i<256; i++){ 370*7dd7cddfSDavid du Colombier for(j=0; j<=8; j++){ /* j <= 8 [sic] */ 371*7dd7cddfSDavid du Colombier small = i & ((1<<j)-1); 372*7dd7cddfSDavid du Colombier replbit[j][i] = (small*replmul[j])>>8; 373*7dd7cddfSDavid du Colombier } 374*7dd7cddfSDavid du Colombier } 375*7dd7cddfSDavid du Colombier 376*7dd7cddfSDavid du Colombier /* bit unpacking up to 8 bits, only powers of 2 */ 377*7dd7cddfSDavid du Colombier for(i=0; i<256; i++){ 378*7dd7cddfSDavid du Colombier for(j=0, sh=7, mask=1; j<8; j++, sh--) 379*7dd7cddfSDavid du Colombier conv18[i][j] = replbit[1][(i>>sh)&mask]; 380*7dd7cddfSDavid du Colombier 381*7dd7cddfSDavid du Colombier for(j=0, sh=6, mask=3; j<4; j++, sh-=2) 382*7dd7cddfSDavid du Colombier conv28[i][j] = replbit[2][(i>>sh)&mask]; 383*7dd7cddfSDavid du Colombier 384*7dd7cddfSDavid du Colombier for(j=0, sh=4, mask=15; j<2; j++, sh-=4) 385*7dd7cddfSDavid du Colombier conv48[i][j] = replbit[4][(i>>sh)&mask]; 386*7dd7cddfSDavid du Colombier } 387*7dd7cddfSDavid du Colombier } 388*7dd7cddfSDavid du Colombier 389*7dd7cddfSDavid du Colombier /* 390*7dd7cddfSDavid du Colombier * General alpha drawing case. Can handle anything. 391*7dd7cddfSDavid du Colombier */ 392*7dd7cddfSDavid du Colombier typedef struct Buffer Buffer; 393*7dd7cddfSDavid du Colombier struct Buffer { 394*7dd7cddfSDavid du Colombier uchar *red; 395*7dd7cddfSDavid du Colombier uchar *grn; 396*7dd7cddfSDavid du Colombier uchar *blu; 397*7dd7cddfSDavid du Colombier uchar *alpha; 398*7dd7cddfSDavid du Colombier uchar *grey; 399*7dd7cddfSDavid du Colombier 400*7dd7cddfSDavid du Colombier int delta; /* number of bytes to add to pointer to get next pixel to the right */ 401*7dd7cddfSDavid du Colombier uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ 402*7dd7cddfSDavid du Colombier int mskip; /* no. of left bits to skip in *m */ 403*7dd7cddfSDavid du Colombier uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ 404*7dd7cddfSDavid du Colombier int bmskip; /* no. of left bits to skip in *bm */ 405*7dd7cddfSDavid du Colombier uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ 406*7dd7cddfSDavid du Colombier int emskip; /* no. of right bits to skip in *em */ 407*7dd7cddfSDavid du Colombier }; 408*7dd7cddfSDavid du Colombier 409*7dd7cddfSDavid du Colombier typedef struct Param Param; 410*7dd7cddfSDavid du Colombier typedef Buffer Readfn(Param *notusedpar, uchar *notusedbuf, int notusedi); 411*7dd7cddfSDavid du Colombier typedef void Writefn(Param *notusedpar, uchar *notusedbuf, Buffer notusedb); 412*7dd7cddfSDavid du Colombier typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int notusedi); 413*7dd7cddfSDavid du Colombier 414*7dd7cddfSDavid du Colombier enum { 415*7dd7cddfSDavid du Colombier MAXBCACHE = 16 416*7dd7cddfSDavid du Colombier }; 417*7dd7cddfSDavid du Colombier 418*7dd7cddfSDavid du Colombier /* giant rathole to customize functions with */ 419*7dd7cddfSDavid du Colombier struct Param { 420*7dd7cddfSDavid du Colombier Readfn *replcall; 421*7dd7cddfSDavid du Colombier Readfn *greymaskcall; 422*7dd7cddfSDavid du Colombier Readfn *convreadcall; 423*7dd7cddfSDavid du Colombier Writefn *convwritecall; 424*7dd7cddfSDavid du Colombier 425*7dd7cddfSDavid du Colombier Memimage *img; 426*7dd7cddfSDavid du Colombier Rectangle r; 427*7dd7cddfSDavid du Colombier int dx; /* of r */ 428*7dd7cddfSDavid du Colombier int needbuf; 429*7dd7cddfSDavid du Colombier int convgrey; 430*7dd7cddfSDavid du Colombier int alphaonly; 431*7dd7cddfSDavid du Colombier 432*7dd7cddfSDavid du Colombier uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ 433*7dd7cddfSDavid du Colombier uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ 434*7dd7cddfSDavid du Colombier uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ 435*7dd7cddfSDavid du Colombier int bwidth; 436*7dd7cddfSDavid du Colombier 437*7dd7cddfSDavid du Colombier int replcache; /* if set, cache buffers */ 438*7dd7cddfSDavid du Colombier Buffer bcache[MAXBCACHE]; 439*7dd7cddfSDavid du Colombier ulong bfilled; 440*7dd7cddfSDavid du Colombier uchar *bufbase; 441*7dd7cddfSDavid du Colombier int bufoff; 442*7dd7cddfSDavid du Colombier int bufdelta; 443*7dd7cddfSDavid du Colombier 444*7dd7cddfSDavid du Colombier int dir; 445*7dd7cddfSDavid du Colombier 446*7dd7cddfSDavid du Colombier int convbufoff; 447*7dd7cddfSDavid du Colombier uchar *convbuf; 448*7dd7cddfSDavid du Colombier Param *convdpar; 449*7dd7cddfSDavid du Colombier int convdx; 450*7dd7cddfSDavid du Colombier }; 451*7dd7cddfSDavid du Colombier 452*7dd7cddfSDavid du Colombier static uchar *drawbuf; 453*7dd7cddfSDavid du Colombier static int ndrawbuf; 454*7dd7cddfSDavid du Colombier static int mdrawbuf; 455*7dd7cddfSDavid du Colombier static Param spar, mpar, dpar; /* easier on the stacks */ 456*7dd7cddfSDavid du Colombier static Readfn greymaskread, replread, readptr; 457*7dd7cddfSDavid du Colombier static Writefn nullwrite; 458*7dd7cddfSDavid du Colombier static Calcfn alphacalc; 459*7dd7cddfSDavid du Colombier static Calcfn boolcalc; 460*7dd7cddfSDavid du Colombier 461*7dd7cddfSDavid du Colombier static Readfn* readfn(Memimage*); 462*7dd7cddfSDavid du Colombier static Readfn* readalphafn(Memimage*); 463*7dd7cddfSDavid du Colombier static Writefn* writefn(Memimage*); 464*7dd7cddfSDavid du Colombier 465*7dd7cddfSDavid du Colombier static Calcfn* boolcopyfn(Memimage*, Memimage*); 466*7dd7cddfSDavid du Colombier static Readfn* convfn(Memimage*, Param *notusedpar, Memimage*, Param*); 467*7dd7cddfSDavid du Colombier static Readfn* ptrfn(Memimage*); 468*7dd7cddfSDavid du Colombier 469*7dd7cddfSDavid du Colombier static int 470*7dd7cddfSDavid du Colombier allocdrawbuf(void) 471*7dd7cddfSDavid du Colombier { 472*7dd7cddfSDavid du Colombier uchar *p; 473*7dd7cddfSDavid du Colombier 474*7dd7cddfSDavid du Colombier if(ndrawbuf > mdrawbuf){ 475*7dd7cddfSDavid du Colombier p = realloc(drawbuf, ndrawbuf); 476*7dd7cddfSDavid du Colombier if(p == nil){ 477*7dd7cddfSDavid du Colombier werrstr("memimagedraw out of memory"); 478*7dd7cddfSDavid du Colombier return -1; 479*7dd7cddfSDavid du Colombier } 480*7dd7cddfSDavid du Colombier drawbuf = p; 481*7dd7cddfSDavid du Colombier mdrawbuf = ndrawbuf; 482*7dd7cddfSDavid du Colombier } 483*7dd7cddfSDavid du Colombier return 0; 484*7dd7cddfSDavid du Colombier } 485*7dd7cddfSDavid du Colombier 486*7dd7cddfSDavid du Colombier static Param 487*7dd7cddfSDavid du Colombier getparam(Memimage *img, Rectangle r, int convgrey, int needbuf) 488*7dd7cddfSDavid du Colombier { 489*7dd7cddfSDavid du Colombier Param p; 490*7dd7cddfSDavid du Colombier int nbuf; 491*7dd7cddfSDavid du Colombier 492*7dd7cddfSDavid du Colombier memset(&p, 0, sizeof p); 493*7dd7cddfSDavid du Colombier 494*7dd7cddfSDavid du Colombier p.img = img; 495*7dd7cddfSDavid du Colombier p.r = r; 496*7dd7cddfSDavid du Colombier p.dx = Dx(r); 497*7dd7cddfSDavid du Colombier p.needbuf = needbuf; 498*7dd7cddfSDavid du Colombier p.convgrey = convgrey; 499*7dd7cddfSDavid du Colombier 500*7dd7cddfSDavid du Colombier assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x); 501*7dd7cddfSDavid du Colombier 502*7dd7cddfSDavid du Colombier p.bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y)); 503*7dd7cddfSDavid du Colombier p.bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y)); 504*7dd7cddfSDavid du Colombier p.bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y)); 505*7dd7cddfSDavid du Colombier p.bwidth = sizeof(ulong)*img->width; 506*7dd7cddfSDavid du Colombier 507*7dd7cddfSDavid du Colombier assert(p.bytey0s <= p.bytermin && p.bytermin <= p.bytey0e); 508*7dd7cddfSDavid du Colombier 509*7dd7cddfSDavid du Colombier if(p.r.min.x == p.img->r.min.x) 510*7dd7cddfSDavid du Colombier assert(p.bytermin == p.bytey0s); 511*7dd7cddfSDavid du Colombier 512*7dd7cddfSDavid du Colombier nbuf = 1; 513*7dd7cddfSDavid du Colombier if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){ 514*7dd7cddfSDavid du Colombier p.replcache = 1; 515*7dd7cddfSDavid du Colombier nbuf = Dy(img->r); 516*7dd7cddfSDavid du Colombier } 517*7dd7cddfSDavid du Colombier p.bufdelta = 4*p.dx; 518*7dd7cddfSDavid du Colombier p.bufoff = ndrawbuf; 519*7dd7cddfSDavid du Colombier ndrawbuf += p.bufdelta*nbuf; 520*7dd7cddfSDavid du Colombier 521*7dd7cddfSDavid du Colombier return p; 522*7dd7cddfSDavid du Colombier } 523*7dd7cddfSDavid du Colombier 524*7dd7cddfSDavid du Colombier static void 525*7dd7cddfSDavid du Colombier clipy(Memimage *img, int *y) 526*7dd7cddfSDavid du Colombier { 527*7dd7cddfSDavid du Colombier int dy; 528*7dd7cddfSDavid du Colombier 529*7dd7cddfSDavid du Colombier dy = Dy(img->r); 530*7dd7cddfSDavid du Colombier if(*y == dy) 531*7dd7cddfSDavid du Colombier *y = 0; 532*7dd7cddfSDavid du Colombier else if(*y == -1) 533*7dd7cddfSDavid du Colombier *y = dy-1; 534*7dd7cddfSDavid du Colombier assert(0 <= *y && *y < dy); 535*7dd7cddfSDavid du Colombier } 536*7dd7cddfSDavid du Colombier 537*7dd7cddfSDavid du Colombier static void 538*7dd7cddfSDavid du Colombier dumpbuf(char *s, Buffer b, int n) 539*7dd7cddfSDavid du Colombier { 540*7dd7cddfSDavid du Colombier int i; 541*7dd7cddfSDavid du Colombier uchar *p; 542*7dd7cddfSDavid du Colombier 543*7dd7cddfSDavid du Colombier print("%s", s); 544*7dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 545*7dd7cddfSDavid du Colombier print(" "); 546*7dd7cddfSDavid du Colombier if(p=b.grey){ 547*7dd7cddfSDavid du Colombier print(" k%.2uX", *p); 548*7dd7cddfSDavid du Colombier b.grey += b.delta; 549*7dd7cddfSDavid du Colombier }else{ 550*7dd7cddfSDavid du Colombier if(p=b.red){ 551*7dd7cddfSDavid du Colombier print(" r%.2uX", *p); 552*7dd7cddfSDavid du Colombier b.red += b.delta; 553*7dd7cddfSDavid du Colombier } 554*7dd7cddfSDavid du Colombier if(p=b.grn){ 555*7dd7cddfSDavid du Colombier print(" g%.2uX", *p); 556*7dd7cddfSDavid du Colombier b.grn += b.delta; 557*7dd7cddfSDavid du Colombier } 558*7dd7cddfSDavid du Colombier if(p=b.blu){ 559*7dd7cddfSDavid du Colombier print(" b%.2uX", *p); 560*7dd7cddfSDavid du Colombier b.blu += b.delta; 561*7dd7cddfSDavid du Colombier } 562*7dd7cddfSDavid du Colombier } 563*7dd7cddfSDavid du Colombier if(p=b.alpha){ 564*7dd7cddfSDavid du Colombier print(" α%.2uX", *p); 565*7dd7cddfSDavid du Colombier b.alpha += b.delta; 566*7dd7cddfSDavid du Colombier } 567*7dd7cddfSDavid du Colombier } 568*7dd7cddfSDavid du Colombier print("\n"); 569*7dd7cddfSDavid du Colombier } 570*7dd7cddfSDavid du Colombier 571*7dd7cddfSDavid du Colombier /* 572*7dd7cddfSDavid du Colombier * For each scan line, we expand the pixels from source, mask, and destination 573*7dd7cddfSDavid du Colombier * into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not 574*7dd7cddfSDavid du Colombier * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32), 575*7dd7cddfSDavid du Colombier * the readers need not copy the data: they can simply return pointers to the data. 576*7dd7cddfSDavid du Colombier * If the destination image is grey and the source is not, it is converted using the NTSC 577*7dd7cddfSDavid du Colombier * formula. 578*7dd7cddfSDavid du Colombier * 579*7dd7cddfSDavid du Colombier * Once we have all the channels, we call either rgbcalc or greycalc, depending on 580*7dd7cddfSDavid du Colombier * whether the destination image is color. This is allowed to overwrite the dst buffer (perhaps 581*7dd7cddfSDavid du Colombier * the actual data, perhaps a copy) with its result. It should only overwrite the dst buffer 582*7dd7cddfSDavid du Colombier * with the same format (i.e. red bytes with red bytes, etc.) A new buffer is returned from 583*7dd7cddfSDavid du Colombier * the calculator, and that buffer is passed to a function to write it to the destination. 584*7dd7cddfSDavid du Colombier * If the buffer is already pointing at the destination, the writing function is a no-op. 585*7dd7cddfSDavid du Colombier */ 586*7dd7cddfSDavid du Colombier #define DBG if(0) 587*7dd7cddfSDavid du Colombier static int 588*7dd7cddfSDavid du Colombier alphadraw(Memdrawparam *par) 589*7dd7cddfSDavid du Colombier { 590*7dd7cddfSDavid du Colombier int isgrey, starty, endy; 591*7dd7cddfSDavid du Colombier int needbuf, dsty, srcy, masky; 592*7dd7cddfSDavid du Colombier int y, dir, dx, dy; 593*7dd7cddfSDavid du Colombier Buffer bsrc, bdst, bmask; 594*7dd7cddfSDavid du Colombier Readfn *rdsrc, *rdmask, *rddst; 595*7dd7cddfSDavid du Colombier Calcfn *calc; 596*7dd7cddfSDavid du Colombier Writefn *wrdst; 597*7dd7cddfSDavid du Colombier Memimage *src, *mask, *dst; 598*7dd7cddfSDavid du Colombier Rectangle r, sr, mr; 599*7dd7cddfSDavid du Colombier 600*7dd7cddfSDavid du Colombier r = par->r; 601*7dd7cddfSDavid du Colombier dx = Dx(r); 602*7dd7cddfSDavid du Colombier dy = Dy(r); 603*7dd7cddfSDavid du Colombier 604*7dd7cddfSDavid du Colombier ndrawbuf = 0; 605*7dd7cddfSDavid du Colombier 606*7dd7cddfSDavid du Colombier src = par->src; 607*7dd7cddfSDavid du Colombier mask = par->mask; 608*7dd7cddfSDavid du Colombier dst = par->dst; 609*7dd7cddfSDavid du Colombier sr = par->sr; 610*7dd7cddfSDavid du Colombier mr = par->mr; 611*7dd7cddfSDavid du Colombier 612*7dd7cddfSDavid du Colombier isgrey = dst->flags&Fgrey; 613*7dd7cddfSDavid du Colombier 614*7dd7cddfSDavid du Colombier /* 615*7dd7cddfSDavid du Colombier * Buffering when src and dst are the same bitmap is sufficient but not 616*7dd7cddfSDavid du Colombier * necessary. There are stronger conditions we could use. We could 617*7dd7cddfSDavid du Colombier * check to see if the rectangles intersect, and if simply moving in the 618*7dd7cddfSDavid du Colombier * correct y direction can avoid the need to buffer. 619*7dd7cddfSDavid du Colombier */ 620*7dd7cddfSDavid du Colombier needbuf = (src->data == dst->data); 621*7dd7cddfSDavid du Colombier 622*7dd7cddfSDavid du Colombier spar = getparam(src, sr, isgrey, needbuf); 623*7dd7cddfSDavid du Colombier mpar = getparam(mask, mr, isgrey, needbuf); 624*7dd7cddfSDavid du Colombier dpar = getparam(dst, r, isgrey, needbuf); 625*7dd7cddfSDavid du Colombier 626*7dd7cddfSDavid du Colombier dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1; 627*7dd7cddfSDavid du Colombier spar.dir = mpar.dir = dpar.dir = dir; 628*7dd7cddfSDavid du Colombier 629*7dd7cddfSDavid du Colombier /* 630*7dd7cddfSDavid du Colombier * If the mask is purely boolean, we can convert from src to dst format 631*7dd7cddfSDavid du Colombier * when we read src, and then just copy it to dst where the mask tells us to. 632*7dd7cddfSDavid du Colombier * This requires a boolean (1-bit grey) mask and lack of a source alpha channel. 633*7dd7cddfSDavid du Colombier * 634*7dd7cddfSDavid du Colombier * The computation is accomplished by assigning the function pointers as follows: 635*7dd7cddfSDavid du Colombier * rdsrc - read and convert source into dst format in a buffer 636*7dd7cddfSDavid du Colombier * rdmask - convert mask to bytes, set pointer to it 637*7dd7cddfSDavid du Colombier * rddst - fill with pointer to real dst data, but do no reads 638*7dd7cddfSDavid du Colombier * calc - copy src onto dst when mask says to. 639*7dd7cddfSDavid du Colombier * wrdst - do nothing 640*7dd7cddfSDavid du Colombier * This is slightly sleazy, since things aren't doing exactly what their names say, 641*7dd7cddfSDavid du Colombier * but it avoids a fair amount of code duplication to make this a case here 642*7dd7cddfSDavid du Colombier * rather than have a separate booldraw. 643*7dd7cddfSDavid du Colombier */ 644*7dd7cddfSDavid du Colombier if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth); 645*7dd7cddfSDavid du Colombier if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8){ 646*7dd7cddfSDavid du Colombier if(drawdebug) iprint("boolcopy..."); 647*7dd7cddfSDavid du Colombier rdsrc = convfn(dst, &dpar, src, &spar); 648*7dd7cddfSDavid du Colombier rddst = readptr; 649*7dd7cddfSDavid du Colombier rdmask = readfn(mask); 650*7dd7cddfSDavid du Colombier calc = boolcopyfn(dst, mask); 651*7dd7cddfSDavid du Colombier wrdst = nullwrite; 652*7dd7cddfSDavid du Colombier }else{ 653*7dd7cddfSDavid du Colombier /* usual alphadraw parameter fetching */ 654*7dd7cddfSDavid du Colombier rdsrc = readfn(src); 655*7dd7cddfSDavid du Colombier rddst = readfn(dst); 656*7dd7cddfSDavid du Colombier wrdst = writefn(dst); 657*7dd7cddfSDavid du Colombier calc = alphacalc; 658*7dd7cddfSDavid du Colombier 659*7dd7cddfSDavid du Colombier /* 660*7dd7cddfSDavid du Colombier * If there is no alpha channel, we'll ask for a grey channel 661*7dd7cddfSDavid du Colombier * and pretend it is the alpha. 662*7dd7cddfSDavid du Colombier */ 663*7dd7cddfSDavid du Colombier if(mask->flags&Falpha){ 664*7dd7cddfSDavid du Colombier rdmask = readalphafn(mask); 665*7dd7cddfSDavid du Colombier mpar.alphaonly = 1; 666*7dd7cddfSDavid du Colombier }else{ 667*7dd7cddfSDavid du Colombier mpar.greymaskcall = readfn(mask); 668*7dd7cddfSDavid du Colombier mpar.convgrey = 1; 669*7dd7cddfSDavid du Colombier rdmask = greymaskread; 670*7dd7cddfSDavid du Colombier 671*7dd7cddfSDavid du Colombier /* 672*7dd7cddfSDavid du Colombier * Should really be above, but then boolcopyfns would have 673*7dd7cddfSDavid du Colombier * to deal with bit alignment, and I haven't written that. 674*7dd7cddfSDavid du Colombier * 675*7dd7cddfSDavid du Colombier * This is a common case for things like ellipse drawing. 676*7dd7cddfSDavid du Colombier * When there's no alpha involved and the mask is boolean, 677*7dd7cddfSDavid du Colombier * we can avoid all the division and multiplication. 678*7dd7cddfSDavid du Colombier */ 679*7dd7cddfSDavid du Colombier if(mask->chan == GREY1 && !(src->flags&Falpha)) 680*7dd7cddfSDavid du Colombier calc = boolcalc; 681*7dd7cddfSDavid du Colombier } 682*7dd7cddfSDavid du Colombier } 683*7dd7cddfSDavid du Colombier 684*7dd7cddfSDavid du Colombier /* 685*7dd7cddfSDavid du Colombier * If the image has a small enough repl rectangle, 686*7dd7cddfSDavid du Colombier * we can just read each line once and cache them. 687*7dd7cddfSDavid du Colombier */ 688*7dd7cddfSDavid du Colombier if(spar.replcache){ 689*7dd7cddfSDavid du Colombier spar.replcall = rdsrc; 690*7dd7cddfSDavid du Colombier rdsrc = replread; 691*7dd7cddfSDavid du Colombier } 692*7dd7cddfSDavid du Colombier if(mpar.replcache){ 693*7dd7cddfSDavid du Colombier mpar.replcall = rdmask; 694*7dd7cddfSDavid du Colombier rdmask = replread; 695*7dd7cddfSDavid du Colombier } 696*7dd7cddfSDavid du Colombier 697*7dd7cddfSDavid du Colombier if(allocdrawbuf() < 0) 698*7dd7cddfSDavid du Colombier return 0; 699*7dd7cddfSDavid du Colombier 700*7dd7cddfSDavid du Colombier /* 701*7dd7cddfSDavid du Colombier * Before we were saving only offsets from drawbuf in the parameter 702*7dd7cddfSDavid du Colombier * structures; now that drawbuf has been grown to accomodate us, 703*7dd7cddfSDavid du Colombier * we can fill in the pointers. 704*7dd7cddfSDavid du Colombier */ 705*7dd7cddfSDavid du Colombier spar.bufbase = drawbuf+spar.bufoff; 706*7dd7cddfSDavid du Colombier mpar.bufbase = drawbuf+mpar.bufoff; 707*7dd7cddfSDavid du Colombier dpar.bufbase = drawbuf+dpar.bufoff; 708*7dd7cddfSDavid du Colombier spar.convbuf = drawbuf+spar.convbufoff; 709*7dd7cddfSDavid du Colombier 710*7dd7cddfSDavid du Colombier if(dir == 1){ 711*7dd7cddfSDavid du Colombier starty = 0; 712*7dd7cddfSDavid du Colombier endy = dy; 713*7dd7cddfSDavid du Colombier }else{ 714*7dd7cddfSDavid du Colombier starty = dy-1; 715*7dd7cddfSDavid du Colombier endy = -1; 716*7dd7cddfSDavid du Colombier } 717*7dd7cddfSDavid du Colombier 718*7dd7cddfSDavid du Colombier /* 719*7dd7cddfSDavid du Colombier * srcy, masky, and dsty are offsets from the top of their 720*7dd7cddfSDavid du Colombier * respective Rectangles. they need to be contained within 721*7dd7cddfSDavid du Colombier * the rectangles, so clipy can keep them there without division. 722*7dd7cddfSDavid du Colombier */ 723*7dd7cddfSDavid du Colombier srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r); 724*7dd7cddfSDavid du Colombier masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r); 725*7dd7cddfSDavid du Colombier dsty = starty + r.min.y - dst->r.min.y; 726*7dd7cddfSDavid du Colombier 727*7dd7cddfSDavid du Colombier assert(0 <= srcy && srcy < Dy(src->r)); 728*7dd7cddfSDavid du Colombier assert(0 <= masky && masky < Dy(mask->r)); 729*7dd7cddfSDavid du Colombier assert(0 <= dsty && dsty < Dy(dst->r)); 730*7dd7cddfSDavid du Colombier 731*7dd7cddfSDavid du Colombier for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){ 732*7dd7cddfSDavid du Colombier clipy(src, &srcy); 733*7dd7cddfSDavid du Colombier clipy(dst, &dsty); 734*7dd7cddfSDavid du Colombier clipy(mask, &masky); 735*7dd7cddfSDavid du Colombier 736*7dd7cddfSDavid du Colombier bsrc = rdsrc(&spar, spar.bufbase, srcy); 737*7dd7cddfSDavid du Colombier DBG print("["); 738*7dd7cddfSDavid du Colombier bmask = rdmask(&mpar, mpar.bufbase, masky); 739*7dd7cddfSDavid du Colombier DBG print("]\n"); 740*7dd7cddfSDavid du Colombier bdst = rddst(&dpar, dpar.bufbase, dsty); 741*7dd7cddfSDavid du Colombier DBG dumpbuf("src", bsrc, dx); 742*7dd7cddfSDavid du Colombier DBG dumpbuf("mask", bmask, dx); 743*7dd7cddfSDavid du Colombier DBG dumpbuf("dst", bdst, dx); 744*7dd7cddfSDavid du Colombier bdst = calc(bdst, bsrc, bmask, dx, isgrey); 745*7dd7cddfSDavid du Colombier wrdst(&dpar, dpar.bytermin+dsty*dpar.bwidth, bdst); 746*7dd7cddfSDavid du Colombier } 747*7dd7cddfSDavid du Colombier 748*7dd7cddfSDavid du Colombier return 1; 749*7dd7cddfSDavid du Colombier } 750*7dd7cddfSDavid du Colombier #undef DBG 751*7dd7cddfSDavid du Colombier 752*7dd7cddfSDavid du Colombier #define DBG if(0) 753*7dd7cddfSDavid du Colombier static Buffer 754*7dd7cddfSDavid du Colombier alphacalc(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey) 755*7dd7cddfSDavid du Colombier { 756*7dd7cddfSDavid du Colombier Buffer obdst; 757*7dd7cddfSDavid du Colombier uchar *salpha, ones = ~0; 758*7dd7cddfSDavid du Colombier int antialpha, sadelta; 759*7dd7cddfSDavid du Colombier int i, sa, ma; 760*7dd7cddfSDavid du Colombier 761*7dd7cddfSDavid du Colombier obdst = bdst; 762*7dd7cddfSDavid du Colombier if((salpha = bsrc.alpha) == nil) 763*7dd7cddfSDavid du Colombier salpha = &ones, sadelta = 0; 764*7dd7cddfSDavid du Colombier else 765*7dd7cddfSDavid du Colombier sadelta = bsrc.delta; 766*7dd7cddfSDavid du Colombier 767*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 768*7dd7cddfSDavid du Colombier sa = *salpha; 769*7dd7cddfSDavid du Colombier ma = *bmask.alpha; 770*7dd7cddfSDavid du Colombier antialpha = 255-DIV255(ma*sa); 771*7dd7cddfSDavid du Colombier 772*7dd7cddfSDavid du Colombier if(grey){ 773*7dd7cddfSDavid du Colombier DBG print("(%d %d in %d) over %d =", *bsrc.grey, sa, ma, *bdst.grey); 774*7dd7cddfSDavid du Colombier *bdst.grey = DIV255(*bsrc.grey*ma+*bdst.grey*antialpha); 775*7dd7cddfSDavid du Colombier DBG print(" %d\n", *bdst.grey); 776*7dd7cddfSDavid du Colombier bsrc.grey += bsrc.delta; 777*7dd7cddfSDavid du Colombier bdst.grey += bdst.delta; 778*7dd7cddfSDavid du Colombier }else{ 779*7dd7cddfSDavid du Colombier *bdst.red = DIV255(*bsrc.red*ma+*bdst.red*antialpha); 780*7dd7cddfSDavid du Colombier *bdst.grn = DIV255(*bsrc.grn*ma+*bdst.grn*antialpha); 781*7dd7cddfSDavid du Colombier *bdst.blu = DIV255(*bsrc.blu*ma+*bdst.blu*antialpha); 782*7dd7cddfSDavid du Colombier 783*7dd7cddfSDavid du Colombier bsrc.red += bsrc.delta; 784*7dd7cddfSDavid du Colombier bsrc.blu += bsrc.delta; 785*7dd7cddfSDavid du Colombier bsrc.grn += bsrc.delta; 786*7dd7cddfSDavid du Colombier 787*7dd7cddfSDavid du Colombier bdst.red += bdst.delta; 788*7dd7cddfSDavid du Colombier bdst.blu += bdst.delta; 789*7dd7cddfSDavid du Colombier bdst.grn += bdst.delta; 790*7dd7cddfSDavid du Colombier } 791*7dd7cddfSDavid du Colombier 792*7dd7cddfSDavid du Colombier salpha += sadelta; 793*7dd7cddfSDavid du Colombier bmask.alpha += bmask.delta; 794*7dd7cddfSDavid du Colombier 795*7dd7cddfSDavid du Colombier if(bdst.alpha) { 796*7dd7cddfSDavid du Colombier *bdst.alpha = DIV255(sa*ma+*bdst.alpha*(antialpha)); 797*7dd7cddfSDavid du Colombier bdst.alpha += bdst.delta; 798*7dd7cddfSDavid du Colombier } 799*7dd7cddfSDavid du Colombier } 800*7dd7cddfSDavid du Colombier return obdst; 801*7dd7cddfSDavid du Colombier } 802*7dd7cddfSDavid du Colombier #undef DBG 803*7dd7cddfSDavid du Colombier 804*7dd7cddfSDavid du Colombier #define DBG if(0) 805*7dd7cddfSDavid du Colombier static Buffer 806*7dd7cddfSDavid du Colombier boolcalc(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey) 807*7dd7cddfSDavid du Colombier { 808*7dd7cddfSDavid du Colombier Buffer obdst; 809*7dd7cddfSDavid du Colombier int i, ma; 810*7dd7cddfSDavid du Colombier 811*7dd7cddfSDavid du Colombier obdst = bdst; 812*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 813*7dd7cddfSDavid du Colombier ma = *bmask.alpha; 814*7dd7cddfSDavid du Colombier 815*7dd7cddfSDavid du Colombier if(grey){ 816*7dd7cddfSDavid du Colombier DBG print("(%d) in %d over %d =", *bsrc.grey, ma, *bdst.grey); 817*7dd7cddfSDavid du Colombier if(ma) 818*7dd7cddfSDavid du Colombier *bdst.grey = *bsrc.grey; 819*7dd7cddfSDavid du Colombier DBG print(" %d\n", *bdst.grey); 820*7dd7cddfSDavid du Colombier bsrc.grey += bsrc.delta; 821*7dd7cddfSDavid du Colombier bdst.grey += bdst.delta; 822*7dd7cddfSDavid du Colombier }else{ 823*7dd7cddfSDavid du Colombier if(ma){ 824*7dd7cddfSDavid du Colombier *bdst.red = *bsrc.red*ma; 825*7dd7cddfSDavid du Colombier *bdst.grn = *bsrc.grn*ma; 826*7dd7cddfSDavid du Colombier *bdst.blu = *bsrc.blu*ma; 827*7dd7cddfSDavid du Colombier } 828*7dd7cddfSDavid du Colombier 829*7dd7cddfSDavid du Colombier bsrc.red += bsrc.delta; 830*7dd7cddfSDavid du Colombier bsrc.blu += bsrc.delta; 831*7dd7cddfSDavid du Colombier bsrc.grn += bsrc.delta; 832*7dd7cddfSDavid du Colombier 833*7dd7cddfSDavid du Colombier bdst.red += bdst.delta; 834*7dd7cddfSDavid du Colombier bdst.blu += bdst.delta; 835*7dd7cddfSDavid du Colombier bdst.grn += bdst.delta; 836*7dd7cddfSDavid du Colombier } 837*7dd7cddfSDavid du Colombier 838*7dd7cddfSDavid du Colombier bmask.alpha += bmask.delta; 839*7dd7cddfSDavid du Colombier 840*7dd7cddfSDavid du Colombier if(bdst.alpha) { 841*7dd7cddfSDavid du Colombier if(ma) 842*7dd7cddfSDavid du Colombier *bdst.alpha = ma; 843*7dd7cddfSDavid du Colombier bdst.alpha += bdst.delta; 844*7dd7cddfSDavid du Colombier } 845*7dd7cddfSDavid du Colombier } 846*7dd7cddfSDavid du Colombier return obdst; 847*7dd7cddfSDavid du Colombier } 848*7dd7cddfSDavid du Colombier #undef DBG 849*7dd7cddfSDavid du Colombier 850*7dd7cddfSDavid du Colombier /* 851*7dd7cddfSDavid du Colombier * Replicated cached scan line read. Call the function listed in the Param, 852*7dd7cddfSDavid du Colombier * but cache the result so that for replicated images we only do the work once. 853*7dd7cddfSDavid du Colombier */ 854*7dd7cddfSDavid du Colombier static Buffer 855*7dd7cddfSDavid du Colombier replread(Param *p, uchar *notusedbuf, int y) 856*7dd7cddfSDavid du Colombier { 857*7dd7cddfSDavid du Colombier Buffer *b; 858*7dd7cddfSDavid du Colombier 859*7dd7cddfSDavid du Colombier b = &p->bcache[y]; 860*7dd7cddfSDavid du Colombier if((p->bfilled & (1<<y)) == 0){ 861*7dd7cddfSDavid du Colombier p->bfilled |= 1<<y; 862*7dd7cddfSDavid du Colombier *b = p->replcall(p, p->bufbase+y*p->bufdelta, y); 863*7dd7cddfSDavid du Colombier } 864*7dd7cddfSDavid du Colombier return *b; 865*7dd7cddfSDavid du Colombier } 866*7dd7cddfSDavid du Colombier 867*7dd7cddfSDavid du Colombier /* 868*7dd7cddfSDavid du Colombier * Alpha reading function that simply relabels the grey pointer. 869*7dd7cddfSDavid du Colombier */ 870*7dd7cddfSDavid du Colombier static Buffer 871*7dd7cddfSDavid du Colombier greymaskread(Param *p, uchar *buf, int y) 872*7dd7cddfSDavid du Colombier { 873*7dd7cddfSDavid du Colombier Buffer b; 874*7dd7cddfSDavid du Colombier 875*7dd7cddfSDavid du Colombier b = p->greymaskcall(p, buf, y); 876*7dd7cddfSDavid du Colombier b.alpha = b.grey; 877*7dd7cddfSDavid du Colombier return b; 878*7dd7cddfSDavid du Colombier } 879*7dd7cddfSDavid du Colombier 880*7dd7cddfSDavid du Colombier #define DBG if(0) 881*7dd7cddfSDavid du Colombier static Buffer 882*7dd7cddfSDavid du Colombier readnbit(Param *p, uchar *buf, int y) 883*7dd7cddfSDavid du Colombier { 884*7dd7cddfSDavid du Colombier Buffer b; 885*7dd7cddfSDavid du Colombier Memimage *img; 886*7dd7cddfSDavid du Colombier uchar *repl, *r, *w, *ow, bits; 887*7dd7cddfSDavid du Colombier int i, n, sh, depth, x, dx, npack, nbits; 888*7dd7cddfSDavid du Colombier 889*7dd7cddfSDavid du Colombier b.grey = w = buf; 890*7dd7cddfSDavid du Colombier b.red = b.blu = b.grn = w; 891*7dd7cddfSDavid du Colombier b.alpha = nil; 892*7dd7cddfSDavid du Colombier b.delta = 1; 893*7dd7cddfSDavid du Colombier 894*7dd7cddfSDavid du Colombier dx = p->dx; 895*7dd7cddfSDavid du Colombier img = p->img; 896*7dd7cddfSDavid du Colombier depth = img->depth; 897*7dd7cddfSDavid du Colombier repl = &replbit[depth][0]; 898*7dd7cddfSDavid du Colombier npack = 8/depth; 899*7dd7cddfSDavid du Colombier sh = 8-depth; 900*7dd7cddfSDavid du Colombier 901*7dd7cddfSDavid du Colombier /* copy from p->r.min.x until end of repl rectangle */ 902*7dd7cddfSDavid du Colombier x = p->r.min.x; 903*7dd7cddfSDavid du Colombier n = dx; 904*7dd7cddfSDavid du Colombier if(n > p->img->r.max.x - x) 905*7dd7cddfSDavid du Colombier n = p->img->r.max.x - x; 906*7dd7cddfSDavid du Colombier 907*7dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 908*7dd7cddfSDavid du Colombier DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n); 909*7dd7cddfSDavid du Colombier bits = *r++; 910*7dd7cddfSDavid du Colombier nbits = 8; 911*7dd7cddfSDavid du Colombier if(i=x&(npack-1)){ 912*7dd7cddfSDavid du Colombier DBG print("throwaway %d...", i); 913*7dd7cddfSDavid du Colombier bits <<= depth*i; 914*7dd7cddfSDavid du Colombier nbits -= depth*i; 915*7dd7cddfSDavid du Colombier } 916*7dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 917*7dd7cddfSDavid du Colombier if(nbits == 0){ 918*7dd7cddfSDavid du Colombier DBG print("(%.2ux)...", *r); 919*7dd7cddfSDavid du Colombier bits = *r++; 920*7dd7cddfSDavid du Colombier nbits = 8; 921*7dd7cddfSDavid du Colombier } 922*7dd7cddfSDavid du Colombier *w++ = repl[bits>>sh]; 923*7dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]); 924*7dd7cddfSDavid du Colombier bits <<= depth; 925*7dd7cddfSDavid du Colombier nbits -= depth; 926*7dd7cddfSDavid du Colombier } 927*7dd7cddfSDavid du Colombier dx -= n; 928*7dd7cddfSDavid du Colombier if(dx == 0) 929*7dd7cddfSDavid du Colombier return b; 930*7dd7cddfSDavid du Colombier 931*7dd7cddfSDavid du Colombier assert(x+i == p->img->r.max.x); 932*7dd7cddfSDavid du Colombier 933*7dd7cddfSDavid du Colombier /* copy from beginning of repl rectangle until where we were before. */ 934*7dd7cddfSDavid du Colombier x = p->img->r.min.x; 935*7dd7cddfSDavid du Colombier n = dx; 936*7dd7cddfSDavid du Colombier if(n > p->r.min.x - x) 937*7dd7cddfSDavid du Colombier n = p->r.min.x - x; 938*7dd7cddfSDavid du Colombier 939*7dd7cddfSDavid du Colombier r = p->bytey0s + y*p->bwidth; 940*7dd7cddfSDavid du Colombier DBG print("x=%d r=%p...", x, r); 941*7dd7cddfSDavid du Colombier bits = *r++; 942*7dd7cddfSDavid du Colombier nbits = 8; 943*7dd7cddfSDavid du Colombier if(i=x&(npack-1)){ 944*7dd7cddfSDavid du Colombier bits <<= depth*i; 945*7dd7cddfSDavid du Colombier nbits -= depth*i; 946*7dd7cddfSDavid du Colombier } 947*7dd7cddfSDavid du Colombier DBG print("nbits=%d...", nbits); 948*7dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 949*7dd7cddfSDavid du Colombier if(nbits == 0){ 950*7dd7cddfSDavid du Colombier bits = *r++; 951*7dd7cddfSDavid du Colombier nbits = 8; 952*7dd7cddfSDavid du Colombier } 953*7dd7cddfSDavid du Colombier *w++ = repl[bits>>sh]; 954*7dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]); 955*7dd7cddfSDavid du Colombier bits <<= depth; 956*7dd7cddfSDavid du Colombier nbits -= depth; 957*7dd7cddfSDavid du Colombier DBG print("bits %x nbits %d...", bits, nbits); 958*7dd7cddfSDavid du Colombier } 959*7dd7cddfSDavid du Colombier dx -= n; 960*7dd7cddfSDavid du Colombier if(dx == 0) 961*7dd7cddfSDavid du Colombier return b; 962*7dd7cddfSDavid du Colombier 963*7dd7cddfSDavid du Colombier assert(dx > 0); 964*7dd7cddfSDavid du Colombier /* now we have exactly one full scan line: just replicate the buffer itself until we are done */ 965*7dd7cddfSDavid du Colombier ow = buf; 966*7dd7cddfSDavid du Colombier while(dx--) 967*7dd7cddfSDavid du Colombier *w++ = *ow++; 968*7dd7cddfSDavid du Colombier 969*7dd7cddfSDavid du Colombier return b; 970*7dd7cddfSDavid du Colombier } 971*7dd7cddfSDavid du Colombier #undef DBG 972*7dd7cddfSDavid du Colombier 973*7dd7cddfSDavid du Colombier #define DBG if(0) 974*7dd7cddfSDavid du Colombier static void 975*7dd7cddfSDavid du Colombier writenbit(Param *p, uchar *w, Buffer src) 976*7dd7cddfSDavid du Colombier { 977*7dd7cddfSDavid du Colombier uchar *r; 978*7dd7cddfSDavid du Colombier ulong bits; 979*7dd7cddfSDavid du Colombier int i, sh, depth, npack, nbits, x, ex; 980*7dd7cddfSDavid du Colombier 981*7dd7cddfSDavid du Colombier assert(src.grey != nil && src.delta == 1); 982*7dd7cddfSDavid du Colombier 983*7dd7cddfSDavid du Colombier x = p->r.min.x; 984*7dd7cddfSDavid du Colombier ex = x+p->dx; 985*7dd7cddfSDavid du Colombier depth = p->img->depth; 986*7dd7cddfSDavid du Colombier npack = 8/depth; 987*7dd7cddfSDavid du Colombier 988*7dd7cddfSDavid du Colombier i=x&(npack-1); 989*7dd7cddfSDavid du Colombier bits = i ? (*w >> (8-depth*i)) : 0; 990*7dd7cddfSDavid du Colombier nbits = depth*i; 991*7dd7cddfSDavid du Colombier sh = 8-depth; 992*7dd7cddfSDavid du Colombier r = src.grey; 993*7dd7cddfSDavid du Colombier 994*7dd7cddfSDavid du Colombier for(; x<ex; x++){ 995*7dd7cddfSDavid du Colombier bits <<= depth; 996*7dd7cddfSDavid du Colombier DBG print(" %x", *r); 997*7dd7cddfSDavid du Colombier bits |= (*r++ >> sh); 998*7dd7cddfSDavid du Colombier nbits += depth; 999*7dd7cddfSDavid du Colombier if(nbits == 8){ 1000*7dd7cddfSDavid du Colombier *w++ = bits; 1001*7dd7cddfSDavid du Colombier nbits = 0; 1002*7dd7cddfSDavid du Colombier } 1003*7dd7cddfSDavid du Colombier } 1004*7dd7cddfSDavid du Colombier 1005*7dd7cddfSDavid du Colombier if(nbits){ 1006*7dd7cddfSDavid du Colombier sh = 8-nbits; 1007*7dd7cddfSDavid du Colombier bits <<= sh; 1008*7dd7cddfSDavid du Colombier bits |= *w & ((1<<sh)-1); 1009*7dd7cddfSDavid du Colombier *w = bits; 1010*7dd7cddfSDavid du Colombier } 1011*7dd7cddfSDavid du Colombier DBG print("\n"); 1012*7dd7cddfSDavid du Colombier return; 1013*7dd7cddfSDavid du Colombier } 1014*7dd7cddfSDavid du Colombier #undef DBG 1015*7dd7cddfSDavid du Colombier 1016*7dd7cddfSDavid du Colombier static Buffer 1017*7dd7cddfSDavid du Colombier readcmap(Param *p, uchar *buf, int y) 1018*7dd7cddfSDavid du Colombier { 1019*7dd7cddfSDavid du Colombier Buffer b; 1020*7dd7cddfSDavid du Colombier int i, dx, convgrey; 1021*7dd7cddfSDavid du Colombier uchar *q, *cmap, *begin, *end, *r, *w; 1022*7dd7cddfSDavid du Colombier 1023*7dd7cddfSDavid du Colombier begin = p->bytey0s + y*p->bwidth; 1024*7dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 1025*7dd7cddfSDavid du Colombier end = p->bytey0e + y*p->bwidth; 1026*7dd7cddfSDavid du Colombier cmap = p->img->cmap->cmap2rgb; 1027*7dd7cddfSDavid du Colombier convgrey = p->convgrey; 1028*7dd7cddfSDavid du Colombier 1029*7dd7cddfSDavid du Colombier w = buf; 1030*7dd7cddfSDavid du Colombier dx = p->dx; 1031*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 1032*7dd7cddfSDavid du Colombier q = cmap+*r++*3; 1033*7dd7cddfSDavid du Colombier if(r == end) 1034*7dd7cddfSDavid du Colombier r = begin; 1035*7dd7cddfSDavid du Colombier if(convgrey){ 1036*7dd7cddfSDavid du Colombier *w++ = RGB2K(q[0], q[1], q[2]); 1037*7dd7cddfSDavid du Colombier }else{ 1038*7dd7cddfSDavid du Colombier *w++ = q[2]; /* blue */ 1039*7dd7cddfSDavid du Colombier *w++ = q[1]; /* green */ 1040*7dd7cddfSDavid du Colombier *w++ = q[0]; /* red */ 1041*7dd7cddfSDavid du Colombier } 1042*7dd7cddfSDavid du Colombier } 1043*7dd7cddfSDavid du Colombier 1044*7dd7cddfSDavid du Colombier if(convgrey){ 1045*7dd7cddfSDavid du Colombier b.alpha = nil; 1046*7dd7cddfSDavid du Colombier b.grey = buf; 1047*7dd7cddfSDavid du Colombier b.red = b.blu = b.grn = buf; 1048*7dd7cddfSDavid du Colombier b.delta = 1; 1049*7dd7cddfSDavid du Colombier }else{ 1050*7dd7cddfSDavid du Colombier b.blu = buf; 1051*7dd7cddfSDavid du Colombier b.grn = buf+1; 1052*7dd7cddfSDavid du Colombier b.red = buf+2; 1053*7dd7cddfSDavid du Colombier b.alpha = nil; 1054*7dd7cddfSDavid du Colombier b.grey = nil; 1055*7dd7cddfSDavid du Colombier b.delta = 3; 1056*7dd7cddfSDavid du Colombier } 1057*7dd7cddfSDavid du Colombier return b; 1058*7dd7cddfSDavid du Colombier } 1059*7dd7cddfSDavid du Colombier 1060*7dd7cddfSDavid du Colombier static void 1061*7dd7cddfSDavid du Colombier writecmap(Param *p, uchar *w, Buffer src) 1062*7dd7cddfSDavid du Colombier { 1063*7dd7cddfSDavid du Colombier uchar *cmap, *red, *grn, *blu; 1064*7dd7cddfSDavid du Colombier int i, dx, delta; 1065*7dd7cddfSDavid du Colombier 1066*7dd7cddfSDavid du Colombier cmap = p->img->cmap->rgb2cmap; 1067*7dd7cddfSDavid du Colombier 1068*7dd7cddfSDavid du Colombier delta = src.delta; 1069*7dd7cddfSDavid du Colombier red= src.red; 1070*7dd7cddfSDavid du Colombier grn = src.grn; 1071*7dd7cddfSDavid du Colombier blu = src.blu; 1072*7dd7cddfSDavid du Colombier 1073*7dd7cddfSDavid du Colombier dx = p->dx; 1074*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta) 1075*7dd7cddfSDavid du Colombier *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)]; 1076*7dd7cddfSDavid du Colombier } 1077*7dd7cddfSDavid du Colombier 1078*7dd7cddfSDavid du Colombier static Buffer 1079*7dd7cddfSDavid du Colombier readbyte(Param *p, uchar *buf, int y) 1080*7dd7cddfSDavid du Colombier { 1081*7dd7cddfSDavid du Colombier Buffer b; 1082*7dd7cddfSDavid du Colombier Memimage *img; 1083*7dd7cddfSDavid du Colombier int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb; 1084*7dd7cddfSDavid du Colombier uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl; 1085*7dd7cddfSDavid du Colombier uchar ured, ugrn, ublu; 1086*7dd7cddfSDavid du Colombier ulong u; 1087*7dd7cddfSDavid du Colombier 1088*7dd7cddfSDavid du Colombier img = p->img; 1089*7dd7cddfSDavid du Colombier begin = p->bytey0s + y*p->bwidth; 1090*7dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 1091*7dd7cddfSDavid du Colombier end = p->bytey0e + y*p->bwidth; 1092*7dd7cddfSDavid du Colombier 1093*7dd7cddfSDavid du Colombier w = buf; 1094*7dd7cddfSDavid du Colombier dx = p->dx; 1095*7dd7cddfSDavid du Colombier nb = img->depth/8; 1096*7dd7cddfSDavid du Colombier 1097*7dd7cddfSDavid du Colombier convgrey = p->convgrey; /* convert rgb to grey */ 1098*7dd7cddfSDavid du Colombier isgrey = img->flags&Fgrey; 1099*7dd7cddfSDavid du Colombier alphaonly = p->alphaonly; 1100*7dd7cddfSDavid du Colombier copyalpha = convgrey==0 && (img->flags&Falpha); 1101*7dd7cddfSDavid du Colombier 1102*7dd7cddfSDavid du Colombier /* if we can, avoid processing everything */ 1103*7dd7cddfSDavid du Colombier if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){ 1104*7dd7cddfSDavid du Colombier memset(&b, 0, sizeof b); 1105*7dd7cddfSDavid du Colombier if(p->needbuf){ 1106*7dd7cddfSDavid du Colombier memmove(buf, r, dx*nb); 1107*7dd7cddfSDavid du Colombier r = buf; 1108*7dd7cddfSDavid du Colombier } 1109*7dd7cddfSDavid du Colombier if(copyalpha) 1110*7dd7cddfSDavid du Colombier b.alpha = r+img->shift[CAlpha]/8; 1111*7dd7cddfSDavid du Colombier if(isgrey){ 1112*7dd7cddfSDavid du Colombier b.grey = r+img->shift[CGrey]/8; 1113*7dd7cddfSDavid du Colombier b.red = b.grn = b.blu = b.grey; 1114*7dd7cddfSDavid du Colombier }else{ 1115*7dd7cddfSDavid du Colombier b.red = r+img->shift[CRed]/8; 1116*7dd7cddfSDavid du Colombier b.grn = r+img->shift[CGreen]/8; 1117*7dd7cddfSDavid du Colombier b.blu = r+img->shift[CBlue]/8; 1118*7dd7cddfSDavid du Colombier } 1119*7dd7cddfSDavid du Colombier b.delta = nb; 1120*7dd7cddfSDavid du Colombier return b; 1121*7dd7cddfSDavid du Colombier } 1122*7dd7cddfSDavid du Colombier 1123*7dd7cddfSDavid du Colombier rrepl = replbit[img->nbits[CRed]]; 1124*7dd7cddfSDavid du Colombier grepl = replbit[img->nbits[CGreen]]; 1125*7dd7cddfSDavid du Colombier brepl = replbit[img->nbits[CBlue]]; 1126*7dd7cddfSDavid du Colombier arepl = replbit[img->nbits[CAlpha]]; 1127*7dd7cddfSDavid du Colombier krepl = replbit[img->nbits[CGrey]]; 1128*7dd7cddfSDavid du Colombier 1129*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 1130*7dd7cddfSDavid du Colombier u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24); 1131*7dd7cddfSDavid du Colombier if(copyalpha) 1132*7dd7cddfSDavid du Colombier *w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]]; 1133*7dd7cddfSDavid du Colombier 1134*7dd7cddfSDavid du Colombier if(isgrey) 1135*7dd7cddfSDavid du Colombier *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]]; 1136*7dd7cddfSDavid du Colombier else if(!alphaonly){ 1137*7dd7cddfSDavid du Colombier ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; 1138*7dd7cddfSDavid du Colombier ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; 1139*7dd7cddfSDavid du Colombier ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; 1140*7dd7cddfSDavid du Colombier if(convgrey){ 1141*7dd7cddfSDavid du Colombier *w++ = RGB2K(ured, ugrn, ublu); 1142*7dd7cddfSDavid du Colombier }else{ 1143*7dd7cddfSDavid du Colombier *w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; 1144*7dd7cddfSDavid du Colombier *w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; 1145*7dd7cddfSDavid du Colombier *w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; 1146*7dd7cddfSDavid du Colombier } 1147*7dd7cddfSDavid du Colombier } 1148*7dd7cddfSDavid du Colombier r += nb; 1149*7dd7cddfSDavid du Colombier if(r == end) 1150*7dd7cddfSDavid du Colombier r = begin; 1151*7dd7cddfSDavid du Colombier } 1152*7dd7cddfSDavid du Colombier 1153*7dd7cddfSDavid du Colombier b.alpha = copyalpha ? buf : nil; 1154*7dd7cddfSDavid du Colombier if(alphaonly){ 1155*7dd7cddfSDavid du Colombier b.red = b.grn = b.blu = b.grey = nil; 1156*7dd7cddfSDavid du Colombier b.delta = 1; 1157*7dd7cddfSDavid du Colombier }else if(isgrey || convgrey){ 1158*7dd7cddfSDavid du Colombier b.grey = buf+copyalpha; 1159*7dd7cddfSDavid du Colombier b.red = b.grn = b.blu = buf+copyalpha; 1160*7dd7cddfSDavid du Colombier b.delta = copyalpha+1; 1161*7dd7cddfSDavid du Colombier }else{ 1162*7dd7cddfSDavid du Colombier b.blu = buf+copyalpha; 1163*7dd7cddfSDavid du Colombier b.grn = buf+copyalpha+1; 1164*7dd7cddfSDavid du Colombier b.grey = nil; 1165*7dd7cddfSDavid du Colombier b.red = buf+copyalpha+2; 1166*7dd7cddfSDavid du Colombier b.delta = copyalpha+3; 1167*7dd7cddfSDavid du Colombier } 1168*7dd7cddfSDavid du Colombier return b; 1169*7dd7cddfSDavid du Colombier } 1170*7dd7cddfSDavid du Colombier 1171*7dd7cddfSDavid du Colombier #define DBG if(0) 1172*7dd7cddfSDavid du Colombier static void 1173*7dd7cddfSDavid du Colombier writebyte(Param *p, uchar *w, Buffer src) 1174*7dd7cddfSDavid du Colombier { 1175*7dd7cddfSDavid du Colombier Memimage *img; 1176*7dd7cddfSDavid du Colombier int i, isalpha, isgrey, nb, delta, dx, adelta; 1177*7dd7cddfSDavid du Colombier uchar ff, *red, *grn, *blu, *grey, *alpha; 1178*7dd7cddfSDavid du Colombier ulong u, mask; 1179*7dd7cddfSDavid du Colombier 1180*7dd7cddfSDavid du Colombier img = p->img; 1181*7dd7cddfSDavid du Colombier 1182*7dd7cddfSDavid du Colombier red = src.red; 1183*7dd7cddfSDavid du Colombier grn = src.grn; 1184*7dd7cddfSDavid du Colombier blu = src.blu; 1185*7dd7cddfSDavid du Colombier alpha = src.alpha; 1186*7dd7cddfSDavid du Colombier delta = src.delta; 1187*7dd7cddfSDavid du Colombier grey = src.grey; 1188*7dd7cddfSDavid du Colombier dx = p->dx; 1189*7dd7cddfSDavid du Colombier 1190*7dd7cddfSDavid du Colombier nb = img->depth/8; 1191*7dd7cddfSDavid du Colombier mask = (nb==4) ? 0 : ~((1<<img->depth)-1); 1192*7dd7cddfSDavid du Colombier 1193*7dd7cddfSDavid du Colombier isalpha = img->flags&Falpha; 1194*7dd7cddfSDavid du Colombier isgrey = img->flags&Fgrey; 1195*7dd7cddfSDavid du Colombier adelta = src.delta; 1196*7dd7cddfSDavid du Colombier 1197*7dd7cddfSDavid du Colombier if(isalpha && alpha == nil){ 1198*7dd7cddfSDavid du Colombier ff = 0xFF; 1199*7dd7cddfSDavid du Colombier alpha = &ff; 1200*7dd7cddfSDavid du Colombier adelta = 0; 1201*7dd7cddfSDavid du Colombier } 1202*7dd7cddfSDavid du Colombier 1203*7dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 1204*7dd7cddfSDavid du Colombier u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24); 1205*7dd7cddfSDavid du Colombier DBG print("u %.8lux...", u); 1206*7dd7cddfSDavid du Colombier u &= mask; 1207*7dd7cddfSDavid du Colombier DBG print("&mask %.8lux...", u); 1208*7dd7cddfSDavid du Colombier if(isgrey){ 1209*7dd7cddfSDavid du Colombier u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey]; 1210*7dd7cddfSDavid du Colombier DBG print("|grey %.8lux...", u); 1211*7dd7cddfSDavid du Colombier grey += delta; 1212*7dd7cddfSDavid du Colombier }else{ 1213*7dd7cddfSDavid du Colombier u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed]; 1214*7dd7cddfSDavid du Colombier u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen]; 1215*7dd7cddfSDavid du Colombier u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue]; 1216*7dd7cddfSDavid du Colombier red += delta; 1217*7dd7cddfSDavid du Colombier grn += delta; 1218*7dd7cddfSDavid du Colombier blu += delta; 1219*7dd7cddfSDavid du Colombier DBG print("|rgb %.8lux...", u); 1220*7dd7cddfSDavid du Colombier } 1221*7dd7cddfSDavid du Colombier 1222*7dd7cddfSDavid du Colombier if(isalpha){ 1223*7dd7cddfSDavid du Colombier u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha]; 1224*7dd7cddfSDavid du Colombier alpha += adelta; 1225*7dd7cddfSDavid du Colombier DBG print("|alpha %.8lux...", u); 1226*7dd7cddfSDavid du Colombier } 1227*7dd7cddfSDavid du Colombier 1228*7dd7cddfSDavid du Colombier w[0] = u; 1229*7dd7cddfSDavid du Colombier w[1] = u>>8; 1230*7dd7cddfSDavid du Colombier w[2] = u>>16; 1231*7dd7cddfSDavid du Colombier w[3] = u>>24; 1232*7dd7cddfSDavid du Colombier w += nb; 1233*7dd7cddfSDavid du Colombier } 1234*7dd7cddfSDavid du Colombier } 1235*7dd7cddfSDavid du Colombier #undef DBG 1236*7dd7cddfSDavid du Colombier 1237*7dd7cddfSDavid du Colombier static Readfn* 1238*7dd7cddfSDavid du Colombier readfn(Memimage *img) 1239*7dd7cddfSDavid du Colombier { 1240*7dd7cddfSDavid du Colombier if(img->depth < 8) 1241*7dd7cddfSDavid du Colombier return readnbit; 1242*7dd7cddfSDavid du Colombier if(img->chan == CMAP8) 1243*7dd7cddfSDavid du Colombier return readcmap; 1244*7dd7cddfSDavid du Colombier return readbyte; 1245*7dd7cddfSDavid du Colombier } 1246*7dd7cddfSDavid du Colombier 1247*7dd7cddfSDavid du Colombier static Readfn* 1248*7dd7cddfSDavid du Colombier readalphafn(Memimage *notused) 1249*7dd7cddfSDavid du Colombier { 1250*7dd7cddfSDavid du Colombier return readbyte; 1251*7dd7cddfSDavid du Colombier } 1252*7dd7cddfSDavid du Colombier 1253*7dd7cddfSDavid du Colombier static Writefn* 1254*7dd7cddfSDavid du Colombier writefn(Memimage *img) 1255*7dd7cddfSDavid du Colombier { 1256*7dd7cddfSDavid du Colombier if(img->depth < 8) 1257*7dd7cddfSDavid du Colombier return writenbit; 1258*7dd7cddfSDavid du Colombier if(img->chan == CMAP8) 1259*7dd7cddfSDavid du Colombier return writecmap; 1260*7dd7cddfSDavid du Colombier return writebyte; 1261*7dd7cddfSDavid du Colombier } 1262*7dd7cddfSDavid du Colombier 1263*7dd7cddfSDavid du Colombier static void 1264*7dd7cddfSDavid du Colombier nullwrite(Param *notusedpar, uchar *notusedbuf, Buffer notusedb) 1265*7dd7cddfSDavid du Colombier { 1266*7dd7cddfSDavid du Colombier } 1267*7dd7cddfSDavid du Colombier 1268*7dd7cddfSDavid du Colombier static Buffer 1269*7dd7cddfSDavid du Colombier readptr(Param *p, uchar *notusedbuf, int y) 1270*7dd7cddfSDavid du Colombier { 1271*7dd7cddfSDavid du Colombier Buffer b; 1272*7dd7cddfSDavid du Colombier uchar *q; 1273*7dd7cddfSDavid du Colombier 1274*7dd7cddfSDavid du Colombier q = p->bytermin + y*p->bwidth; 1275*7dd7cddfSDavid du Colombier b.red = q; /* ptr to data */ 1276*7dd7cddfSDavid du Colombier b.grn = b.blu = b.grey = b.alpha = nil; 1277*7dd7cddfSDavid du Colombier b.delta = p->img->depth/8; 1278*7dd7cddfSDavid du Colombier return b; 1279*7dd7cddfSDavid du Colombier } 1280*7dd7cddfSDavid du Colombier 1281*7dd7cddfSDavid du Colombier static Buffer 1282*7dd7cddfSDavid du Colombier boolmemmove(Buffer bdst, Buffer bsrc, Buffer notusedb, int dx, int notusedi) 1283*7dd7cddfSDavid du Colombier { 1284*7dd7cddfSDavid du Colombier memmove(bdst.red, bsrc.red, dx*bdst.delta); 1285*7dd7cddfSDavid du Colombier return bdst; 1286*7dd7cddfSDavid du Colombier } 1287*7dd7cddfSDavid du Colombier 1288*7dd7cddfSDavid du Colombier static Buffer 1289*7dd7cddfSDavid du Colombier boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 1290*7dd7cddfSDavid du Colombier { 1291*7dd7cddfSDavid du Colombier uchar *m, *r, *w, *ew; 1292*7dd7cddfSDavid du Colombier 1293*7dd7cddfSDavid du Colombier m = bmask.grey; 1294*7dd7cddfSDavid du Colombier w = bdst.red; 1295*7dd7cddfSDavid du Colombier r = bsrc.red; 1296*7dd7cddfSDavid du Colombier ew = w+dx; 1297*7dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 1298*7dd7cddfSDavid du Colombier if(*m++) 1299*7dd7cddfSDavid du Colombier *w = *r; 1300*7dd7cddfSDavid du Colombier return bdst; /* not used */ 1301*7dd7cddfSDavid du Colombier } 1302*7dd7cddfSDavid du Colombier 1303*7dd7cddfSDavid du Colombier static Buffer 1304*7dd7cddfSDavid du Colombier boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 1305*7dd7cddfSDavid du Colombier { 1306*7dd7cddfSDavid du Colombier uchar *m; 1307*7dd7cddfSDavid du Colombier ushort *r, *w, *ew; 1308*7dd7cddfSDavid du Colombier 1309*7dd7cddfSDavid du Colombier m = bmask.grey; 1310*7dd7cddfSDavid du Colombier w = (ushort*)bdst.red; 1311*7dd7cddfSDavid du Colombier r = (ushort*)bsrc.red; 1312*7dd7cddfSDavid du Colombier ew = w+dx; 1313*7dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 1314*7dd7cddfSDavid du Colombier if(*m++) 1315*7dd7cddfSDavid du Colombier *w = *r; 1316*7dd7cddfSDavid du Colombier return bdst; /* not used */ 1317*7dd7cddfSDavid du Colombier } 1318*7dd7cddfSDavid du Colombier 1319*7dd7cddfSDavid du Colombier static Buffer 1320*7dd7cddfSDavid du Colombier boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 1321*7dd7cddfSDavid du Colombier { 1322*7dd7cddfSDavid du Colombier uchar *m; 1323*7dd7cddfSDavid du Colombier uchar *r, *w, *ew; 1324*7dd7cddfSDavid du Colombier 1325*7dd7cddfSDavid du Colombier m = bmask.grey; 1326*7dd7cddfSDavid du Colombier w = bdst.red; 1327*7dd7cddfSDavid du Colombier r = bsrc.red; 1328*7dd7cddfSDavid du Colombier ew = w+dx*3; 1329*7dd7cddfSDavid du Colombier while(w < ew){ 1330*7dd7cddfSDavid du Colombier if(*m++){ 1331*7dd7cddfSDavid du Colombier *w++ = *r++; 1332*7dd7cddfSDavid du Colombier *w++ = *r++; 1333*7dd7cddfSDavid du Colombier *w++ = *r++; 1334*7dd7cddfSDavid du Colombier }else{ 1335*7dd7cddfSDavid du Colombier w += 3; 1336*7dd7cddfSDavid du Colombier r += 3; 1337*7dd7cddfSDavid du Colombier } 1338*7dd7cddfSDavid du Colombier } 1339*7dd7cddfSDavid du Colombier return bdst; /* not used */ 1340*7dd7cddfSDavid du Colombier } 1341*7dd7cddfSDavid du Colombier 1342*7dd7cddfSDavid du Colombier static Buffer 1343*7dd7cddfSDavid du Colombier boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 1344*7dd7cddfSDavid du Colombier { 1345*7dd7cddfSDavid du Colombier uchar *m; 1346*7dd7cddfSDavid du Colombier ulong *r, *w, *ew; 1347*7dd7cddfSDavid du Colombier 1348*7dd7cddfSDavid du Colombier m = bmask.grey; 1349*7dd7cddfSDavid du Colombier w = (ulong*)bdst.red; 1350*7dd7cddfSDavid du Colombier r = (ulong*)bsrc.red; 1351*7dd7cddfSDavid du Colombier ew = w+dx; 1352*7dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 1353*7dd7cddfSDavid du Colombier if(*m++) 1354*7dd7cddfSDavid du Colombier *w = *r; 1355*7dd7cddfSDavid du Colombier return bdst; /* not used */ 1356*7dd7cddfSDavid du Colombier } 1357*7dd7cddfSDavid du Colombier 1358*7dd7cddfSDavid du Colombier static Buffer 1359*7dd7cddfSDavid du Colombier genconv(Param *p, uchar *buf, int y) 1360*7dd7cddfSDavid du Colombier { 1361*7dd7cddfSDavid du Colombier Buffer b; 1362*7dd7cddfSDavid du Colombier int nb; 1363*7dd7cddfSDavid du Colombier uchar *r, *w, *ew; 1364*7dd7cddfSDavid du Colombier 1365*7dd7cddfSDavid du Colombier /* read from source into RGB format in convbuf */ 1366*7dd7cddfSDavid du Colombier b = p->convreadcall(p, p->convbuf, y); 1367*7dd7cddfSDavid du Colombier 1368*7dd7cddfSDavid du Colombier /* write RGB format into dst format in buf */ 1369*7dd7cddfSDavid du Colombier p->convwritecall(p->convdpar, buf, b); 1370*7dd7cddfSDavid du Colombier 1371*7dd7cddfSDavid du Colombier if(p->convdx){ 1372*7dd7cddfSDavid du Colombier nb = p->convdpar->img->depth/8; 1373*7dd7cddfSDavid du Colombier r = buf; 1374*7dd7cddfSDavid du Colombier w = buf+nb*p->dx; 1375*7dd7cddfSDavid du Colombier ew = buf+nb*p->convdx; 1376*7dd7cddfSDavid du Colombier while(w<ew) 1377*7dd7cddfSDavid du Colombier *w++ = *r++; 1378*7dd7cddfSDavid du Colombier } 1379*7dd7cddfSDavid du Colombier 1380*7dd7cddfSDavid du Colombier b.red = buf; 1381*7dd7cddfSDavid du Colombier b.blu = b.grn = b.grey = b.alpha = nil; 1382*7dd7cddfSDavid du Colombier b.delta = 0; 1383*7dd7cddfSDavid du Colombier 1384*7dd7cddfSDavid du Colombier return b; 1385*7dd7cddfSDavid du Colombier } 1386*7dd7cddfSDavid du Colombier 1387*7dd7cddfSDavid du Colombier static Readfn* 1388*7dd7cddfSDavid du Colombier convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar) 1389*7dd7cddfSDavid du Colombier { 1390*7dd7cddfSDavid du Colombier if(dst->chan == src->chan && !(src->flags&Frepl)){ 1391*7dd7cddfSDavid du Colombier return readptr; 1392*7dd7cddfSDavid du Colombier } 1393*7dd7cddfSDavid du Colombier 1394*7dd7cddfSDavid du Colombier if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){ 1395*7dd7cddfSDavid du Colombier /* cheat because we know the replicated value is exactly the color map entry. */ 1396*7dd7cddfSDavid du Colombier return readnbit; 1397*7dd7cddfSDavid du Colombier } 1398*7dd7cddfSDavid du Colombier 1399*7dd7cddfSDavid du Colombier spar->convreadcall = readfn(src); 1400*7dd7cddfSDavid du Colombier spar->convwritecall = writefn(dst); 1401*7dd7cddfSDavid du Colombier spar->convdpar = dpar; 1402*7dd7cddfSDavid du Colombier 1403*7dd7cddfSDavid du Colombier /* allocate a conversion buffer */ 1404*7dd7cddfSDavid du Colombier spar->convbufoff = ndrawbuf; 1405*7dd7cddfSDavid du Colombier ndrawbuf += spar->dx*4; 1406*7dd7cddfSDavid du Colombier 1407*7dd7cddfSDavid du Colombier if(spar->dx > Dx(spar->img->r)){ 1408*7dd7cddfSDavid du Colombier spar->convdx = spar->dx; 1409*7dd7cddfSDavid du Colombier spar->dx = Dx(spar->img->r); 1410*7dd7cddfSDavid du Colombier } 1411*7dd7cddfSDavid du Colombier 1412*7dd7cddfSDavid du Colombier return genconv; 1413*7dd7cddfSDavid du Colombier } 1414*7dd7cddfSDavid du Colombier 1415*7dd7cddfSDavid du Colombier ulong 1416*7dd7cddfSDavid du Colombier _pixelbits(Memimage *i, Point pt) 1417*7dd7cddfSDavid du Colombier { 1418*7dd7cddfSDavid du Colombier uchar *p; 1419*7dd7cddfSDavid du Colombier ulong val; 1420*7dd7cddfSDavid du Colombier int off, bpp, npack; 1421*7dd7cddfSDavid du Colombier 1422*7dd7cddfSDavid du Colombier val = 0; 1423*7dd7cddfSDavid du Colombier p = byteaddr(i, pt); 1424*7dd7cddfSDavid du Colombier switch(bpp=i->depth){ 1425*7dd7cddfSDavid du Colombier case 1: 1426*7dd7cddfSDavid du Colombier case 2: 1427*7dd7cddfSDavid du Colombier case 4: 1428*7dd7cddfSDavid du Colombier npack = 8/bpp; 1429*7dd7cddfSDavid du Colombier off = pt.x%npack; 1430*7dd7cddfSDavid du Colombier val = p[0] >> bpp*(npack-1-off); 1431*7dd7cddfSDavid du Colombier val &= (1<<bpp)-1; 1432*7dd7cddfSDavid du Colombier break; 1433*7dd7cddfSDavid du Colombier case 8: 1434*7dd7cddfSDavid du Colombier val = p[0]; 1435*7dd7cddfSDavid du Colombier break; 1436*7dd7cddfSDavid du Colombier case 16: 1437*7dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8); 1438*7dd7cddfSDavid du Colombier break; 1439*7dd7cddfSDavid du Colombier case 24: 1440*7dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8)|(p[2]<<16); 1441*7dd7cddfSDavid du Colombier break; 1442*7dd7cddfSDavid du Colombier case 32: 1443*7dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); 1444*7dd7cddfSDavid du Colombier break; 1445*7dd7cddfSDavid du Colombier } 1446*7dd7cddfSDavid du Colombier while(bpp<32){ 1447*7dd7cddfSDavid du Colombier val |= val<<bpp; 1448*7dd7cddfSDavid du Colombier bpp *= 2; 1449*7dd7cddfSDavid du Colombier } 1450*7dd7cddfSDavid du Colombier return val; 1451*7dd7cddfSDavid du Colombier } 1452*7dd7cddfSDavid du Colombier 1453*7dd7cddfSDavid du Colombier static Calcfn* 1454*7dd7cddfSDavid du Colombier boolcopyfn(Memimage *img, Memimage *mask) 1455*7dd7cddfSDavid du Colombier { 1456*7dd7cddfSDavid du Colombier if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && _pixelbits(mask, mask->r.min)==~0) 1457*7dd7cddfSDavid du Colombier return boolmemmove; 1458*7dd7cddfSDavid du Colombier 1459*7dd7cddfSDavid du Colombier switch(img->depth){ 1460*7dd7cddfSDavid du Colombier case 8: 1461*7dd7cddfSDavid du Colombier return boolcopy8; 1462*7dd7cddfSDavid du Colombier case 16: 1463*7dd7cddfSDavid du Colombier return boolcopy16; 1464*7dd7cddfSDavid du Colombier case 24: 1465*7dd7cddfSDavid du Colombier return boolcopy24; 1466*7dd7cddfSDavid du Colombier case 32: 1467*7dd7cddfSDavid du Colombier return boolcopy32; 1468*7dd7cddfSDavid du Colombier default: 1469*7dd7cddfSDavid du Colombier assert(0 /* boolcopyfn */); 1470*7dd7cddfSDavid du Colombier } 1471*7dd7cddfSDavid du Colombier return nil; 1472*7dd7cddfSDavid du Colombier } 1473*7dd7cddfSDavid du Colombier 1474*7dd7cddfSDavid du Colombier /* 1475*7dd7cddfSDavid du Colombier * Optimized draw for filling and scrolling; uses memset and memmove. 1476*7dd7cddfSDavid du Colombier */ 1477*7dd7cddfSDavid du Colombier static void 1478*7dd7cddfSDavid du Colombier memsetb(void *vp, uchar val, int n) 1479*7dd7cddfSDavid du Colombier { 1480*7dd7cddfSDavid du Colombier uchar *p, *ep; 1481*7dd7cddfSDavid du Colombier 1482*7dd7cddfSDavid du Colombier p = vp; 1483*7dd7cddfSDavid du Colombier ep = p+n; 1484*7dd7cddfSDavid du Colombier while(p<ep) 1485*7dd7cddfSDavid du Colombier *p++ = val; 1486*7dd7cddfSDavid du Colombier } 1487*7dd7cddfSDavid du Colombier 1488*7dd7cddfSDavid du Colombier static void 1489*7dd7cddfSDavid du Colombier memsets(void *vp, ushort val, int n) 1490*7dd7cddfSDavid du Colombier { 1491*7dd7cddfSDavid du Colombier ushort *p, *ep; 1492*7dd7cddfSDavid du Colombier 1493*7dd7cddfSDavid du Colombier p = vp; 1494*7dd7cddfSDavid du Colombier ep = p+n; 1495*7dd7cddfSDavid du Colombier while(p<ep) 1496*7dd7cddfSDavid du Colombier *p++ = val; 1497*7dd7cddfSDavid du Colombier } 1498*7dd7cddfSDavid du Colombier 1499*7dd7cddfSDavid du Colombier static void 1500*7dd7cddfSDavid du Colombier memsetl(void *vp, ulong val, int n) 1501*7dd7cddfSDavid du Colombier { 1502*7dd7cddfSDavid du Colombier ulong *p, *ep; 1503*7dd7cddfSDavid du Colombier 1504*7dd7cddfSDavid du Colombier p = vp; 1505*7dd7cddfSDavid du Colombier ep = p+n; 1506*7dd7cddfSDavid du Colombier while(p<ep) 1507*7dd7cddfSDavid du Colombier *p++ = val; 1508*7dd7cddfSDavid du Colombier } 1509*7dd7cddfSDavid du Colombier 1510*7dd7cddfSDavid du Colombier void 1511*7dd7cddfSDavid du Colombier memset24(void *vp, ulong val, int n) 1512*7dd7cddfSDavid du Colombier { 1513*7dd7cddfSDavid du Colombier uchar *p, *ep; 1514*7dd7cddfSDavid du Colombier uchar a,b,c; 1515*7dd7cddfSDavid du Colombier 1516*7dd7cddfSDavid du Colombier p = vp; 1517*7dd7cddfSDavid du Colombier ep = p+3*n; 1518*7dd7cddfSDavid du Colombier a = val; 1519*7dd7cddfSDavid du Colombier b = val>>8; 1520*7dd7cddfSDavid du Colombier c = val>>16; 1521*7dd7cddfSDavid du Colombier while(p<ep){ 1522*7dd7cddfSDavid du Colombier *p++ = a; 1523*7dd7cddfSDavid du Colombier *p++ = b; 1524*7dd7cddfSDavid du Colombier *p++ = c; 1525*7dd7cddfSDavid du Colombier } 1526*7dd7cddfSDavid du Colombier } 1527*7dd7cddfSDavid du Colombier 1528*7dd7cddfSDavid du Colombier ulong 1529*7dd7cddfSDavid du Colombier _imgtorgba(Memimage *img, ulong val) 1530*7dd7cddfSDavid du Colombier { 1531*7dd7cddfSDavid du Colombier uchar r, g, b, a; 1532*7dd7cddfSDavid du Colombier int nb, ov, v; 1533*7dd7cddfSDavid du Colombier ulong chan; 1534*7dd7cddfSDavid du Colombier uchar *p; 1535*7dd7cddfSDavid du Colombier 1536*7dd7cddfSDavid du Colombier a = 0xFF; 1537*7dd7cddfSDavid du Colombier r = g = b = 0xAA; /* garbage */ 1538*7dd7cddfSDavid du Colombier for(chan=img->chan; chan; chan>>=8){ 1539*7dd7cddfSDavid du Colombier nb = NBITS(chan); 1540*7dd7cddfSDavid du Colombier ov = v = val&((1<<nb)-1); 1541*7dd7cddfSDavid du Colombier val >>= nb; 1542*7dd7cddfSDavid du Colombier 1543*7dd7cddfSDavid du Colombier while(nb < 8){ 1544*7dd7cddfSDavid du Colombier v |= v<<nb; 1545*7dd7cddfSDavid du Colombier nb *= 2; 1546*7dd7cddfSDavid du Colombier } 1547*7dd7cddfSDavid du Colombier v >>= (nb-8); 1548*7dd7cddfSDavid du Colombier 1549*7dd7cddfSDavid du Colombier switch(TYPE(chan)){ 1550*7dd7cddfSDavid du Colombier case CRed: 1551*7dd7cddfSDavid du Colombier r = v; 1552*7dd7cddfSDavid du Colombier break; 1553*7dd7cddfSDavid du Colombier case CGreen: 1554*7dd7cddfSDavid du Colombier g = v; 1555*7dd7cddfSDavid du Colombier break; 1556*7dd7cddfSDavid du Colombier case CBlue: 1557*7dd7cddfSDavid du Colombier b = v; 1558*7dd7cddfSDavid du Colombier break; 1559*7dd7cddfSDavid du Colombier case CAlpha: 1560*7dd7cddfSDavid du Colombier a = v; 1561*7dd7cddfSDavid du Colombier break; 1562*7dd7cddfSDavid du Colombier case CGrey: 1563*7dd7cddfSDavid du Colombier r = g = b = v; 1564*7dd7cddfSDavid du Colombier break; 1565*7dd7cddfSDavid du Colombier case CMap: 1566*7dd7cddfSDavid du Colombier p = img->cmap->cmap2rgb+3*ov; 1567*7dd7cddfSDavid du Colombier r = *p++; 1568*7dd7cddfSDavid du Colombier g = *p++; 1569*7dd7cddfSDavid du Colombier b = *p; 1570*7dd7cddfSDavid du Colombier break; 1571*7dd7cddfSDavid du Colombier } 1572*7dd7cddfSDavid du Colombier } 1573*7dd7cddfSDavid du Colombier return (r<<24)|(g<<16)|(b<<8)|a; 1574*7dd7cddfSDavid du Colombier } 1575*7dd7cddfSDavid du Colombier 1576*7dd7cddfSDavid du Colombier ulong 1577*7dd7cddfSDavid du Colombier _rgbatoimg(Memimage *img, ulong rgba) 1578*7dd7cddfSDavid du Colombier { 1579*7dd7cddfSDavid du Colombier ulong chan; 1580*7dd7cddfSDavid du Colombier int d, nb; 1581*7dd7cddfSDavid du Colombier ulong v; 1582*7dd7cddfSDavid du Colombier uchar *p, r, g, b, a, m; 1583*7dd7cddfSDavid du Colombier 1584*7dd7cddfSDavid du Colombier v = 0; 1585*7dd7cddfSDavid du Colombier r = rgba>>24; 1586*7dd7cddfSDavid du Colombier g = rgba>>16; 1587*7dd7cddfSDavid du Colombier b = rgba>>8; 1588*7dd7cddfSDavid du Colombier a = rgba; 1589*7dd7cddfSDavid du Colombier d = 0; 1590*7dd7cddfSDavid du Colombier for(chan=img->chan; chan; chan>>=8){ 1591*7dd7cddfSDavid du Colombier nb = NBITS(chan); 1592*7dd7cddfSDavid du Colombier switch(TYPE(chan)){ 1593*7dd7cddfSDavid du Colombier case CRed: 1594*7dd7cddfSDavid du Colombier v |= (r>>(8-nb))<<d; 1595*7dd7cddfSDavid du Colombier break; 1596*7dd7cddfSDavid du Colombier case CGreen: 1597*7dd7cddfSDavid du Colombier v |= (g>>(8-nb))<<d; 1598*7dd7cddfSDavid du Colombier break; 1599*7dd7cddfSDavid du Colombier case CBlue: 1600*7dd7cddfSDavid du Colombier v |= (b>>(8-nb))<<d; 1601*7dd7cddfSDavid du Colombier break; 1602*7dd7cddfSDavid du Colombier case CAlpha: 1603*7dd7cddfSDavid du Colombier v |= (a>>(8-nb))<<d; 1604*7dd7cddfSDavid du Colombier break; 1605*7dd7cddfSDavid du Colombier case CMap: 1606*7dd7cddfSDavid du Colombier p = img->cmap->rgb2cmap; 1607*7dd7cddfSDavid du Colombier m = p[(r>>4)*256+(g>>4)*16+(b>>4)]; 1608*7dd7cddfSDavid du Colombier v |= m<<d; 1609*7dd7cddfSDavid du Colombier break; 1610*7dd7cddfSDavid du Colombier case CGrey: 1611*7dd7cddfSDavid du Colombier m = RGB2K(r,g,b); 1612*7dd7cddfSDavid du Colombier v |= m<<d; 1613*7dd7cddfSDavid du Colombier break; 1614*7dd7cddfSDavid du Colombier } 1615*7dd7cddfSDavid du Colombier d += nb; 1616*7dd7cddfSDavid du Colombier } 1617*7dd7cddfSDavid du Colombier return v; 1618*7dd7cddfSDavid du Colombier } 1619*7dd7cddfSDavid du Colombier 1620*7dd7cddfSDavid du Colombier static int 1621*7dd7cddfSDavid du Colombier memoptdraw(Memdrawparam *par) 1622*7dd7cddfSDavid du Colombier { 1623*7dd7cddfSDavid du Colombier int y, dy, dx; 1624*7dd7cddfSDavid du Colombier ulong v; 1625*7dd7cddfSDavid du Colombier unsigned m; 1626*7dd7cddfSDavid du Colombier Memimage *src; 1627*7dd7cddfSDavid du Colombier Memimage *dst; 1628*7dd7cddfSDavid du Colombier 1629*7dd7cddfSDavid du Colombier dx = Dx(par->r); 1630*7dd7cddfSDavid du Colombier dy = Dy(par->r); 1631*7dd7cddfSDavid du Colombier src = par->src; 1632*7dd7cddfSDavid du Colombier dst = par->dst; 1633*7dd7cddfSDavid du Colombier 1634*7dd7cddfSDavid du Colombier /* 1635*7dd7cddfSDavid du Colombier * If we have an opaque mask and source is one opaque pixel we can convert to the 1636*7dd7cddfSDavid du Colombier * destination format and just replicate with memset. 1637*7dd7cddfSDavid du Colombier */ 1638*7dd7cddfSDavid du Colombier m = Simplesrc|Simplemask|Fullmask; 1639*7dd7cddfSDavid du Colombier if((par->state&m)==m){ 1640*7dd7cddfSDavid du Colombier uchar *dp, p[4]; 1641*7dd7cddfSDavid du Colombier int dwid, ppb, np, nb; 1642*7dd7cddfSDavid du Colombier uchar lm, rm; 1643*7dd7cddfSDavid du Colombier 1644*7dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 1645*7dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 1646*7dd7cddfSDavid du Colombier v = par->sdval; 1647*7dd7cddfSDavid du Colombier switch(dst->depth){ 1648*7dd7cddfSDavid du Colombier case 1: 1649*7dd7cddfSDavid du Colombier case 2: 1650*7dd7cddfSDavid du Colombier case 4: 1651*7dd7cddfSDavid du Colombier ppb = 8/dst->depth; /* pixels per byte */ 1652*7dd7cddfSDavid du Colombier m = ppb-1; 1653*7dd7cddfSDavid du Colombier /* left edge */ 1654*7dd7cddfSDavid du Colombier np = par->r.min.x&m; /* no. pixels unused on left side of word */ 1655*7dd7cddfSDavid du Colombier dx -= (ppb-np); 1656*7dd7cddfSDavid du Colombier nb = 8 - np * dst->depth; /* no. bits used on right side of word */ 1657*7dd7cddfSDavid du Colombier lm = (1<<nb)-1; 1658*7dd7cddfSDavid du Colombier 1659*7dd7cddfSDavid du Colombier /* right edge */ 1660*7dd7cddfSDavid du Colombier np = par->r.max.x&m; /* no. pixels used on left side of word */ 1661*7dd7cddfSDavid du Colombier dx -= np; 1662*7dd7cddfSDavid du Colombier nb = 8 - np * dst->depth; /* no. bits unused on right side of word */ 1663*7dd7cddfSDavid du Colombier rm = ~((1<<nb)-1); 1664*7dd7cddfSDavid du Colombier 1665*7dd7cddfSDavid du Colombier /* lm, rm are masks that are 1 where we should touch the bits */ 1666*7dd7cddfSDavid du Colombier if(dx < 0){ /* just one byte */ 1667*7dd7cddfSDavid du Colombier lm &= rm; 1668*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 1669*7dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 1670*7dd7cddfSDavid du Colombier }else if(dx == 0){ /* no full bytes */ 1671*7dd7cddfSDavid du Colombier if(lm) 1672*7dd7cddfSDavid du Colombier dwid--; 1673*7dd7cddfSDavid du Colombier 1674*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid){ 1675*7dd7cddfSDavid du Colombier if(lm){ 1676*7dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 1677*7dd7cddfSDavid du Colombier dp++; 1678*7dd7cddfSDavid du Colombier } 1679*7dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & rm; 1680*7dd7cddfSDavid du Colombier } 1681*7dd7cddfSDavid du Colombier }else{ /* full bytes in middle */ 1682*7dd7cddfSDavid du Colombier dx /= ppb; 1683*7dd7cddfSDavid du Colombier if(lm) 1684*7dd7cddfSDavid du Colombier dwid--; 1685*7dd7cddfSDavid du Colombier dwid -= dx; 1686*7dd7cddfSDavid du Colombier 1687*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid){ 1688*7dd7cddfSDavid du Colombier if(lm){ 1689*7dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 1690*7dd7cddfSDavid du Colombier dp++; 1691*7dd7cddfSDavid du Colombier } 1692*7dd7cddfSDavid du Colombier memset(dp, v, dx); 1693*7dd7cddfSDavid du Colombier dp += dx; 1694*7dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & rm; 1695*7dd7cddfSDavid du Colombier } 1696*7dd7cddfSDavid du Colombier } 1697*7dd7cddfSDavid du Colombier return 1; 1698*7dd7cddfSDavid du Colombier case 8: 1699*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 1700*7dd7cddfSDavid du Colombier memset(dp, v, dx); 1701*7dd7cddfSDavid du Colombier return 1; 1702*7dd7cddfSDavid du Colombier case 16: 1703*7dd7cddfSDavid du Colombier p[0] = v; /* make little endian */ 1704*7dd7cddfSDavid du Colombier p[1] = v>>8; 1705*7dd7cddfSDavid du Colombier v = *(ushort*)p; 1706*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 1707*7dd7cddfSDavid du Colombier memsets(dp, v, dx); 1708*7dd7cddfSDavid du Colombier return 1; 1709*7dd7cddfSDavid du Colombier case 24: 1710*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 1711*7dd7cddfSDavid du Colombier memset24(dp, v, dx); 1712*7dd7cddfSDavid du Colombier return 1; 1713*7dd7cddfSDavid du Colombier case 32: 1714*7dd7cddfSDavid du Colombier p[0] = v; /* make little endian */ 1715*7dd7cddfSDavid du Colombier p[1] = v>>8; 1716*7dd7cddfSDavid du Colombier p[2] = v>>16; 1717*7dd7cddfSDavid du Colombier p[3] = v>>24; 1718*7dd7cddfSDavid du Colombier v = *(ulong*)p; 1719*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 1720*7dd7cddfSDavid du Colombier memsetl(dp, v, dx); 1721*7dd7cddfSDavid du Colombier return 1; 1722*7dd7cddfSDavid du Colombier default: 1723*7dd7cddfSDavid du Colombier assert(0 /* bad dest depth in memoptdraw */); 1724*7dd7cddfSDavid du Colombier } 1725*7dd7cddfSDavid du Colombier } 1726*7dd7cddfSDavid du Colombier 1727*7dd7cddfSDavid du Colombier /* 1728*7dd7cddfSDavid du Colombier * If no source alpha, an opaque mask, we can just copy the 1729*7dd7cddfSDavid du Colombier * source onto the destination. If the channels are the same and 1730*7dd7cddfSDavid du Colombier * the source is not replicated, memmove suffices. 1731*7dd7cddfSDavid du Colombier */ 1732*7dd7cddfSDavid du Colombier m = Simplemask|Fullmask; 1733*7dd7cddfSDavid du Colombier if((par->state&(m|Replsrc))==m && src->depth >= 8 1734*7dd7cddfSDavid du Colombier && src->chan == dst->chan && !(src->flags&Falpha)){ 1735*7dd7cddfSDavid du Colombier uchar *sp, *dp; 1736*7dd7cddfSDavid du Colombier long swid, dwid, nb; 1737*7dd7cddfSDavid du Colombier int dir; 1738*7dd7cddfSDavid du Colombier 1739*7dd7cddfSDavid du Colombier if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)) 1740*7dd7cddfSDavid du Colombier dir = -1; 1741*7dd7cddfSDavid du Colombier else 1742*7dd7cddfSDavid du Colombier dir = 1; 1743*7dd7cddfSDavid du Colombier 1744*7dd7cddfSDavid du Colombier swid = src->width*sizeof(ulong); 1745*7dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 1746*7dd7cddfSDavid du Colombier sp = byteaddr(src, par->sr.min); 1747*7dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 1748*7dd7cddfSDavid du Colombier if(dir == -1){ 1749*7dd7cddfSDavid du Colombier sp += (dy-1)*swid; 1750*7dd7cddfSDavid du Colombier dp += (dy-1)*dwid; 1751*7dd7cddfSDavid du Colombier swid = -swid; 1752*7dd7cddfSDavid du Colombier dwid = -dwid; 1753*7dd7cddfSDavid du Colombier } 1754*7dd7cddfSDavid du Colombier nb = (dx*src->depth)/8; 1755*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, sp+=swid, dp+=dwid) 1756*7dd7cddfSDavid du Colombier memmove(dp, sp, nb); 1757*7dd7cddfSDavid du Colombier return 1; 1758*7dd7cddfSDavid du Colombier } 1759*7dd7cddfSDavid du Colombier 1760*7dd7cddfSDavid du Colombier /* 1761*7dd7cddfSDavid du Colombier * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and 1762*7dd7cddfSDavid du Colombier * they're all bit aligned, we can just use bit operators. This happens 1763*7dd7cddfSDavid du Colombier * when we're manipulating boolean masks, e.g. in the arc code. 1764*7dd7cddfSDavid du Colombier */ 1765*7dd7cddfSDavid du Colombier if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0 1766*7dd7cddfSDavid du Colombier && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1 1767*7dd7cddfSDavid du Colombier && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){ 1768*7dd7cddfSDavid du Colombier uchar *sp, *dp, *mp; 1769*7dd7cddfSDavid du Colombier uchar lm, rm; 1770*7dd7cddfSDavid du Colombier long swid, dwid, mwid; 1771*7dd7cddfSDavid du Colombier int i, x, dir; 1772*7dd7cddfSDavid du Colombier 1773*7dd7cddfSDavid du Colombier sp = byteaddr(src, par->sr.min); 1774*7dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 1775*7dd7cddfSDavid du Colombier mp = byteaddr(par->mask, par->mr.min); 1776*7dd7cddfSDavid du Colombier swid = src->width*sizeof(ulong); 1777*7dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 1778*7dd7cddfSDavid du Colombier mwid = par->mask->width*sizeof(ulong); 1779*7dd7cddfSDavid du Colombier 1780*7dd7cddfSDavid du Colombier if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){ 1781*7dd7cddfSDavid du Colombier dir = -1; 1782*7dd7cddfSDavid du Colombier }else 1783*7dd7cddfSDavid du Colombier dir = 1; 1784*7dd7cddfSDavid du Colombier 1785*7dd7cddfSDavid du Colombier lm = 0xFF>>(par->r.min.x&7); 1786*7dd7cddfSDavid du Colombier rm = 0xFF<<(8-(par->r.max.x&7)); 1787*7dd7cddfSDavid du Colombier dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7); 1788*7dd7cddfSDavid du Colombier 1789*7dd7cddfSDavid du Colombier if(dx < 0){ /* one byte wide */ 1790*7dd7cddfSDavid du Colombier lm &= rm; 1791*7dd7cddfSDavid du Colombier if(dir == -1){ 1792*7dd7cddfSDavid du Colombier dp += dwid*(dy-1); 1793*7dd7cddfSDavid du Colombier sp += swid*(dy-1); 1794*7dd7cddfSDavid du Colombier mp += mwid*(dy-1); 1795*7dd7cddfSDavid du Colombier dwid = -dwid; 1796*7dd7cddfSDavid du Colombier swid = -swid; 1797*7dd7cddfSDavid du Colombier mwid = -mwid; 1798*7dd7cddfSDavid du Colombier } 1799*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++){ 1800*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp) & *mp & lm; 1801*7dd7cddfSDavid du Colombier dp += dwid; 1802*7dd7cddfSDavid du Colombier sp += swid; 1803*7dd7cddfSDavid du Colombier mp += mwid; 1804*7dd7cddfSDavid du Colombier } 1805*7dd7cddfSDavid du Colombier return 1; 1806*7dd7cddfSDavid du Colombier } 1807*7dd7cddfSDavid du Colombier 1808*7dd7cddfSDavid du Colombier dx /= 8; 1809*7dd7cddfSDavid du Colombier if(dir == 1){ 1810*7dd7cddfSDavid du Colombier i = (lm!=0)+dx+(rm!=0); 1811*7dd7cddfSDavid du Colombier mwid -= i; 1812*7dd7cddfSDavid du Colombier swid -= i; 1813*7dd7cddfSDavid du Colombier dwid -= i; 1814*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ 1815*7dd7cddfSDavid du Colombier if(lm){ 1816*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++ & lm; 1817*7dd7cddfSDavid du Colombier dp++; 1818*7dd7cddfSDavid du Colombier } 1819*7dd7cddfSDavid du Colombier for(x=0; x<dx; x++){ 1820*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++; 1821*7dd7cddfSDavid du Colombier dp++; 1822*7dd7cddfSDavid du Colombier } 1823*7dd7cddfSDavid du Colombier if(rm){ 1824*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++ & rm; 1825*7dd7cddfSDavid du Colombier dp++; 1826*7dd7cddfSDavid du Colombier } 1827*7dd7cddfSDavid du Colombier } 1828*7dd7cddfSDavid du Colombier return 1; 1829*7dd7cddfSDavid du Colombier }else{ 1830*7dd7cddfSDavid du Colombier /* dir == -1 */ 1831*7dd7cddfSDavid du Colombier i = (lm!=0)+dx+(rm!=0); 1832*7dd7cddfSDavid du Colombier dp += dwid*(dy-1)+i-1; 1833*7dd7cddfSDavid du Colombier sp += swid*(dy-1)+i-1; 1834*7dd7cddfSDavid du Colombier mp += mwid*(dy-1)+i-1; 1835*7dd7cddfSDavid du Colombier dwid = -dwid+i; 1836*7dd7cddfSDavid du Colombier swid = -swid+i; 1837*7dd7cddfSDavid du Colombier mwid = -mwid+i; 1838*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ 1839*7dd7cddfSDavid du Colombier if(rm){ 1840*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp-- & rm; 1841*7dd7cddfSDavid du Colombier dp--; 1842*7dd7cddfSDavid du Colombier } 1843*7dd7cddfSDavid du Colombier for(x=0; x<dx; x++){ 1844*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp--; 1845*7dd7cddfSDavid du Colombier dp--; 1846*7dd7cddfSDavid du Colombier } 1847*7dd7cddfSDavid du Colombier if(lm){ 1848*7dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp-- & lm; 1849*7dd7cddfSDavid du Colombier dp--; 1850*7dd7cddfSDavid du Colombier } 1851*7dd7cddfSDavid du Colombier } 1852*7dd7cddfSDavid du Colombier } 1853*7dd7cddfSDavid du Colombier return 1; 1854*7dd7cddfSDavid du Colombier } 1855*7dd7cddfSDavid du Colombier return 0; 1856*7dd7cddfSDavid du Colombier } 1857*7dd7cddfSDavid du Colombier 1858*7dd7cddfSDavid du Colombier /* 1859*7dd7cddfSDavid du Colombier * Boolean character drawing. 1860*7dd7cddfSDavid du Colombier * Solid opaque color through a 1-bit greyscale mask. 1861*7dd7cddfSDavid du Colombier */ 1862*7dd7cddfSDavid du Colombier #define DBG if(0) 1863*7dd7cddfSDavid du Colombier static int 1864*7dd7cddfSDavid du Colombier chardraw(Memdrawparam *par) 1865*7dd7cddfSDavid du Colombier { 1866*7dd7cddfSDavid du Colombier ulong bits; 1867*7dd7cddfSDavid du Colombier int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth; 1868*7dd7cddfSDavid du Colombier ulong v, maskwid, dstwid; 1869*7dd7cddfSDavid du Colombier uchar *wp, *rp, *q, *wc; 1870*7dd7cddfSDavid du Colombier ushort *ws; 1871*7dd7cddfSDavid du Colombier ulong *wl; 1872*7dd7cddfSDavid du Colombier uchar sp[4]; 1873*7dd7cddfSDavid du Colombier Rectangle r, mr; 1874*7dd7cddfSDavid du Colombier Memimage *mask, *src, *dst; 1875*7dd7cddfSDavid du Colombier 1876*7dd7cddfSDavid du Colombier if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n", 1877*7dd7cddfSDavid du Colombier par->mask->flags, par->mask->depth, par->src->flags, 1878*7dd7cddfSDavid du Colombier Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data); 1879*7dd7cddfSDavid du Colombier 1880*7dd7cddfSDavid du Colombier mask = par->mask; 1881*7dd7cddfSDavid du Colombier src = par->src; 1882*7dd7cddfSDavid du Colombier dst = par->dst; 1883*7dd7cddfSDavid du Colombier r = par->r; 1884*7dd7cddfSDavid du Colombier mr = par->mr; 1885*7dd7cddfSDavid du Colombier 1886*7dd7cddfSDavid du Colombier if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc) 1887*7dd7cddfSDavid du Colombier || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data) 1888*7dd7cddfSDavid du Colombier return 0; 1889*7dd7cddfSDavid du Colombier 1890*7dd7cddfSDavid du Colombier depth = mask->depth; 1891*7dd7cddfSDavid du Colombier maskwid = mask->width*sizeof(ulong); 1892*7dd7cddfSDavid du Colombier rp = byteaddr(mask, mr.min); 1893*7dd7cddfSDavid du Colombier npack = 8/depth; 1894*7dd7cddfSDavid du Colombier bsh = (mr.min.x % npack) * depth; 1895*7dd7cddfSDavid du Colombier 1896*7dd7cddfSDavid du Colombier wp = byteaddr(dst, r.min); 1897*7dd7cddfSDavid du Colombier dstwid = dst->width*sizeof(ulong); 1898*7dd7cddfSDavid du Colombier DBG print("bsh %d\n", bsh); 1899*7dd7cddfSDavid du Colombier dy = Dy(r); 1900*7dd7cddfSDavid du Colombier dx = Dx(r); 1901*7dd7cddfSDavid du Colombier 1902*7dd7cddfSDavid du Colombier ddepth = dst->depth; 1903*7dd7cddfSDavid du Colombier 1904*7dd7cddfSDavid du Colombier /* 1905*7dd7cddfSDavid du Colombier * for loop counts from bsh to bsh+dx 1906*7dd7cddfSDavid du Colombier * 1907*7dd7cddfSDavid du Colombier * we want the bottom bits to be the amount 1908*7dd7cddfSDavid du Colombier * to shift the pixels down, so for n≡0 (mod 8) we want 1909*7dd7cddfSDavid du Colombier * bottom bits 7. for n≡1, 6, etc. 1910*7dd7cddfSDavid du Colombier * the bits come from -n-1. 1911*7dd7cddfSDavid du Colombier */ 1912*7dd7cddfSDavid du Colombier 1913*7dd7cddfSDavid du Colombier bx = -bsh-1; 1914*7dd7cddfSDavid du Colombier ex = -bsh-1-dx; 1915*7dd7cddfSDavid du Colombier SET(bits); 1916*7dd7cddfSDavid du Colombier v = par->sdval; 1917*7dd7cddfSDavid du Colombier 1918*7dd7cddfSDavid du Colombier /* make little endian */ 1919*7dd7cddfSDavid du Colombier sp[0] = v; 1920*7dd7cddfSDavid du Colombier sp[1] = v>>8; 1921*7dd7cddfSDavid du Colombier sp[2] = v>>16; 1922*7dd7cddfSDavid du Colombier sp[3] = v>>24; 1923*7dd7cddfSDavid du Colombier 1924*7dd7cddfSDavid du Colombier for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){ 1925*7dd7cddfSDavid du Colombier q = rp; 1926*7dd7cddfSDavid du Colombier if(bsh) 1927*7dd7cddfSDavid du Colombier bits = *q++; 1928*7dd7cddfSDavid du Colombier switch(ddepth){ 1929*7dd7cddfSDavid du Colombier case 8: 1930*7dd7cddfSDavid du Colombier wc = wp; 1931*7dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wc++){ 1932*7dd7cddfSDavid du Colombier i = x&7; 1933*7dd7cddfSDavid du Colombier if(i == 8-1) 1934*7dd7cddfSDavid du Colombier bits = *q++; 1935*7dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 1936*7dd7cddfSDavid du Colombier if((bits>>i)&1) 1937*7dd7cddfSDavid du Colombier *wc = v; 1938*7dd7cddfSDavid du Colombier } 1939*7dd7cddfSDavid du Colombier break; 1940*7dd7cddfSDavid du Colombier case 16: 1941*7dd7cddfSDavid du Colombier ws = (ushort*)wp; 1942*7dd7cddfSDavid du Colombier v = *(ushort*)sp; 1943*7dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, ws++){ 1944*7dd7cddfSDavid du Colombier i = x&7; 1945*7dd7cddfSDavid du Colombier if(i == 8-1) 1946*7dd7cddfSDavid du Colombier bits = *q++; 1947*7dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 1948*7dd7cddfSDavid du Colombier if((bits>>i)&1) 1949*7dd7cddfSDavid du Colombier *ws = v; 1950*7dd7cddfSDavid du Colombier } 1951*7dd7cddfSDavid du Colombier break; 1952*7dd7cddfSDavid du Colombier case 24: 1953*7dd7cddfSDavid du Colombier wc = wp; 1954*7dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wc+=3){ 1955*7dd7cddfSDavid du Colombier i = x&7; 1956*7dd7cddfSDavid du Colombier if(i == 8-1) 1957*7dd7cddfSDavid du Colombier bits = *q++; 1958*7dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 1959*7dd7cddfSDavid du Colombier if((bits>>i)&1){ 1960*7dd7cddfSDavid du Colombier wc[0] = sp[0]; 1961*7dd7cddfSDavid du Colombier wc[1] = sp[1]; 1962*7dd7cddfSDavid du Colombier wc[2] = sp[2]; 1963*7dd7cddfSDavid du Colombier } 1964*7dd7cddfSDavid du Colombier } 1965*7dd7cddfSDavid du Colombier break; 1966*7dd7cddfSDavid du Colombier case 32: 1967*7dd7cddfSDavid du Colombier wl = (ulong*)wp; 1968*7dd7cddfSDavid du Colombier v = *(ulong*)sp; 1969*7dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wl++){ 1970*7dd7cddfSDavid du Colombier i = x&7; 1971*7dd7cddfSDavid du Colombier if(i == 8-1) 1972*7dd7cddfSDavid du Colombier bits = *q++; 1973*7dd7cddfSDavid du Colombier DBG iprint("bits %lux sh %d...", bits, i); 1974*7dd7cddfSDavid du Colombier if((bits>>i)&1) 1975*7dd7cddfSDavid du Colombier *wl = v; 1976*7dd7cddfSDavid du Colombier } 1977*7dd7cddfSDavid du Colombier break; 1978*7dd7cddfSDavid du Colombier } 1979*7dd7cddfSDavid du Colombier } 1980*7dd7cddfSDavid du Colombier 1981*7dd7cddfSDavid du Colombier DBG print("\n"); 1982*7dd7cddfSDavid du Colombier return 1; 1983*7dd7cddfSDavid du Colombier } 1984*7dd7cddfSDavid du Colombier #undef DBG 1985*7dd7cddfSDavid du Colombier 1986