⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 draw.c

📁 这是一个同样来自贝尔实验室的和UNIX有着渊源的操作系统, 其简洁的设计和实现易于我们学习和理解
💻 C
📖 第 1 页 / 共 4 页
字号:
#include <u.h>#include <libc.h>#include <draw.h>#include <memdraw.h>#include <pool.h>extern Pool* imagmem;int drawdebug;static int	tablesbuilt;/* perfect approximation to NTSC = .299r+.587g+.114b when 0 ≤ r,g,b < 256 */#define RGB2K(r,g,b)	((156763*(r)+307758*(g)+59769*(b))>>19)/* * for 0 ≤ x ≤ 255*255, (x*0x0101+0x100)>>16 is a perfect approximation. * for 0 ≤ x < (1<<16), x/255 = ((x+1)*0x0101)>>16 is a perfect approximation. * the last one is perfect for all up to 1<<16, avoids a multiply, but requires a rathole. *//* #define DIV255(x) (((x)*257+256)>>16)  */#define DIV255(x) ((((x)+1)*257)>>16)/* #define DIV255(x) (tmp=(x)+1, (tmp+(tmp>>8))>>8) */#define MUL(x, y, t)	(t = (x)*(y)+128, (t+(t>>8))>>8)#define MASK13	0xFF00FF00#define MASK02	0x00FF00FF#define MUL13(a, x, t)		(t = (a)*(((x)&MASK13)>>8)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)#define MUL02(a, x, t)		(t = (a)*(((x)&MASK02)>>0)+128, ((t+((t>>8)&MASK02))>>8)&MASK02)#define MUL0123(a, x, s, t)	((MUL13(a, x, s)<<8)|MUL02(a, x, t))#define MUL2(u, v, x, y)	(t = (u)*(v)+(x)*(y)+256, (t+(t>>8))>>8)static void mktables(void);typedef int Subdraw(Memdrawparam*);static Subdraw chardraw, alphadraw, memoptdraw;static Memimage*	memones;static Memimage*	memzeros;Memimage *memwhite;Memimage *memblack;Memimage *memtransparent;Memimage *memopaque;int	_ifmt(Fmt*);voidmemimageinit(void){	static int didinit = 0;	if(didinit)		return;	didinit = 1;	if(strcmp(imagmem->name, "Image") == 0 || strcmp(imagmem->name, "image") == 0)		imagmem->move = memimagemove;	mktables();	_memmkcmap();	fmtinstall('R', Rfmt); 	fmtinstall('P', Pfmt);	fmtinstall('b', _ifmt);	memones = allocmemimage(Rect(0,0,1,1), GREY1);	memones->flags |= Frepl;	memones->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);	*byteaddr(memones, ZP) = ~0;	memzeros = allocmemimage(Rect(0,0,1,1), GREY1);	memzeros->flags |= Frepl;	memzeros->clipr = Rect(-0x3FFFFFF, -0x3FFFFFF, 0x3FFFFFF, 0x3FFFFFF);	*byteaddr(memzeros, ZP) = 0;	if(memones == nil || memzeros == nil)		assert(0 /*cannot initialize memimage library */);	/* RSC BUG */	memwhite = memones;	memblack = memzeros;	memopaque = memones;	memtransparent = memzeros;}static ulong imgtorgba(Memimage*, ulong);static ulong rgbatoimg(Memimage*, ulong);static ulong pixelbits(Memimage*, Point);#define DBG if(0)voidmemimagedraw(Memimage *dst, Rectangle r, Memimage *src, Point p0, Memimage *mask, Point p1, int op){	static int n = 0;	Memdrawparam par;	if(mask == nil)		mask = memopaque;DBG	print("memimagedraw %p/%luX %R @ %p %p/%luX %P %p/%luX %P... ", dst, dst->chan, r, dst->data->bdata, src, src->chan, p0, mask, mask->chan, p1);	if(drawclip(dst, &r, src, &p0, mask, &p1, &par.sr, &par.mr) == 0){//		if(drawdebug)//			iprint("empty clipped rectangle\n");		return;	}	if(op < Clear || op > SoverD){//		if(drawdebug)//			iprint("op out of range: %d\n", op);		return;	}	par.op = op;	par.dst = dst;	par.r = r;	par.src = src;	/* par.sr set by drawclip */	par.mask = mask;	/* par.mr set by drawclip */	par.state = 0;	if(src->flags&Frepl){		par.state |= Replsrc;		if(Dx(src->r)==1 && Dy(src->r)==1){			par.sval = pixelbits(src, src->r.min);			par.state |= Simplesrc;			par.srgba = imgtorgba(src, par.sval);			par.sdval = rgbatoimg(dst, par.srgba);			if((par.srgba&0xFF) == 0 && (op&DoutS)){//				if (drawdebug) iprint("fill with transparent source\n");				return;	/* no-op successfully handled */			}		}	}	if(mask->flags & Frepl){		par.state |= Replmask;		if(Dx(mask->r)==1 && Dy(mask->r)==1){			par.mval = pixelbits(mask, mask->r.min);			if(par.mval == 0 && (op&DoutS)){//				if(drawdebug) iprint("fill with zero mask\n");				return;	/* no-op successfully handled */			}			par.state |= Simplemask;			if(par.mval == ~0)				par.state |= Fullmask;			par.mrgba = imgtorgba(mask, par.mval);		}	}//	if(drawdebug)//		iprint("dr %R sr %R mr %R...", r, par.sr, par.mr);DBG print("draw dr %R sr %R mr %R %lux\n", r, par.sr, par.mr, par.state);	/*	 * Now that we've clipped the parameters down to be consistent, we 	 * simply try sub-drawing routines in order until we find one that was able	 * to handle us.  If the sub-drawing routine returns zero, it means it was	 * unable to satisfy the request, so we do not return.	 */	/*	 * Hardware support.  Each video driver provides this function,	 * which checks to see if there is anything it can help with.	 * There could be an if around this checking to see if dst is in video memory.	 */DBG print("test hwdraw\n");	if(hwdraw(&par)){//if(drawdebug) iprint("hw handled\n");DBG print("hwdraw handled\n");		return;	}	/*	 * Optimizations using memmove and memset.	 */DBG print("test memoptdraw\n");	if(memoptdraw(&par)){//if(drawdebug) iprint("memopt handled\n");DBG print("memopt handled\n");		return;	}	/*	 * Character drawing.	 * Solid source color being painted through a boolean mask onto a high res image.	 */DBG print("test chardraw\n");	if(chardraw(&par)){//if(drawdebug) iprint("chardraw handled\n");DBG print("chardraw handled\n");		return;	}	/*	 * General calculation-laden case that does alpha for each pixel.	 */DBG print("do alphadraw\n");	alphadraw(&par);//if(drawdebug) iprint("alphadraw handled\n");DBG print("alphadraw handled\n");}#undef DBG/* * Clip the destination rectangle further based on the properties of the  * source and mask rectangles.  Once the destination rectangle is properly * clipped, adjust the source and mask rectangles to be the same size. * Then if source or mask is replicated, move its clipped rectangle * so that its minimum point falls within the repl rectangle. * * Return zero if the final rectangle is null. */intdrawclip(Memimage *dst, Rectangle *r, Memimage *src, Point *p0, Memimage *mask, Point *p1, Rectangle *sr, Rectangle *mr){	Point rmin, delta;	int splitcoords;	Rectangle omr;	if(r->min.x>=r->max.x || r->min.y>=r->max.y)		return 0;	splitcoords = (p0->x!=p1->x) || (p0->y!=p1->y);	/* clip to destination */	rmin = r->min;	if(!rectclip(r, dst->r) || !rectclip(r, dst->clipr))		return 0;	/* move mask point */	p1->x += r->min.x-rmin.x;	p1->y += r->min.y-rmin.y;	/* move source point */	p0->x += r->min.x-rmin.x;	p0->y += r->min.y-rmin.y;	/* map destination rectangle into source */	sr->min = *p0;	sr->max.x = p0->x+Dx(*r);	sr->max.y = p0->y+Dy(*r);	/* sr is r in source coordinates; clip to source */	if(!(src->flags&Frepl) && !rectclip(sr, src->r))		return 0;	if(!rectclip(sr, src->clipr))		return 0;	/* compute and clip rectangle in mask */	if(splitcoords){		/* move mask point with source */		p1->x += sr->min.x-p0->x;		p1->y += sr->min.y-p0->y;		mr->min = *p1;		mr->max.x = p1->x+Dx(*sr);		mr->max.y = p1->y+Dy(*sr);		omr = *mr;		/* mr is now rectangle in mask; clip it */		if(!(mask->flags&Frepl) && !rectclip(mr, mask->r))			return 0;		if(!rectclip(mr, mask->clipr))			return 0;		/* reflect any clips back to source */		sr->min.x += mr->min.x-omr.min.x;		sr->min.y += mr->min.y-omr.min.y;		sr->max.x += mr->max.x-omr.max.x;		sr->max.y += mr->max.y-omr.max.y;		*p1 = mr->min;	}else{		if(!(mask->flags&Frepl) && !rectclip(sr, mask->r))			return 0;		if(!rectclip(sr, mask->clipr))			return 0;		*p1 = sr->min;	}	/* move source clipping back to destination */	delta.x = r->min.x - p0->x;	delta.y = r->min.y - p0->y;	r->min.x = sr->min.x + delta.x;	r->min.y = sr->min.y + delta.y;	r->max.x = sr->max.x + delta.x;	r->max.y = sr->max.y + delta.y;	/* move source rectangle so sr->min is in src->r */	if(src->flags&Frepl) {		delta.x = drawreplxy(src->r.min.x, src->r.max.x, sr->min.x) - sr->min.x;		delta.y = drawreplxy(src->r.min.y, src->r.max.y, sr->min.y) - sr->min.y;		sr->min.x += delta.x;		sr->min.y += delta.y;		sr->max.x += delta.x;		sr->max.y += delta.y;	}	*p0 = sr->min;	/* move mask point so it is in mask->r */	*p1 = drawrepl(mask->r, *p1);	mr->min = *p1;	mr->max.x = p1->x+Dx(*sr);	mr->max.y = p1->y+Dy(*sr);	assert(Dx(*sr) == Dx(*mr) && Dx(*mr) == Dx(*r));	assert(Dy(*sr) == Dy(*mr) && Dy(*mr) == Dy(*r));	assert(ptinrect(*p0, src->r));	assert(ptinrect(*p1, mask->r));	assert(ptinrect(r->min, dst->r));	return 1;}/* * Conversion tables. */static uchar replbit[1+8][256];		/* replbit[x][y] is the replication of the x-bit quantity y to 8-bit depth */static uchar conv18[256][8];		/* conv18[x][y] is the yth pixel in the depth-1 pixel x */static uchar conv28[256][4];		/* ... */static uchar conv48[256][2];/* * bitmap of how to replicate n bits to fill 8, for 1 ≤ n ≤ 8. * the X's are where to put the bottom (ones) bit of the n-bit pattern. * only the top 8 bits of the result are actually used. * (the lower 8 bits are needed to get bits in the right place * when n is not a divisor of 8.) * * Should check to see if its easier to just refer to replmul than * use the precomputed values in replbit.  On PCs it may well * be; on machines with slow multiply instructions it probably isn't. */#define a ((((((((((((((((0#define X *2+1)#define _ *2)static int replmul[1+8] = {	0,	a X X X X X X X X X X X X X X X X,	a _ X _ X _ X _ X _ X _ X _ X _ X,	a _ _ X _ _ X _ _ X _ _ X _ _ X _,	a _ _ _ X _ _ _ X _ _ _ X _ _ _ X,	a _ _ _ _ X _ _ _ _ X _ _ _ _ X _,	a _ _ _ _ _ X _ _ _ _ _ X _ _ _ _, 	a _ _ _ _ _ _ X _ _ _ _ _ _ X _ _,	a _ _ _ _ _ _ _ X _ _ _ _ _ _ _ X,};#undef a#undef X#undef _static voidmktables(void){	int i, j, mask, sh, small;			if(tablesbuilt)		return;	fmtinstall('R', Rfmt);	fmtinstall('P', Pfmt);	tablesbuilt = 1;	/* bit replication up to 8 bits */	for(i=0; i<256; i++){		for(j=0; j<=8; j++){	/* j <= 8 [sic] */			small = i & ((1<<j)-1);			replbit[j][i] = (small*replmul[j])>>8;		}	}	/* bit unpacking up to 8 bits, only powers of 2 */	for(i=0; i<256; i++){		for(j=0, sh=7, mask=1; j<8; j++, sh--)			conv18[i][j] = replbit[1][(i>>sh)&mask];		for(j=0, sh=6, mask=3; j<4; j++, sh-=2)			conv28[i][j] = replbit[2][(i>>sh)&mask];		for(j=0, sh=4, mask=15; j<2; j++, sh-=4)			conv48[i][j] = replbit[4][(i>>sh)&mask];	}}static uchar ones = 0xff;/* * General alpha drawing case.  Can handle anything. */typedef struct	Buffer	Buffer;struct Buffer {	/* used by most routines */	uchar	*red;	uchar	*grn;	uchar	*blu;	uchar	*alpha;	uchar	*grey;	ulong	*rgba;	int	delta;	/* number of bytes to add to pointer to get next pixel to the right */	/* used by boolcalc* for mask data */	uchar	*m;		/* ptr to mask data r.min byte; like p->bytermin */	int		mskip;	/* no. of left bits to skip in *m */	uchar	*bm;		/* ptr to mask data img->r.min byte; like p->bytey0s */	int		bmskip;	/* no. of left bits to skip in *bm */	uchar	*em;		/* ptr to mask data img->r.max.x byte; like p->bytey0e */	int		emskip;	/* no. of right bits to skip in *em */};typedef struct	Param	Param;typedef Buffer	Readfn(Param*, uchar*, int);typedef void	Writefn(Param*, uchar*, Buffer);typedef Buffer	Calcfn(Buffer, Buffer, Buffer, int, int, int);enum {	MAXBCACHE = 16};/* giant rathole to customize functions with */struct Param {	Readfn	*replcall;	Readfn	*greymaskcall;		Readfn	*convreadcall;	Writefn	*convwritecall;	Memimage *img;	Rectangle	r;	int	dx;	/* of r */	int	needbuf;	int	convgrey;	int	alphaonly;	uchar	*bytey0s;		/* byteaddr(Pt(img->r.min.x, img->r.min.y)) */	uchar	*bytermin;	/* byteaddr(Pt(r.min.x, img->r.min.y)) */	uchar	*bytey0e;		/* byteaddr(Pt(img->r.max.x, img->r.min.y)) */	int		bwidth;	int	replcache;	/* if set, cache buffers */	Buffer	bcache[MAXBCACHE];	ulong	bfilled;	uchar	*bufbase;	int	bufoff;	int	bufdelta;	int	dir;	int	convbufoff;	uchar	*convbuf;	Param	*convdpar;	int	convdx;};static uchar *drawbuf;static int	ndrawbuf;static int	mdrawbuf;static Readfn	greymaskread, replread, readptr;static Writefn	nullwrite;static Calcfn	alphacalc0, alphacalc14, alphacalc2810, alphacalc3679, alphacalc5, alphacalc11, alphacalcS;static Calcfn	boolcalc14, boolcalc236789, boolcalc1011;static Readfn*	readfn(Memimage*);static Readfn*	readalphafn(Memimage*);static Writefn*	writefn(Memimage*);static Calcfn*	boolcopyfn(Memimage*, Memimage*);static Readfn*	convfn(Memimage*, Param*, Memimage*, Param*, int*);static Readfn*	ptrfn(Memimage*);static Calcfn *alphacalc[Ncomp] = {	alphacalc0,		/* Clear */	alphacalc14,		/* DoutS */	alphacalc2810,		/* SoutD */	alphacalc3679,		/* DxorS */	alphacalc14,		/* DinS */	alphacalc5,		/* D */	alphacalc3679,		/* DatopS */	alphacalc3679,		/* DoverS */	alphacalc2810,		/* SinD */	alphacalc3679,		/* SatopD */	alphacalc2810,		/* S */	alphacalc11,		/* SoverD */};static Calcfn *boolcalc[Ncomp] ={	alphacalc0,		/* Clear */	boolcalc14,		/* DoutS */	boolcalc236789,		/* SoutD */	boolcalc236789,		/* DxorS */	boolcalc14,		/* DinS */	alphacalc5,		/* D */	boolcalc236789,		/* DatopS */	boolcalc236789,		/* DoverS */	boolcalc236789,		/* SinD */	boolcalc236789,		/* SatopD */	boolcalc1011,		/* S */	boolcalc1011,		/* SoverD */};/* * Avoid standard Lock, QLock so that can be used in kernel. */typedef struct Dbuf Dbuf;struct Dbuf{	uchar *p;	int n;	Param spar, mpar, dpar;	int inuse;};static Dbuf dbuf[10];static Dbuf*allocdbuf(void){	int i;	for(i=0; i<nelem(dbuf); i++){		if(dbuf[i].inuse)			continue;		if(!_tas(&dbuf[i].inuse))			return &dbuf[i];	}	return nil;}static voidgetparam(Param *p, Memimage *img, Rectangle r, int convgrey, int needbuf, int *ndrawbuf){	int nbuf;	memset(p, 0, sizeof *p);	p->img = img;	p->r = r;	p->dx = Dx(r);	p->needbuf = needbuf;	p->convgrey = convgrey;	assert(img->r.min.x <= r.min.x && r.min.x < img->r.max.x);	p->bytey0s = byteaddr(img, Pt(img->r.min.x, img->r.min.y));	p->bytermin = byteaddr(img, Pt(r.min.x, img->r.min.y));	p->bytey0e = byteaddr(img, Pt(img->r.max.x, img->r.min.y));	p->bwidth = sizeof(ulong)*img->width;	assert(p->bytey0s <= p->bytermin && p->bytermin <= p->bytey0e);	if(p->r.min.x == p->img->r.min.x)		assert(p->bytermin == p->bytey0s);	nbuf = 1;	if((img->flags&Frepl) && Dy(img->r) <= MAXBCACHE && Dy(img->r) < Dy(r)){		p->replcache = 1;		nbuf = Dy(img->r);	}	p->bufdelta = 4*p->dx;	p->bufoff = *ndrawbuf;	*ndrawbuf += p->bufdelta*nbuf;}static voidclipy(Memimage *img, int *y){	int dy;	dy = Dy(img->r);	if(*y == dy)		*y = 0;	else if(*y == -1)		*y = dy-1;	assert(0 <= *y && *y < dy);}static voiddumpbuf(char *s, Buffer b, int n){	int i;	uchar *p;		print("%s", s);	for(i=0; i<n; i++){		print(" ");		if(p=b.grey){			print(" k%.2uX", *p);			b.grey += b.delta;		}else{				if(p=b.red){				print(" r%.2uX", *p);				b.red += b.delta;			}			if(p=b.grn){				print(" g%.2uX", *p);				b.grn += b.delta;			}			if(p=b.blu){				print(" b%.2uX", *p);				b.blu += b.delta;			}		}		if((p=b.alpha) != &ones){			print(" α%.2uX", *p);			b.alpha += b.delta;		}	}	print("\n");}/* * For each scan line, we expand the pixels from source, mask, and destination * into byte-aligned red, green, blue, alpha, and grey channels.  If buffering is not * needed and the channels were already byte-aligned (grey8, rgb24, rgba32, rgb32), * the readers need not copy the data: they can simply return pointers to the data. * If the destination image is grey and the source is not, it is converted using the NTSC * formula. * * Once we have all the channels, we call either rgbcalc or greycalc, depending on  * whether the destination image is color.  This is allowed to overwrite the dst buffer (perhaps * the actual data, perhaps a copy) with its result.  It should only overwrite the dst buffer * with the same format (i.e. red bytes with red bytes, etc.)  A new buffer is returned from * the calculator, and that buffer is passed to a function to write it to the destination. * If the buffer is already pointing at the destination, the writing function is a no-op. */#define DBG if(0)static intalphadraw(Memdrawparam *par){	int isgrey, starty, endy, op;	int needbuf, dsty, srcy, masky;	int y, dir, dx, dy, ndrawbuf;	uchar *drawbuf;	Buffer bsrc, bdst, bmask;	Readfn *rdsrc, *rdmask, *rddst;	Calcfn *calc;	Writefn *wrdst;	Memimage *src, *mask, *dst;	Rectangle r, sr, mr;	Dbuf *z;	r = par->r;	dx = Dx(r);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -