17dd7cddfSDavid du Colombier #include "../lib9.h" 27dd7cddfSDavid du Colombier 37dd7cddfSDavid du Colombier #include "../libdraw/draw.h" 47dd7cddfSDavid du Colombier #include "../libmemdraw/memdraw.h" 57dd7cddfSDavid du Colombier 67dd7cddfSDavid du Colombier /* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */ 77dd7cddfSDavid du Colombier #define RGB2K(r,g,b) ((156763*(r)+307758*(g)+59769*(b))>>19) 87dd7cddfSDavid du Colombier 97dd7cddfSDavid du Colombier /* 107dd7cddfSDavid du Colombier * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation. 117dd7cddfSDavid du Colombier * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation. 127dd7cddfSDavid du Colombier * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole. 137dd7cddfSDavid du Colombier */ 147dd7cddfSDavid du Colombier /* #define DIV255(x) (((x)*257+256)>>16) */ 157dd7cddfSDavid du Colombier #define DIV255(x) ((((x)+1)*257)>>16) 167dd7cddfSDavid du Colombier /* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */ 177dd7cddfSDavid du Colombier 187dd7cddfSDavid du Colombier static void mktables(void); 197dd7cddfSDavid du Colombier typedef int Subdraw(Memdrawparam*); 207dd7cddfSDavid du Colombier static Subdraw chardraw, alphadraw, memoptdraw; 217dd7cddfSDavid du Colombier 227dd7cddfSDavid du Colombier static Memimage* memones; 237dd7cddfSDavid du Colombier static Memimage* memzeros; 247dd7cddfSDavid du Colombier Memimage *memwhite; 257dd7cddfSDavid du Colombier Memimage *memblack; 267dd7cddfSDavid du Colombier Memimage *memtransparent; 277dd7cddfSDavid du Colombier Memimage *memopaque; 287dd7cddfSDavid du Colombier 297dd7cddfSDavid du Colombier int 307dd7cddfSDavid du Colombier Rconv(va_list *o, Fconv *f) 317dd7cddfSDavid du Colombier { 327dd7cddfSDavid du Colombier Rectangle r; 337dd7cddfSDavid du Colombier char buf[128]; 347dd7cddfSDavid du Colombier 357dd7cddfSDavid du Colombier r = va_arg(*o, Rectangle); 367dd7cddfSDavid du Colombier sprint(buf, "%P %P", r.min, r.max); 377dd7cddfSDavid du Colombier strconv(buf, f); 387dd7cddfSDavid du Colombier return sizeof r; 397dd7cddfSDavid du Colombier } 407dd7cddfSDavid du Colombier 417dd7cddfSDavid du Colombier int 427dd7cddfSDavid du Colombier Pconv(va_list *o, Fconv *f) 437dd7cddfSDavid du Colombier { 447dd7cddfSDavid du Colombier Point p; 457dd7cddfSDavid du Colombier char buf[64]; 467dd7cddfSDavid du Colombier 477dd7cddfSDavid du Colombier p = va_arg(*o, Point); 487dd7cddfSDavid du Colombier sprint(buf, "[%d %d]", p.x, p.y); 497dd7cddfSDavid du Colombier strconv(buf, f); 507dd7cddfSDavid du Colombier return sizeof p; 517dd7cddfSDavid du Colombier } 527dd7cddfSDavid du Colombier 537dd7cddfSDavid du Colombier void 547dd7cddfSDavid du Colombier _memimageinit(void) 557dd7cddfSDavid du Colombier { 567dd7cddfSDavid du Colombier static int didinit = 0; 577dd7cddfSDavid du Colombier 587dd7cddfSDavid du Colombier if(didinit) 597dd7cddfSDavid du Colombier return; 607dd7cddfSDavid du Colombier 617dd7cddfSDavid du Colombier didinit = 1; 627dd7cddfSDavid du Colombier 637dd7cddfSDavid du Colombier fmtinstall('R', Rconv); 647dd7cddfSDavid du Colombier fmtinstall('P', Pconv); 657dd7cddfSDavid du Colombier 667dd7cddfSDavid du Colombier mktables(); 677dd7cddfSDavid du Colombier memmkcmap(); 687dd7cddfSDavid du Colombier 697dd7cddfSDavid du Colombier memones = allocmemimage(Rect(0,0,1,1), GREY1); 707dd7cddfSDavid du Colombier memones->flags |= Frepl; 717dd7cddfSDavid du Colombier memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); 727dd7cddfSDavid du Colombier *byteaddr(memones, ZP) = ~0; 737dd7cddfSDavid du Colombier 747dd7cddfSDavid du Colombier memzeros = allocmemimage(Rect(0,0,1,1), GREY1); 757dd7cddfSDavid du Colombier memzeros->flags |= Frepl; 767dd7cddfSDavid du Colombier memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF); 777dd7cddfSDavid du Colombier *byteaddr(memzeros, ZP) = 0; 787dd7cddfSDavid du Colombier 797dd7cddfSDavid du Colombier if(memones == nil || memzeros == nil) 807dd7cddfSDavid du Colombier assert(0 /*cannot initialize memimage library */); /* RSC BUG */ 817dd7cddfSDavid du Colombier 827dd7cddfSDavid du Colombier memwhite = memones; 837dd7cddfSDavid du Colombier memblack = memzeros; 847dd7cddfSDavid du Colombier memopaque = memones; 857dd7cddfSDavid du Colombier memtransparent = memzeros; 867dd7cddfSDavid du Colombier } 877dd7cddfSDavid du Colombier 887dd7cddfSDavid du Colombier int 897dd7cddfSDavid du Colombier drawreplxy(int min, int max, int x) 907dd7cddfSDavid du Colombier { 917dd7cddfSDavid du Colombier int sx; 927dd7cddfSDavid du Colombier 937dd7cddfSDavid du Colombier sx = (x-min)%(max-min); 947dd7cddfSDavid du Colombier if(sx < 0) 957dd7cddfSDavid du Colombier sx += max-min; 967dd7cddfSDavid du Colombier return sx+min; 977dd7cddfSDavid du Colombier } 987dd7cddfSDavid du Colombier 997dd7cddfSDavid du Colombier Point 1007dd7cddfSDavid du Colombier drawrepl(Rectangle r, Point p) 1017dd7cddfSDavid du Colombier { 1027dd7cddfSDavid du Colombier p.x = drawreplxy(r.min.x, r.max.x, p.x); 1037dd7cddfSDavid du Colombier p.y = drawreplxy(r.min.y, r.max.y, p.y); 1047dd7cddfSDavid du Colombier return p; 1057dd7cddfSDavid du Colombier } 1067dd7cddfSDavid du Colombier 1077dd7cddfSDavid du Colombier #define DBG if(0) 1087dd7cddfSDavid du Colombier static Memdrawparam par; /* sleazily left for the X implementation */ 1097dd7cddfSDavid du Colombier Memdrawparam* 1107dd7cddfSDavid du Colombier _memimagedrawsetup(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1) 1117dd7cddfSDavid du Colombier { 1127dd7cddfSDavid du Colombier static int n = 0; 1137dd7cddfSDavid du Colombier 1147dd7cddfSDavid du Colombier if(mask == nil) 1157dd7cddfSDavid du Colombier mask = memopaque; 1167dd7cddfSDavid du Colombier 1177dd7cddfSDavid du Colombier if(drawdebug) 1187dd7cddfSDavid 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); 1197dd7cddfSDavid du Colombier 1207dd7cddfSDavid du Colombier if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){ 1217dd7cddfSDavid du Colombier if(drawdebug) 1227dd7cddfSDavid du Colombier iprint("empty clipped rectangle\n"); 1237dd7cddfSDavid du Colombier return nil; 1247dd7cddfSDavid du Colombier } 1257dd7cddfSDavid du Colombier 1267dd7cddfSDavid du Colombier par.dst = dst; 1277dd7cddfSDavid du Colombier par.r = r; 1287dd7cddfSDavid du Colombier par.src = src; 1297dd7cddfSDavid du Colombier /* par.sr set by drawclip */ 1307dd7cddfSDavid du Colombier par.mask = mask; 1317dd7cddfSDavid du Colombier /* par.mr set by drawclip */ 1327dd7cddfSDavid du Colombier 1337dd7cddfSDavid du Colombier par.state = 0; 1347dd7cddfSDavid du Colombier if(src->flags&Frepl){ 1357dd7cddfSDavid du Colombier par.state |= Replsrc; 1367dd7cddfSDavid du Colombier if(Dx(src->r)==1 && Dy(src->r)==1){ 1377dd7cddfSDavid du Colombier par.sval = pixelbits(src, src->r.min); 1387dd7cddfSDavid du Colombier par.state |= Simplesrc; 1397dd7cddfSDavid du Colombier par.srgba = _imgtorgba(src, par.sval); 1407dd7cddfSDavid du Colombier par.sdval = _rgbatoimg(dst, par.srgba); 1417dd7cddfSDavid du Colombier } 1427dd7cddfSDavid du Colombier } 1437dd7cddfSDavid du Colombier 1447dd7cddfSDavid du Colombier if(mask->flags & Frepl){ 1457dd7cddfSDavid du Colombier par.state |= Replmask; 1467dd7cddfSDavid du Colombier if(Dx(mask->r)==1 && Dy(mask->r)==1){ 1477dd7cddfSDavid du Colombier par.mval = pixelbits(mask, mask->r.min); 1487dd7cddfSDavid du Colombier if(par.mval == 0){ 1497dd7cddfSDavid du Colombier if(drawdebug) iprint("fill with zero mask\n"); 1507dd7cddfSDavid du Colombier return nil; /* no-op successfully handled */ 1517dd7cddfSDavid du Colombier } 1527dd7cddfSDavid du Colombier par.state |= Simplemask; 1537dd7cddfSDavid du Colombier if(par.mval == ~0) 1547dd7cddfSDavid du Colombier par.state |= Fullmask; 1557dd7cddfSDavid du Colombier par.mrgba = _imgtorgba(mask, par.mval); 1567dd7cddfSDavid du Colombier } 1577dd7cddfSDavid du Colombier } 1587dd7cddfSDavid du Colombier 1597dd7cddfSDavid du Colombier if(drawdebug) 1607dd7cddfSDavid du Colombier iprint("dr %R sr %R mr %R...", r, par.sr, par.mr); 1617dd7cddfSDavid du Colombier DBG print("draw dr %R sr %R mr %R\n", r, par.sr, par.mr); 1627dd7cddfSDavid du Colombier 1637dd7cddfSDavid du Colombier return ∥ 1647dd7cddfSDavid du Colombier } 1657dd7cddfSDavid du Colombier 1667dd7cddfSDavid du Colombier void 1677dd7cddfSDavid du Colombier _memimagedraw(Memdrawparam *par) 1687dd7cddfSDavid du Colombier { 1697dd7cddfSDavid du Colombier if(par == nil) 1707dd7cddfSDavid du Colombier return; 1717dd7cddfSDavid du Colombier 1727dd7cddfSDavid du Colombier /* 1737dd7cddfSDavid du Colombier * Now that we've clipped the parameters down to be consistent, we 1747dd7cddfSDavid du Colombier * simply try sub-drawing routines in order until we find one that was able 1757dd7cddfSDavid du Colombier * to handle us. If the sub-drawing routine returns zero, it means it was 1767dd7cddfSDavid du Colombier * unable to satisfy the request, so we do not return. 1777dd7cddfSDavid du Colombier */ 1787dd7cddfSDavid du Colombier 1797dd7cddfSDavid du Colombier /* 1807dd7cddfSDavid du Colombier * Hardware support. Each video driver provides this function, 1817dd7cddfSDavid du Colombier * which checks to see if there is anything it can help with. 1827dd7cddfSDavid du Colombier * There could be an if around this checking to see if dst is in video memory. 1837dd7cddfSDavid du Colombier */ 1847dd7cddfSDavid du Colombier if(hwdraw(par)) 1857dd7cddfSDavid du Colombier { 1867dd7cddfSDavid du Colombier if(drawdebug) iprint("hw handled\n"); 1877dd7cddfSDavid du Colombier return; 1887dd7cddfSDavid du Colombier } 1897dd7cddfSDavid du Colombier /* 1907dd7cddfSDavid du Colombier * Optimizations using memmove and memset. 1917dd7cddfSDavid du Colombier */ 1927dd7cddfSDavid du Colombier if(memoptdraw(par)){ 1937dd7cddfSDavid du Colombier if(drawdebug) iprint("memopt handled\n"); 1947dd7cddfSDavid du Colombier { 1957dd7cddfSDavid du Colombier return; 1967dd7cddfSDavid du Colombier } 1977dd7cddfSDavid du Colombier } 1987dd7cddfSDavid du Colombier 1997dd7cddfSDavid du Colombier /* 2007dd7cddfSDavid du Colombier * Character drawing. 2017dd7cddfSDavid du Colombier * Solid source color being painted through a boolean mask onto a high res image. 2027dd7cddfSDavid du Colombier */ 2037dd7cddfSDavid du Colombier if(chardraw(par)){ 2047dd7cddfSDavid du Colombier if(drawdebug) iprint("chardraw handled\n"); 2057dd7cddfSDavid du Colombier return; 2067dd7cddfSDavid du Colombier } 2077dd7cddfSDavid du Colombier 2087dd7cddfSDavid du Colombier /* 2097dd7cddfSDavid du Colombier * General calculation-laden case that does alpha for each pixel. 2107dd7cddfSDavid du Colombier */ 2117dd7cddfSDavid du Colombier alphadraw(par); 2127dd7cddfSDavid du Colombier if(drawdebug) iprint("alphadraw handled\n"); 2137dd7cddfSDavid du Colombier return; 2147dd7cddfSDavid du Colombier } 2157dd7cddfSDavid du Colombier #undef DBG 2167dd7cddfSDavid du Colombier 2177dd7cddfSDavid du Colombier /* 2187dd7cddfSDavid du Colombier * Clip the destination rectangle further based on the properties of the 2197dd7cddfSDavid du Colombier * source and mask rectangles. Once the destination rectangle is properly 2207dd7cddfSDavid du Colombier * clipped, adjust the source and mask rectangles to be the same size. 2217dd7cddfSDavid du Colombier * Then if source or mask is replicated, move its clipped rectangle 2227dd7cddfSDavid du Colombier * so that its minimum point falls within the repl rectangle. 2237dd7cddfSDavid du Colombier * 2247dd7cddfSDavid du Colombier * Return zero if the final rectangle is null. 2257dd7cddfSDavid du Colombier */ 2267dd7cddfSDavid du Colombier int 2277dd7cddfSDavid du Colombier drawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr) 2287dd7cddfSDavid du Colombier { 2297dd7cddfSDavid du Colombier Point rmin, delta; 2307dd7cddfSDavid du Colombier int splitcoords; 2317dd7cddfSDavid du Colombier Rectangle omr; 2327dd7cddfSDavid du Colombier Point p; 2337dd7cddfSDavid du Colombier 2347dd7cddfSDavid du Colombier if(r->min.x>=r->max.x || r->min.y>=r->max.y) 2357dd7cddfSDavid du Colombier return 0; 2367dd7cddfSDavid du Colombier splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y); 2377dd7cddfSDavid du Colombier /* clip to destination */ 2387dd7cddfSDavid du Colombier rmin = r->min; 2397dd7cddfSDavid du Colombier if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr)) 2407dd7cddfSDavid du Colombier return 0; 2417dd7cddfSDavid du Colombier /* move mask point */ 2427dd7cddfSDavid du Colombier p1->x += r->min.x-rmin.x; 2437dd7cddfSDavid du Colombier p1->y += r->min.y-rmin.y; 2447dd7cddfSDavid du Colombier /* move source point */ 2457dd7cddfSDavid du Colombier p0->x += r->min.x-rmin.x; 2467dd7cddfSDavid du Colombier p0->y += r->min.y-rmin.y; 2477dd7cddfSDavid du Colombier /* map destination rectangle into source */ 2487dd7cddfSDavid du Colombier sr->min = *p0; 2497dd7cddfSDavid du Colombier sr->max.x = p0->x+Dx(*r); 2507dd7cddfSDavid du Colombier sr->max.y = p0->y+Dy(*r); 2517dd7cddfSDavid du Colombier /* sr is r in source coordinates; clip to source */ 2527dd7cddfSDavid du Colombier if(!(src->flags&Frepl) && !rectclip(sr, src->r)) 2537dd7cddfSDavid du Colombier return 0; 2547dd7cddfSDavid du Colombier if(!rectclip(sr, src->clipr)) 2557dd7cddfSDavid du Colombier return 0; 2567dd7cddfSDavid du Colombier /* compute and clip rectangle in mask */ 2577dd7cddfSDavid du Colombier if(splitcoords){ 2587dd7cddfSDavid du Colombier /* move mask point with source */ 2597dd7cddfSDavid du Colombier p1->x += sr->min.x-p0->x; 2607dd7cddfSDavid du Colombier p1->y += sr->min.y-p0->y; 2617dd7cddfSDavid du Colombier mr->min = *p1; 2627dd7cddfSDavid du Colombier mr->max.x = p1->x+Dx(*sr); 2637dd7cddfSDavid du Colombier mr->max.y = p1->y+Dy(*sr); 2647dd7cddfSDavid du Colombier omr = *mr; 2657dd7cddfSDavid du Colombier /* mr is now rectangle in mask; clip it */ 2667dd7cddfSDavid du Colombier if(!(mask->flags&Frepl) && !rectclip(mr, mask->r)) 2677dd7cddfSDavid du Colombier return 0; 2687dd7cddfSDavid du Colombier if(!rectclip(mr, mask->clipr)) 2697dd7cddfSDavid du Colombier return 0; 2707dd7cddfSDavid du Colombier /* reflect any clips back to source */ 2717dd7cddfSDavid du Colombier sr->min.x += mr->min.x-omr.min.x; 2727dd7cddfSDavid du Colombier sr->min.y += mr->min.y-omr.min.y; 2737dd7cddfSDavid du Colombier sr->max.x += mr->max.x-omr.max.x; 2747dd7cddfSDavid du Colombier sr->max.y += mr->max.y-omr.max.y; 2757dd7cddfSDavid du Colombier *p1 = mr->min; 2767dd7cddfSDavid du Colombier }else{ 2777dd7cddfSDavid du Colombier if(!(mask->flags&Frepl) && !rectclip(sr, mask->r)) 2787dd7cddfSDavid du Colombier return 0; 2797dd7cddfSDavid du Colombier if(!rectclip(sr, mask->clipr)) 2807dd7cddfSDavid du Colombier return 0; 2817dd7cddfSDavid du Colombier *p1 = sr->min; 2827dd7cddfSDavid du Colombier } 2837dd7cddfSDavid du Colombier 2847dd7cddfSDavid du Colombier /* move source clipping back to destination */ 2857dd7cddfSDavid du Colombier delta.x = r->min.x - p0->x; 2867dd7cddfSDavid du Colombier delta.y = r->min.y - p0->y; 2877dd7cddfSDavid du Colombier r->min.x = sr->min.x + delta.x; 2887dd7cddfSDavid du Colombier r->min.y = sr->min.y + delta.y; 2897dd7cddfSDavid du Colombier r->max.x = sr->max.x + delta.x; 2907dd7cddfSDavid du Colombier r->max.y = sr->max.y + delta.y; 2917dd7cddfSDavid du Colombier 2927dd7cddfSDavid du Colombier /* move source rectangle so sr->min is in src->r */ 2937dd7cddfSDavid du Colombier if(src->flags&Frepl) { 2947dd7cddfSDavid du Colombier delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x; 2957dd7cddfSDavid du Colombier delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y; 2967dd7cddfSDavid du Colombier sr->min.x += delta.x; 2977dd7cddfSDavid du Colombier sr->min.y += delta.y; 2987dd7cddfSDavid du Colombier sr->max.x += delta.x; 2997dd7cddfSDavid du Colombier sr->max.y += delta.y; 3007dd7cddfSDavid du Colombier } 3017dd7cddfSDavid du Colombier *p0 = sr->min; 3027dd7cddfSDavid du Colombier 3037dd7cddfSDavid du Colombier /* move mask point so it is in mask->r */ 3047dd7cddfSDavid du Colombier /* use temporary point p to avoid warnings about unaligned volatiles on digital unix */ 3057dd7cddfSDavid du Colombier p = *p1; 3067dd7cddfSDavid du Colombier p = drawrepl(mask->r, p); 3077dd7cddfSDavid du Colombier *p1 = p; 3087dd7cddfSDavid du Colombier mr->min = *p1; 3097dd7cddfSDavid du Colombier mr->max.x = p1->x+Dx(*sr); 3107dd7cddfSDavid du Colombier mr->max.y = p1->y+Dy(*sr); 3117dd7cddfSDavid du Colombier 3127dd7cddfSDavid du Colombier assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r)); 3137dd7cddfSDavid du Colombier assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r)); 3147dd7cddfSDavid du Colombier assert((p=*p0, ptinrect(p, src->r))); 3157dd7cddfSDavid du Colombier assert((p=*p1, ptinrect(p, mask->r))); 3167dd7cddfSDavid du Colombier assert((p=r->min, ptinrect(p, dst->r))); 3177dd7cddfSDavid du Colombier 3187dd7cddfSDavid du Colombier return 1; 3197dd7cddfSDavid du Colombier } 3207dd7cddfSDavid du Colombier 3217dd7cddfSDavid du Colombier /* 3227dd7cddfSDavid du Colombier * Conversion tables. 3237dd7cddfSDavid du Colombier */ 3247dd7cddfSDavid du Colombier static uchar replbit[1+8][256]; /* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */ 3257dd7cddfSDavid du Colombier static uchar conv18[256][8]; /* conv18[x][y] is the yth pixel in the depth-1 pixel x */ 3267dd7cddfSDavid du Colombier static uchar conv28[256][4]; /* ... */ 3277dd7cddfSDavid du Colombier static uchar conv48[256][2]; 3287dd7cddfSDavid du Colombier static int tablesbuilt; 3297dd7cddfSDavid du Colombier 3307dd7cddfSDavid du Colombier /* 3317dd7cddfSDavid du Colombier * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. 3327dd7cddfSDavid du Colombier * the X's are where to put the bottom (ones) bit of the n-bit pattern. 3337dd7cddfSDavid du Colombier * only the top 8 bits of the result are actually used. 3347dd7cddfSDavid du Colombier * (the lower 8 bits are needed to get bits in the right place 3357dd7cddfSDavid du Colombier * when n is not a divisor of 8.) 3367dd7cddfSDavid du Colombier * 3377dd7cddfSDavid du Colombier * Should check to see if its easier to just refer to replmul than 3387dd7cddfSDavid du Colombier * use the precomputed values in replbit. On PCs it may well 3397dd7cddfSDavid du Colombier * be; on machines with slow multiply instructions it probably isn't. 3407dd7cddfSDavid du Colombier */ 3417dd7cddfSDavid du Colombier #define a ((((((((((((((((0 3427dd7cddfSDavid du Colombier #define X *2+1) 3437dd7cddfSDavid du Colombier #define _ *2) 3447dd7cddfSDavid du Colombier static int replmul[1+8] = { 3457dd7cddfSDavid du Colombier 0, 3467dd7cddfSDavid du Colombier a X X X X X X X X X X X X X X X X, 3477dd7cddfSDavid du Colombier a _ X _ X _ X _ X _ X _ X _ X _ X, 3487dd7cddfSDavid du Colombier a _ _ X _ _ X _ _ X _ _ X _ _ X _, 3497dd7cddfSDavid du Colombier a _ _ _ X _ _ _ X _ _ _ X _ _ _ X, 3507dd7cddfSDavid du Colombier a _ _ _ _ X _ _ _ _ X _ _ _ _ X _, 3517dd7cddfSDavid du Colombier a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, 3527dd7cddfSDavid du Colombier a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _, 3537dd7cddfSDavid du Colombier a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X, 3547dd7cddfSDavid du Colombier }; 3557dd7cddfSDavid du Colombier #undef a 3567dd7cddfSDavid du Colombier #undef X 3577dd7cddfSDavid du Colombier #undef _ 3587dd7cddfSDavid du Colombier 3597dd7cddfSDavid du Colombier static void 3607dd7cddfSDavid du Colombier mktables(void) 3617dd7cddfSDavid du Colombier { 3627dd7cddfSDavid du Colombier int i, j, mask, sh, small; 3637dd7cddfSDavid du Colombier 3647dd7cddfSDavid du Colombier if(tablesbuilt) 3657dd7cddfSDavid du Colombier return; 3667dd7cddfSDavid du Colombier 3677dd7cddfSDavid du Colombier tablesbuilt = 1; 3687dd7cddfSDavid du Colombier /* bit replication up to 8 bits */ 3697dd7cddfSDavid du Colombier for(i=0; i<256; i++){ 3707dd7cddfSDavid du Colombier for(j=0; j<=8; j++){ /* j <= 8 [sic] */ 3717dd7cddfSDavid du Colombier small = i & ((1<<j)-1); 3727dd7cddfSDavid du Colombier replbit[j][i] = (small*replmul[j])>>8; 3737dd7cddfSDavid du Colombier } 3747dd7cddfSDavid du Colombier } 3757dd7cddfSDavid du Colombier 3767dd7cddfSDavid du Colombier /* bit unpacking up to 8 bits, only powers of 2 */ 3777dd7cddfSDavid du Colombier for(i=0; i<256; i++){ 3787dd7cddfSDavid du Colombier for(j=0, sh=7, mask=1; j<8; j++, sh--) 3797dd7cddfSDavid du Colombier conv18[i][j] = replbit[1][(i>>sh)&mask]; 3807dd7cddfSDavid du Colombier 3817dd7cddfSDavid du Colombier for(j=0, sh=6, mask=3; j<4; j++, sh-=2) 3827dd7cddfSDavid du Colombier conv28[i][j] = replbit[2][(i>>sh)&mask]; 3837dd7cddfSDavid du Colombier 3847dd7cddfSDavid du Colombier for(j=0, sh=4, mask=15; j<2; j++, sh-=4) 3857dd7cddfSDavid du Colombier conv48[i][j] = replbit[4][(i>>sh)&mask]; 3867dd7cddfSDavid du Colombier } 3877dd7cddfSDavid du Colombier } 3887dd7cddfSDavid du Colombier 3897dd7cddfSDavid du Colombier /* 3907dd7cddfSDavid du Colombier * General alpha drawing case. Can handle anything. 3917dd7cddfSDavid du Colombier */ 3927dd7cddfSDavid du Colombier typedef struct Buffer Buffer; 3937dd7cddfSDavid du Colombier struct Buffer { 3947dd7cddfSDavid du Colombier uchar *red; 3957dd7cddfSDavid du Colombier uchar *grn; 3967dd7cddfSDavid du Colombier uchar *blu; 3977dd7cddfSDavid du Colombier uchar *alpha; 3987dd7cddfSDavid du Colombier uchar *grey; 3997dd7cddfSDavid du Colombier 4007dd7cddfSDavid du Colombier int delta; /* number of bytes to add to pointer to get next pixel to the right */ 4017dd7cddfSDavid du Colombier uchar *m; /* ptr to mask data r.min byte; like p->bytermin */ 4027dd7cddfSDavid du Colombier int mskip; /* no. of left bits to skip in *m */ 4037dd7cddfSDavid du Colombier uchar *bm; /* ptr to mask data img->r.min byte; like p->bytey0s */ 4047dd7cddfSDavid du Colombier int bmskip; /* no. of left bits to skip in *bm */ 4057dd7cddfSDavid du Colombier uchar *em; /* ptr to mask data img->r.max.x byte; like p->bytey0e */ 4067dd7cddfSDavid du Colombier int emskip; /* no. of right bits to skip in *em */ 4077dd7cddfSDavid du Colombier }; 4087dd7cddfSDavid du Colombier 4097dd7cddfSDavid du Colombier typedef struct Param Param; 4107dd7cddfSDavid du Colombier typedef Buffer Readfn(Param *notusedpar, uchar *notusedbuf, int notusedi); 4117dd7cddfSDavid du Colombier typedef void Writefn(Param *notusedpar, uchar *notusedbuf, Buffer notusedb); 4127dd7cddfSDavid du Colombier typedef Buffer Calcfn(Buffer, Buffer, Buffer, int, int notusedi); 4137dd7cddfSDavid du Colombier 4147dd7cddfSDavid du Colombier enum { 4157dd7cddfSDavid du Colombier MAXBCACHE = 16 4167dd7cddfSDavid du Colombier }; 4177dd7cddfSDavid du Colombier 4187dd7cddfSDavid du Colombier /* giant rathole to customize functions with */ 4197dd7cddfSDavid du Colombier struct Param { 4207dd7cddfSDavid du Colombier Readfn *replcall; 4217dd7cddfSDavid du Colombier Readfn *greymaskcall; 4227dd7cddfSDavid du Colombier Readfn *convreadcall; 4237dd7cddfSDavid du Colombier Writefn *convwritecall; 4247dd7cddfSDavid du Colombier 4257dd7cddfSDavid du Colombier Memimage *img; 4267dd7cddfSDavid du Colombier Rectangle r; 4277dd7cddfSDavid du Colombier int dx; /* of r */ 4287dd7cddfSDavid du Colombier int needbuf; 4297dd7cddfSDavid du Colombier int convgrey; 4307dd7cddfSDavid du Colombier int alphaonly; 4317dd7cddfSDavid du Colombier 4327dd7cddfSDavid du Colombier uchar *bytey0s; /* byteaddr(Pt(img->r.min.x, img->r.min.y)) */ 4337dd7cddfSDavid du Colombier uchar *bytermin; /* byteaddr(Pt(r.min.x, img->r.min.y)) */ 4347dd7cddfSDavid du Colombier uchar *bytey0e; /* byteaddr(Pt(img->r.max.x, img->r.min.y)) */ 4357dd7cddfSDavid du Colombier int bwidth; 4367dd7cddfSDavid du Colombier 4377dd7cddfSDavid du Colombier int replcache; /* if set, cache buffers */ 4387dd7cddfSDavid du Colombier Buffer bcache[MAXBCACHE]; 4397dd7cddfSDavid du Colombier ulong bfilled; 4407dd7cddfSDavid du Colombier uchar *bufbase; 4417dd7cddfSDavid du Colombier int bufoff; 4427dd7cddfSDavid du Colombier int bufdelta; 4437dd7cddfSDavid du Colombier 4447dd7cddfSDavid du Colombier int dir; 4457dd7cddfSDavid du Colombier 4467dd7cddfSDavid du Colombier int convbufoff; 4477dd7cddfSDavid du Colombier uchar *convbuf; 4487dd7cddfSDavid du Colombier Param *convdpar; 4497dd7cddfSDavid du Colombier int convdx; 4507dd7cddfSDavid du Colombier }; 4517dd7cddfSDavid du Colombier 4527dd7cddfSDavid du Colombier static uchar *drawbuf; 4537dd7cddfSDavid du Colombier static int ndrawbuf; 4547dd7cddfSDavid du Colombier static int mdrawbuf; 4557dd7cddfSDavid du Colombier static Param spar, mpar, dpar; /* easier on the stacks */ 4567dd7cddfSDavid du Colombier static Readfn greymaskread, replread, readptr; 4577dd7cddfSDavid du Colombier static Writefn nullwrite; 4587dd7cddfSDavid du Colombier static Calcfn alphacalc; 4597dd7cddfSDavid du Colombier static Calcfn boolcalc; 4607dd7cddfSDavid du Colombier 4617dd7cddfSDavid du Colombier static Readfn* readfn(Memimage*); 4627dd7cddfSDavid du Colombier static Readfn* readalphafn(Memimage*); 4637dd7cddfSDavid du Colombier static Writefn* writefn(Memimage*); 4647dd7cddfSDavid du Colombier 4657dd7cddfSDavid du Colombier static Calcfn* boolcopyfn(Memimage*, Memimage*); 4667dd7cddfSDavid du Colombier static Readfn* convfn(Memimage*, Param *notusedpar, Memimage*, Param*); 4677dd7cddfSDavid du Colombier static Readfn* ptrfn(Memimage*); 4687dd7cddfSDavid du Colombier 4697dd7cddfSDavid du Colombier static int 4707dd7cddfSDavid du Colombier allocdrawbuf(void) 4717dd7cddfSDavid du Colombier { 4727dd7cddfSDavid du Colombier uchar *p; 4737dd7cddfSDavid du Colombier 4747dd7cddfSDavid du Colombier if(ndrawbuf > mdrawbuf){ 4757dd7cddfSDavid du Colombier p = realloc(drawbuf, ndrawbuf); 4767dd7cddfSDavid du Colombier if(p == nil){ 4777dd7cddfSDavid du Colombier werrstr("memimagedraw out of memory"); 4787dd7cddfSDavid du Colombier return -1; 4797dd7cddfSDavid du Colombier } 4807dd7cddfSDavid du Colombier drawbuf = p; 4817dd7cddfSDavid du Colombier mdrawbuf = ndrawbuf; 4827dd7cddfSDavid du Colombier } 4837dd7cddfSDavid du Colombier return 0; 4847dd7cddfSDavid du Colombier } 4857dd7cddfSDavid du Colombier 4867dd7cddfSDavid du Colombier static Param 4877dd7cddfSDavid du Colombier getparam(Memimage *img, Rectangle r, int convgrey, int needbuf) 4887dd7cddfSDavid du Colombier { 4897dd7cddfSDavid du Colombier Param p; 4907dd7cddfSDavid du Colombier int nbuf; 4917dd7cddfSDavid du Colombier 4927dd7cddfSDavid du Colombier memset(&p, 0, sizeof p); 4937dd7cddfSDavid du Colombier 4947dd7cddfSDavid du Colombier p.img = img; 4957dd7cddfSDavid du Colombier p.r = r; 4967dd7cddfSDavid du Colombier p.dx = Dx(r); 4977dd7cddfSDavid du Colombier p.needbuf = needbuf; 4987dd7cddfSDavid du Colombier p.convgrey = convgrey; 4997dd7cddfSDavid du Colombier 5007dd7cddfSDavid du Colombier assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x); 5017dd7cddfSDavid du Colombier 5027dd7cddfSDavid du Colombier p.bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y)); 5037dd7cddfSDavid du Colombier p.bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y)); 5047dd7cddfSDavid du Colombier p.bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y)); 5057dd7cddfSDavid du Colombier p.bwidth = sizeof(ulong)*img->width; 5067dd7cddfSDavid du Colombier 5077dd7cddfSDavid du Colombier assert(p.bytey0s <= p.bytermin && p.bytermin <= p.bytey0e); 5087dd7cddfSDavid du Colombier 5097dd7cddfSDavid du Colombier if(p.r.min.x == p.img->r.min.x) 5107dd7cddfSDavid du Colombier assert(p.bytermin == p.bytey0s); 5117dd7cddfSDavid du Colombier 5127dd7cddfSDavid du Colombier nbuf = 1; 5137dd7cddfSDavid du Colombier if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){ 5147dd7cddfSDavid du Colombier p.replcache = 1; 5157dd7cddfSDavid du Colombier nbuf = Dy(img->r); 5167dd7cddfSDavid du Colombier } 5177dd7cddfSDavid du Colombier p.bufdelta = 4*p.dx; 5187dd7cddfSDavid du Colombier p.bufoff = ndrawbuf; 5197dd7cddfSDavid du Colombier ndrawbuf += p.bufdelta*nbuf; 5207dd7cddfSDavid du Colombier 5217dd7cddfSDavid du Colombier return p; 5227dd7cddfSDavid du Colombier } 5237dd7cddfSDavid du Colombier 5247dd7cddfSDavid du Colombier static void 5257dd7cddfSDavid du Colombier clipy(Memimage *img, int *y) 5267dd7cddfSDavid du Colombier { 5277dd7cddfSDavid du Colombier int dy; 5287dd7cddfSDavid du Colombier 5297dd7cddfSDavid du Colombier dy = Dy(img->r); 5307dd7cddfSDavid du Colombier if(*y == dy) 5317dd7cddfSDavid du Colombier *y = 0; 5327dd7cddfSDavid du Colombier else if(*y == -1) 5337dd7cddfSDavid du Colombier *y = dy-1; 5347dd7cddfSDavid du Colombier assert(0 <= *y && *y < dy); 5357dd7cddfSDavid du Colombier } 5367dd7cddfSDavid du Colombier 5377dd7cddfSDavid du Colombier static void 5387dd7cddfSDavid du Colombier dumpbuf(char *s, Buffer b, int n) 5397dd7cddfSDavid du Colombier { 5407dd7cddfSDavid du Colombier int i; 5417dd7cddfSDavid du Colombier uchar *p; 5427dd7cddfSDavid du Colombier 5437dd7cddfSDavid du Colombier print("%s", s); 5447dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 5457dd7cddfSDavid du Colombier print(" "); 5467dd7cddfSDavid du Colombier if(p=b.grey){ 5477dd7cddfSDavid du Colombier print(" k%.2uX", *p); 5487dd7cddfSDavid du Colombier b.grey += b.delta; 5497dd7cddfSDavid du Colombier }else{ 5507dd7cddfSDavid du Colombier if(p=b.red){ 5517dd7cddfSDavid du Colombier print(" r%.2uX", *p); 5527dd7cddfSDavid du Colombier b.red += b.delta; 5537dd7cddfSDavid du Colombier } 5547dd7cddfSDavid du Colombier if(p=b.grn){ 5557dd7cddfSDavid du Colombier print(" g%.2uX", *p); 5567dd7cddfSDavid du Colombier b.grn += b.delta; 5577dd7cddfSDavid du Colombier } 5587dd7cddfSDavid du Colombier if(p=b.blu){ 5597dd7cddfSDavid du Colombier print(" b%.2uX", *p); 5607dd7cddfSDavid du Colombier b.blu += b.delta; 5617dd7cddfSDavid du Colombier } 5627dd7cddfSDavid du Colombier } 5637dd7cddfSDavid du Colombier if(p=b.alpha){ 5647dd7cddfSDavid du Colombier print(" α%.2uX", *p); 5657dd7cddfSDavid du Colombier b.alpha += b.delta; 5667dd7cddfSDavid du Colombier } 5677dd7cddfSDavid du Colombier } 5687dd7cddfSDavid du Colombier print("\n"); 5697dd7cddfSDavid du Colombier } 5707dd7cddfSDavid du Colombier 5717dd7cddfSDavid du Colombier /* 5727dd7cddfSDavid du Colombier * For each scan line, we expand the pixels from source, mask, and destination 5737dd7cddfSDavid du Colombier * into byte-aligned red, green, blue, alpha, and grey channels. If buffering is not 5747dd7cddfSDavid du Colombier * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32), 5757dd7cddfSDavid du Colombier * the readers need not copy the data: they can simply return pointers to the data. 5767dd7cddfSDavid du Colombier * If the destination image is grey and the source is not, it is converted using the NTSC 5777dd7cddfSDavid du Colombier * formula. 5787dd7cddfSDavid du Colombier * 5797dd7cddfSDavid du Colombier * Once we have all the channels, we call either rgbcalc or greycalc, depending on 5807dd7cddfSDavid du Colombier * whether the destination image is color. This is allowed to overwrite the dst buffer (perhaps 5817dd7cddfSDavid du Colombier * the actual data, perhaps a copy) with its result. It should only overwrite the dst buffer 5827dd7cddfSDavid du Colombier * with the same format (i.e. red bytes with red bytes, etc.) A new buffer is returned from 5837dd7cddfSDavid du Colombier * the calculator, and that buffer is passed to a function to write it to the destination. 5847dd7cddfSDavid du Colombier * If the buffer is already pointing at the destination, the writing function is a no-op. 5857dd7cddfSDavid du Colombier */ 5867dd7cddfSDavid du Colombier #define DBG if(0) 5877dd7cddfSDavid du Colombier static int 5887dd7cddfSDavid du Colombier alphadraw(Memdrawparam *par) 5897dd7cddfSDavid du Colombier { 5907dd7cddfSDavid du Colombier int isgrey, starty, endy; 5917dd7cddfSDavid du Colombier int needbuf, dsty, srcy, masky; 5927dd7cddfSDavid du Colombier int y, dir, dx, dy; 5937dd7cddfSDavid du Colombier Buffer bsrc, bdst, bmask; 5947dd7cddfSDavid du Colombier Readfn *rdsrc, *rdmask, *rddst; 5957dd7cddfSDavid du Colombier Calcfn *calc; 5967dd7cddfSDavid du Colombier Writefn *wrdst; 5977dd7cddfSDavid du Colombier Memimage *src, *mask, *dst; 5987dd7cddfSDavid du Colombier Rectangle r, sr, mr; 5997dd7cddfSDavid du Colombier 6007dd7cddfSDavid du Colombier r = par->r; 6017dd7cddfSDavid du Colombier dx = Dx(r); 6027dd7cddfSDavid du Colombier dy = Dy(r); 6037dd7cddfSDavid du Colombier 6047dd7cddfSDavid du Colombier ndrawbuf = 0; 6057dd7cddfSDavid du Colombier 6067dd7cddfSDavid du Colombier src = par->src; 6077dd7cddfSDavid du Colombier mask = par->mask; 6087dd7cddfSDavid du Colombier dst = par->dst; 6097dd7cddfSDavid du Colombier sr = par->sr; 6107dd7cddfSDavid du Colombier mr = par->mr; 6117dd7cddfSDavid du Colombier 6127dd7cddfSDavid du Colombier isgrey = dst->flags&Fgrey; 6137dd7cddfSDavid du Colombier 6147dd7cddfSDavid du Colombier /* 6157dd7cddfSDavid du Colombier * Buffering when src and dst are the same bitmap is sufficient but not 6167dd7cddfSDavid du Colombier * necessary. There are stronger conditions we could use. We could 6177dd7cddfSDavid du Colombier * check to see if the rectangles intersect, and if simply moving in the 6187dd7cddfSDavid du Colombier * correct y direction can avoid the need to buffer. 6197dd7cddfSDavid du Colombier */ 6207dd7cddfSDavid du Colombier needbuf = (src->data == dst->data); 6217dd7cddfSDavid du Colombier 6227dd7cddfSDavid du Colombier spar = getparam(src, sr, isgrey, needbuf); 6237dd7cddfSDavid du Colombier mpar = getparam(mask, mr, isgrey, needbuf); 6247dd7cddfSDavid du Colombier dpar = getparam(dst, r, isgrey, needbuf); 6257dd7cddfSDavid du Colombier 6267dd7cddfSDavid du Colombier dir = (needbuf && byteaddr(dst, r.min) > byteaddr(src, sr.min)) ? -1 : 1; 6277dd7cddfSDavid du Colombier spar.dir = mpar.dir = dpar.dir = dir; 6287dd7cddfSDavid du Colombier 6297dd7cddfSDavid du Colombier /* 6307dd7cddfSDavid du Colombier * If the mask is purely boolean, we can convert from src to dst format 6317dd7cddfSDavid du Colombier * when we read src, and then just copy it to dst where the mask tells us to. 6327dd7cddfSDavid du Colombier * This requires a boolean (1-bit grey) mask and lack of a source alpha channel. 6337dd7cddfSDavid du Colombier * 6347dd7cddfSDavid du Colombier * The computation is accomplished by assigning the function pointers as follows: 6357dd7cddfSDavid du Colombier * rdsrc - read and convert source into dst format in a buffer 6367dd7cddfSDavid du Colombier * rdmask - convert mask to bytes, set pointer to it 6377dd7cddfSDavid du Colombier * rddst - fill with pointer to real dst data, but do no reads 6387dd7cddfSDavid du Colombier * calc - copy src onto dst when mask says to. 6397dd7cddfSDavid du Colombier * wrdst - do nothing 6407dd7cddfSDavid du Colombier * This is slightly sleazy, since things aren't doing exactly what their names say, 6417dd7cddfSDavid du Colombier * but it avoids a fair amount of code duplication to make this a case here 6427dd7cddfSDavid du Colombier * rather than have a separate booldraw. 6437dd7cddfSDavid du Colombier */ 6447dd7cddfSDavid du Colombier if(drawdebug) iprint("flag %lud mchan %lux=?%x dd %d\n", src->flags&Falpha, mask->chan, GREY1, dst->depth); 6457dd7cddfSDavid du Colombier if(!(src->flags&Falpha) && mask->chan == GREY1 && dst->depth >= 8){ 6467dd7cddfSDavid du Colombier if(drawdebug) iprint("boolcopy..."); 6477dd7cddfSDavid du Colombier rdsrc = convfn(dst, &dpar, src, &spar); 6487dd7cddfSDavid du Colombier rddst = readptr; 6497dd7cddfSDavid du Colombier rdmask = readfn(mask); 6507dd7cddfSDavid du Colombier calc = boolcopyfn(dst, mask); 6517dd7cddfSDavid du Colombier wrdst = nullwrite; 6527dd7cddfSDavid du Colombier }else{ 6537dd7cddfSDavid du Colombier /* usual alphadraw parameter fetching */ 6547dd7cddfSDavid du Colombier rdsrc = readfn(src); 6557dd7cddfSDavid du Colombier rddst = readfn(dst); 6567dd7cddfSDavid du Colombier wrdst = writefn(dst); 6577dd7cddfSDavid du Colombier calc = alphacalc; 6587dd7cddfSDavid du Colombier 6597dd7cddfSDavid du Colombier /* 6607dd7cddfSDavid du Colombier * If there is no alpha channel, we'll ask for a grey channel 6617dd7cddfSDavid du Colombier * and pretend it is the alpha. 6627dd7cddfSDavid du Colombier */ 6637dd7cddfSDavid du Colombier if(mask->flags&Falpha){ 6647dd7cddfSDavid du Colombier rdmask = readalphafn(mask); 6657dd7cddfSDavid du Colombier mpar.alphaonly = 1; 6667dd7cddfSDavid du Colombier }else{ 6677dd7cddfSDavid du Colombier mpar.greymaskcall = readfn(mask); 6687dd7cddfSDavid du Colombier mpar.convgrey = 1; 6697dd7cddfSDavid du Colombier rdmask = greymaskread; 6707dd7cddfSDavid du Colombier 6717dd7cddfSDavid du Colombier /* 6727dd7cddfSDavid du Colombier * Should really be above, but then boolcopyfns would have 6737dd7cddfSDavid du Colombier * to deal with bit alignment, and I haven't written that. 6747dd7cddfSDavid du Colombier * 6757dd7cddfSDavid du Colombier * This is a common case for things like ellipse drawing. 6767dd7cddfSDavid du Colombier * When there's no alpha involved and the mask is boolean, 6777dd7cddfSDavid du Colombier * we can avoid all the division and multiplication. 6787dd7cddfSDavid du Colombier */ 6797dd7cddfSDavid du Colombier if(mask->chan == GREY1 && !(src->flags&Falpha)) 6807dd7cddfSDavid du Colombier calc = boolcalc; 6817dd7cddfSDavid du Colombier } 6827dd7cddfSDavid du Colombier } 6837dd7cddfSDavid du Colombier 6847dd7cddfSDavid du Colombier /* 6857dd7cddfSDavid du Colombier * If the image has a small enough repl rectangle, 6867dd7cddfSDavid du Colombier * we can just read each line once and cache them. 6877dd7cddfSDavid du Colombier */ 6887dd7cddfSDavid du Colombier if(spar.replcache){ 6897dd7cddfSDavid du Colombier spar.replcall = rdsrc; 6907dd7cddfSDavid du Colombier rdsrc = replread; 6917dd7cddfSDavid du Colombier } 6927dd7cddfSDavid du Colombier if(mpar.replcache){ 6937dd7cddfSDavid du Colombier mpar.replcall = rdmask; 6947dd7cddfSDavid du Colombier rdmask = replread; 6957dd7cddfSDavid du Colombier } 6967dd7cddfSDavid du Colombier 6977dd7cddfSDavid du Colombier if(allocdrawbuf() < 0) 6987dd7cddfSDavid du Colombier return 0; 6997dd7cddfSDavid du Colombier 7007dd7cddfSDavid du Colombier /* 7017dd7cddfSDavid du Colombier * Before we were saving only offsets from drawbuf in the parameter 7027dd7cddfSDavid du Colombier * structures; now that drawbuf has been grown to accomodate us, 7037dd7cddfSDavid du Colombier * we can fill in the pointers. 7047dd7cddfSDavid du Colombier */ 7057dd7cddfSDavid du Colombier spar.bufbase = drawbuf+spar.bufoff; 7067dd7cddfSDavid du Colombier mpar.bufbase = drawbuf+mpar.bufoff; 7077dd7cddfSDavid du Colombier dpar.bufbase = drawbuf+dpar.bufoff; 7087dd7cddfSDavid du Colombier spar.convbuf = drawbuf+spar.convbufoff; 7097dd7cddfSDavid du Colombier 7107dd7cddfSDavid du Colombier if(dir == 1){ 7117dd7cddfSDavid du Colombier starty = 0; 7127dd7cddfSDavid du Colombier endy = dy; 7137dd7cddfSDavid du Colombier }else{ 7147dd7cddfSDavid du Colombier starty = dy-1; 7157dd7cddfSDavid du Colombier endy = -1; 7167dd7cddfSDavid du Colombier } 7177dd7cddfSDavid du Colombier 7187dd7cddfSDavid du Colombier /* 7197dd7cddfSDavid du Colombier * srcy, masky, and dsty are offsets from the top of their 7207dd7cddfSDavid du Colombier * respective Rectangles. they need to be contained within 7217dd7cddfSDavid du Colombier * the rectangles, so clipy can keep them there without division. 7227dd7cddfSDavid du Colombier */ 7237dd7cddfSDavid du Colombier srcy = (starty + sr.min.y - src->r.min.y)%Dy(src->r); 7247dd7cddfSDavid du Colombier masky = (starty + mr.min.y - mask->r.min.y)%Dy(mask->r); 7257dd7cddfSDavid du Colombier dsty = starty + r.min.y - dst->r.min.y; 7267dd7cddfSDavid du Colombier 7277dd7cddfSDavid du Colombier assert(0 <= srcy && srcy < Dy(src->r)); 7287dd7cddfSDavid du Colombier assert(0 <= masky && masky < Dy(mask->r)); 7297dd7cddfSDavid du Colombier assert(0 <= dsty && dsty < Dy(dst->r)); 7307dd7cddfSDavid du Colombier 7317dd7cddfSDavid du Colombier for(y=starty; y!=endy; y+=dir, srcy+=dir, masky+=dir, dsty+=dir){ 7327dd7cddfSDavid du Colombier clipy(src, &srcy); 7337dd7cddfSDavid du Colombier clipy(dst, &dsty); 7347dd7cddfSDavid du Colombier clipy(mask, &masky); 7357dd7cddfSDavid du Colombier 7367dd7cddfSDavid du Colombier bsrc = rdsrc(&spar, spar.bufbase, srcy); 7377dd7cddfSDavid du Colombier DBG print("["); 7387dd7cddfSDavid du Colombier bmask = rdmask(&mpar, mpar.bufbase, masky); 7397dd7cddfSDavid du Colombier DBG print("]\n"); 7407dd7cddfSDavid du Colombier bdst = rddst(&dpar, dpar.bufbase, dsty); 7417dd7cddfSDavid du Colombier DBG dumpbuf("src", bsrc, dx); 7427dd7cddfSDavid du Colombier DBG dumpbuf("mask", bmask, dx); 7437dd7cddfSDavid du Colombier DBG dumpbuf("dst", bdst, dx); 7447dd7cddfSDavid du Colombier bdst = calc(bdst, bsrc, bmask, dx, isgrey); 7457dd7cddfSDavid du Colombier wrdst(&dpar, dpar.bytermin+dsty*dpar.bwidth, bdst); 7467dd7cddfSDavid du Colombier } 7477dd7cddfSDavid du Colombier 7487dd7cddfSDavid du Colombier return 1; 7497dd7cddfSDavid du Colombier } 7507dd7cddfSDavid du Colombier #undef DBG 7517dd7cddfSDavid du Colombier 7527dd7cddfSDavid du Colombier #define DBG if(0) 7537dd7cddfSDavid du Colombier static Buffer 7547dd7cddfSDavid du Colombier alphacalc(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey) 7557dd7cddfSDavid du Colombier { 7567dd7cddfSDavid du Colombier Buffer obdst; 7577dd7cddfSDavid du Colombier uchar *salpha, ones = ~0; 7587dd7cddfSDavid du Colombier int antialpha, sadelta; 7597dd7cddfSDavid du Colombier int i, sa, ma; 7607dd7cddfSDavid du Colombier 7617dd7cddfSDavid du Colombier obdst = bdst; 7627dd7cddfSDavid du Colombier if((salpha = bsrc.alpha) == nil) 7637dd7cddfSDavid du Colombier salpha = &ones, sadelta = 0; 7647dd7cddfSDavid du Colombier else 7657dd7cddfSDavid du Colombier sadelta = bsrc.delta; 7667dd7cddfSDavid du Colombier 7677dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 7687dd7cddfSDavid du Colombier sa = *salpha; 7697dd7cddfSDavid du Colombier ma = *bmask.alpha; 7707dd7cddfSDavid du Colombier antialpha = 255-DIV255(ma*sa); 7717dd7cddfSDavid du Colombier 7727dd7cddfSDavid du Colombier if(grey){ 7737dd7cddfSDavid du Colombier DBG print("(%d %d in %d) over %d =", *bsrc.grey, sa, ma, *bdst.grey); 7747dd7cddfSDavid du Colombier *bdst.grey = DIV255(*bsrc.grey*ma+*bdst.grey*antialpha); 7757dd7cddfSDavid du Colombier DBG print(" %d\n", *bdst.grey); 7767dd7cddfSDavid du Colombier bsrc.grey += bsrc.delta; 7777dd7cddfSDavid du Colombier bdst.grey += bdst.delta; 7787dd7cddfSDavid du Colombier }else{ 7797dd7cddfSDavid du Colombier *bdst.red = DIV255(*bsrc.red*ma+*bdst.red*antialpha); 7807dd7cddfSDavid du Colombier *bdst.grn = DIV255(*bsrc.grn*ma+*bdst.grn*antialpha); 7817dd7cddfSDavid du Colombier *bdst.blu = DIV255(*bsrc.blu*ma+*bdst.blu*antialpha); 7827dd7cddfSDavid du Colombier 7837dd7cddfSDavid du Colombier bsrc.red += bsrc.delta; 7847dd7cddfSDavid du Colombier bsrc.blu += bsrc.delta; 7857dd7cddfSDavid du Colombier bsrc.grn += bsrc.delta; 7867dd7cddfSDavid du Colombier 7877dd7cddfSDavid du Colombier bdst.red += bdst.delta; 7887dd7cddfSDavid du Colombier bdst.blu += bdst.delta; 7897dd7cddfSDavid du Colombier bdst.grn += bdst.delta; 7907dd7cddfSDavid du Colombier } 7917dd7cddfSDavid du Colombier 7927dd7cddfSDavid du Colombier salpha += sadelta; 7937dd7cddfSDavid du Colombier bmask.alpha += bmask.delta; 7947dd7cddfSDavid du Colombier 7957dd7cddfSDavid du Colombier if(bdst.alpha) { 7967dd7cddfSDavid du Colombier *bdst.alpha = DIV255(sa*ma+*bdst.alpha*(antialpha)); 7977dd7cddfSDavid du Colombier bdst.alpha += bdst.delta; 7987dd7cddfSDavid du Colombier } 7997dd7cddfSDavid du Colombier } 8007dd7cddfSDavid du Colombier return obdst; 8017dd7cddfSDavid du Colombier } 8027dd7cddfSDavid du Colombier #undef DBG 8037dd7cddfSDavid du Colombier 8047dd7cddfSDavid du Colombier #define DBG if(0) 8057dd7cddfSDavid du Colombier static Buffer 8067dd7cddfSDavid du Colombier boolcalc(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int grey) 8077dd7cddfSDavid du Colombier { 8087dd7cddfSDavid du Colombier Buffer obdst; 8097dd7cddfSDavid du Colombier int i, ma; 8107dd7cddfSDavid du Colombier 8117dd7cddfSDavid du Colombier obdst = bdst; 8127dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 8137dd7cddfSDavid du Colombier ma = *bmask.alpha; 8147dd7cddfSDavid du Colombier 8157dd7cddfSDavid du Colombier if(grey){ 8167dd7cddfSDavid du Colombier DBG print("(%d) in %d over %d =", *bsrc.grey, ma, *bdst.grey); 8177dd7cddfSDavid du Colombier if(ma) 8187dd7cddfSDavid du Colombier *bdst.grey = *bsrc.grey; 8197dd7cddfSDavid du Colombier DBG print(" %d\n", *bdst.grey); 8207dd7cddfSDavid du Colombier bsrc.grey += bsrc.delta; 8217dd7cddfSDavid du Colombier bdst.grey += bdst.delta; 8227dd7cddfSDavid du Colombier }else{ 8237dd7cddfSDavid du Colombier if(ma){ 8247dd7cddfSDavid du Colombier *bdst.red = *bsrc.red*ma; 8257dd7cddfSDavid du Colombier *bdst.grn = *bsrc.grn*ma; 8267dd7cddfSDavid du Colombier *bdst.blu = *bsrc.blu*ma; 8277dd7cddfSDavid du Colombier } 8287dd7cddfSDavid du Colombier 8297dd7cddfSDavid du Colombier bsrc.red += bsrc.delta; 8307dd7cddfSDavid du Colombier bsrc.blu += bsrc.delta; 8317dd7cddfSDavid du Colombier bsrc.grn += bsrc.delta; 8327dd7cddfSDavid du Colombier 8337dd7cddfSDavid du Colombier bdst.red += bdst.delta; 8347dd7cddfSDavid du Colombier bdst.blu += bdst.delta; 8357dd7cddfSDavid du Colombier bdst.grn += bdst.delta; 8367dd7cddfSDavid du Colombier } 8377dd7cddfSDavid du Colombier 8387dd7cddfSDavid du Colombier bmask.alpha += bmask.delta; 8397dd7cddfSDavid du Colombier 8407dd7cddfSDavid du Colombier if(bdst.alpha) { 8417dd7cddfSDavid du Colombier if(ma) 8427dd7cddfSDavid du Colombier *bdst.alpha = ma; 8437dd7cddfSDavid du Colombier bdst.alpha += bdst.delta; 8447dd7cddfSDavid du Colombier } 8457dd7cddfSDavid du Colombier } 8467dd7cddfSDavid du Colombier return obdst; 8477dd7cddfSDavid du Colombier } 8487dd7cddfSDavid du Colombier #undef DBG 8497dd7cddfSDavid du Colombier 8507dd7cddfSDavid du Colombier /* 8517dd7cddfSDavid du Colombier * Replicated cached scan line read. Call the function listed in the Param, 8527dd7cddfSDavid du Colombier * but cache the result so that for replicated images we only do the work once. 8537dd7cddfSDavid du Colombier */ 8547dd7cddfSDavid du Colombier static Buffer 8557dd7cddfSDavid du Colombier replread(Param *p, uchar *notusedbuf, int y) 8567dd7cddfSDavid du Colombier { 8577dd7cddfSDavid du Colombier Buffer *b; 8587dd7cddfSDavid du Colombier 8597dd7cddfSDavid du Colombier b = &p->bcache[y]; 8607dd7cddfSDavid du Colombier if((p->bfilled & (1<<y)) == 0){ 8617dd7cddfSDavid du Colombier p->bfilled |= 1<<y; 8627dd7cddfSDavid du Colombier *b = p->replcall(p, p->bufbase+y*p->bufdelta, y); 8637dd7cddfSDavid du Colombier } 8647dd7cddfSDavid du Colombier return *b; 8657dd7cddfSDavid du Colombier } 8667dd7cddfSDavid du Colombier 8677dd7cddfSDavid du Colombier /* 8687dd7cddfSDavid du Colombier * Alpha reading function that simply relabels the grey pointer. 8697dd7cddfSDavid du Colombier */ 8707dd7cddfSDavid du Colombier static Buffer 8717dd7cddfSDavid du Colombier greymaskread(Param *p, uchar *buf, int y) 8727dd7cddfSDavid du Colombier { 8737dd7cddfSDavid du Colombier Buffer b; 8747dd7cddfSDavid du Colombier 8757dd7cddfSDavid du Colombier b = p->greymaskcall(p, buf, y); 8767dd7cddfSDavid du Colombier b.alpha = b.grey; 8777dd7cddfSDavid du Colombier return b; 8787dd7cddfSDavid du Colombier } 8797dd7cddfSDavid du Colombier 8807dd7cddfSDavid du Colombier #define DBG if(0) 8817dd7cddfSDavid du Colombier static Buffer 8827dd7cddfSDavid du Colombier readnbit(Param *p, uchar *buf, int y) 8837dd7cddfSDavid du Colombier { 8847dd7cddfSDavid du Colombier Buffer b; 8857dd7cddfSDavid du Colombier Memimage *img; 8867dd7cddfSDavid du Colombier uchar *repl, *r, *w, *ow, bits; 8877dd7cddfSDavid du Colombier int i, n, sh, depth, x, dx, npack, nbits; 8887dd7cddfSDavid du Colombier 8897dd7cddfSDavid du Colombier b.grey = w = buf; 8907dd7cddfSDavid du Colombier b.red = b.blu = b.grn = w; 8917dd7cddfSDavid du Colombier b.alpha = nil; 8927dd7cddfSDavid du Colombier b.delta = 1; 8937dd7cddfSDavid du Colombier 8947dd7cddfSDavid du Colombier dx = p->dx; 8957dd7cddfSDavid du Colombier img = p->img; 8967dd7cddfSDavid du Colombier depth = img->depth; 8977dd7cddfSDavid du Colombier repl = &replbit[depth][0]; 8987dd7cddfSDavid du Colombier npack = 8/depth; 8997dd7cddfSDavid du Colombier sh = 8-depth; 9007dd7cddfSDavid du Colombier 9017dd7cddfSDavid du Colombier /* copy from p->r.min.x until end of repl rectangle */ 9027dd7cddfSDavid du Colombier x = p->r.min.x; 9037dd7cddfSDavid du Colombier n = dx; 9047dd7cddfSDavid du Colombier if(n > p->img->r.max.x - x) 9057dd7cddfSDavid du Colombier n = p->img->r.max.x - x; 9067dd7cddfSDavid du Colombier 9077dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 9087dd7cddfSDavid du Colombier DBG print("readnbit dx %d %p=%p+%d*%d, *r=%d fetch %d ", dx, r, p->bytermin, y, p->bwidth, *r, n); 9097dd7cddfSDavid du Colombier bits = *r++; 9107dd7cddfSDavid du Colombier nbits = 8; 9117dd7cddfSDavid du Colombier if(i=x&(npack-1)){ 9127dd7cddfSDavid du Colombier DBG print("throwaway %d...", i); 9137dd7cddfSDavid du Colombier bits <<= depth*i; 9147dd7cddfSDavid du Colombier nbits -= depth*i; 9157dd7cddfSDavid du Colombier } 9167dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 9177dd7cddfSDavid du Colombier if(nbits == 0){ 9187dd7cddfSDavid du Colombier DBG print("(%.2ux)...", *r); 9197dd7cddfSDavid du Colombier bits = *r++; 9207dd7cddfSDavid du Colombier nbits = 8; 9217dd7cddfSDavid du Colombier } 9227dd7cddfSDavid du Colombier *w++ = repl[bits>>sh]; 9237dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]); 9247dd7cddfSDavid du Colombier bits <<= depth; 9257dd7cddfSDavid du Colombier nbits -= depth; 9267dd7cddfSDavid du Colombier } 9277dd7cddfSDavid du Colombier dx -= n; 9287dd7cddfSDavid du Colombier if(dx == 0) 9297dd7cddfSDavid du Colombier return b; 9307dd7cddfSDavid du Colombier 9317dd7cddfSDavid du Colombier assert(x+i == p->img->r.max.x); 9327dd7cddfSDavid du Colombier 9337dd7cddfSDavid du Colombier /* copy from beginning of repl rectangle until where we were before. */ 9347dd7cddfSDavid du Colombier x = p->img->r.min.x; 9357dd7cddfSDavid du Colombier n = dx; 9367dd7cddfSDavid du Colombier if(n > p->r.min.x - x) 9377dd7cddfSDavid du Colombier n = p->r.min.x - x; 9387dd7cddfSDavid du Colombier 9397dd7cddfSDavid du Colombier r = p->bytey0s + y*p->bwidth; 9407dd7cddfSDavid du Colombier DBG print("x=%d r=%p...", x, r); 9417dd7cddfSDavid du Colombier bits = *r++; 9427dd7cddfSDavid du Colombier nbits = 8; 9437dd7cddfSDavid du Colombier if(i=x&(npack-1)){ 9447dd7cddfSDavid du Colombier bits <<= depth*i; 9457dd7cddfSDavid du Colombier nbits -= depth*i; 9467dd7cddfSDavid du Colombier } 9477dd7cddfSDavid du Colombier DBG print("nbits=%d...", nbits); 9487dd7cddfSDavid du Colombier for(i=0; i<n; i++){ 9497dd7cddfSDavid du Colombier if(nbits == 0){ 9507dd7cddfSDavid du Colombier bits = *r++; 9517dd7cddfSDavid du Colombier nbits = 8; 9527dd7cddfSDavid du Colombier } 9537dd7cddfSDavid du Colombier *w++ = repl[bits>>sh]; 9547dd7cddfSDavid du Colombier DBG print("bit %x...", repl[bits>>sh]); 9557dd7cddfSDavid du Colombier bits <<= depth; 9567dd7cddfSDavid du Colombier nbits -= depth; 9577dd7cddfSDavid du Colombier DBG print("bits %x nbits %d...", bits, nbits); 9587dd7cddfSDavid du Colombier } 9597dd7cddfSDavid du Colombier dx -= n; 9607dd7cddfSDavid du Colombier if(dx == 0) 9617dd7cddfSDavid du Colombier return b; 9627dd7cddfSDavid du Colombier 9637dd7cddfSDavid du Colombier assert(dx > 0); 9647dd7cddfSDavid du Colombier /* now we have exactly one full scan line: just replicate the buffer itself until we are done */ 9657dd7cddfSDavid du Colombier ow = buf; 9667dd7cddfSDavid du Colombier while(dx--) 9677dd7cddfSDavid du Colombier *w++ = *ow++; 9687dd7cddfSDavid du Colombier 9697dd7cddfSDavid du Colombier return b; 9707dd7cddfSDavid du Colombier } 9717dd7cddfSDavid du Colombier #undef DBG 9727dd7cddfSDavid du Colombier 9737dd7cddfSDavid du Colombier #define DBG if(0) 9747dd7cddfSDavid du Colombier static void 9757dd7cddfSDavid du Colombier writenbit(Param *p, uchar *w, Buffer src) 9767dd7cddfSDavid du Colombier { 9777dd7cddfSDavid du Colombier uchar *r; 9787dd7cddfSDavid du Colombier ulong bits; 9797dd7cddfSDavid du Colombier int i, sh, depth, npack, nbits, x, ex; 9807dd7cddfSDavid du Colombier 9817dd7cddfSDavid du Colombier assert(src.grey != nil && src.delta == 1); 9827dd7cddfSDavid du Colombier 9837dd7cddfSDavid du Colombier x = p->r.min.x; 9847dd7cddfSDavid du Colombier ex = x+p->dx; 9857dd7cddfSDavid du Colombier depth = p->img->depth; 9867dd7cddfSDavid du Colombier npack = 8/depth; 9877dd7cddfSDavid du Colombier 9887dd7cddfSDavid du Colombier i=x&(npack-1); 9897dd7cddfSDavid du Colombier bits = i ? (*w >> (8-depth*i)) : 0; 9907dd7cddfSDavid du Colombier nbits = depth*i; 9917dd7cddfSDavid du Colombier sh = 8-depth; 9927dd7cddfSDavid du Colombier r = src.grey; 9937dd7cddfSDavid du Colombier 9947dd7cddfSDavid du Colombier for(; x<ex; x++){ 9957dd7cddfSDavid du Colombier bits <<= depth; 9967dd7cddfSDavid du Colombier DBG print(" %x", *r); 9977dd7cddfSDavid du Colombier bits |= (*r++ >> sh); 9987dd7cddfSDavid du Colombier nbits += depth; 9997dd7cddfSDavid du Colombier if(nbits == 8){ 10007dd7cddfSDavid du Colombier *w++ = bits; 10017dd7cddfSDavid du Colombier nbits = 0; 10027dd7cddfSDavid du Colombier } 10037dd7cddfSDavid du Colombier } 10047dd7cddfSDavid du Colombier 10057dd7cddfSDavid du Colombier if(nbits){ 10067dd7cddfSDavid du Colombier sh = 8-nbits; 10077dd7cddfSDavid du Colombier bits <<= sh; 10087dd7cddfSDavid du Colombier bits |= *w & ((1<<sh)-1); 10097dd7cddfSDavid du Colombier *w = bits; 10107dd7cddfSDavid du Colombier } 10117dd7cddfSDavid du Colombier DBG print("\n"); 10127dd7cddfSDavid du Colombier return; 10137dd7cddfSDavid du Colombier } 10147dd7cddfSDavid du Colombier #undef DBG 10157dd7cddfSDavid du Colombier 10167dd7cddfSDavid du Colombier static Buffer 10177dd7cddfSDavid du Colombier readcmap(Param *p, uchar *buf, int y) 10187dd7cddfSDavid du Colombier { 10197dd7cddfSDavid du Colombier Buffer b; 10207dd7cddfSDavid du Colombier int i, dx, convgrey; 10217dd7cddfSDavid du Colombier uchar *q, *cmap, *begin, *end, *r, *w; 10227dd7cddfSDavid du Colombier 10237dd7cddfSDavid du Colombier begin = p->bytey0s + y*p->bwidth; 10247dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 10257dd7cddfSDavid du Colombier end = p->bytey0e + y*p->bwidth; 10267dd7cddfSDavid du Colombier cmap = p->img->cmap->cmap2rgb; 10277dd7cddfSDavid du Colombier convgrey = p->convgrey; 10287dd7cddfSDavid du Colombier 10297dd7cddfSDavid du Colombier w = buf; 10307dd7cddfSDavid du Colombier dx = p->dx; 10317dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 10327dd7cddfSDavid du Colombier q = cmap+*r++*3; 10337dd7cddfSDavid du Colombier if(r == end) 10347dd7cddfSDavid du Colombier r = begin; 10357dd7cddfSDavid du Colombier if(convgrey){ 10367dd7cddfSDavid du Colombier *w++ = RGB2K(q[0], q[1], q[2]); 10377dd7cddfSDavid du Colombier }else{ 10387dd7cddfSDavid du Colombier *w++ = q[2]; /* blue */ 10397dd7cddfSDavid du Colombier *w++ = q[1]; /* green */ 10407dd7cddfSDavid du Colombier *w++ = q[0]; /* red */ 10417dd7cddfSDavid du Colombier } 10427dd7cddfSDavid du Colombier } 10437dd7cddfSDavid du Colombier 10447dd7cddfSDavid du Colombier if(convgrey){ 10457dd7cddfSDavid du Colombier b.alpha = nil; 10467dd7cddfSDavid du Colombier b.grey = buf; 10477dd7cddfSDavid du Colombier b.red = b.blu = b.grn = buf; 10487dd7cddfSDavid du Colombier b.delta = 1; 10497dd7cddfSDavid du Colombier }else{ 10507dd7cddfSDavid du Colombier b.blu = buf; 10517dd7cddfSDavid du Colombier b.grn = buf+1; 10527dd7cddfSDavid du Colombier b.red = buf+2; 10537dd7cddfSDavid du Colombier b.alpha = nil; 10547dd7cddfSDavid du Colombier b.grey = nil; 10557dd7cddfSDavid du Colombier b.delta = 3; 10567dd7cddfSDavid du Colombier } 10577dd7cddfSDavid du Colombier return b; 10587dd7cddfSDavid du Colombier } 10597dd7cddfSDavid du Colombier 10607dd7cddfSDavid du Colombier static void 10617dd7cddfSDavid du Colombier writecmap(Param *p, uchar *w, Buffer src) 10627dd7cddfSDavid du Colombier { 10637dd7cddfSDavid du Colombier uchar *cmap, *red, *grn, *blu; 10647dd7cddfSDavid du Colombier int i, dx, delta; 10657dd7cddfSDavid du Colombier 10667dd7cddfSDavid du Colombier cmap = p->img->cmap->rgb2cmap; 10677dd7cddfSDavid du Colombier 10687dd7cddfSDavid du Colombier delta = src.delta; 10697dd7cddfSDavid du Colombier red= src.red; 10707dd7cddfSDavid du Colombier grn = src.grn; 10717dd7cddfSDavid du Colombier blu = src.blu; 10727dd7cddfSDavid du Colombier 10737dd7cddfSDavid du Colombier dx = p->dx; 10747dd7cddfSDavid du Colombier for(i=0; i<dx; i++, red+=delta, grn+=delta, blu+=delta) 10757dd7cddfSDavid du Colombier *w++ = cmap[(*red>>4)*256+(*grn>>4)*16+(*blu>>4)]; 10767dd7cddfSDavid du Colombier } 10777dd7cddfSDavid du Colombier 10787dd7cddfSDavid du Colombier static Buffer 10797dd7cddfSDavid du Colombier readbyte(Param *p, uchar *buf, int y) 10807dd7cddfSDavid du Colombier { 10817dd7cddfSDavid du Colombier Buffer b; 10827dd7cddfSDavid du Colombier Memimage *img; 10837dd7cddfSDavid du Colombier int dx, isgrey, convgrey, alphaonly, copyalpha, i, nb; 10847dd7cddfSDavid du Colombier uchar *begin, *end, *r, *w, *rrepl, *grepl, *brepl, *arepl, *krepl; 10857dd7cddfSDavid du Colombier uchar ured, ugrn, ublu; 10867dd7cddfSDavid du Colombier ulong u; 10877dd7cddfSDavid du Colombier 10887dd7cddfSDavid du Colombier img = p->img; 10897dd7cddfSDavid du Colombier begin = p->bytey0s + y*p->bwidth; 10907dd7cddfSDavid du Colombier r = p->bytermin + y*p->bwidth; 10917dd7cddfSDavid du Colombier end = p->bytey0e + y*p->bwidth; 10927dd7cddfSDavid du Colombier 10937dd7cddfSDavid du Colombier w = buf; 10947dd7cddfSDavid du Colombier dx = p->dx; 10957dd7cddfSDavid du Colombier nb = img->depth/8; 10967dd7cddfSDavid du Colombier 10977dd7cddfSDavid du Colombier convgrey = p->convgrey; /* convert rgb to grey */ 10987dd7cddfSDavid du Colombier isgrey = img->flags&Fgrey; 10997dd7cddfSDavid du Colombier alphaonly = p->alphaonly; 1100*59cc4ca5SDavid du Colombier copyalpha = (img->flags&Falpha) ? 1 : 0; 11017dd7cddfSDavid du Colombier 11027dd7cddfSDavid du Colombier /* if we can, avoid processing everything */ 11037dd7cddfSDavid du Colombier if(!(img->flags&Frepl) && !convgrey && (img->flags&Fbytes)){ 11047dd7cddfSDavid du Colombier memset(&b, 0, sizeof b); 11057dd7cddfSDavid du Colombier if(p->needbuf){ 11067dd7cddfSDavid du Colombier memmove(buf, r, dx*nb); 11077dd7cddfSDavid du Colombier r = buf; 11087dd7cddfSDavid du Colombier } 11097dd7cddfSDavid du Colombier if(copyalpha) 11107dd7cddfSDavid du Colombier b.alpha = r+img->shift[CAlpha]/8; 11117dd7cddfSDavid du Colombier if(isgrey){ 11127dd7cddfSDavid du Colombier b.grey = r+img->shift[CGrey]/8; 11137dd7cddfSDavid du Colombier b.red = b.grn = b.blu = b.grey; 11147dd7cddfSDavid du Colombier }else{ 11157dd7cddfSDavid du Colombier b.red = r+img->shift[CRed]/8; 11167dd7cddfSDavid du Colombier b.grn = r+img->shift[CGreen]/8; 11177dd7cddfSDavid du Colombier b.blu = r+img->shift[CBlue]/8; 11187dd7cddfSDavid du Colombier } 11197dd7cddfSDavid du Colombier b.delta = nb; 11207dd7cddfSDavid du Colombier return b; 11217dd7cddfSDavid du Colombier } 11227dd7cddfSDavid du Colombier 11237dd7cddfSDavid du Colombier rrepl = replbit[img->nbits[CRed]]; 11247dd7cddfSDavid du Colombier grepl = replbit[img->nbits[CGreen]]; 11257dd7cddfSDavid du Colombier brepl = replbit[img->nbits[CBlue]]; 11267dd7cddfSDavid du Colombier arepl = replbit[img->nbits[CAlpha]]; 11277dd7cddfSDavid du Colombier krepl = replbit[img->nbits[CGrey]]; 11287dd7cddfSDavid du Colombier 11297dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 11307dd7cddfSDavid du Colombier u = r[0] | (r[1]<<8) | (r[2]<<16) | (r[3]<<24); 11317dd7cddfSDavid du Colombier if(copyalpha) 11327dd7cddfSDavid du Colombier *w++ = arepl[(u>>img->shift[CAlpha]) & img->mask[CAlpha]]; 11337dd7cddfSDavid du Colombier 11347dd7cddfSDavid du Colombier if(isgrey) 11357dd7cddfSDavid du Colombier *w++ = krepl[(u >> img->shift[CGrey]) & img->mask[CGrey]]; 11367dd7cddfSDavid du Colombier else if(!alphaonly){ 11377dd7cddfSDavid du Colombier ured = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; 11387dd7cddfSDavid du Colombier ugrn = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; 11397dd7cddfSDavid du Colombier ublu = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; 11407dd7cddfSDavid du Colombier if(convgrey){ 11417dd7cddfSDavid du Colombier *w++ = RGB2K(ured, ugrn, ublu); 11427dd7cddfSDavid du Colombier }else{ 11437dd7cddfSDavid du Colombier *w++ = brepl[(u >> img->shift[CBlue]) & img->mask[CBlue]]; 11447dd7cddfSDavid du Colombier *w++ = grepl[(u >> img->shift[CGreen]) & img->mask[CGreen]]; 11457dd7cddfSDavid du Colombier *w++ = rrepl[(u >> img->shift[CRed]) & img->mask[CRed]]; 11467dd7cddfSDavid du Colombier } 11477dd7cddfSDavid du Colombier } 11487dd7cddfSDavid du Colombier r += nb; 11497dd7cddfSDavid du Colombier if(r == end) 11507dd7cddfSDavid du Colombier r = begin; 11517dd7cddfSDavid du Colombier } 11527dd7cddfSDavid du Colombier 11537dd7cddfSDavid du Colombier b.alpha = copyalpha ? buf : nil; 11547dd7cddfSDavid du Colombier if(alphaonly){ 11557dd7cddfSDavid du Colombier b.red = b.grn = b.blu = b.grey = nil; 11567dd7cddfSDavid du Colombier b.delta = 1; 11577dd7cddfSDavid du Colombier }else if(isgrey || convgrey){ 11587dd7cddfSDavid du Colombier b.grey = buf+copyalpha; 11597dd7cddfSDavid du Colombier b.red = b.grn = b.blu = buf+copyalpha; 11607dd7cddfSDavid du Colombier b.delta = copyalpha+1; 11617dd7cddfSDavid du Colombier }else{ 11627dd7cddfSDavid du Colombier b.blu = buf+copyalpha; 11637dd7cddfSDavid du Colombier b.grn = buf+copyalpha+1; 11647dd7cddfSDavid du Colombier b.grey = nil; 11657dd7cddfSDavid du Colombier b.red = buf+copyalpha+2; 11667dd7cddfSDavid du Colombier b.delta = copyalpha+3; 11677dd7cddfSDavid du Colombier } 11687dd7cddfSDavid du Colombier return b; 11697dd7cddfSDavid du Colombier } 11707dd7cddfSDavid du Colombier 11717dd7cddfSDavid du Colombier #define DBG if(0) 11727dd7cddfSDavid du Colombier static void 11737dd7cddfSDavid du Colombier writebyte(Param *p, uchar *w, Buffer src) 11747dd7cddfSDavid du Colombier { 11757dd7cddfSDavid du Colombier Memimage *img; 11767dd7cddfSDavid du Colombier int i, isalpha, isgrey, nb, delta, dx, adelta; 11777dd7cddfSDavid du Colombier uchar ff, *red, *grn, *blu, *grey, *alpha; 11787dd7cddfSDavid du Colombier ulong u, mask; 11797dd7cddfSDavid du Colombier 11807dd7cddfSDavid du Colombier img = p->img; 11817dd7cddfSDavid du Colombier 11827dd7cddfSDavid du Colombier red = src.red; 11837dd7cddfSDavid du Colombier grn = src.grn; 11847dd7cddfSDavid du Colombier blu = src.blu; 11857dd7cddfSDavid du Colombier alpha = src.alpha; 11867dd7cddfSDavid du Colombier delta = src.delta; 11877dd7cddfSDavid du Colombier grey = src.grey; 11887dd7cddfSDavid du Colombier dx = p->dx; 11897dd7cddfSDavid du Colombier 11907dd7cddfSDavid du Colombier nb = img->depth/8; 11917dd7cddfSDavid du Colombier mask = (nb==4) ? 0 : ~((1<<img->depth)-1); 11927dd7cddfSDavid du Colombier 11937dd7cddfSDavid du Colombier isalpha = img->flags&Falpha; 11947dd7cddfSDavid du Colombier isgrey = img->flags&Fgrey; 11957dd7cddfSDavid du Colombier adelta = src.delta; 11967dd7cddfSDavid du Colombier 11977dd7cddfSDavid du Colombier if(isalpha && alpha == nil){ 11987dd7cddfSDavid du Colombier ff = 0xFF; 11997dd7cddfSDavid du Colombier alpha = &ff; 12007dd7cddfSDavid du Colombier adelta = 0; 12017dd7cddfSDavid du Colombier } 12027dd7cddfSDavid du Colombier 12037dd7cddfSDavid du Colombier for(i=0; i<dx; i++){ 12047dd7cddfSDavid du Colombier u = w[0] | (w[1]<<8) | (w[2]<<16) | (w[3]<<24); 12057dd7cddfSDavid du Colombier DBG print("u %.8lux...", u); 12067dd7cddfSDavid du Colombier u &= mask; 12077dd7cddfSDavid du Colombier DBG print("&mask %.8lux...", u); 12087dd7cddfSDavid du Colombier if(isgrey){ 12097dd7cddfSDavid du Colombier u |= ((*grey >> (8-img->nbits[CGrey])) & img->mask[CGrey]) << img->shift[CGrey]; 12107dd7cddfSDavid du Colombier DBG print("|grey %.8lux...", u); 12117dd7cddfSDavid du Colombier grey += delta; 12127dd7cddfSDavid du Colombier }else{ 12137dd7cddfSDavid du Colombier u |= ((*red >> (8-img->nbits[CRed])) & img->mask[CRed]) << img->shift[CRed]; 12147dd7cddfSDavid du Colombier u |= ((*grn >> (8-img->nbits[CGreen])) & img->mask[CGreen]) << img->shift[CGreen]; 12157dd7cddfSDavid du Colombier u |= ((*blu >> (8-img->nbits[CBlue])) & img->mask[CBlue]) << img->shift[CBlue]; 12167dd7cddfSDavid du Colombier red += delta; 12177dd7cddfSDavid du Colombier grn += delta; 12187dd7cddfSDavid du Colombier blu += delta; 12197dd7cddfSDavid du Colombier DBG print("|rgb %.8lux...", u); 12207dd7cddfSDavid du Colombier } 12217dd7cddfSDavid du Colombier 12227dd7cddfSDavid du Colombier if(isalpha){ 12237dd7cddfSDavid du Colombier u |= ((*alpha >> (8-img->nbits[CAlpha])) & img->mask[CAlpha]) << img->shift[CAlpha]; 12247dd7cddfSDavid du Colombier alpha += adelta; 12257dd7cddfSDavid du Colombier DBG print("|alpha %.8lux...", u); 12267dd7cddfSDavid du Colombier } 12277dd7cddfSDavid du Colombier 12287dd7cddfSDavid du Colombier w[0] = u; 12297dd7cddfSDavid du Colombier w[1] = u>>8; 12307dd7cddfSDavid du Colombier w[2] = u>>16; 12317dd7cddfSDavid du Colombier w[3] = u>>24; 12327dd7cddfSDavid du Colombier w += nb; 12337dd7cddfSDavid du Colombier } 12347dd7cddfSDavid du Colombier } 12357dd7cddfSDavid du Colombier #undef DBG 12367dd7cddfSDavid du Colombier 12377dd7cddfSDavid du Colombier static Readfn* 12387dd7cddfSDavid du Colombier readfn(Memimage *img) 12397dd7cddfSDavid du Colombier { 12407dd7cddfSDavid du Colombier if(img->depth < 8) 12417dd7cddfSDavid du Colombier return readnbit; 12427dd7cddfSDavid du Colombier if(img->chan == CMAP8) 12437dd7cddfSDavid du Colombier return readcmap; 12447dd7cddfSDavid du Colombier return readbyte; 12457dd7cddfSDavid du Colombier } 12467dd7cddfSDavid du Colombier 12477dd7cddfSDavid du Colombier static Readfn* 12487dd7cddfSDavid du Colombier readalphafn(Memimage *notused) 12497dd7cddfSDavid du Colombier { 12507dd7cddfSDavid du Colombier return readbyte; 12517dd7cddfSDavid du Colombier } 12527dd7cddfSDavid du Colombier 12537dd7cddfSDavid du Colombier static Writefn* 12547dd7cddfSDavid du Colombier writefn(Memimage *img) 12557dd7cddfSDavid du Colombier { 12567dd7cddfSDavid du Colombier if(img->depth < 8) 12577dd7cddfSDavid du Colombier return writenbit; 12587dd7cddfSDavid du Colombier if(img->chan == CMAP8) 12597dd7cddfSDavid du Colombier return writecmap; 12607dd7cddfSDavid du Colombier return writebyte; 12617dd7cddfSDavid du Colombier } 12627dd7cddfSDavid du Colombier 12637dd7cddfSDavid du Colombier static void 12647dd7cddfSDavid du Colombier nullwrite(Param *notusedpar, uchar *notusedbuf, Buffer notusedb) 12657dd7cddfSDavid du Colombier { 12667dd7cddfSDavid du Colombier } 12677dd7cddfSDavid du Colombier 12687dd7cddfSDavid du Colombier static Buffer 12697dd7cddfSDavid du Colombier readptr(Param *p, uchar *notusedbuf, int y) 12707dd7cddfSDavid du Colombier { 12717dd7cddfSDavid du Colombier Buffer b; 12727dd7cddfSDavid du Colombier uchar *q; 12737dd7cddfSDavid du Colombier 12747dd7cddfSDavid du Colombier q = p->bytermin + y*p->bwidth; 12757dd7cddfSDavid du Colombier b.red = q; /* ptr to data */ 12767dd7cddfSDavid du Colombier b.grn = b.blu = b.grey = b.alpha = nil; 12777dd7cddfSDavid du Colombier b.delta = p->img->depth/8; 12787dd7cddfSDavid du Colombier return b; 12797dd7cddfSDavid du Colombier } 12807dd7cddfSDavid du Colombier 12817dd7cddfSDavid du Colombier static Buffer 12827dd7cddfSDavid du Colombier boolmemmove(Buffer bdst, Buffer bsrc, Buffer notusedb, int dx, int notusedi) 12837dd7cddfSDavid du Colombier { 12847dd7cddfSDavid du Colombier memmove(bdst.red, bsrc.red, dx*bdst.delta); 12857dd7cddfSDavid du Colombier return bdst; 12867dd7cddfSDavid du Colombier } 12877dd7cddfSDavid du Colombier 12887dd7cddfSDavid du Colombier static Buffer 12897dd7cddfSDavid du Colombier boolcopy8(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 12907dd7cddfSDavid du Colombier { 12917dd7cddfSDavid du Colombier uchar *m, *r, *w, *ew; 12927dd7cddfSDavid du Colombier 12937dd7cddfSDavid du Colombier m = bmask.grey; 12947dd7cddfSDavid du Colombier w = bdst.red; 12957dd7cddfSDavid du Colombier r = bsrc.red; 12967dd7cddfSDavid du Colombier ew = w+dx; 12977dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 12987dd7cddfSDavid du Colombier if(*m++) 12997dd7cddfSDavid du Colombier *w = *r; 13007dd7cddfSDavid du Colombier return bdst; /* not used */ 13017dd7cddfSDavid du Colombier } 13027dd7cddfSDavid du Colombier 13037dd7cddfSDavid du Colombier static Buffer 13047dd7cddfSDavid du Colombier boolcopy16(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 13057dd7cddfSDavid du Colombier { 13067dd7cddfSDavid du Colombier uchar *m; 13077dd7cddfSDavid du Colombier ushort *r, *w, *ew; 13087dd7cddfSDavid du Colombier 13097dd7cddfSDavid du Colombier m = bmask.grey; 13107dd7cddfSDavid du Colombier w = (ushort*)bdst.red; 13117dd7cddfSDavid du Colombier r = (ushort*)bsrc.red; 13127dd7cddfSDavid du Colombier ew = w+dx; 13137dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 13147dd7cddfSDavid du Colombier if(*m++) 13157dd7cddfSDavid du Colombier *w = *r; 13167dd7cddfSDavid du Colombier return bdst; /* not used */ 13177dd7cddfSDavid du Colombier } 13187dd7cddfSDavid du Colombier 13197dd7cddfSDavid du Colombier static Buffer 13207dd7cddfSDavid du Colombier boolcopy24(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 13217dd7cddfSDavid du Colombier { 13227dd7cddfSDavid du Colombier uchar *m; 13237dd7cddfSDavid du Colombier uchar *r, *w, *ew; 13247dd7cddfSDavid du Colombier 13257dd7cddfSDavid du Colombier m = bmask.grey; 13267dd7cddfSDavid du Colombier w = bdst.red; 13277dd7cddfSDavid du Colombier r = bsrc.red; 13287dd7cddfSDavid du Colombier ew = w+dx*3; 13297dd7cddfSDavid du Colombier while(w < ew){ 13307dd7cddfSDavid du Colombier if(*m++){ 13317dd7cddfSDavid du Colombier *w++ = *r++; 13327dd7cddfSDavid du Colombier *w++ = *r++; 13337dd7cddfSDavid du Colombier *w++ = *r++; 13347dd7cddfSDavid du Colombier }else{ 13357dd7cddfSDavid du Colombier w += 3; 13367dd7cddfSDavid du Colombier r += 3; 13377dd7cddfSDavid du Colombier } 13387dd7cddfSDavid du Colombier } 13397dd7cddfSDavid du Colombier return bdst; /* not used */ 13407dd7cddfSDavid du Colombier } 13417dd7cddfSDavid du Colombier 13427dd7cddfSDavid du Colombier static Buffer 13437dd7cddfSDavid du Colombier boolcopy32(Buffer bdst, Buffer bsrc, Buffer bmask, int dx, int notusedi) 13447dd7cddfSDavid du Colombier { 13457dd7cddfSDavid du Colombier uchar *m; 13467dd7cddfSDavid du Colombier ulong *r, *w, *ew; 13477dd7cddfSDavid du Colombier 13487dd7cddfSDavid du Colombier m = bmask.grey; 13497dd7cddfSDavid du Colombier w = (ulong*)bdst.red; 13507dd7cddfSDavid du Colombier r = (ulong*)bsrc.red; 13517dd7cddfSDavid du Colombier ew = w+dx; 13527dd7cddfSDavid du Colombier for(; w < ew; w++,r++) 13537dd7cddfSDavid du Colombier if(*m++) 13547dd7cddfSDavid du Colombier *w = *r; 13557dd7cddfSDavid du Colombier return bdst; /* not used */ 13567dd7cddfSDavid du Colombier } 13577dd7cddfSDavid du Colombier 13587dd7cddfSDavid du Colombier static Buffer 13597dd7cddfSDavid du Colombier genconv(Param *p, uchar *buf, int y) 13607dd7cddfSDavid du Colombier { 13617dd7cddfSDavid du Colombier Buffer b; 13627dd7cddfSDavid du Colombier int nb; 13637dd7cddfSDavid du Colombier uchar *r, *w, *ew; 13647dd7cddfSDavid du Colombier 13657dd7cddfSDavid du Colombier /* read from source into RGB format in convbuf */ 13667dd7cddfSDavid du Colombier b = p->convreadcall(p, p->convbuf, y); 13677dd7cddfSDavid du Colombier 13687dd7cddfSDavid du Colombier /* write RGB format into dst format in buf */ 13697dd7cddfSDavid du Colombier p->convwritecall(p->convdpar, buf, b); 13707dd7cddfSDavid du Colombier 13717dd7cddfSDavid du Colombier if(p->convdx){ 13727dd7cddfSDavid du Colombier nb = p->convdpar->img->depth/8; 13737dd7cddfSDavid du Colombier r = buf; 13747dd7cddfSDavid du Colombier w = buf+nb*p->dx; 13757dd7cddfSDavid du Colombier ew = buf+nb*p->convdx; 13767dd7cddfSDavid du Colombier while(w<ew) 13777dd7cddfSDavid du Colombier *w++ = *r++; 13787dd7cddfSDavid du Colombier } 13797dd7cddfSDavid du Colombier 13807dd7cddfSDavid du Colombier b.red = buf; 13817dd7cddfSDavid du Colombier b.blu = b.grn = b.grey = b.alpha = nil; 13827dd7cddfSDavid du Colombier b.delta = 0; 13837dd7cddfSDavid du Colombier 13847dd7cddfSDavid du Colombier return b; 13857dd7cddfSDavid du Colombier } 13867dd7cddfSDavid du Colombier 13877dd7cddfSDavid du Colombier static Readfn* 13887dd7cddfSDavid du Colombier convfn(Memimage *dst, Param *dpar, Memimage *src, Param *spar) 13897dd7cddfSDavid du Colombier { 13907dd7cddfSDavid du Colombier if(dst->chan == src->chan && !(src->flags&Frepl)){ 13917dd7cddfSDavid du Colombier return readptr; 13927dd7cddfSDavid du Colombier } 13937dd7cddfSDavid du Colombier 13947dd7cddfSDavid du Colombier if(dst->chan==CMAP8 && (src->chan==GREY1||src->chan==GREY2||src->chan==GREY4)){ 13957dd7cddfSDavid du Colombier /* cheat because we know the replicated value is exactly the color map entry. */ 13967dd7cddfSDavid du Colombier return readnbit; 13977dd7cddfSDavid du Colombier } 13987dd7cddfSDavid du Colombier 13997dd7cddfSDavid du Colombier spar->convreadcall = readfn(src); 14007dd7cddfSDavid du Colombier spar->convwritecall = writefn(dst); 14017dd7cddfSDavid du Colombier spar->convdpar = dpar; 14027dd7cddfSDavid du Colombier 14037dd7cddfSDavid du Colombier /* allocate a conversion buffer */ 14047dd7cddfSDavid du Colombier spar->convbufoff = ndrawbuf; 14057dd7cddfSDavid du Colombier ndrawbuf += spar->dx*4; 14067dd7cddfSDavid du Colombier 14077dd7cddfSDavid du Colombier if(spar->dx > Dx(spar->img->r)){ 14087dd7cddfSDavid du Colombier spar->convdx = spar->dx; 14097dd7cddfSDavid du Colombier spar->dx = Dx(spar->img->r); 14107dd7cddfSDavid du Colombier } 14117dd7cddfSDavid du Colombier 14127dd7cddfSDavid du Colombier return genconv; 14137dd7cddfSDavid du Colombier } 14147dd7cddfSDavid du Colombier 14157dd7cddfSDavid du Colombier ulong 14167dd7cddfSDavid du Colombier _pixelbits(Memimage *i, Point pt) 14177dd7cddfSDavid du Colombier { 14187dd7cddfSDavid du Colombier uchar *p; 14197dd7cddfSDavid du Colombier ulong val; 14207dd7cddfSDavid du Colombier int off, bpp, npack; 14217dd7cddfSDavid du Colombier 14227dd7cddfSDavid du Colombier val = 0; 14237dd7cddfSDavid du Colombier p = byteaddr(i, pt); 14247dd7cddfSDavid du Colombier switch(bpp=i->depth){ 14257dd7cddfSDavid du Colombier case 1: 14267dd7cddfSDavid du Colombier case 2: 14277dd7cddfSDavid du Colombier case 4: 14287dd7cddfSDavid du Colombier npack = 8/bpp; 14297dd7cddfSDavid du Colombier off = pt.x%npack; 14307dd7cddfSDavid du Colombier val = p[0] >> bpp*(npack-1-off); 14317dd7cddfSDavid du Colombier val &= (1<<bpp)-1; 14327dd7cddfSDavid du Colombier break; 14337dd7cddfSDavid du Colombier case 8: 14347dd7cddfSDavid du Colombier val = p[0]; 14357dd7cddfSDavid du Colombier break; 14367dd7cddfSDavid du Colombier case 16: 14377dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8); 14387dd7cddfSDavid du Colombier break; 14397dd7cddfSDavid du Colombier case 24: 14407dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8)|(p[2]<<16); 14417dd7cddfSDavid du Colombier break; 14427dd7cddfSDavid du Colombier case 32: 14437dd7cddfSDavid du Colombier val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); 14447dd7cddfSDavid du Colombier break; 14457dd7cddfSDavid du Colombier } 14467dd7cddfSDavid du Colombier while(bpp<32){ 14477dd7cddfSDavid du Colombier val |= val<<bpp; 14487dd7cddfSDavid du Colombier bpp *= 2; 14497dd7cddfSDavid du Colombier } 14507dd7cddfSDavid du Colombier return val; 14517dd7cddfSDavid du Colombier } 14527dd7cddfSDavid du Colombier 14537dd7cddfSDavid du Colombier static Calcfn* 14547dd7cddfSDavid du Colombier boolcopyfn(Memimage *img, Memimage *mask) 14557dd7cddfSDavid du Colombier { 14567dd7cddfSDavid du Colombier if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && _pixelbits(mask, mask->r.min)==~0) 14577dd7cddfSDavid du Colombier return boolmemmove; 14587dd7cddfSDavid du Colombier 14597dd7cddfSDavid du Colombier switch(img->depth){ 14607dd7cddfSDavid du Colombier case 8: 14617dd7cddfSDavid du Colombier return boolcopy8; 14627dd7cddfSDavid du Colombier case 16: 14637dd7cddfSDavid du Colombier return boolcopy16; 14647dd7cddfSDavid du Colombier case 24: 14657dd7cddfSDavid du Colombier return boolcopy24; 14667dd7cddfSDavid du Colombier case 32: 14677dd7cddfSDavid du Colombier return boolcopy32; 14687dd7cddfSDavid du Colombier default: 14697dd7cddfSDavid du Colombier assert(0 /* boolcopyfn */); 14707dd7cddfSDavid du Colombier } 14717dd7cddfSDavid du Colombier return nil; 14727dd7cddfSDavid du Colombier } 14737dd7cddfSDavid du Colombier 14747dd7cddfSDavid du Colombier /* 14757dd7cddfSDavid du Colombier * Optimized draw for filling and scrolling; uses memset and memmove. 14767dd7cddfSDavid du Colombier */ 14777dd7cddfSDavid du Colombier static void 14787dd7cddfSDavid du Colombier memsetb(void *vp, uchar val, int n) 14797dd7cddfSDavid du Colombier { 14807dd7cddfSDavid du Colombier uchar *p, *ep; 14817dd7cddfSDavid du Colombier 14827dd7cddfSDavid du Colombier p = vp; 14837dd7cddfSDavid du Colombier ep = p+n; 14847dd7cddfSDavid du Colombier while(p<ep) 14857dd7cddfSDavid du Colombier *p++ = val; 14867dd7cddfSDavid du Colombier } 14877dd7cddfSDavid du Colombier 14887dd7cddfSDavid du Colombier static void 14897dd7cddfSDavid du Colombier memsets(void *vp, ushort val, int n) 14907dd7cddfSDavid du Colombier { 14917dd7cddfSDavid du Colombier ushort *p, *ep; 14927dd7cddfSDavid du Colombier 14937dd7cddfSDavid du Colombier p = vp; 14947dd7cddfSDavid du Colombier ep = p+n; 14957dd7cddfSDavid du Colombier while(p<ep) 14967dd7cddfSDavid du Colombier *p++ = val; 14977dd7cddfSDavid du Colombier } 14987dd7cddfSDavid du Colombier 14997dd7cddfSDavid du Colombier static void 15007dd7cddfSDavid du Colombier memsetl(void *vp, ulong val, int n) 15017dd7cddfSDavid du Colombier { 15027dd7cddfSDavid du Colombier ulong *p, *ep; 15037dd7cddfSDavid du Colombier 15047dd7cddfSDavid du Colombier p = vp; 15057dd7cddfSDavid du Colombier ep = p+n; 15067dd7cddfSDavid du Colombier while(p<ep) 15077dd7cddfSDavid du Colombier *p++ = val; 15087dd7cddfSDavid du Colombier } 15097dd7cddfSDavid du Colombier 15107dd7cddfSDavid du Colombier void 15117dd7cddfSDavid du Colombier memset24(void *vp, ulong val, int n) 15127dd7cddfSDavid du Colombier { 15137dd7cddfSDavid du Colombier uchar *p, *ep; 15147dd7cddfSDavid du Colombier uchar a,b,c; 15157dd7cddfSDavid du Colombier 15167dd7cddfSDavid du Colombier p = vp; 15177dd7cddfSDavid du Colombier ep = p+3*n; 15187dd7cddfSDavid du Colombier a = val; 15197dd7cddfSDavid du Colombier b = val>>8; 15207dd7cddfSDavid du Colombier c = val>>16; 15217dd7cddfSDavid du Colombier while(p<ep){ 15227dd7cddfSDavid du Colombier *p++ = a; 15237dd7cddfSDavid du Colombier *p++ = b; 15247dd7cddfSDavid du Colombier *p++ = c; 15257dd7cddfSDavid du Colombier } 15267dd7cddfSDavid du Colombier } 15277dd7cddfSDavid du Colombier 15287dd7cddfSDavid du Colombier ulong 15297dd7cddfSDavid du Colombier _imgtorgba(Memimage *img, ulong val) 15307dd7cddfSDavid du Colombier { 15317dd7cddfSDavid du Colombier uchar r, g, b, a; 15327dd7cddfSDavid du Colombier int nb, ov, v; 15337dd7cddfSDavid du Colombier ulong chan; 15347dd7cddfSDavid du Colombier uchar *p; 15357dd7cddfSDavid du Colombier 15367dd7cddfSDavid du Colombier a = 0xFF; 15377dd7cddfSDavid du Colombier r = g = b = 0xAA; /* garbage */ 15387dd7cddfSDavid du Colombier for(chan=img->chan; chan; chan>>=8){ 15397dd7cddfSDavid du Colombier nb = NBITS(chan); 15407dd7cddfSDavid du Colombier ov = v = val&((1<<nb)-1); 15417dd7cddfSDavid du Colombier val >>= nb; 15427dd7cddfSDavid du Colombier 15437dd7cddfSDavid du Colombier while(nb < 8){ 15447dd7cddfSDavid du Colombier v |= v<<nb; 15457dd7cddfSDavid du Colombier nb *= 2; 15467dd7cddfSDavid du Colombier } 15477dd7cddfSDavid du Colombier v >>= (nb-8); 15487dd7cddfSDavid du Colombier 15497dd7cddfSDavid du Colombier switch(TYPE(chan)){ 15507dd7cddfSDavid du Colombier case CRed: 15517dd7cddfSDavid du Colombier r = v; 15527dd7cddfSDavid du Colombier break; 15537dd7cddfSDavid du Colombier case CGreen: 15547dd7cddfSDavid du Colombier g = v; 15557dd7cddfSDavid du Colombier break; 15567dd7cddfSDavid du Colombier case CBlue: 15577dd7cddfSDavid du Colombier b = v; 15587dd7cddfSDavid du Colombier break; 15597dd7cddfSDavid du Colombier case CAlpha: 15607dd7cddfSDavid du Colombier a = v; 15617dd7cddfSDavid du Colombier break; 15627dd7cddfSDavid du Colombier case CGrey: 15637dd7cddfSDavid du Colombier r = g = b = v; 15647dd7cddfSDavid du Colombier break; 15657dd7cddfSDavid du Colombier case CMap: 15667dd7cddfSDavid du Colombier p = img->cmap->cmap2rgb+3*ov; 15677dd7cddfSDavid du Colombier r = *p++; 15687dd7cddfSDavid du Colombier g = *p++; 15697dd7cddfSDavid du Colombier b = *p; 15707dd7cddfSDavid du Colombier break; 15717dd7cddfSDavid du Colombier } 15727dd7cddfSDavid du Colombier } 15737dd7cddfSDavid du Colombier return (r<<24)|(g<<16)|(b<<8)|a; 15747dd7cddfSDavid du Colombier } 15757dd7cddfSDavid du Colombier 15767dd7cddfSDavid du Colombier ulong 15777dd7cddfSDavid du Colombier _rgbatoimg(Memimage *img, ulong rgba) 15787dd7cddfSDavid du Colombier { 15797dd7cddfSDavid du Colombier ulong chan; 15807dd7cddfSDavid du Colombier int d, nb; 15817dd7cddfSDavid du Colombier ulong v; 15827dd7cddfSDavid du Colombier uchar *p, r, g, b, a, m; 15837dd7cddfSDavid du Colombier 15847dd7cddfSDavid du Colombier v = 0; 15857dd7cddfSDavid du Colombier r = rgba>>24; 15867dd7cddfSDavid du Colombier g = rgba>>16; 15877dd7cddfSDavid du Colombier b = rgba>>8; 15887dd7cddfSDavid du Colombier a = rgba; 15897dd7cddfSDavid du Colombier d = 0; 15907dd7cddfSDavid du Colombier for(chan=img->chan; chan; chan>>=8){ 15917dd7cddfSDavid du Colombier nb = NBITS(chan); 15927dd7cddfSDavid du Colombier switch(TYPE(chan)){ 15937dd7cddfSDavid du Colombier case CRed: 15947dd7cddfSDavid du Colombier v |= (r>>(8-nb))<<d; 15957dd7cddfSDavid du Colombier break; 15967dd7cddfSDavid du Colombier case CGreen: 15977dd7cddfSDavid du Colombier v |= (g>>(8-nb))<<d; 15987dd7cddfSDavid du Colombier break; 15997dd7cddfSDavid du Colombier case CBlue: 16007dd7cddfSDavid du Colombier v |= (b>>(8-nb))<<d; 16017dd7cddfSDavid du Colombier break; 16027dd7cddfSDavid du Colombier case CAlpha: 16037dd7cddfSDavid du Colombier v |= (a>>(8-nb))<<d; 16047dd7cddfSDavid du Colombier break; 16057dd7cddfSDavid du Colombier case CMap: 16067dd7cddfSDavid du Colombier p = img->cmap->rgb2cmap; 16077dd7cddfSDavid du Colombier m = p[(r>>4)*256+(g>>4)*16+(b>>4)]; 1608*59cc4ca5SDavid du Colombier v |= (m>>(8-nb))<<d; 16097dd7cddfSDavid du Colombier break; 16107dd7cddfSDavid du Colombier case CGrey: 16117dd7cddfSDavid du Colombier m = RGB2K(r,g,b); 1612*59cc4ca5SDavid du Colombier v |= (m>>(8-nb))<<d; 16137dd7cddfSDavid du Colombier break; 16147dd7cddfSDavid du Colombier } 16157dd7cddfSDavid du Colombier d += nb; 16167dd7cddfSDavid du Colombier } 16177dd7cddfSDavid du Colombier return v; 16187dd7cddfSDavid du Colombier } 16197dd7cddfSDavid du Colombier 16207dd7cddfSDavid du Colombier static int 16217dd7cddfSDavid du Colombier memoptdraw(Memdrawparam *par) 16227dd7cddfSDavid du Colombier { 16237dd7cddfSDavid du Colombier int y, dy, dx; 16247dd7cddfSDavid du Colombier ulong v; 16257dd7cddfSDavid du Colombier unsigned m; 16267dd7cddfSDavid du Colombier Memimage *src; 16277dd7cddfSDavid du Colombier Memimage *dst; 16287dd7cddfSDavid du Colombier 16297dd7cddfSDavid du Colombier dx = Dx(par->r); 16307dd7cddfSDavid du Colombier dy = Dy(par->r); 16317dd7cddfSDavid du Colombier src = par->src; 16327dd7cddfSDavid du Colombier dst = par->dst; 16337dd7cddfSDavid du Colombier 16347dd7cddfSDavid du Colombier /* 16357dd7cddfSDavid du Colombier * If we have an opaque mask and source is one opaque pixel we can convert to the 16367dd7cddfSDavid du Colombier * destination format and just replicate with memset. 16377dd7cddfSDavid du Colombier */ 16387dd7cddfSDavid du Colombier m = Simplesrc|Simplemask|Fullmask; 1639*59cc4ca5SDavid du Colombier if((par->state&m)==m && ((par->srgba&0xFF) == 0xFF)){ 16407dd7cddfSDavid du Colombier uchar *dp, p[4]; 1641*59cc4ca5SDavid du Colombier int d, dwid, ppb, np, nb; 16427dd7cddfSDavid du Colombier uchar lm, rm; 16437dd7cddfSDavid du Colombier 16447dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 16457dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 16467dd7cddfSDavid du Colombier v = par->sdval; 16477dd7cddfSDavid du Colombier switch(dst->depth){ 16487dd7cddfSDavid du Colombier case 1: 16497dd7cddfSDavid du Colombier case 2: 16507dd7cddfSDavid du Colombier case 4: 1651*59cc4ca5SDavid du Colombier for(d=dst->depth; d<8; d*=2) 1652*59cc4ca5SDavid du Colombier v |= (v<<d); 16537dd7cddfSDavid du Colombier ppb = 8/dst->depth; /* pixels per byte */ 16547dd7cddfSDavid du Colombier m = ppb-1; 16557dd7cddfSDavid du Colombier /* left edge */ 16567dd7cddfSDavid du Colombier np = par->r.min.x&m; /* no. pixels unused on left side of word */ 16577dd7cddfSDavid du Colombier dx -= (ppb-np); 16587dd7cddfSDavid du Colombier nb = 8 - np * dst->depth; /* no. bits used on right side of word */ 16597dd7cddfSDavid du Colombier lm = (1<<nb)-1; 16607dd7cddfSDavid du Colombier 16617dd7cddfSDavid du Colombier /* right edge */ 16627dd7cddfSDavid du Colombier np = par->r.max.x&m; /* no. pixels used on left side of word */ 16637dd7cddfSDavid du Colombier dx -= np; 16647dd7cddfSDavid du Colombier nb = 8 - np * dst->depth; /* no. bits unused on right side of word */ 16657dd7cddfSDavid du Colombier rm = ~((1<<nb)-1); 16667dd7cddfSDavid du Colombier 16677dd7cddfSDavid du Colombier /* lm, rm are masks that are 1 where we should touch the bits */ 16687dd7cddfSDavid du Colombier if(dx < 0){ /* just one byte */ 16697dd7cddfSDavid du Colombier lm &= rm; 16707dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 16717dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 16727dd7cddfSDavid du Colombier }else if(dx == 0){ /* no full bytes */ 16737dd7cddfSDavid du Colombier if(lm) 16747dd7cddfSDavid du Colombier dwid--; 16757dd7cddfSDavid du Colombier 16767dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid){ 16777dd7cddfSDavid du Colombier if(lm){ 16787dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 16797dd7cddfSDavid du Colombier dp++; 16807dd7cddfSDavid du Colombier } 16817dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & rm; 16827dd7cddfSDavid du Colombier } 16837dd7cddfSDavid du Colombier }else{ /* full bytes in middle */ 16847dd7cddfSDavid du Colombier dx /= ppb; 16857dd7cddfSDavid du Colombier if(lm) 16867dd7cddfSDavid du Colombier dwid--; 16877dd7cddfSDavid du Colombier dwid -= dx; 16887dd7cddfSDavid du Colombier 16897dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid){ 16907dd7cddfSDavid du Colombier if(lm){ 16917dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & lm; 16927dd7cddfSDavid du Colombier dp++; 16937dd7cddfSDavid du Colombier } 16947dd7cddfSDavid du Colombier memset(dp, v, dx); 16957dd7cddfSDavid du Colombier dp += dx; 16967dd7cddfSDavid du Colombier *dp ^= (v ^ *dp) & rm; 16977dd7cddfSDavid du Colombier } 16987dd7cddfSDavid du Colombier } 16997dd7cddfSDavid du Colombier return 1; 17007dd7cddfSDavid du Colombier case 8: 17017dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 17027dd7cddfSDavid du Colombier memset(dp, v, dx); 17037dd7cddfSDavid du Colombier return 1; 17047dd7cddfSDavid du Colombier case 16: 17057dd7cddfSDavid du Colombier p[0] = v; /* make little endian */ 17067dd7cddfSDavid du Colombier p[1] = v>>8; 17077dd7cddfSDavid du Colombier v = *(ushort*)p; 17087dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 17097dd7cddfSDavid du Colombier memsets(dp, v, dx); 17107dd7cddfSDavid du Colombier return 1; 17117dd7cddfSDavid du Colombier case 24: 17127dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 17137dd7cddfSDavid du Colombier memset24(dp, v, dx); 17147dd7cddfSDavid du Colombier return 1; 17157dd7cddfSDavid du Colombier case 32: 17167dd7cddfSDavid du Colombier p[0] = v; /* make little endian */ 17177dd7cddfSDavid du Colombier p[1] = v>>8; 17187dd7cddfSDavid du Colombier p[2] = v>>16; 17197dd7cddfSDavid du Colombier p[3] = v>>24; 17207dd7cddfSDavid du Colombier v = *(ulong*)p; 17217dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid) 17227dd7cddfSDavid du Colombier memsetl(dp, v, dx); 17237dd7cddfSDavid du Colombier return 1; 17247dd7cddfSDavid du Colombier default: 17257dd7cddfSDavid du Colombier assert(0 /* bad dest depth in memoptdraw */); 17267dd7cddfSDavid du Colombier } 17277dd7cddfSDavid du Colombier } 17287dd7cddfSDavid du Colombier 17297dd7cddfSDavid du Colombier /* 17307dd7cddfSDavid du Colombier * If no source alpha, an opaque mask, we can just copy the 17317dd7cddfSDavid du Colombier * source onto the destination. If the channels are the same and 17327dd7cddfSDavid du Colombier * the source is not replicated, memmove suffices. 17337dd7cddfSDavid du Colombier */ 17347dd7cddfSDavid du Colombier m = Simplemask|Fullmask; 17357dd7cddfSDavid du Colombier if((par->state&(m|Replsrc))==m && src->depth >= 8 17367dd7cddfSDavid du Colombier && src->chan == dst->chan && !(src->flags&Falpha)){ 17377dd7cddfSDavid du Colombier uchar *sp, *dp; 17387dd7cddfSDavid du Colombier long swid, dwid, nb; 17397dd7cddfSDavid du Colombier int dir; 17407dd7cddfSDavid du Colombier 17417dd7cddfSDavid du Colombier if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)) 17427dd7cddfSDavid du Colombier dir = -1; 17437dd7cddfSDavid du Colombier else 17447dd7cddfSDavid du Colombier dir = 1; 17457dd7cddfSDavid du Colombier 17467dd7cddfSDavid du Colombier swid = src->width*sizeof(ulong); 17477dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 17487dd7cddfSDavid du Colombier sp = byteaddr(src, par->sr.min); 17497dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 17507dd7cddfSDavid du Colombier if(dir == -1){ 17517dd7cddfSDavid du Colombier sp += (dy-1)*swid; 17527dd7cddfSDavid du Colombier dp += (dy-1)*dwid; 17537dd7cddfSDavid du Colombier swid = -swid; 17547dd7cddfSDavid du Colombier dwid = -dwid; 17557dd7cddfSDavid du Colombier } 17567dd7cddfSDavid du Colombier nb = (dx*src->depth)/8; 17577dd7cddfSDavid du Colombier for(y=0; y<dy; y++, sp+=swid, dp+=dwid) 17587dd7cddfSDavid du Colombier memmove(dp, sp, nb); 17597dd7cddfSDavid du Colombier return 1; 17607dd7cddfSDavid du Colombier } 17617dd7cddfSDavid du Colombier 17627dd7cddfSDavid du Colombier /* 17637dd7cddfSDavid du Colombier * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and 17647dd7cddfSDavid du Colombier * they're all bit aligned, we can just use bit operators. This happens 17657dd7cddfSDavid du Colombier * when we're manipulating boolean masks, e.g. in the arc code. 17667dd7cddfSDavid du Colombier */ 17677dd7cddfSDavid du Colombier if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0 17687dd7cddfSDavid du Colombier && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1 17697dd7cddfSDavid du Colombier && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){ 17707dd7cddfSDavid du Colombier uchar *sp, *dp, *mp; 17717dd7cddfSDavid du Colombier uchar lm, rm; 17727dd7cddfSDavid du Colombier long swid, dwid, mwid; 17737dd7cddfSDavid du Colombier int i, x, dir; 17747dd7cddfSDavid du Colombier 17757dd7cddfSDavid du Colombier sp = byteaddr(src, par->sr.min); 17767dd7cddfSDavid du Colombier dp = byteaddr(dst, par->r.min); 17777dd7cddfSDavid du Colombier mp = byteaddr(par->mask, par->mr.min); 17787dd7cddfSDavid du Colombier swid = src->width*sizeof(ulong); 17797dd7cddfSDavid du Colombier dwid = dst->width*sizeof(ulong); 17807dd7cddfSDavid du Colombier mwid = par->mask->width*sizeof(ulong); 17817dd7cddfSDavid du Colombier 17827dd7cddfSDavid du Colombier if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){ 17837dd7cddfSDavid du Colombier dir = -1; 17847dd7cddfSDavid du Colombier }else 17857dd7cddfSDavid du Colombier dir = 1; 17867dd7cddfSDavid du Colombier 17877dd7cddfSDavid du Colombier lm = 0xFF>>(par->r.min.x&7); 17887dd7cddfSDavid du Colombier rm = 0xFF<<(8-(par->r.max.x&7)); 17897dd7cddfSDavid du Colombier dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7); 17907dd7cddfSDavid du Colombier 17917dd7cddfSDavid du Colombier if(dx < 0){ /* one byte wide */ 17927dd7cddfSDavid du Colombier lm &= rm; 17937dd7cddfSDavid du Colombier if(dir == -1){ 17947dd7cddfSDavid du Colombier dp += dwid*(dy-1); 17957dd7cddfSDavid du Colombier sp += swid*(dy-1); 17967dd7cddfSDavid du Colombier mp += mwid*(dy-1); 17977dd7cddfSDavid du Colombier dwid = -dwid; 17987dd7cddfSDavid du Colombier swid = -swid; 17997dd7cddfSDavid du Colombier mwid = -mwid; 18007dd7cddfSDavid du Colombier } 18017dd7cddfSDavid du Colombier for(y=0; y<dy; y++){ 18027dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp) & *mp & lm; 18037dd7cddfSDavid du Colombier dp += dwid; 18047dd7cddfSDavid du Colombier sp += swid; 18057dd7cddfSDavid du Colombier mp += mwid; 18067dd7cddfSDavid du Colombier } 18077dd7cddfSDavid du Colombier return 1; 18087dd7cddfSDavid du Colombier } 18097dd7cddfSDavid du Colombier 18107dd7cddfSDavid du Colombier dx /= 8; 18117dd7cddfSDavid du Colombier if(dir == 1){ 18127dd7cddfSDavid du Colombier i = (lm!=0)+dx+(rm!=0); 18137dd7cddfSDavid du Colombier mwid -= i; 18147dd7cddfSDavid du Colombier swid -= i; 18157dd7cddfSDavid du Colombier dwid -= i; 18167dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ 18177dd7cddfSDavid du Colombier if(lm){ 18187dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++ & lm; 18197dd7cddfSDavid du Colombier dp++; 18207dd7cddfSDavid du Colombier } 18217dd7cddfSDavid du Colombier for(x=0; x<dx; x++){ 18227dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++; 18237dd7cddfSDavid du Colombier dp++; 18247dd7cddfSDavid du Colombier } 18257dd7cddfSDavid du Colombier if(rm){ 18267dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp++) & *mp++ & rm; 18277dd7cddfSDavid du Colombier dp++; 18287dd7cddfSDavid du Colombier } 18297dd7cddfSDavid du Colombier } 18307dd7cddfSDavid du Colombier return 1; 18317dd7cddfSDavid du Colombier }else{ 18327dd7cddfSDavid du Colombier /* dir == -1 */ 18337dd7cddfSDavid du Colombier i = (lm!=0)+dx+(rm!=0); 18347dd7cddfSDavid du Colombier dp += dwid*(dy-1)+i-1; 18357dd7cddfSDavid du Colombier sp += swid*(dy-1)+i-1; 18367dd7cddfSDavid du Colombier mp += mwid*(dy-1)+i-1; 18377dd7cddfSDavid du Colombier dwid = -dwid+i; 18387dd7cddfSDavid du Colombier swid = -swid+i; 18397dd7cddfSDavid du Colombier mwid = -mwid+i; 18407dd7cddfSDavid du Colombier for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ 18417dd7cddfSDavid du Colombier if(rm){ 18427dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp-- & rm; 18437dd7cddfSDavid du Colombier dp--; 18447dd7cddfSDavid du Colombier } 18457dd7cddfSDavid du Colombier for(x=0; x<dx; x++){ 18467dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp--; 18477dd7cddfSDavid du Colombier dp--; 18487dd7cddfSDavid du Colombier } 18497dd7cddfSDavid du Colombier if(lm){ 18507dd7cddfSDavid du Colombier *dp ^= (*dp ^ *sp--) & *mp-- & lm; 18517dd7cddfSDavid du Colombier dp--; 18527dd7cddfSDavid du Colombier } 18537dd7cddfSDavid du Colombier } 18547dd7cddfSDavid du Colombier } 18557dd7cddfSDavid du Colombier return 1; 18567dd7cddfSDavid du Colombier } 18577dd7cddfSDavid du Colombier return 0; 18587dd7cddfSDavid du Colombier } 18597dd7cddfSDavid du Colombier 18607dd7cddfSDavid du Colombier /* 18617dd7cddfSDavid du Colombier * Boolean character drawing. 18627dd7cddfSDavid du Colombier * Solid opaque color through a 1-bit greyscale mask. 18637dd7cddfSDavid du Colombier */ 18647dd7cddfSDavid du Colombier #define DBG if(0) 18657dd7cddfSDavid du Colombier static int 18667dd7cddfSDavid du Colombier chardraw(Memdrawparam *par) 18677dd7cddfSDavid du Colombier { 18687dd7cddfSDavid du Colombier ulong bits; 18697dd7cddfSDavid du Colombier int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth; 18707dd7cddfSDavid du Colombier ulong v, maskwid, dstwid; 18717dd7cddfSDavid du Colombier uchar *wp, *rp, *q, *wc; 18727dd7cddfSDavid du Colombier ushort *ws; 18737dd7cddfSDavid du Colombier ulong *wl; 18747dd7cddfSDavid du Colombier uchar sp[4]; 18757dd7cddfSDavid du Colombier Rectangle r, mr; 18767dd7cddfSDavid du Colombier Memimage *mask, *src, *dst; 18777dd7cddfSDavid du Colombier 18787dd7cddfSDavid 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", 18797dd7cddfSDavid du Colombier par->mask->flags, par->mask->depth, par->src->flags, 18807dd7cddfSDavid du Colombier Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data); 18817dd7cddfSDavid du Colombier 18827dd7cddfSDavid du Colombier mask = par->mask; 18837dd7cddfSDavid du Colombier src = par->src; 18847dd7cddfSDavid du Colombier dst = par->dst; 18857dd7cddfSDavid du Colombier r = par->r; 18867dd7cddfSDavid du Colombier mr = par->mr; 18877dd7cddfSDavid du Colombier 18887dd7cddfSDavid du Colombier if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc) 18897dd7cddfSDavid du Colombier || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data) 18907dd7cddfSDavid du Colombier return 0; 18917dd7cddfSDavid du Colombier 18927dd7cddfSDavid du Colombier depth = mask->depth; 18937dd7cddfSDavid du Colombier maskwid = mask->width*sizeof(ulong); 18947dd7cddfSDavid du Colombier rp = byteaddr(mask, mr.min); 18957dd7cddfSDavid du Colombier npack = 8/depth; 18967dd7cddfSDavid du Colombier bsh = (mr.min.x % npack) * depth; 18977dd7cddfSDavid du Colombier 18987dd7cddfSDavid du Colombier wp = byteaddr(dst, r.min); 18997dd7cddfSDavid du Colombier dstwid = dst->width*sizeof(ulong); 19007dd7cddfSDavid du Colombier DBG print("bsh %d\n", bsh); 19017dd7cddfSDavid du Colombier dy = Dy(r); 19027dd7cddfSDavid du Colombier dx = Dx(r); 19037dd7cddfSDavid du Colombier 19047dd7cddfSDavid du Colombier ddepth = dst->depth; 19057dd7cddfSDavid du Colombier 19067dd7cddfSDavid du Colombier /* 19077dd7cddfSDavid du Colombier * for loop counts from bsh to bsh+dx 19087dd7cddfSDavid du Colombier * 19097dd7cddfSDavid du Colombier * we want the bottom bits to be the amount 19107dd7cddfSDavid du Colombier * to shift the pixels down, so for n≡0 (mod 8) we want 19117dd7cddfSDavid du Colombier * bottom bits 7. for n≡1, 6, etc. 19127dd7cddfSDavid du Colombier * the bits come from -n-1. 19137dd7cddfSDavid du Colombier */ 19147dd7cddfSDavid du Colombier 19157dd7cddfSDavid du Colombier bx = -bsh-1; 19167dd7cddfSDavid du Colombier ex = -bsh-1-dx; 19177dd7cddfSDavid du Colombier SET(bits); 19187dd7cddfSDavid du Colombier v = par->sdval; 19197dd7cddfSDavid du Colombier 19207dd7cddfSDavid du Colombier /* make little endian */ 19217dd7cddfSDavid du Colombier sp[0] = v; 19227dd7cddfSDavid du Colombier sp[1] = v>>8; 19237dd7cddfSDavid du Colombier sp[2] = v>>16; 19247dd7cddfSDavid du Colombier sp[3] = v>>24; 19257dd7cddfSDavid du Colombier 19267dd7cddfSDavid du Colombier for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){ 19277dd7cddfSDavid du Colombier q = rp; 19287dd7cddfSDavid du Colombier if(bsh) 19297dd7cddfSDavid du Colombier bits = *q++; 19307dd7cddfSDavid du Colombier switch(ddepth){ 19317dd7cddfSDavid du Colombier case 8: 19327dd7cddfSDavid du Colombier wc = wp; 19337dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wc++){ 19347dd7cddfSDavid du Colombier i = x&7; 19357dd7cddfSDavid du Colombier if(i == 8-1) 19367dd7cddfSDavid du Colombier bits = *q++; 19377dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 19387dd7cddfSDavid du Colombier if((bits>>i)&1) 19397dd7cddfSDavid du Colombier *wc = v; 19407dd7cddfSDavid du Colombier } 19417dd7cddfSDavid du Colombier break; 19427dd7cddfSDavid du Colombier case 16: 19437dd7cddfSDavid du Colombier ws = (ushort*)wp; 19447dd7cddfSDavid du Colombier v = *(ushort*)sp; 19457dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, ws++){ 19467dd7cddfSDavid du Colombier i = x&7; 19477dd7cddfSDavid du Colombier if(i == 8-1) 19487dd7cddfSDavid du Colombier bits = *q++; 19497dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 19507dd7cddfSDavid du Colombier if((bits>>i)&1) 19517dd7cddfSDavid du Colombier *ws = v; 19527dd7cddfSDavid du Colombier } 19537dd7cddfSDavid du Colombier break; 19547dd7cddfSDavid du Colombier case 24: 19557dd7cddfSDavid du Colombier wc = wp; 19567dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wc+=3){ 19577dd7cddfSDavid du Colombier i = x&7; 19587dd7cddfSDavid du Colombier if(i == 8-1) 19597dd7cddfSDavid du Colombier bits = *q++; 19607dd7cddfSDavid du Colombier DBG print("bits %lux sh %d...", bits, i); 19617dd7cddfSDavid du Colombier if((bits>>i)&1){ 19627dd7cddfSDavid du Colombier wc[0] = sp[0]; 19637dd7cddfSDavid du Colombier wc[1] = sp[1]; 19647dd7cddfSDavid du Colombier wc[2] = sp[2]; 19657dd7cddfSDavid du Colombier } 19667dd7cddfSDavid du Colombier } 19677dd7cddfSDavid du Colombier break; 19687dd7cddfSDavid du Colombier case 32: 19697dd7cddfSDavid du Colombier wl = (ulong*)wp; 19707dd7cddfSDavid du Colombier v = *(ulong*)sp; 19717dd7cddfSDavid du Colombier for(x=bx; x>ex; x--, wl++){ 19727dd7cddfSDavid du Colombier i = x&7; 19737dd7cddfSDavid du Colombier if(i == 8-1) 19747dd7cddfSDavid du Colombier bits = *q++; 19757dd7cddfSDavid du Colombier DBG iprint("bits %lux sh %d...", bits, i); 19767dd7cddfSDavid du Colombier if((bits>>i)&1) 19777dd7cddfSDavid du Colombier *wl = v; 19787dd7cddfSDavid du Colombier } 19797dd7cddfSDavid du Colombier break; 19807dd7cddfSDavid du Colombier } 19817dd7cddfSDavid du Colombier } 19827dd7cddfSDavid du Colombier 19837dd7cddfSDavid du Colombier DBG print("\n"); 19847dd7cddfSDavid du Colombier return 1; 19857dd7cddfSDavid du Colombier } 19867dd7cddfSDavid du Colombier #undef DBG 19877dd7cddfSDavid du Colombier 1988*59cc4ca5SDavid du Colombier void 1989*59cc4ca5SDavid du Colombier _memfillcolor(Memimage *i, ulong val) 1990*59cc4ca5SDavid du Colombier { 1991*59cc4ca5SDavid du Colombier ulong bits; 1992*59cc4ca5SDavid du Colombier int d, y; 1993*59cc4ca5SDavid du Colombier 1994*59cc4ca5SDavid du Colombier if(val == DNofill) 1995*59cc4ca5SDavid du Colombier return; 1996*59cc4ca5SDavid du Colombier 1997*59cc4ca5SDavid du Colombier bits = _rgbatoimg(i, val); 1998*59cc4ca5SDavid du Colombier switch(i->depth){ 1999*59cc4ca5SDavid du Colombier case 24: /* 24-bit images suck */ 2000*59cc4ca5SDavid du Colombier for(y=i->r.min.y; y<i->r.max.y; y++) 2001*59cc4ca5SDavid du Colombier memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r)); 2002*59cc4ca5SDavid du Colombier break; 2003*59cc4ca5SDavid du Colombier default: /* 1, 2, 4, 8, 16, 32 */ 2004*59cc4ca5SDavid du Colombier for(d=i->depth; d<32; d*=2) 2005*59cc4ca5SDavid du Colombier bits = (bits << d) | bits; 2006*59cc4ca5SDavid du Colombier memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r)); 2007*59cc4ca5SDavid du Colombier break; 2008*59cc4ca5SDavid du Colombier } 2009*59cc4ca5SDavid du Colombier } 2010