www.pudn.com > emGUI.rar > draw.c


/* 
 *  Drawing Layer 
 * 
 * 
 *  COPYRIGHT (c) 2001 - 2010. 
 *  emTech System Corporation. 
 * 
 *  The license and distribution terms for this file may be 
 *  found in found in the file LICENSE. 
 */ 
 
/*	Huangf emcore@263.net 
 */ 
  
#include "emGUI.h" 
 
static void 
extendrow(int y,int x1,int y1,int x2,int y2, int *minxptr,int *maxxptr); 
 
void GrLine( 
	WndID 		id,  
	GC_ID 		gc,  
	int 		x1,  
	int 		y1,  
	int 		x2,  
	int 		y2, 
	boolean 	bDrawLastPoint 
) 
{ 
	 
	int c, mode; 
	unsigned short *pmem; 
  	int xdelta;			/* width of rectangle around line */ 
  	int ydelta;			/* height of rectangle around line */ 
  	int xinc;			/* increment for moving x coordinate */ 
  	int yinc;			/* increment for moving y coordinate */ 
  	int rem;			/* current remainder */ 
  	 
	c 		= gc->fcolor; 
	mode 	= gc->mode; 
	pmem	= WndDrawMemory(id); 
	if (pmem == NULL){ 
		return ; 
	} 
	 
	if (x1 < 0 || y1 < 0 || x2 < 0 || y2 < 0) 
		return; 
 
	/*  change to absolute cood */ 
	x1 += id->left; 
	x2 += id->left; 
	y1 += id->top; 
	y2 += id->top; 
	 
	if (x1 == x2){ 
		DrawVertLine( 
			pmem,  
			x1,  
			y1,  
			y2, 
			c, 
			mode			 
		); 
 
		return; 
	} 
 
	if (y1 == y2){ 
		DrawHorzLine( 
			pmem,  
			x1,  
			y1, 
			x2,  
			c,  
			mode 
		); 
		 
		return; 
	} 
 
	/*	The line may be partially obscured. Do the draw line algorithm 
	 * 	checking each point against the clipping regions. 
   	 */ 
  	xdelta = x2 - x1; 
  	ydelta = y2 - y1; 
  	if (xdelta < 0) xdelta = -xdelta; 
  	if (ydelta < 0) ydelta = -ydelta; 
  	xinc = (x2 > x1) ? 1 : -1; 
  	yinc = (y2 > y1) ? 1 : -1; 
	DrawPixel( 
		pmem, 
		x1,  
		y1,  
		c, 
		mode 
	); 
	 
	if (xdelta >= ydelta) { 
		rem = xdelta / 2; 
		for(;;) { 
			if(!bDrawLastPoint && x1 == x2) 
				break; 
			x1 += xinc; 
			rem += ydelta; 
			if (rem >= xdelta) { 
				rem -= xdelta; 
				y1 += yinc; 
			} 
			DrawPixel( 
				pmem, 
				x1,  
				y1,  
				c, 
				mode 
			); 
			if(bDrawLastPoint && x1 == x2) 
				break; 
		} 
  	}  
  	else { 
		rem = ydelta / 2; 
		for(;;) { 
			if(!bDrawLastPoint && y1 == y2) 
				break; 
			y1 += yinc; 
			rem += xdelta; 
			if (rem >= ydelta) { 
				rem -= ydelta; 
				x1 += xinc; 
			} 
			DrawPixel( 
				pmem, 
				x1,  
				y1,  
				c, 
				mode 
			); 
			if(bDrawLastPoint && y1 == y2) 
				break; 
		} 
	} 
 
} 
 
void GrPoint( 
	WndID id,  
	GC_ID gc,  
	int x,  
	int y 
) 
{ 
	int c, mode; 
	unsigned short *pmem; 
 
	if (x < 0 || y < 0) 
		return; 
		 
	pmem 	= WndDrawMemory(id); 
	if (pmem == NULL){ 
		return; 
	} 
 
	x += id->left; 
	y += id->top; 
	 
	c 		= gc->fcolor; 
	mode 	= gc->mode;	 
	DrawPixel( 
		pmem, 
		x, 
		y, 
		c, 
		mode 
	); 
} 
 
void GrRect( 
	WndID id,  
	GC_ID gc,  
	int x,  
	int y, 
	int width,  
	int height 
) 
{ 
	int maxx; 
  	int maxy; 
	int mode; 
	unsigned short *pmem; 
	int c; 
	 
	pmem = WndDrawMemory(id); 
	if (pmem == NULL){ 
		return; 
	} 
 
	c = gc->fcolor; 
	mode = gc->mode; 
 
  	if (width <= 0 || height <= 0) 
	  	return; 
 
	x += id->left; 
	y += id->top; 
	 
  	maxx = x + width - 1; 
  	maxy = y + height - 1; 
  	DrawHorzLine( 
		pmem, 
		x, 
		y, 
		maxx, 
		c, 
		mode 
	); 
	 
  	if (height > 1) 
	  DrawHorzLine( 
	  	pmem,  
	  	x,  
	  	maxx,  
	  	maxy, 
	  	c, 
	  	mode 
	); 
	 
  	if (height < 3) 
		return; 
		 
  	y++; 
  	maxy--; 
  	DrawVertLine(pmem, x, y, maxy, c, mode); 
  	if (width > 1) 
	  	DrawVertLine( 
	  		pmem, 
	  		maxx, 
	  		y, 
	  		maxy, 
	  		c, 
	  		mode 
	  	);	 
}   
	 
void GrFillRect( 
	WndID id,  
	GC_ID gc,  
	int x,  
	int y, 
	int width,  
	int height 
) 
{ 
	int x1, y1; 
	int c; 
	unsigned short *pmem; 
	if (id == NULL){ 
		return; 
	} 
	if (x < 0 || y < 0 || width < 0 || height < 0){ 
		return; 
	} 
	x1 		= x + width; 
	y1 		= y + height; 
	c 		= gc->fcolor; 
	pmem 	= WndDrawMemory(id); 
	FillRect( 
		pmem, 
		x, 
		y, 
		x1,  
		y1, 
		c 
	); 
} 
 
void GrPoly( 
	WndID 	wId,  
	GID 	gId,  
	int 	count,  
	LPPOINT points 
) 
{ 
	int	firstx; 
	int	firsty; 
	int	didline; 
	unsigned short *pmem; 
	int	c, mode; 
	 
	pmem = WndDrawMemory(wId); 
	if (pmem == NULL){ 
		return; 
	} 
	 
	if (count < 2) 
	  return; 
	 
	c 		= gId->fcolor; 
	mode	= gId->mode; 
	 
	firstx 	= points->x; 
	firsty 	= points->y; 
	didline = FALSE; 
	 
	while (count-- > 1) { 
		if (didline && (gId->mode == GR_XOR)) 
			DrawPixel(pmem, points->x + wId->left, points->y + wId->top, c, mode); 
		 
		GrLine(wId, gId, points[0].x, points[0].y, points[1].x, points[1].y, TRUE); 
		points++; 
		didline = TRUE; 
	} 
	 
	if (gId->mode == GR_XOR) { 
		points--; 
		if (points->x == firstx && points->y == firsty){ 
			DrawPixel(pmem, points->x + wId->left, points->y + wId->top, c, mode); 
		} 
	} 
} 
 
/* 
 * Fill a polygon in the foreground color, applying clipping if necessary. 
 * The last point may be a duplicate of the first point, but this is 
 * not required. 
 * Note: this routine currently only correctly fills convex polygons. 
 */ 
void  
GrFillPoly( 
	WndID 	wId,  
	GID 	gId,  
	int 	count,  
	LPPOINT points) 
{ 
	LPPOINT pp;		/* current point */ 
	int		miny;	/* minimum row */ 
	int		maxy;	/* maximum row */ 
	int		minx;	/* minimum column */ 
	int		maxx;	/* maximum column */ 
	int		i;		/* counter */ 
	unsigned short *pmem; 
	int	c, mode; 
	 
	pmem = WndDrawMemory(wId); 
	if (pmem == NULL){ 
		return; 
	} 
	 
	 
	if (count <= 0) 
		return; 
	 
	c 		= gId->fcolor; 
	mode	= gId->mode; 
 
	/* First determine the minimum and maximum rows for the polygon. */ 
	pp   = points; 
	miny = pp->y; 
	maxy = pp->y; 
	for (i = count; i-- > 0; pp++) { 
		if (miny > pp->y)  
			miny = pp->y; 
		if (maxy < pp->y)  
			maxy = pp->y; 
	} 
	 
	if (miny < 0) 
		miny = 0; 
 
/*		 
	if (maxy >= psd->yvirtres) 
		maxy = psd->yvirtres - 1; 
*/		 
	if (miny > maxy) 
		return; 
	 
	/* Now for each row, scan the list of points and determine the 
	 * minimum and maximum x coordinate for each line, and plot the row. 
	 * The last point connects with the first point automatically. 
	 */ 
	for (; miny <= maxy; miny++) { 
		minx = 0x0FFFFFFF; 
		maxx = 0x00000000; 
		pp 	 = points; 
		 
		for (i = count; --i > 0; pp++) 
			extendrow(miny, pp[0].x, pp[0].y, pp[1].x, pp[1].y,	&minx, &maxx); 
			 
		extendrow(miny, pp[0].x, pp[0].y, points[0].x, points[0].y,	&minx, &maxx); 
		 
		if (minx <= maxx){ 
			DrawHorzLine(pmem, minx + wId->left, miny + wId->top, maxx + wId->left, c, mode); 
		} 
	} 
} 
 
/* Utility routine for filling polygons.  Find the intersection point (if 
 * any) of a horizontal line with an arbitrary line, and extend the current 
 * minimum and maximum x values as needed to include the intersection point. 
 * Input parms: 
 *	y 	row to check for intersection 
 *	x1, y1	first endpoint 
 *	x2, y2	second enpoint 
 *	minxptr	address of current minimum x 
 *	maxxptr	address of current maximum x 
 */ 
static void 
extendrow( 
	int y, 
	int x1, 
	int y1, 
	int x2, 
	int y2, 
	int *minxptr, 
	int *maxxptr 
) 
{ 
	int x;			/* x coordinate of intersection */ 
	long num;			/* numerator of fraction */ 
	 
	/* First make sure the specified line segment includes the specified 
	 * row number.  If not, then there is no intersection. 
	 */ 
	if (((y < y1) || (y > y2)) && ((y < y2) || (y > y1))) 
		return; 
	 
	/* If a horizontal line, then check the two endpoints. */ 
	if (y1 == y2) { 
		if (*minxptr > x1)  
			*minxptr = x1; 
			 
		if (*minxptr > x2)  
			*minxptr = x2; 
			 
		if (*maxxptr < x1)  
			*maxxptr = x1; 
		 
		if (*maxxptr < x2)  
			*maxxptr = x2; 
		return; 
	} 
	 
	/* If a vertical line, then check the x coordinate. */ 
	if (x1 == x2) { 
		if (*minxptr > x1)  
			*minxptr = x1; 
		if (*maxxptr < x1)  
			*maxxptr = x1; 
		return; 
	} 
 
	/* An arbitrary line.  Calculate the intersection point using the 
	 * formula x = x1 + (y - y1) * (x2 - x1) / (y2 - y1). 
	 */ 
	num = ((long) (y - y1)) * (x2 - x1); 
	x = x1 + num / (y2 - y1); 
	if (*minxptr > x)  
		*minxptr = x; 
		 
	if (*maxxptr < x)  
		*maxxptr = x; 
} 
 
/* 
 * Draw a rectangular area using the current clipping region and the 
 * specified bit map.  This differs from rectangle drawing in that the 
 * rectangle is drawn using the foreground color and possibly the background 
 * color as determined by the bit map.  Each row of bits is aligned to the 
 * next bitmap word boundary (so there is padding at the end of the row). 
 * The background bit values are only written if the gr_usebg flag 
 * is set. 
 */ 
void 
GrBitmap( 
	WndID	win,  
	GID		gc, 
	int	 	x,  
	int 	y,  
	int 	width,  
	int 	height, 
	MWIMAGEBITS *imagebits 
) 
{ 
  	int minx; 
  	int maxx; 
  	MWIMAGEBITS bitvalue = 0;	/* bitmap word value */ 
  	int bitcount;			/* number of bits left in bitmap word */ 
 
	GrFillRect(win, gc, x, y, width, height); 
  	minx = x; 
  	maxx = x + width - 1; 
  	bitcount = 0; 
  	while (height > 0) { 
		if (bitcount <= 0) { 
			bitcount = MWIMAGE_BITSPERIMAGE; 
			bitvalue = *imagebits++; 
		} 
		if (MWIMAGE_TESTBIT(bitvalue)){ 
			GrPoint(win, gc, x, y); 
		} 
		bitvalue = MWIMAGE_SHIFTBIT(bitvalue); 
		bitcount--; 
		if (x++ == maxx) { 
			x = minx; 
			y++; 
			height--; 
			bitcount = 0; 
		} 
  } 
}