📄 graphics.c
字号:
* foreground/background colors, the drawing pens, and the brushes * for filled regions. */static void InitDrawingTools(void){ int i; nFonts = 0; previousColor = 0; drawColor = RGB(0, 0, 0); eraseColor = RGB(255, 255, 255); drawPen = (HPEN) CreatePen(PS_SOLID, 1, drawColor); erasePen = (HPEN) CreatePen(PS_SOLID, 1, eraseColor); nullPen = (HPEN) GetStockObject(NULL_PEN); if (drawPen == NULL || erasePen == NULL || nullPen == NULL) { Error("Internal error: Can't initialize pens"); } for (i = 0; i < NFills; i++) { fillBitmaps[i] = CreateBitmap(8, 8, 1, 1, fillList[i]); } SelectObject(osdc, drawPen);}/* * Function: DisplayExit * Usage: DisplayExit(); * --------------------- * This function is called when the program exits and waits for the * user to type a carriage return. After reading and ignoring the * return key, this function frees the window system handles and * destroys the console window, thereby exiting the program. */static void DisplayExit(void){ int i; if (pauseOnExit) (void) getchar(); DeleteDC(osdc); DeleteDC(gdc); DestroyWindow(consoleWindow); DestroyWindow(graphicsWindow); DeleteObject(drawPen); DeleteObject(erasePen); DeleteObject(nullPen); for (i = 0; i < nFonts; i++) { DeleteObject(fontTable[i].font); } for (i = 0; i < NFills; i++) { DeleteObject(fillBitmaps[i]); }}/* * Function: FindConsoleWindow * Usage: window = FindConsoleWindow(); * ------------------------------------ * The EasyWin package makes almost everything about the graphics * package easy in the Borland world. The only thing that is hard * is getting the handle of the window used for the console in the * first place. This function finds the console window handle by * enumerating the windows and looking for the first one whose * title ends with .EXE, which the EasyWin package puts there. */static HWND FindConsoleWindow(void){ HWND result; EnumWindows(EnumerateProc, (LPARAM) &result); return (result);}/* * Function: EnumerateProc * Usage: Not called directly * -------------------------- * This callback procedure is used by the FindConsoleWindow * call to find the window whose title ends with .EXE. */static BOOL CALLBACK EnumerateProc(HWND window, LPARAM clientData){ HWND *wptr; char title[MaxTitle]; bool ok; wptr = (HWND *) clientData; ok = GetWindowText(window, title, MaxTitle-1); if (ok && strcmp(title + strlen(title) - 4, ".EXE")==0) { *wptr = window; return (0); } return (1);}/* * Function: RegisterWindowClass * Usage: RegisterWindowClass(); * ----------------------------- * This function registers the window class used for the graphics * window. */static void RegisterWindowClass(void){ WNDCLASS wcApp; wcApp.lpszClassName = GWClassName; wcApp.hInstance = NULL; wcApp.lpfnWndProc = GraphicsEventProc; wcApp.hCursor = NULL; wcApp.hIcon = NULL; wcApp.lpszMenuName = NULL; wcApp.hbrBackground = GetStockObject(WHITE_BRUSH); wcApp.style = CS_HREDRAW | CS_VREDRAW; wcApp.cbClsExtra = wcApp.cbWndExtra = 0; if (!RegisterClass(&wcApp)) { Error("Internal error: RegisterClass failed\n"); }}/* * Function: GraphicsEventProc * Usage: Not called directly * -------------------------- * This function is called when an event is received for the * graphics window. The only event this package needs to handle * is the paint event, which forces a screen update. */static LONG FAR PASCAL GraphicsEventProc(HWND w, UINT msg, WPARAM p1, LPARAM p2){ if (msg == WM_PAINT) { DoUpdate(); return (0L); } if (msg >= WM_MOUSEFIRST && msg <= WM_MOUSELAST) { mouseX = LOWORD(p2); mouseY = HIWORD(p2); mouseButton = (p1 & AnyButton) != 0; return (0L); } return (DefWindowProc(w, msg, p1, p2));}/* * Function: DoUpdate * Usage: DoUpdate(); * ------------------ * This function redraws the graphics window by copying bits from * the offscreen bitmap behind the osdc device context into the * actual display context. */static void DoUpdate(void){ HDC dc; dc = BeginPaint(graphicsWindow, &ps); BitBlt(dc, 0, 0, pixelWidth, pixelHeight, osdc, 0, 0, SRCCOPY); EndPaint(graphicsWindow, &ps);}/* * Function: DisplayClear * Usage: DisplayClear(); * ---------------------- * This function clears all the bits in the offscreen bitmap. */static void DisplayClear(void){ RECT r; SetRect(&r, 0, 0, pixelWidth, pixelHeight); InvalidateRect(graphicsWindow, &r, TRUE); BitBlt(osdc, 0, 0, pixelWidth, pixelHeight, osdc, 0, 0, WHITENESS);}/* * Function: PrepareToDraw * Usage: PrepareToDraw(); * ----------------------- * This function must be called before any rendering operation * to ensure the pen modes and colors are correctly set. */static void PrepareToDraw(void){ int red, green, blue; HPEN oldPen; if (eraseMode) { (void) SelectObject(osdc, erasePen); SetTextColor(osdc, eraseColor); } else { if (penColor != previousColor) { red = colorTable[penColor].red * 256 - Epsilon; green = colorTable[penColor].green * 256 - Epsilon; blue = colorTable[penColor].blue * 256 - Epsilon; drawColor = RGB(red, green, blue); oldPen = drawPen; drawPen = CreatePen(PS_SOLID, 1, drawColor); (void) SelectObject(osdc, drawPen); DeleteObject(oldPen); previousColor = penColor; } else { (void) SelectObject(osdc, drawPen); } (void) SetTextColor(osdc, drawColor); }}/* * Function: DisplayLine * Usage: DisplayLine(x, y, dx, dy); * --------------------------------- * This function renders a line into the offscreen bitmap. If the * region is started, it adds the line to the developing polygonal * region instead. */static void DisplayLine(double x, double y, double dx, double dy){ int x0, y0, x1, y1; RECT r; PrepareToDraw(); x0 = ScaleX(x); y0 = ScaleY(y); x1 = ScaleX(x + dx); y1 = ScaleY(y + dy); if (regionState == NoRegion) { SetLineBB(&r, x, y, dx, dy); InvalidateRect(graphicsWindow, &r, TRUE); MoveTo(osdc, x0, y0); LineTo(osdc, x1, y1); } else { AddSegment(x0, y0, x1, y1); }}/* * Function: DisplayArc * Usage: DisplayArc(xc, yc, rx, ry, start, sweep); * ------------------------------------------------ * This function is used to draw an arc. The arguments are slightly * different from those in the client interface because xc and yc * designate the center. This function is only called if a region * is not being assembled; if it is, the package calls RenderArc * instead. */static void DisplayArc(double xc, double yc, double rx, double ry, double start, double sweep){ RECT r; int xmax, xmin, ymax, ymin; int ix0, iy0, ix1, iy1; PrepareToDraw(); SetArcBB(&r, xc, yc, rx, ry, start, sweep); InvalidateRect(graphicsWindow, &r, TRUE); xmin = ScaleX(xc - rx); ymin = ScaleY(yc + ry); xmax = xmin + PixelsX(2 * rx); ymax = ymin + PixelsX(2 * ry); if (sweep < 0) { start += sweep; sweep = -sweep; } if (start < 0) { start = 360 - fmod(-start, 360); } else { start = fmod(start, 360); } ix0 = ScaleX(xc + rx * cos(Radians(start))); iy0 = ScaleY(yc + ry * sin(Radians(start))); ix1 = ScaleX(xc + rx * cos(Radians(start + sweep))); iy1 = ScaleY(yc + ry * sin(Radians(start + sweep))); Arc(osdc, xmin, ymin, xmax, ymax, ix0, iy0, ix1, iy1);}/* * Function: RenderArc * Usage: RenderArc(xc, yc, rx, ry, start, sweep); * ----------------------------------------------- * This function is identical to DisplayArc except that, instead * of calling the Arc function, RenderArc simulates the arc by * constructing a path of consecutive segments, which are added * to the current polygonal region. */static void RenderArc(double x, double y, double rx, double ry, double start, double sweep){ double t, mint, maxt, dt, maxd; int ix0, iy0, ix1, iy1; PrepareToDraw(); if (sweep < 0) { start += sweep; sweep = -sweep; } if (fabs(rx) > fabs(ry)) { maxd = fabs(rx); } else { maxd = fabs(rx); } dt = atan2(InchesY(1), maxd); mint = Radians(start); maxt = Radians(start + sweep); ix0 = ScaleX(x + rx * cos(mint)); iy0 = ScaleY(y + ry * sin(mint)); for (t = mint + dt; t < maxt; t += dt) { if (t > maxt - dt / 2) t = maxt; ix1 = ScaleX(x + rx * cos(t)); iy1 = ScaleY(y + ry * sin(t)); AddSegment(ix0, iy0, ix1, iy1); ix0 = ix1; iy0 = iy1; }}/* * Function: DisplayText * Usage: DisplayText(x, y, text); * ------------------------------- * This function displays a text string at (x, y) in the current * font and size. The hard work is done in DisplayFont. */static void DisplayText(double x, double y, string text){ RECT r; PrepareToDraw(); SetTextBB(&r, x, y, text); InvalidateRect(graphicsWindow, &r, TRUE); SetBkMode(osdc, TRANSPARENT); TextOut(osdc, ScaleX(x), ScaleY(y) - fontTable[currentFont].ascent, text, strlen(text)); SetBkMode(osdc, OPAQUE);}/* * Function: DisplayFont * Usage: DisplayFont(font, size, style); * -------------------------------------- * This function updates the font information used for drawing * text. The program first uses FindExistingFont to see * if the desired font/size pair has been entered in the table, * in which case the program uses the stored handle of the font. * If not, the program uses CreateFont to try to create an * appropriate font, accepting only those whose typeface * matches the desired font string. If an acceptable font * is found, its data is entered into the font table. */static void DisplayFont(string font, int size, int style){ char fontBuffer[MaxFontName + 1]; char faceName[MaxFontName + 1]; string fontName; HFONT newFont, oldFont; TEXTMETRIC metrics; int i, fontIndex; for (i = 0; (fontBuffer[i] = tolower(font[i])) != '\0'; i++); if (StringEqual("default", fontBuffer)) { fontName = DefaultFont; } else { fontName = fontBuffer; } fontIndex = FindExistingFont(fontName, size, style); if (fontIndex == -1) { newFont = CreateFont(-size, 0, 0, 0, (style & Bold) ? FW_BOLD : FW_NORMAL, (style & Italic) != 0, 0, 0, 0, 0, 0, 0, 0, fontName); if (newFont != NULL) { oldFont = (HFONT) SelectObject(osdc, newFont); GetTextFace(osdc, MaxFontName, faceName); if (PrefixMatch(fontName, faceName) && GetTextMetrics(osdc, &metrics)) { if (nFonts == MaxFonts) Error("Too many fonts loaded"); fontIndex = nFonts++; fontTable[fontIndex].name = CopyString(fontName); fontTable[fontIndex].size = size; fontTable[fontIndex].style = style; fontTable[fontIndex].font = newFont; fontTable[fontIndex].ascent = metrics.tmAscent; fontTable[fontIndex].descent = metrics.tmDescent; fontTable[fontIndex].height = metrics.tmHeight + metrics.tmExternalLeading; fontTable[fontIndex].points = metrics.tmHeight - metrics.tmInternalLeading; currentFont = fontIndex; textFont = CopyString(font); pointSize = fontTable[fontIndex].points; textStyle = style; } else { (void) SelectObject(osdc, oldFont); } } } else { (void) SelectObject(osdc, fontTable[fontIndex].font); currentFont = fontIndex; textFont = CopyString(font); pointSize = fontTable[fontIndex].points; textStyle = style; }}/* * Function: FindExistingFont * Usage: fontIndex = FindExistingFont(name, size, style); * ------------------------------------------------------- * This function searches the font table for a matching font * entry. The function returns the matching table index or -1 if * no match is found, The caller has already converted the name * to lower case to preserve the case-insensitivity requirement. */static int FindExistingFont(string name, int size, int style){ int i;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -