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

📄 devdraw.c

📁 开放源码实时操作系统源码.
💻 C
📖 第 1 页 / 共 3 页
字号:
/*
 * Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com>
 * Portions Copyright (c) 1991 David I. Bell
 * Permission is granted to use, distribute, or modify this source,
 * provided that this copyright notice remains intact.
 *
 * Device-independent mid level drawing and color routines.
 *
 * These routines do the necessary range checking, clipping, and cursor
 * overwriting checks, and then call the lower level device dependent
 * routines to actually do the drawing.  The lower level routines are
 * only called when it is known that all the pixels to be drawn are
 * within the device area and are visible.
 */
/*#define NDEBUG*/
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#include "device.h"

extern MWPIXELVAL gr_foreground;      /* current foreground color */
extern MWPIXELVAL gr_background;      /* current background color */
extern MWBOOL 	  gr_usebg;    	      /* TRUE if background drawn in pixmaps */
extern int 	  gr_mode; 	      /* drawing mode */
extern MWPALENTRY gr_palette[256];    /* current palette*/
extern int	  gr_firstuserpalentry;/* first user-changable palette entry*/
extern int 	  gr_nextpalentry;    /* next available palette entry*/

/*static*/ void drawpoint(PSD psd,MWCOORD x, MWCOORD y);
/*static*/ void drawrow(PSD psd,MWCOORD x1,MWCOORD x2,MWCOORD y);
static void drawcol(PSD psd,MWCOORD x,MWCOORD y1,MWCOORD y2);

/*
 * Set the drawing mode for future calls.
 */
int
GdSetMode(int mode)
{
	int	oldmode = gr_mode;

	gr_mode = mode;
	return oldmode;
}

/*
 * Set whether or not the background is used for drawing pixmaps and text.
 */
MWBOOL
GdSetUseBackground(MWBOOL flag)
{
	MWBOOL	oldusebg = gr_usebg;

	gr_usebg = flag;
	return oldusebg;
}

/*
 * Set the foreground color for drawing.
 */
MWPIXELVAL
GdSetForeground(MWPIXELVAL fg)
{
	MWPIXELVAL	oldfg = gr_foreground;

	gr_foreground = fg;
	return oldfg;
}

/*
 * Set the background color for bitmap and text backgrounds.
 */
MWPIXELVAL
GdSetBackground(MWPIXELVAL bg)
{
	MWPIXELVAL	oldbg = gr_background;

	gr_background = bg;
	return oldbg;
}

/*
 * Draw a point using the current clipping region and foreground color.
 */
void
GdPoint(PSD psd, MWCOORD x, MWCOORD y)
{
	if (GdClipPoint(psd, x, y)) {
		psd->DrawPixel(psd, x, y, gr_foreground);
		GdFixCursor(psd);
	}
}

/*
 * Draw an arbitrary line using the current clipping region and foreground color
 * If bDrawLastPoint is FALSE, draw up to but not including point x2, y2.
 *
 * This routine is the only routine that adjusts coordinates for supporting
 * two different types of upper levels, those that draw the last point
 * in a line, and those that draw up to the last point.  All other local
 * routines draw the last point.  This gives this routine a bit more overhead,
 * but keeps overall complexity down.
 */
void
GdLine(PSD psd, MWCOORD x1, MWCOORD y1, MWCOORD x2, MWCOORD y2,
	MWBOOL bDrawLastPoint)
{
  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 */
  MWCOORD temp;

  /* See if the line is horizontal or vertical. If so, then call
   * special routines.
   */
  if (y1 == y2) {
	/*
	 * Adjust coordinates if not drawing last point.  Tricky.
	 */
	if(!bDrawLastPoint) {
		if (x1 > x2) {
			temp = x1;
			x1 = x2 + 1;
			x2 = temp;
		} else
			--x2;
	}

	/* call faster line drawing routine*/
	drawrow(psd, x1, x2, y1);
	GdFixCursor(psd);
	return;
  }
  if (x1 == x2) {
	/*
	 * Adjust coordinates if not drawing last point.  Tricky.
	 */
	if(!bDrawLastPoint) {
		if (y1 > y2) {
			temp = y1;
			y1 = y2 + 1;
			y2 = temp;
		} else
			--y2;
	}

	/* call faster line drawing routine*/
	drawcol(psd, x1, y1, y2);
	GdFixCursor(psd);
	return;
  }

  /* See if the line is either totally visible or totally invisible. If
   * so, then the line drawing is easy.
   */
  switch (GdClipArea(psd, x1, y1, x2, y2)) {
      case CLIP_VISIBLE:
	/*
	 * For size considerations, there's no low-level bresenham
	 * line draw, so we've got to draw all non-vertical
	 * and non-horizontal lines with per-point
	 * clipping for the time being
	psd->Line(psd, x1, y1, x2, y2, gr_foreground);
	GdFixCursor(psd);
	return;
	 */
	break;
      case CLIP_INVISIBLE:
	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;
  if (GdClipPoint(psd, x1, y1))
	  psd->DrawPixel(psd, x1, y1, gr_foreground);
  if (xdelta >= ydelta) {
	rem = xdelta / 2;
	for(;;) {
		if(!bDrawLastPoint && x1 == x2)
			break;
		x1 += xinc;
		rem += ydelta;
		if (rem >= xdelta) {
			rem -= xdelta;
			y1 += yinc;
		}
		if (GdClipPoint(psd, x1, y1))
			psd->DrawPixel(psd, x1, y1, gr_foreground);
		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;
		}
		if (GdClipPoint(psd, x1, y1))
			psd->DrawPixel(psd, x1, y1, gr_foreground);
		if(bDrawLastPoint && y1 == y2)
			break;
	}
  }
  GdFixCursor(psd);
}

/* Draw a point in the foreground color, applying clipping if necessary*/
/*static*/ void
drawpoint(PSD psd, MWCOORD x, MWCOORD y)
{
	if (GdClipPoint(psd, x, y))
		psd->DrawPixel(psd, x, y, gr_foreground);
}

/* Draw a horizontal line from x1 to and including x2 in the
 * foreground color, applying clipping if necessary.
 */
/*static*/ void
drawrow(PSD psd, MWCOORD x1, MWCOORD x2, MWCOORD y)
{
  MWCOORD temp;

  /* reverse endpoints if necessary*/
  if (x1 > x2) {
	temp = x1;
	x1 = x2;
	x2 = temp;
  }

  /* clip to physical device*/
  if (x1 < 0)
	  x1 = 0;
  if (x2 >= psd->xvirtres)
	  x2 = psd->xvirtres - 1;

  /* check cursor intersect once for whole line*/
  GdCheckCursor(psd, x1, y, x2, y);

  while (x1 <= x2) {
	if (GdClipPoint(psd, x1, y)) {
		temp = MWMIN(clipmaxx, x2);
		psd->DrawHorzLine(psd, x1, temp, y, gr_foreground);
	} else
		temp = MWMIN(clipmaxx, x2);
	x1 = temp + 1;
  }
}

/* Draw a vertical line from y1 to and including y2 in the
 * foreground color, applying clipping if necessary.
 */
static void
drawcol(PSD psd, MWCOORD x,MWCOORD y1,MWCOORD y2)
{
  MWCOORD temp;

  /* reverse endpoints if necessary*/
  if (y1 > y2) {
	temp = y1;
	y1 = y2;
	y2 = temp;
  }

  /* clip to physical device*/
  if (y1 < 0)
	  y1 = 0;
  if (y2 >= psd->yvirtres)
	  y2 = psd->yvirtres - 1;

  /* check cursor intersect once for whole line*/
  GdCheckCursor(psd, x, y1, x, y2);

  while (y1 <= y2) {
	if (GdClipPoint(psd, x, y1)) {
		temp = MWMIN(clipmaxy, y2);
		psd->DrawVertLine(psd, x, y1, temp, gr_foreground);
	} else
		temp = MWMIN(clipmaxy, y2);
	y1 = temp + 1;
  }
}

/* Draw a rectangle in the foreground color, applying clipping if necessary.
 * This is careful to not draw points multiple times in case the rectangle
 * is being drawn using XOR.
 */
void
GdRect(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height)
{
  MWCOORD maxx;
  MWCOORD maxy;

  if (width <= 0 || height <= 0)
	  return;
  maxx = x + width - 1;
  maxy = y + height - 1;
  drawrow(psd, x, maxx, y);
  if (height > 1)
	  drawrow(psd, x, maxx, maxy);
  if (height < 3)
	  return;
  y++;
  maxy--;
  drawcol(psd, x, y, maxy);
  if (width > 1)
	  drawcol(psd, maxx, y, maxy);
  GdFixCursor(psd);
}

/* Draw a filled in rectangle in the foreground color, applying
 * clipping if necessary.
 */
void
GdFillRect(PSD psd, MWCOORD x1, MWCOORD y1, MWCOORD width, MWCOORD height)
{
  MWCOORD x2 = x1+width-1;
  MWCOORD y2 = y1+height-1;

  if (width <= 0 || height <= 0)
	  return;

  /* See if the rectangle is either totally visible or totally
   * invisible. If so, then the rectangle drawing is easy.
   */
  switch (GdClipArea(psd, x1, y1, x2, y2)) {
      case CLIP_VISIBLE:
	psd->FillRect(psd, x1, y1, x2, y2, gr_foreground);
	GdFixCursor(psd);
	return;

      case CLIP_INVISIBLE:
	return;
  }

  /* The rectangle may be partially obstructed. So do it line by line. */
  while (y1 <= y2)
	  drawrow(psd, x1, x2, y1++);
  GdFixCursor(psd);
}

/*
 * 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
GdBitmap(PSD psd, MWCOORD x, MWCOORD y, MWCOORD width, MWCOORD height,
	MWIMAGEBITS *imagebits)
{
  MWCOORD minx;
  MWCOORD maxx;
  MWPIXELVAL savecolor;		/* saved foreground color */
  MWIMAGEBITS bitvalue = 0;	/* bitmap word value */
  int bitcount;			/* number of bits left in bitmap word */

  switch (GdClipArea(psd, x, y, x + width - 1, y + height - 1)) {
      case CLIP_VISIBLE:
	/*
	 * For size considerations, there's no low-level bitmap
	 * draw so we've got to draw everything with per-point
	 * clipping for the time being.
	if (gr_usebg)
		psd->FillRect(psd, x, y, x + width - 1, y + height - 1,
			gr_background);
	psd->DrawBitmap(psd, x, y, width, height, imagebits, gr_foreground);
	return;
	*/
	break;

      case CLIP_INVISIBLE:
	return;
  }

  /* The rectangle is partially visible, so must do clipping. First
   * fill a rectangle in the background color if necessary.
   */
  if (gr_usebg) {
	savecolor = gr_foreground;
	gr_foreground = gr_background;
	/* note: change to fillrect*/
	GdFillRect(psd, x, y, width, height);
	gr_foreground = savecolor;
  }
  minx = x;
  maxx = x + width - 1;
  bitcount = 0;
  while (height > 0) {
	if (bitcount <= 0) {
		bitcount = MWIMAGE_BITSPERIMAGE;
		bitvalue = *imagebits++;
	}
	if (MWIMAGE_TESTBIT(bitvalue) && GdClipPoint(psd, x, y))
		psd->DrawPixel(psd, x, y, gr_foreground);
	bitvalue = MWIMAGE_SHIFTBIT(bitvalue);
	bitcount--;
	if (x++ == maxx) {
		x = minx;
		y++;
		height--;
		bitcount = 0;
	}
  }
  GdFixCursor(psd);
}

/*
 * Return true if color is in palette
 */
MWBOOL
GdColorInPalette(MWCOLORVAL cr,MWPALENTRY *palette,int palsize)
{
	int	i;

	for(i=0; i<palsize; ++i)
		if(GETPALENTRY(palette, i) == cr)
			return TRUE;
	return FALSE;
}

/*
 * Create a MWPIXELVAL conversion table between the passed palette
 * and the in-use palette.  The system palette is loaded/merged according
 * to fLoadType.
 */
void
GdMakePaletteConversionTable(PSD psd,MWPALENTRY *palette,int palsize,
	MWPIXELVAL *convtable,int fLoadType)
{
	int		i;
	MWCOLORVAL	cr;
	int		newsize, nextentry;
	MWPALENTRY	newpal[256];

	/*
	 * Check for load palette completely, or add colors
	 * from passed palette to system palette until full.
	 */
	if(psd->pixtype == MWPF_PALETTE) {
	    switch(fLoadType) {
	    case LOADPALETTE:
		/* Load palette from beginning with image's palette.
		 * First palette entries are Microwindows colors
		 * and not changed.
		 */
		GdSetPalette(psd, gr_firstuserpalentry, palsize, palette);
		break;

	    case MERGEPALETTE:
		/* get system palette*/
		for(i=0; i<(int)psd->ncolors; ++i)
			newpal[i] = gr_palette[i];

		/* merge passed palette into system palette*/
		newsize = 0;
		nextentry = gr_nextpalentry;

		/* if color missing and there's room, add it*/
		for(i=0; i<palsize && nextentry < (int)psd->ncolors; ++i) {
			cr = GETPALENTRY(palette, i);
			if(!GdColorInPalette(cr, newpal, nextentry)) {
				newpal[nextentry++] = palette[i];
				++newsize;
			}
		}

		/* set the new palette if any color was added*/
		if(newsize) {
			GdSetPalette(psd, gr_nextpalentry, newsize,
				&newpal[gr_nextpalentry]);
			gr_nextpalentry += newsize;
		}
		break;
	    }
	}

	/*
	 * Build conversion table from inuse system palette and
	 * passed palette.  This will load RGB values directly
	 * if running truecolor, otherwise it will find the
	 * nearest color from the inuse palette.
	 * FIXME: tag the conversion table to the bitmap image
	 */
	for(i=0; i<palsize; ++i) {

⌨️ 快捷键说明

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