📄 draw.c
字号:
off = pt.x%npack; val = p[0] >> bpp*(npack-1-off); val &= (1<<bpp)-1; break; case 8: val = p[0]; break; case 16: val = p[0]|(p[1]<<8); break; case 24: val = p[0]|(p[1]<<8)|(p[2]<<16); break; case 32: val = p[0]|(p[1]<<8)|(p[2]<<16)|(p[3]<<24); break; } while(bpp<32){ val |= val<<bpp; bpp *= 2; } return val;}static Calcfn*boolcopyfn(Memimage *img, Memimage *mask){ if(mask->flags&Frepl && Dx(mask->r)==1 && Dy(mask->r)==1 && pixelbits(mask, mask->r.min)==~0) return boolmemmove; switch(img->depth){ case 8: return boolcopy8; case 16: return boolcopy16; case 24: return boolcopy24; case 32: return boolcopy32; default: assert(0 /* boolcopyfn */); } return nil;}/* * Optimized draw for filling and scrolling; uses memset and memmove. */static voidmemsetb(void *vp, uchar val, int n){ uchar *p, *ep; p = vp; ep = p+n; while(p<ep) *p++ = val;}static voidmemsets(void *vp, ushort val, int n){ ushort *p, *ep; p = vp; ep = p+n; while(p<ep) *p++ = val;}static voidmemsetl(void *vp, ulong val, int n){ ulong *p, *ep; p = vp; ep = p+n; while(p<ep) *p++ = val;}static voidmemset24(void *vp, ulong val, int n){ uchar *p, *ep; uchar a,b,c; p = vp; ep = p+3*n; a = val; b = val>>8; c = val>>16; while(p<ep){ *p++ = a; *p++ = b; *p++ = c; }}static ulongimgtorgba(Memimage *img, ulong val){ uchar r, g, b, a; int nb, ov, v; ulong chan; uchar *p; a = 0xFF; r = g = b = 0xAA; /* garbage */ for(chan=img->chan; chan; chan>>=8){ nb = NBITS(chan); ov = v = val&((1<<nb)-1); val >>= nb; while(nb < 8){ v |= v<<nb; nb *= 2; } v >>= (nb-8); switch(TYPE(chan)){ case CRed: r = v; break; case CGreen: g = v; break; case CBlue: b = v; break; case CAlpha: a = v; break; case CGrey: r = g = b = v; break; case CMap: p = img->cmap->cmap2rgb+3*ov; r = *p++; g = *p++; b = *p; break; } } return (r<<24)|(g<<16)|(b<<8)|a; }static ulongrgbatoimg(Memimage *img, ulong rgba){ ulong chan; int d, nb; ulong v; uchar *p, r, g, b, a, m; v = 0; r = rgba>>24; g = rgba>>16; b = rgba>>8; a = rgba; d = 0; for(chan=img->chan; chan; chan>>=8){ nb = NBITS(chan); switch(TYPE(chan)){ case CRed: v |= (r>>(8-nb))<<d; break; case CGreen: v |= (g>>(8-nb))<<d; break; case CBlue: v |= (b>>(8-nb))<<d; break; case CAlpha: v |= (a>>(8-nb))<<d; break; case CMap: p = img->cmap->rgb2cmap; m = p[(r>>4)*256+(g>>4)*16+(b>>4)]; v |= (m>>(8-nb))<<d; break; case CGrey: m = RGB2K(r,g,b); v |= (m>>(8-nb))<<d; break; } d += nb; }// print("rgba2img %.8lux = %.*lux\n", rgba, 2*d/8, v); return v;}#define DBG if(0)static intmemoptdraw(Memdrawparam *par){ int m, y, dy, dx, op; ulong v; Memimage *src; Memimage *dst; dx = Dx(par->r); dy = Dy(par->r); src = par->src; dst = par->dst; op = par->op;DBG print("state %lux mval %lux dd %d\n", par->state, par->mval, dst->depth); /* * If we have an opaque mask and source is one opaque pixel we can convert to the * destination format and just replicate with memset. */ m = Simplesrc|Simplemask|Fullmask; if((par->state&m)==m && (par->srgba&0xFF) == 0xFF && (op ==S || op == SoverD)){ uchar *dp, p[4]; int d, dwid, ppb, np, nb; uchar lm, rm;DBG print("memopt, dst %p, dst->data->bdata %p\n", dst, dst->data->bdata); dwid = dst->width*sizeof(ulong); dp = byteaddr(dst, par->r.min); v = par->sdval;DBG print("sdval %lud, depth %d\n", v, dst->depth); switch(dst->depth){ case 1: case 2: case 4: for(d=dst->depth; d<8; d*=2) v |= (v<<d); ppb = 8/dst->depth; /* pixels per byte */ m = ppb-1; /* left edge */ np = par->r.min.x&m; /* no. pixels unused on left side of word */ dx -= (ppb-np); nb = 8 - np * dst->depth; /* no. bits used on right side of word */ lm = (1<<nb)-1;DBG print("np %d x %d nb %d lm %ux ppb %d m %ux\n", np, par->r.min.x, nb, lm, ppb, m); /* right edge */ np = par->r.max.x&m; /* no. pixels used on left side of word */ dx -= np; nb = 8 - np * dst->depth; /* no. bits unused on right side of word */ rm = ~((1<<nb)-1);DBG print("np %d x %d nb %d rm %ux ppb %d m %ux\n", np, par->r.max.x, nb, rm, ppb, m); DBG print("dx %d Dx %d\n", dx, Dx(par->r)); /* lm, rm are masks that are 1 where we should touch the bits */ if(dx < 0){ /* just one byte */ lm &= rm; for(y=0; y<dy; y++, dp+=dwid) *dp ^= (v ^ *dp) & lm; }else if(dx == 0){ /* no full bytes */ if(lm) dwid--; for(y=0; y<dy; y++, dp+=dwid){ if(lm){DBG print("dp %p v %lux lm %ux (v ^ *dp) & lm %lux\n", dp, v, lm, (v^*dp)&lm); *dp ^= (v ^ *dp) & lm; dp++; } *dp ^= (v ^ *dp) & rm; } }else{ /* full bytes in middle */ dx /= ppb; if(lm) dwid--; dwid -= dx; for(y=0; y<dy; y++, dp+=dwid){ if(lm){ *dp ^= (v ^ *dp) & lm; dp++; } memset(dp, v, dx); dp += dx; *dp ^= (v ^ *dp) & rm; } } return 1; case 8: for(y=0; y<dy; y++, dp+=dwid) memset(dp, v, dx); return 1; case 16: p[0] = v; /* make little endian */ p[1] = v>>8; v = *(ushort*)p;DBG print("dp=%p; dx=%d; for(y=0; y<%d; y++, dp+=%d)\nmemsets(dp, v, dx);\n", dp, dx, dy, dwid); for(y=0; y<dy; y++, dp+=dwid) memsets(dp, v, dx); return 1; case 24: for(y=0; y<dy; y++, dp+=dwid) memset24(dp, v, dx); return 1; case 32: p[0] = v; /* make little endian */ p[1] = v>>8; p[2] = v>>16; p[3] = v>>24; v = *(ulong*)p; for(y=0; y<dy; y++, dp+=dwid) memsetl(dp, v, dx); return 1; default: assert(0 /* bad dest depth in memoptdraw */); } } /* * If no source alpha, an opaque mask, we can just copy the * source onto the destination. If the channels are the same and * the source is not replicated, memmove suffices. */ m = Simplemask|Fullmask; if((par->state&(m|Replsrc))==m && src->depth >= 8 && src->chan == dst->chan && !(src->flags&Falpha) && (op == S || op == SoverD)){ uchar *sp, *dp; long swid, dwid, nb; int dir; if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)) dir = -1; else dir = 1; swid = src->width*sizeof(ulong); dwid = dst->width*sizeof(ulong); sp = byteaddr(src, par->sr.min); dp = byteaddr(dst, par->r.min); if(dir == -1){ sp += (dy-1)*swid; dp += (dy-1)*dwid; swid = -swid; dwid = -dwid; } nb = (dx*src->depth)/8; for(y=0; y<dy; y++, sp+=swid, dp+=dwid) memmove(dp, sp, nb); return 1; } /* * If we have a 1-bit mask, 1-bit source, and 1-bit destination, and * they're all bit aligned, we can just use bit operators. This happens * when we're manipulating boolean masks, e.g. in the arc code. */ if((par->state&(Simplemask|Simplesrc|Replmask|Replsrc))==0 && dst->chan==GREY1 && src->chan==GREY1 && par->mask->chan==GREY1 && (par->r.min.x&7)==(par->sr.min.x&7) && (par->r.min.x&7)==(par->mr.min.x&7)){ uchar *sp, *dp, *mp; uchar lm, rm; long swid, dwid, mwid; int i, x, dir; sp = byteaddr(src, par->sr.min); dp = byteaddr(dst, par->r.min); mp = byteaddr(par->mask, par->mr.min); swid = src->width*sizeof(ulong); dwid = dst->width*sizeof(ulong); mwid = par->mask->width*sizeof(ulong); if(src->data == dst->data && byteaddr(dst, par->r.min) > byteaddr(src, par->sr.min)){ dir = -1; }else dir = 1; lm = 0xFF>>(par->r.min.x&7); rm = 0xFF<<(8-(par->r.max.x&7)); dx -= (8-(par->r.min.x&7)) + (par->r.max.x&7); if(dx < 0){ /* one byte wide */ lm &= rm; if(dir == -1){ dp += dwid*(dy-1); sp += swid*(dy-1); mp += mwid*(dy-1); dwid = -dwid; swid = -swid; mwid = -mwid; } for(y=0; y<dy; y++){ *dp ^= (*dp ^ *sp) & *mp & lm; dp += dwid; sp += swid; mp += mwid; } return 1; } dx /= 8; if(dir == 1){ i = (lm!=0)+dx+(rm!=0); mwid -= i; swid -= i; dwid -= i; for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ if(lm){ *dp ^= (*dp ^ *sp++) & *mp++ & lm; dp++; } for(x=0; x<dx; x++){ *dp ^= (*dp ^ *sp++) & *mp++; dp++; } if(rm){ *dp ^= (*dp ^ *sp++) & *mp++ & rm; dp++; } } return 1; }else{ /* dir == -1 */ i = (lm!=0)+dx+(rm!=0); dp += dwid*(dy-1)+i-1; sp += swid*(dy-1)+i-1; mp += mwid*(dy-1)+i-1; dwid = -dwid+i; swid = -swid+i; mwid = -mwid+i; for(y=0; y<dy; y++, dp+=dwid, sp+=swid, mp+=mwid){ if(rm){ *dp ^= (*dp ^ *sp--) & *mp-- & rm; dp--; } for(x=0; x<dx; x++){ *dp ^= (*dp ^ *sp--) & *mp--; dp--; } if(lm){ *dp ^= (*dp ^ *sp--) & *mp-- & lm; dp--; } } } return 1; } return 0; }#undef DBG/* * Boolean character drawing. * Solid opaque color through a 1-bit greyscale mask. */#define DBG if(0)static intchardraw(Memdrawparam *par){ ulong bits; int i, ddepth, dy, dx, x, bx, ex, y, npack, bsh, depth, op; ulong v, maskwid, dstwid; uchar *wp, *rp, *q, *wc; ushort *ws; ulong *wl; uchar sp[4]; Rectangle r, mr; Memimage *mask, *src, *dst;if(0) if(drawdebug) iprint("chardraw? mf %lux md %d sf %lux dxs %d dys %d dd %d ddat %p sdat %p\n", par->mask->flags, par->mask->depth, par->src->flags, Dx(par->src->r), Dy(par->src->r), par->dst->depth, par->dst->data, par->src->data); mask = par->mask; src = par->src; dst = par->dst; r = par->r; mr = par->mr; op = par->op; if((par->state&(Replsrc|Simplesrc|Replmask)) != (Replsrc|Simplesrc) || mask->depth != 1 || src->flags&Falpha || dst->depth<8 || dst->data==src->data || op != SoverD) return 0;//if(drawdebug) iprint("chardraw..."); depth = mask->depth; maskwid = mask->width*sizeof(ulong); rp = byteaddr(mask, mr.min); npack = 8/depth; bsh = (mr.min.x % npack) * depth; wp = byteaddr(dst, r.min); dstwid = dst->width*sizeof(ulong);DBG print("bsh %d\n", bsh); dy = Dy(r); dx = Dx(r); ddepth = dst->depth; /* * for loop counts from bsh to bsh+dx * * we want the bottom bits to be the amount * to shift the pixels down, so for n≡0 (mod 8) we want * bottom bits 7. for n≡1, 6, etc. * the bits come from -n-1. */ bx = -bsh-1; ex = -bsh-1-dx; SET(bits); v = par->sdval; /* make little endian */ sp[0] = v; sp[1] = v>>8; sp[2] = v>>16; sp[3] = v>>24;//print("sp %x %x %x %x\n", sp[0], sp[1], sp[2], sp[3]); for(y=0; y<dy; y++, rp+=maskwid, wp+=dstwid){ q = rp; if(bsh) bits = *q++; switch(ddepth){ case 8://if(drawdebug) iprint("8loop..."); wc = wp; for(x=bx; x>ex; x--, wc++){ i = x&7; if(i == 8-1) bits = *q++;DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1) *wc = v; } break; case 16: ws = (ushort*)wp; v = *(ushort*)sp; for(x=bx; x>ex; x--, ws++){ i = x&7; if(i == 8-1) bits = *q++;DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1) *ws = v; } break; case 24: wc = wp; for(x=bx; x>ex; x--, wc+=3){ i = x&7; if(i == 8-1) bits = *q++;DBG print("bits %lux sh %d...", bits, i); if((bits>>i)&1){ wc[0] = sp[0]; wc[1] = sp[1]; wc[2] = sp[2]; } } break; case 32: wl = (ulong*)wp; v = *(ulong*)sp; for(x=bx; x>ex; x--, wl++){ i = x&7; if(i == 8-1) bits = *q++;DBG iprint("bits %lux sh %d...", bits, i); if((bits>>i)&1) *wl = v; } break; } }DBG print("\n"); return 1; }#undef DBG/* * Fill entire byte with replicated (if necessary) copy of source pixel, * assuming destination ldepth is >= source ldepth. * * This code is just plain wrong for >8bpp. *ulongmembyteval(Memimage *src){ int i, val, bpp; uchar uc; unloadmemimage(src, src->r, &uc, 1); bpp = src->depth; uc <<= (src->r.min.x&(7/src->depth))*src->depth; uc &= ~(0xFF>>bpp); /* pixel value is now in high part of byte. repeat throughout byte val = uc; for(i=bpp; i<8; i<<=1) val |= val>>i; return val;} * */voidmemfillcolor(Memimage *i, ulong val){ ulong bits; int d, y; if(val == DNofill) return; bits = rgbatoimg(i, val); switch(i->depth){ case 24: /* 24-bit images suck */ for(y=i->r.min.y; y<i->r.max.y; y++) memset24(byteaddr(i, Pt(i->r.min.x, y)), bits, Dx(i->r)); break; default: /* 1, 2, 4, 8, 16, 32 */ for(d=i->depth; d<32; d*=2) bits = (bits << d) | bits; memsetl(wordaddr(i, i->r.min), bits, i->width*Dy(i->r)); break; }}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -