📄 devdraw.org
字号:
/* * Copyright (c) 1999, 2000, 2001 Greg Haerr <greg@censoft.com> * Portions Copyright (c) 2002 by Koninklijke Philips Electronics N.V. * 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 <string.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*//* JHC - These support drawing dashed lines */extern unsigned long gr_dashmask; /* An actual bitmask of the dash values */extern unsigned long gr_dashcount; /* The number of bits defined in the dashmask */extern int gr_fillmode;/*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. */intGdSetMode(int mode){ int oldmode = gr_mode; gr_mode = mode; return oldmode;}intGdSetFillMode(int mode){ int oldmode = gr_fillmode; gr_fillmode = mode; return oldmode;}/* * Set whether or not the background is used for drawing pixmaps and text. */MWBOOLGdSetUseBackground(MWBOOL flag){ MWBOOL oldusebg = gr_usebg; gr_usebg = flag; return oldusebg;}/* * Set the foreground color for drawing. */MWPIXELVALGdSetForeground(PSD psd, MWPIXELVAL fg){ MWPIXELVAL oldfg = gr_foreground; gr_foreground = fg; return oldfg;}/* * Set the background color for bitmap and text backgrounds. */MWPIXELVALGdSetBackground(PSD psd, MWPIXELVAL bg){ MWPIXELVAL oldbg = gr_background; gr_background = bg; return oldbg;}/* * Set the foreground color for drawing. */MWPIXELVALGdSetForegroundColor(PSD psd, MWCOLORVAL fg){ MWPIXELVAL oldfg = gr_foreground; gr_foreground = GdFindColor(psd, fg); return oldfg;}/* * Set the background color for bitmap and text backgrounds. */MWPIXELVALGdSetBackgroundColor(PSD psd, MWCOLORVAL bg){ MWPIXELVAL oldbg = gr_background; gr_background = GdFindColor(psd, bg); return oldbg;}/* Set the dash mode for future drawing */voidGdSetDash(unsigned long *mask, int *count){ int oldm = gr_dashmask; int oldc = gr_dashcount; if (!mask || !count) return; gr_dashmask = *mask; gr_dashcount = *count; *mask = oldm; *count = oldc;}/* * Draw a point using the current clipping region and foreground color. */voidGdPoint(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. */voidGdLine(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; int bit = 0; /* Used for dashed lines */ /* 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 (gr_dashcount) { if (GdClipPoint(psd, x1, y1) && (gr_dashmask & (1 << bit))) psd->DrawPixel(psd, x1, y1, gr_foreground); bit = (bit + 1) % gr_dashcount; } else { /* No dashes */ 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 we are trying to draw to a dash mask */ if (gr_dashcount) { if (GdClipPoint(psd, x1, y1) && (gr_dashmask & (1 << bit))) psd->DrawPixel(psd, x1, y1, gr_foreground); bit = (bit + 1) % gr_dashcount; } else { /* No dashes */ 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*/ voiddrawpoint(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*/ voiddrawrow(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); /* If aren't trying to draw a dash, then head for the speed */ if (!gr_dashcount) { 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; } } else { int p, bit = 0; /* We want to draw a dashed line instead */ for(p = x1; p <= x2; p++) { if (GdClipPoint(psd, p, y) && (gr_dashmask & (1 << bit))) psd->DrawPixel(psd, p, y, gr_foreground); bit = (bit + 1) % gr_dashcount; } }}/* Draw a vertical line from y1 to and including y2 in the * foreground color, applying clipping if necessary. */static voiddrawcol(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); if (!gr_dashcount) { 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; } } else { int p, bit = 0; /* We want to draw a dashed line instead */ for(p = y1; p <= y2; p++) { if (GdClipPoint(psd, x, p) && (gr_dashmask & (1 << bit))) psd->DrawPixel(psd, x, p, gr_foreground); bit = (bit + 1) % gr_dashcount; } }}/* 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. */voidGdRect(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. */voidGdFillRect(PSD psd, MWCOORD x1, MWCOORD y1, MWCOORD width, MWCOORD height){ unsigned long dm = 0, dc = 0; MWCOORD x2 = x1+width-1; MWCOORD y2 = y1+height-1; if (width <= 0 || height <= 0) return; /* Stipples and tiles have their own drawing routines */ if (gr_fillmode != MWFILL_SOLID) { set_ts_origin(x1, y1); ts_fillrect(psd, x1, y1, width, height); GdFixCursor(psd); 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. */ /* Quickly save off the dash settings to avoid problems with drawrow */ GdSetDash(&dm, (int *) &dc); while (y1 <= y2) drawrow(psd, x1, x2, y1++); /* Restore the dash settings */ GdSetDash(&dm, (int *) &dc); 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. */voidGdBitmap(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 */MWBOOLGdColorInPalette(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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -