📄 graphics.c
字号:
InitCheck(); return (colorOK);}void SetPenColor(string color){ int cindex; InitCheck(); if (checkMemory && !StringMatch(color, "Black") && !StringMatch(color, "White")) { CheckColorMemory(); checkMemory = FALSE; } cindex = FindColorName(color); if (cindex == -1) Error("Undefined color: %s", color); penColor = cindex;}string GetPenColor(void){ InitCheck(); return (colorTable[penColor].name);}void DefineColor(string name, double red, double green, double blue){ int cindex; InitCheck(); if (red < 0 || red > 1 || green < 0 || green > 1 || blue < 0 || blue > 1) { Error("DefineColor: All color intensities must be between 0 and 1"); } cindex = FindColorName(name); if (cindex == -1) { if (nColors == MaxColors) Error("DefineColor: Too many colors"); cindex = nColors++; } colorTable[cindex].name = CopyString(name); colorTable[cindex].red = red; colorTable[cindex].green = green; colorTable[cindex].blue = blue;}/* Section 7 -- Miscellaneous functions */void SetEraseMode(bool mode){ InitCheck(); eraseMode = mode;}bool GetEraseMode(void){ InitCheck(); return (eraseMode);}void SetWindowTitle(string title){ windowTitle = CopyString(title); if (initialized) { SetWTitle((WindowPtr) gWindow, PascalString(title)); }}string GetWindowTitle(void){ return (CopyString(windowTitle));}/* * Implementation notes: UpdateDisplay * ----------------------------------- * This implementation of this function is entirely dependent * on the implementation of the console.h interface. Calling * the I/O event procedure for the console when cnt is 0 and raw * mode is on has the effect of responding to one pending event * without performing any I/O operations. Repeating this call * as long as there are events therefore clears the event queue, * which will end up responding to any pending update events. */void UpdateDisplay(void){ EventRecord event; int cnt; InitCheck(); cnt = consoleFile.cnt; consoleFile.cnt = 0; csetmode(C_RAW, &consoleFile); while (EventAvail(everyEvent, &event) || event.what != nullEvent) { (void) consoleFile.proc(stdin, 0); } consoleFile.cnt = cnt; csetmode(C_ECHO, &consoleFile);}void Pause(double seconds){ long dummy; UpdateDisplay(); Delay(seconds * CLOCKS_PER_SEC, &dummy);}void ExitGraphics(void){ console_options.pause_atexit = FALSE; exit(0);}void SaveGraphicsState(void){ graphicsStateT sb; InitCheck(); sb = New(graphicsStateT); sb->cx = cx; sb->cy = cy; sb->font = textFont; sb->size = pointSize; sb->style = textStyle; sb->erase = eraseMode; sb->color = penColor; sb->link = stateStack; stateStack = sb;}void RestoreGraphicsState(void){ graphicsStateT sb; InitCheck(); if (stateStack == NULL) { Error("RestoreGraphicsState called before SaveGraphicsState"); } sb = stateStack; cx = sb->cx; cy = sb->cy; textFont = sb->font; pointSize = sb->size; textStyle = sb->style; eraseMode = sb->erase; penColor = sb->color; stateStack = sb->link; FreeBlock(sb);}double GetFullScreenWidth(void){ GrafPtr wPort; short xRes, yRes; GetWMgrPort(&wPort); ScreenRes(&xRes, &yRes); return ((double) RectWidth(&wPort->portRect) / xRes);}double GetFullScreenHeight(void){ GrafPtr wPort; short xRes, yRes; GetWMgrPort(&wPort); ScreenRes(&xRes, &yRes); return ((double) RectHeight(&wPort->portRect) / yRes);}void SetWindowSize(double width, double height){ if (initialized) return; windowWidth = width; windowHeight = height;}double GetXResolution(void){ short xRes, yRes; if (initialized) { return (xResolution); } else { ScreenRes(&xRes, &yRes); return (xRes); }}double GetYResolution(void){ short xRes, yRes; if (initialized) { return (yResolution); } else { ScreenRes(&xRes, &yRes); return (yRes); }}/* Private functions *//* * Function: InitCheck * Usage: InitCheck(); * ------------------- * This function merely ensures that the package has been * initialized before the client functions are called. */static void InitCheck(void){ if (!initialized) Error("InitGraphics has not been called");}/* * Function: InitGraphicsState * Usage: InitGraphicsState(); * --------------------------- * This function initializes the graphics state elements to * their default values. */static void InitGraphicsState(void){ cx = cy = 0; eraseMode = FALSE; textFont = "Default"; pointSize = DefaultSize; textStyle = Normal; stateStack = NULL; regionState = NoRegion; SetPenColor("Black");}/* * Function: EraseWindow * Usage: EraseWindow(); * --------------------- * This function erases all of the offscreen memory bits, * thereby clearing the screen image. Note that the portBits * array is typically larger than a Macintosh segment and * therefore cannot be cleared with array operations or memset. */static void EraseWindow(void){ GrafPtr saveWindow; Rect rect; int width, height; GetPort(&saveWindow); SetPort((WindowPtr) gWindow); width = RectWidth(&gWindow->port.portRect); height = RectHeight(&gWindow->port.portRect); SetRect(&rect, 0, 0, width, height); InvalRect(&rect); SetPort(saveWindow); CopyBits(&((GrafPtr) osWindow)->portBits, &((GrafPtr) osWindow)->portBits, &((GrafPtr) osWindow)->portRect, &((GrafPtr) osWindow)->portRect, srcBic, NULL);}/* * Function: CreateGraphicsWindow * Usage: CreateGraphicsWindow(); * ------------------------------ * This function creates the graphics window on the screen and * the offscreen memory to back it up. */static void CreateGraphicsWindow(void){ GrafPtr wPort; WindowPtr cWindow; double xScale, yScale, scaleFactor; double xSpace, ySpace; int gHeight, cHeight; int left, top; Rect bounds; long nBytes; void *base; GetWMgrPort(&wPort); ScreenRes(&xResolution, &yResolution); left = console_options.left; top = console_options.top; xSpace = InchesX(RectWidth(&wPort->portRect) - left) - RightMargin; ySpace = InchesY(RectHeight(&wPort->portRect) - top) - BottomMargin - ConsoleHeight - 2 * InchesY(TitleBarPixels); xScale = yScale = 1.0; if (windowWidth > xSpace) { xScale = xSpace / windowWidth; } if (windowHeight > ySpace) { yScale = ySpace / windowHeight; } scaleFactor = MinF(xScale, yScale); gHeight = PixelsY(windowHeight * scaleFactor) + TitleBarPixels; console_options.top += gHeight + PixelsY(WindowSeparation); console_options.nrows = ConsoleLines; console_options.title = "\pConsole Window"; printf("\n"); fflush(stdout); consoleFile = *stdout; cHeight = RectHeight(&((GrafPtr) stdout->window)->portRect); cWindow = (WindowPtr) stdout->window; SizeWindow(cWindow, PixelsX(DesiredWidth), cHeight, 0); MoveWindow(cWindow, left, console_options.top, TRUE); xResolution *= scaleFactor; yResolution *= scaleFactor; SetRectFromSize(&bounds, left, top, PixelsX(windowWidth), PixelsY(windowHeight)); colorOK = (TestDeviceAttribute(GetMainDevice(), gdDevType) != 0); if (colorOK) colorOK = CreateColorWindow(&bounds); if (!colorOK) { if (!CreateBWWindow(&bounds)) { Error("InitGraphics: Can't create window"); } } EraseWindow(); ShowWindow((WindowPtr) gWindow);}/* * Function: CreateColorWindow * Usage: success = CreateColorWindow(&bounds); * -------------------------------------------- * This function tries to create a color graphics window with * the specified bounds. If it succeeds, the resulting window * is stored in the global variable gWindow and the corresponding * offscreen bitmap is stored in the pseudowindow osWindow. The * function returns TRUE on success and FALSE on failure. */static bool CreateColorWindow(Rect *bounds){ CGrafPtr gPort, osPort; Rect visRect; int nColors; long nBytes; void *base; gWindow = (WindowPeek) NewCWindow(NULL, bounds, PascalString(windowTitle), FALSE, 0, (WindowPtr) -1, FALSE, 0); if (gWindow == NULL) return (FALSE); gPort = (CGrafPtr) gWindow; nColors = (*(*gPort->portPixMap)->pmTable)->ctSize + 1; if (nColors < MinColors) { DisposeWindow((WindowPtr) gWindow); return (FALSE); } osWindow = (WindowPeek) malloc(sizeof(CGrafPort)); if (osWindow == NULL) { DisposeWindow((WindowPtr) gWindow); return (FALSE); } osPort = (CGrafPtr) osWindow; *osPort = *gPort; if ((osPort->visRgn = NewRgn()) == NULL) { free(osWindow); DisposeWindow((WindowPtr) gWindow); return (FALSE); } visRect = *bounds; OffsetRect(&visRect, -bounds->left, -bounds->top); RectRgn(osPort->visRgn, &visRect); if ((osPort->portPixMap = NewPixMap()) == NULL) { free(osWindow); DisposeWindow((WindowPtr) gWindow); return (FALSE); } CopyPixMap(gPort->portPixMap, osPort->portPixMap); nBytes = (long) RectHeight(bounds) * ((*osPort->portPixMap)->rowBytes & 0x3FFF); base = calloc(nBytes, 1); if (base == NULL) { DisposePixMap(osPort->portPixMap); free(osWindow); DisposeWindow((WindowPtr) gWindow); return (FALSE); } (*osPort->portPixMap)->baseAddr = base; return (TRUE);}/* * Function: CreateBWWindow * Usage: success = CreateBWWindow(&bounds); * ----------------------------------------- * This function is identical to CreateColorWindow except that * it creates a black-and-white window. This function is used * if the device does not support color or if there is not * enough memory to create a color bitmap. */static bool CreateBWWindow(Rect *bounds){ GrafPtr gPort, osPort; Rect visRect; void *base; gWindow = (WindowPeek) NewWindow(NULL, bounds, PascalString(windowTitle), FALSE, 0, (WindowPtr) -1, FALSE, 0); if (gWindow == NULL) return (FALSE); gPort = (GrafPtr) gWindow; osWindow = (WindowPeek) malloc(sizeof(GrafPort)); if (osWindow == NULL) { DisposeWindow((WindowPtr) gWindow); return (FALSE); } osPort = (GrafPtr) osWindow; *osPort = *gPort; if ((osPort->visRgn = NewRgn()) == NULL) { free(osWindow); DisposeWindow((WindowPtr) gWindow); return (FALSE); } visRect = *bounds; OffsetRect(&visRect, -bounds->left, -bounds->top); RectRgn(osPort->visRgn, &visRect); base = calloc((long) RectHeight(bounds) * osPort->portBits.rowBytes, 1); if (base == NULL) { free(osWindow); DisposeWindow((WindowPtr) gWindow); return (FALSE); } osPort->portBits.baseAddr = base; return (TRUE);}/* * Function: PrepareToDraw * Usage: PrepareToDraw(); * ----------------------- * This function must be called before any rendering operation * to ensure the pen modes and colors are correctly set. The * port must already be selected when this function is called. */static void PrepareToDraw(void){ bool erase; RGBColor color; erase = eraseMode; if (colorOK) { color.red = colorTable[penColor].red * 0xFFFFL; color.green = colorTable[penColor].green * 0xFFFFL; color.blue = colorTable[penColor].blue * 0xFFFFL; RGBForeColor(&color); } else { if (ShouldBeWhite()) erase = TRUE; } PenMode((erase) ? patBic : patCopy); TextMode((erase) ? srcBic : srcOr);}/* * Function: PrepareToDrawText * Usage: PrepareToDrawText(); * --------------------------- * This function must be called before any text rendering operation. * The port must already be selected when this function is called. */static void PrepareToDrawText(void){ int fnum; PrepareToDraw(); fnum = GetFontNumber(textFont); if (fnum == 0) Error("Internal error: illegal font"); TextFont(fnum); TextSize(pointSize); TextFace(((textStyle & Bold) ? bold : 0) | ((textStyle & Italic) ? italic : 0));}/* * Function: DisplayLine * Usage: DisplayLine(x, y, dx, dy); * --------------------------------- * This function displays a line segment from the point (x, y) * to the point (x + dx, y + dy). Like all of the other graphical * operations, the line is rendered into offscreen memory. The * actual screen is updated only in response to the update event. */static void DisplayLine(double x, double y, double dx, double dy){ GrafPtr saveWindow; Rect rect; int ix0, iy0, ix1, iy1; ix0 = ScaleX(x); iy0 = ScaleY(y); ix1 = ScaleX(x + dx); iy1 = ScaleY(y + dy); SetRect(&rect, Min(ix0,ix1), Min(iy0,iy1), Max(ix0,ix1), Max(iy0,iy1)); UpdateRect(&rect); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDraw(); MoveTo(ix0, iy0); LineTo(ix1, iy1); SetPort(saveWindow);}/* * Function: DisplayArc * Usage: DisplayArc(x, y, rx, ry, start, sweep); * --------------------------------------------- * This function displays an elliptical arc segment centered at * the point (x, y). (Note that the argument signature is different * from that of the client function DrawEllipticalArc.) */static void DisplayArc(double x, double y, double rx, double ry, double start, double sweep){ GrafPtr saveWindow; Rect rect; int ix0, iy0, ix1, iy1, istart, isweep; istart = Round(start); isweep = Round(sweep); ix0 = ScaleX(x - rx); iy0 = ScaleY(y + ry); ix1 = ix0 + PixelsX(2 * rx); iy1 = iy0 + PixelsY(2 * ry); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDraw(); SetArcBB(&rect, x, y, rx, ry, start, sweep); UpdateRect(&rect); SetRect(&rect, ix0, iy0, ix1+1, iy1+1); FrameArc(&rect, 90 - istart, -isweep); SetPort(saveWindow);}/* * Function: RenderArc * Usage: RenderArc(x, y, rx, ry, start, sweep); * --------------------------------------------- * This function is identical to the DisplayArc function except * that the arc is rendered using line segments. This complication * is necessary on the Macintosh for filled shapes because arcs are * not counted as region boundaries. As an optimization, a * complete circle or oval is drawn using the DrawOval tool, which * does add a region boundary. The arc unit is chosen to represent * a pixel width at the specified arc radius. */static void RenderArc(double x, double y, double rx, double ry, double start, double sweep){ GrafPtr saveWindow; double t, mint, maxt, dt; int ix0, iy0, ix1, iy1; Rect rect; GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDraw(); if (sweep < 0) { start += sweep; sweep = -sweep; } if (sweep > 360 - Epsilon) { ix0 = ScaleX(x - rx); iy0 = ScaleY(y + ry); ix1 = ix0 + PixelsX(2 * rx); iy1 = iy0 + PixelsY(2 * ry); SetRect(&rect, ix0, iy0, ix1+1, iy1+1);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -