📄 graphics.c
字号:
/* * File: graphics.c * Version: 3.1 * Last modified on Fri Feb 24 19:42:15 1995 by eroberts * ----------------------------------------------------- * This file implements the graphics.h and extgraph.h interfaces * for the Macintosh using THINK's Lightspeed C. *//* * General implementation notes * ---------------------------- * This implementation is relatively complex for two reasons. * The first source of complexity is that windows on the * Macintosh are dynamically repositioned, obscured, and * reexposed. When these events occur, the drawing in the * window needs to be repainted. Thus, it is not sufficient * to have the drawing package simply issue the appropriate * QuickDraw procedures directly to the screen. This * implementation solves the problem by rendering the image * to an offscreen bitmap and then repainting the image from * that copy whenever update events occur. * * The second problem, which is indeed more severe, is that * that is much more easily understood by experts than by * novices. In a traditional Macintosh application, the * main program is coded as an "event loop," which * continually polls the event manager to see if any activity * is necessary. This strategy runs counter to the more * conventional view of a main program as the highest level * in the problem decomposition. In the context of teaching * programming, we want the main program and its subprograms * to draw the figures -- a strategy which is not easy to * reconcile with the standard Macintosh approach. This * implementation solves this problem by patching in a call * to an update procedure as part of the event loop embedded * in the console input mechanism. */#include <stdio.h>#include <stdlib.h>#include <string.h>#include <ctype.h>#include <console.h>#include <math.h>#include <time.h>#include <Traps.h>#include "genlib.h"#include "gcalloc.h"#include "strlib.h"#include "extgraph.h"/* * Parameters * ---------- * DesiredWidth -- Desired width of the graphics window * DesiredHeight -- Desired height of the graphics window * ConsoleLines -- Console lines * ConsoleHeight -- Estimate of console height (inches) * BottomMargin -- Minimum bottom margin (inches) * RightMargin -- Minimum right margin (inches) * WindowSeparation -- Minimum window separation (inches) * TitleBarPixels -- Pixel height of title bar * DefaultFont -- Font used to implement "Default" font * DefaultSize -- Initial point size for text * MaxColors -- Maximum number of color names allowed * MinColors -- Minimum number of colors the device must support * CheckForColor -- TRUE if abstraction should check for color memory */#define DesiredWidth 7.0#define DesiredHeight 4.0#define ConsoleLines 8#define ConsoleHeight 1.1#define BottomMargin 0.05#define RightMargin 0.05#define WindowSeparation 0.10#define TitleBarPixels 20#define DefaultFont "Geneva"#define DefaultSize 10#define MaxColors 256#define MinColors 16#define CheckForColor FALSE/* * Other constants * --------------- * LargeInt -- Used to signify out of range values * Epsilon -- Small arithmetic offset to reduce aliasing/banding * Pi -- Mathematical constant pi */#define LargeInt 16000#define Epsilon 0.00000000001#define Pi 3.1415926535/* * Type: graphicsStateT * -------------------- * This structure holds the variables that make up the graphics state. */typedef struct graphicsStateT { double cx, cy; string font; int size; int style; bool erase; int color; struct graphicsStateT *link;} *graphicsStateT;/* * Type: regionStateT * ------------------ * The region assembly process has the character of a finite state * machine with the following four states: * * NoRegion Region has not yet been started * RegionStarting Region is started but no line segments yet * RegionActive First line segment appears * PenHasMoved Pen has moved during definition * * The current state determines whether other operations are legal * at that point. */typedef enum { NoRegion, RegionStarting, RegionActive, PenHasMoved} regionStateT;/* * Type: colorEntryT * ----------------- * This type is used for the entries in the color table. */typedef struct { string name; double red, green, blue;} colorEntryT;/* * Global variables * ---------------- * initialized -- TRUE if initialization has been done * windowTitle -- Current window title (initialized statically) * consoleFile -- FILE * for console (saved to allow redirection) * gWindow -- Window pointer for graphics window * osWindow -- Offscreen window pointer for rendering * xResolution -- Horizontal resolution of screen (dots per inch) * yResolution -- Vertical resolution of screen (dots per inch) * windowWidth -- Width of graphics window * windowHeight -- Height of graphics window * regionState -- Current state of the region * regionDensity -- Fill density to apply to region * mouseState -- State of mouse as tracked by event handler * colorTable -- Table of defined colors * nColors -- Number of defined colors * colorOK -- TRUE if color port successfully initialized * checkMemory -- TRUE if application should check color memory * stateStack -- Stack of graphicStateT blocks * cx, cy -- Current coordinates | These * eraseMode -- Setting of erase flag | variables * textFont -- Current font | consititute * textStyle -- Current style | the current * pointSize -- Current point size | graphics * penColor -- Color of pen | state */static bool initialized = FALSE;static string windowTitle = "Graphics Window";static FILE consoleFile;static WindowPeek gWindow, osWindow;static short xResolution, yResolution;static double windowWidth = DesiredWidth;static double windowHeight = DesiredHeight;static regionStateT regionState;static double regionDensity;static bool mouseState;static colorEntryT colorTable[MaxColors];static int nColors;static bool colorOK;static bool checkMemory = CheckForColor;static graphicsStateT stateStack;static double cx, cy;static bool eraseMode;static string textFont;static int textStyle;static int pointSize;static int penColor;/* * Static table: fillList * ---------------------- * This table contains the bitmap patterns for the various density * values. Adding more patterns to this list increases the * precision with which the client can control fill patterns. */static Pattern fillList[] = { { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }, { 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22 }, { 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA, 0x55, 0xAA }, { 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD, 0x77, 0xDD }, { 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF },};#define NFills (sizeof fillList / sizeof fillList[0])/* Private function prototypes */static void InitCheck(void);static void InitGraphicsState(void);static void EraseWindow(void);static void CreateGraphicsWindow(void);static bool CreateColorWindow(Rect *bounds);static bool CreateBWWindow(Rect *bounds);static void PrepareToDraw(void);static void PrepareToDrawText(void);static void DisplayLine(double x, double y, double dx, double dy);static void DisplayArc(double x, double y, double rx, double ry, double start, double sweep);static void RenderArc(double x, double y, double rx, double ry, double start, double sweep);static void DisplayText(double x, double y, string text);static void SetArcBB(Rect *rp, double xc, double yc, double rx, double ry, double start, double sweep);static void SetTextBB(Rect *rp, double x, double y, string text);static void UpdateRect(Rect *rp);static StringPtr PascalString(string cstr);static int GetFontNumber(string fontName);static void InitColors(void);static bool ShouldBeWhite(void);static void CheckColorMemory(void);static int FindColorName(string name);static void PatchEventHandler(void);static long FindSystemTrap(short trap);static void MyEventHandler(EventRecord *ep);static void DoUpdateDisplay(void);static bool StringMatch(string s1, string s2);static int RectWidth(Rect *rp);static int RectHeight(Rect *rp);static void SetRectFromSize(Rect *rp, int x, int y, int width, int height);static double Radians(double degrees);static double Degrees(double radians);static double InchesX(int x);static double InchesY(int y);static int PixelsX(double x);static int PixelsY(double y);static int ScaleX(double x);static int ScaleY(double y);static int Round(double x);static int Min(int x, int y);static int Max(int x, int y);static double MinF(double x, double y);static double MaxF(double x, double y);/* Exported entries *//* Section 1 -- Basic functions from graphics.h */void InitGraphics(void){ if (initialized) { EraseWindow(); } else { initialized = TRUE; ProtectVariable(stateStack); ProtectVariable(windowTitle); ProtectVariable(textFont); InitColors(); CreateGraphicsWindow(); PatchEventHandler(); } InitGraphicsState();}void MovePen(double x, double y){ InitCheck(); if (regionState == RegionActive) regionState = PenHasMoved; cx = x; cy = y;}void DrawLine(double dx, double dy){ InitCheck(); switch (regionState) { case NoRegion: DisplayLine(cx, cy, dx, dy); break; case RegionStarting: case RegionActive: DisplayLine(cx, cy, dx, dy); regionState = RegionActive; break; case PenHasMoved: Error("Region segments must be contiguous"); } cx += dx; cy += dy;}void DrawArc(double r, double start, double sweep){ DrawEllipticalArc(r, r, start, sweep);}double GetWindowWidth(void){ InitCheck(); return (windowWidth);}double GetWindowHeight(void){ InitCheck(); return (windowHeight);}double GetCurrentX(void){ InitCheck(); return (cx);}double GetCurrentY(void){ InitCheck(); return (cy);}/* Section 2 -- Elliptical arcs */void DrawEllipticalArc(double rx, double ry, double start, double sweep){ double x, y; InitCheck(); x = cx + rx * cos(Radians(start + 180)); y = cy + ry * sin(Radians(start + 180)); switch (regionState) { case NoRegion: DisplayArc(x, y, rx, ry, start, sweep); break; case RegionStarting: case RegionActive: RenderArc(x, y, rx, ry, start, sweep); regionState = RegionActive; break; case PenHasMoved: Error("Region segments must be contiguous"); } cx = x + rx * cos(Radians(start + sweep)); cy = y + ry * sin(Radians(start + sweep));}/* Section 3 -- Graphical structures */void StartFilledRegion(double density){ GrafPtr saveWindow; InitCheck(); if (regionState != NoRegion) { Error("Region is already in progress"); } if (density < 0 || density > 1) { Error("Density for regions must be between 0 and 1"); } regionState = RegionStarting; regionDensity = density; GetPort(&saveWindow); SetPort((WindowPtr) osWindow); OpenRgn(); SetPort(saveWindow);}void EndFilledRegion(void){ RgnHandle region; GrafPtr saveWindow; int px; InitCheck(); switch (regionState) { case NoRegion: Error("EndFilledRegion without StartFilledRegion"); case RegionStarting: regionState = NoRegion; return; case RegionActive: case PenHasMoved: regionState = NoRegion; break; } GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDraw(); region = NewRgn(); if (region == NULL) Error("EndFilledRegion: Can't create region"); CloseRgn(region); UpdateRect(&(*region)->rgnBBox); px = regionDensity * (NFills - 1) + 0.5 - Epsilon; if (eraseMode || ShouldBeWhite()) px = 0; FillRgn(region, ((Pattern *) fillList) + px); SetPort(saveWindow); DisposeRgn(region);}/* Section 4 -- String functions */void DrawTextString(string text){ InitCheck(); if (regionState != NoRegion) { Error("Text strings are illegal inside a region"); } DisplayText(cx, cy, text); cx += TextStringWidth(text);}double TextStringWidth(string text){ Rect rect; GrafPtr saveWindow; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDrawText(); SetTextBB(&rect, cx, cy, text); SetPort(saveWindow); return (InchesX(RectWidth(&rect)));}void SetFont(string font){ InitCheck(); if (GetFontNumber(font) != 0) { textFont = CopyString(font); }}string GetFont(void){ InitCheck(); return (CopyString(textFont));}void SetPointSize(int size){ InitCheck(); pointSize = size;}int GetPointSize(void){ InitCheck(); return (pointSize);}void SetStyle(int style){ InitCheck(); textStyle = style;}int GetStyle(void){ InitCheck(); return (textStyle);}double GetFontAscent(void){ FontInfo fInfo; GrafPtr saveWindow; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDrawText(); GetFontInfo(&fInfo); SetPort(saveWindow); return (InchesY(fInfo.ascent));}double GetFontDescent(void){ FontInfo fInfo; GrafPtr saveWindow; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDrawText(); GetFontInfo(&fInfo); SetPort(saveWindow); return (InchesY(fInfo.descent));}double GetFontHeight(void){ FontInfo fInfo; GrafPtr saveWindow; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) osWindow); PrepareToDrawText(); GetFontInfo(&fInfo); SetPort(saveWindow); return (InchesY(fInfo.ascent + fInfo.descent + fInfo.leading));}/* Section 5 -- Mouse support */double GetMouseX(void){ GrafPtr saveWindow; Point pt; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) gWindow); GetMouse(&pt); SetPort(saveWindow); return (InchesX(pt.h));}double GetMouseY(void){ GrafPtr saveWindow; Point pt; InitCheck(); GetPort(&saveWindow); SetPort((WindowPtr) gWindow); GetMouse(&pt); SetPort(saveWindow); return (windowHeight - InchesY(pt.v));}bool MouseButtonIsDown(void){ InitCheck(); return (Button());}void WaitForMouseDown(void){ InitCheck(); mouseState = Button(); while (!mouseState) { UpdateDisplay(); }}void WaitForMouseUp(void){ InitCheck(); mouseState = Button(); while (mouseState) { UpdateDisplay(); }}/* Section 6 -- Color support */bool HasColor(void){
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -