📄 devdraw.c
字号:
/* * 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. */intGdSetMode(int mode){ int oldmode = gr_mode; gr_mode = 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(MWPIXELVAL fg){ MWPIXELVAL oldfg = gr_foreground; gr_foreground = fg; return oldfg;}/* * Set the background color for bitmap and text backgrounds. */MWPIXELVALGdSetBackground(MWPIXELVAL bg){ MWPIXELVAL oldbg = gr_background; gr_background = bg; return oldbg;}/* * 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; /* 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*/ 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); 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 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); 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. */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){ 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. */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. */voidGdMakePaletteConversionTable(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 0 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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -