├── README.md ├── WinBGI ├── stdafx.cpp ├── targetver.h ├── dibutil.h ├── palette.cpp ├── stdafx.h ├── WinBGI.vcxproj.filters ├── mouse.cpp ├── dibapi.h ├── winbgitypes.h ├── WinBGI.vcxproj ├── file.cpp ├── text.cpp ├── winbgi.h ├── graphics.h ├── winthread.cpp ├── misc.cpp ├── winbgi.cpp └── dibutil.cpp ├── .gitattributes ├── LICENSE.md ├── WinBGI.sln └── .gitignore /README.md: -------------------------------------------------------------------------------- 1 | # WinBGI 2 | 3 | Borland Graphics Interface for Windows platform 4 | 5 | > Source: part of [cs1300 toolset](http://cs.colorado.edu/~main/bgi/visual) by [cs-dept @ colorado.edu](http://cs.colorado.edu/~main/bgi) 6 | -------------------------------------------------------------------------------- /WinBGI/stdafx.cpp: -------------------------------------------------------------------------------- 1 | // stdafx.cpp : source file that includes just the standard includes 2 | // WinBGI.pch will be the pre-compiled header 3 | // stdafx.obj will contain the pre-compiled type information 4 | 5 | #include "stdafx.h" 6 | 7 | // TODO: reference any additional headers you need in STDAFX.H 8 | // and not in this file 9 | -------------------------------------------------------------------------------- /WinBGI/targetver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | // Including SDKDDKVer.h defines the highest available Windows platform. 4 | 5 | // If you wish to build your application for a previous Windows platform, include WinSDKVer.h and 6 | // set the _WIN32_WINNT macro to the platform you wish to support before including SDKDDKVer.h. 7 | 8 | #include 9 | -------------------------------------------------------------------------------- /WinBGI/dibutil.h: -------------------------------------------------------------------------------- 1 | /* PortTool v2.2 dibutil.h */ 2 | 3 | /* 4 | * dibutil.h 5 | * 6 | * Copyright (C) 1991-1996 Microsoft Corporation. All rights reserved. 7 | * 8 | * Header file for Device-Independent Bitmap (DIB) API. Provides 9 | * function prototypes and constants for the following functions: 10 | * 11 | * AllocRoomForDIB() - Allocates memory for a DIB 12 | * 13 | */ 14 | 15 | #pragma once 16 | 17 | /* DIB constants */ 18 | #define PALVERSION 0x300 19 | 20 | /* DIB macros */ 21 | #define IS_WIN30_DIB(lpbi) ((*(LPDWORD)(lpbi)) == sizeof(BITMAPINFOHEADER)) 22 | #define RECTWIDTH(lpRect) ((lpRect)->right - (lpRect)->left) 23 | #define RECTHEIGHT(lpRect) ((lpRect)->bottom - (lpRect)->top) 24 | 25 | /* function prototypes */ 26 | HANDLE AllocRoomForDIB(BITMAPINFOHEADER, HBITMAP); 27 | -------------------------------------------------------------------------------- /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | 4 | # Custom for Visual Studio 5 | *.cs diff=csharp 6 | *.sln merge=binary 7 | *.*proj merge=binary 8 | 9 | # Standard to msysgit 10 | *.doc diff=astextplain 11 | *.DOC diff=astextplain 12 | *.docx diff=astextplain 13 | *.DOCX diff=astextplain 14 | *.dot diff=astextplain 15 | *.DOT diff=astextplain 16 | *.pdf diff=astextplain 17 | *.PDF diff=astextplain 18 | *.rtf diff=astextplain 19 | *.RTF diff=astextplain 20 | 21 | # Git LFS 22 | *.jpg filter=lfs diff=lfs merge=lfs -text 23 | *.png filter=lfs diff=lfs merge=lfs -text 24 | *.gif filter=lfs diff=lfs merge=lfs -text 25 | *.bmp filter=lfs diff=lfs merge=lfs -text 26 | *.tiff filter=lfs diff=lfs merge=lfs -text 27 | *.svg filter=lfs diff=lfs merge=lfs -text 28 | *.pdn filter=lfs diff=lfs merge=lfs -text 29 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (__MIT__) 2 | 3 | ## Copyright (c) 2014-2016 NIRIN 4 | 5 | _Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions:_ 11 | 12 | _The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software._ 14 | 15 | __THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE.__ 22 | -------------------------------------------------------------------------------- /WinBGI.sln: -------------------------------------------------------------------------------- 1 | 2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.25420.1 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "WinBGI", "WinBGI\WinBGI.vcxproj", "{C218697F-1F8F-4F5B-8774-32BA17CAE9AD}" 7 | EndProject 8 | Global 9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 10 | Debug|x64 = Debug|x64 11 | Debug|x86 = Debug|x86 12 | Release|x64 = Release|x64 13 | Release|x86 = Release|x86 14 | EndGlobalSection 15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 16 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Debug|x64.ActiveCfg = Debug|x64 17 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Debug|x64.Build.0 = Debug|x64 18 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Debug|x86.ActiveCfg = Debug|Win32 19 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Debug|x86.Build.0 = Debug|Win32 20 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Release|x64.ActiveCfg = Release|x64 21 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Release|x64.Build.0 = Release|x64 22 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Release|x86.ActiveCfg = Release|Win32 23 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD}.Release|x86.Build.0 = Release|Win32 24 | EndGlobalSection 25 | GlobalSection(SolutionProperties) = preSolution 26 | HideSolutionNode = FALSE 27 | EndGlobalSection 28 | EndGlobal 29 | -------------------------------------------------------------------------------- /WinBGI/palette.cpp: -------------------------------------------------------------------------------- 1 | // $Id: palette.cpp,v 1.1 2003/07/08 03:42:28 bush Exp $ 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | 12 | #include "stdafx.h" 13 | //#include "winbgi.h" 14 | //#include "winbgitypes.h" 15 | 16 | /***************************************************************************** 17 | * 18 | * Helper functions 19 | * 20 | *****************************************************************************/ 21 | 22 | 23 | /***************************************************************************** 24 | * 25 | * The actual API calls are implemented below 26 | * 27 | *****************************************************************************/ 28 | palettetype *getdefaultpalette() 29 | { 30 | static palettetype default_palette 31 | { 16, 32 | { 33 | BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, 34 | DARKGRAY, LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, 35 | LIGHTMAGENTA, YELLOW, WHITE 36 | } 37 | }; 38 | 39 | return &default_palette; 40 | } 41 | 42 | 43 | void getpalette(palettetype *palette) 44 | { 45 | 46 | } 47 | 48 | 49 | int getpalettesize() 50 | { 51 | return MAXCOLORS + 1; 52 | } 53 | 54 | 55 | void setallpalette(palettetype *palette) 56 | { 57 | 58 | } 59 | 60 | 61 | void setpalette(int colornum, int color) 62 | { 63 | 64 | } 65 | 66 | 67 | void setrgbpalette(int colornum, int red, int green, int blue) 68 | { 69 | 70 | } 71 | -------------------------------------------------------------------------------- /WinBGI/stdafx.h: -------------------------------------------------------------------------------- 1 | // stdafx.h : include file for standard system include files, 2 | // or project specific include files that are used frequently, but 3 | // are changed infrequently 4 | // 5 | 6 | #pragma once 7 | 8 | #define STDAFX_H_ 9 | #define STRICT // enable strict type checking 10 | #define _USE_MATH_DEFINES // Actually use the definitions in math.h 11 | //#define WIN32_LEAN_AND_MEAN // Exclude rarely-used stuff from Windows headers 12 | 13 | // Default 14 | #include "targetver.h" 15 | 16 | // C 17 | #include 18 | #include 19 | #include 20 | #include // Provides INT_MAX 21 | #include // Provides math functions 22 | #include // Provides string functions 23 | #include 24 | #include 25 | #include // Provides Win32 API 26 | #include // Provides GDI helper macros 27 | #include // IPicture 28 | #include // Support for IPicture 29 | 30 | // C++ 31 | #include // Standard String Library 32 | #include // Standard IO Stream Library 33 | #include // Standard String Stream Library 34 | #include // Added for BGI__WindowTable 35 | #include // Provides queue 36 | 37 | using namespace std; 38 | 39 | // Shims 40 | #ifndef M_PI 41 | #define M_PI 3.14159265358979323846 42 | #endif 43 | #ifndef min 44 | #define min(a,b) ((a) < (b) ? (a) : (b)) 45 | #endif 46 | #ifndef max 47 | #define max(a,b) ((a) > (b) ? (a) : (b)) 48 | #endif 49 | 50 | #ifndef SC_US 51 | #define SC_US(value) static_cast(value) 52 | #endif 53 | 54 | // Graphics 55 | #include "dibapi.h" 56 | #include "dibutil.h" 57 | #include "winbgi.h" 58 | #include "winbgitypes.h" 59 | 60 | // TODO: reference additional headers your program requires here 61 | -------------------------------------------------------------------------------- /WinBGI/WinBGI.vcxproj.filters: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {4FC737F1-C7A5-4376-A066-2A32D752A2FF} 6 | cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx 7 | 8 | 9 | {93995380-89BD-4b04-88EB-625FBE52EBFB} 10 | h;hh;hpp;hxx;hm;inl;inc;xsd 11 | 12 | 13 | {67DA6AB6-F800-4c08-8B7A-83BB121AAD01} 14 | rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav;mfcribbon-ms 15 | 16 | 17 | 18 | 19 | Header Files 20 | 21 | 22 | Header Files 23 | 24 | 25 | Header Files 26 | 27 | 28 | Header Files 29 | 30 | 31 | Header Files 32 | 33 | 34 | Header Files 35 | 36 | 37 | 38 | 39 | Source Files 40 | 41 | 42 | Source Files 43 | 44 | 45 | Source Files 46 | 47 | 48 | Source Files 49 | 50 | 51 | Source Files 52 | 53 | 54 | Source Files 55 | 56 | 57 | Source Files 58 | 59 | 60 | Source Files 61 | 62 | 63 | Source Files 64 | 65 | 66 | Source Files 67 | 68 | 69 | -------------------------------------------------------------------------------- /WinBGI/mouse.cpp: -------------------------------------------------------------------------------- 1 | // $Id: mouse.cpp,v 1.1 2003/05/06 03:32:35 bush Exp $ 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | 12 | #include "stdafx.h" 13 | //#include "winbgi.h" 14 | //#include "winbgitypes.h" 15 | 16 | /***************************************************************************** 17 | * 18 | * Helper functions 19 | * 20 | *****************************************************************************/ 21 | // This function tests whether a given kind of mouse event is in range 22 | // MGM: Added static to prevent linker conflicts 23 | static bool MouseKindInRange(int kind) 24 | { 25 | return kind >= WM_MOUSEFIRST && kind <= WM_MOUSELAST; 26 | } 27 | 28 | 29 | /***************************************************************************** 30 | * 31 | * The actual API calls are implemented below 32 | * MGM: Moved ismouseclick function to top to stop g++ 3.2.3 internal error. 33 | *****************************************************************************/ 34 | bool ismouseclick(int kind) 35 | { 36 | auto pWndData = BGI__GetWindowDataPtr(); 37 | return (MouseKindInRange(kind) && pWndData->clicks[kind - WM_MOUSEFIRST].size()); 38 | } 39 | 40 | void clearmouseclick(int kind) 41 | { 42 | auto pWndData = BGI__GetWindowDataPtr(); 43 | 44 | // Clear the mouse event 45 | if (MouseKindInRange(kind) && pWndData->clicks[kind - WM_MOUSEFIRST].size()) 46 | pWndData->clicks[kind - WM_MOUSEFIRST].pop(); 47 | } 48 | 49 | void getmouseclick(int kind, int& x, int& y) 50 | { 51 | auto pWndData = BGI__GetWindowDataPtr(); 52 | POINTS where; // POINT (short) to tell where mouse event happened. 53 | 54 | // Check if mouse event is in range 55 | if (!MouseKindInRange(kind)) 56 | return; 57 | 58 | // Set position variables to mouse location, or to NO_CLICK if no event occured 59 | if (MouseKindInRange(kind) && pWndData->clicks[kind - WM_MOUSEFIRST].size()) 60 | { 61 | where = pWndData->clicks[kind - WM_MOUSEFIRST].front(); 62 | pWndData->clicks[kind - WM_MOUSEFIRST].pop(); 63 | x = where.x; 64 | y = where.y; 65 | } 66 | else 67 | { 68 | x = y = NO_CLICK; 69 | } 70 | } 71 | 72 | void setmousequeuestatus(int kind, bool status) 73 | { 74 | if (MouseKindInRange(kind)) 75 | BGI__GetWindowDataPtr()->mouse_queuing[kind - WM_MOUSEFIRST] = status; 76 | } 77 | 78 | // TODO: This may be viewport relative. The documentation specifies with will range from 0 to getmaxx() 79 | int mousex() 80 | { 81 | auto pWndData = BGI__GetWindowDataPtr(); 82 | return pWndData->mouse.x; 83 | } 84 | 85 | 86 | // TODO: This may be viewport relative. The documentation specifies with will range from 0 to getmaxy() 87 | int mousey() 88 | { 89 | auto pWndData = BGI__GetWindowDataPtr(); 90 | return pWndData->mouse.y; 91 | } 92 | 93 | 94 | void registermousehandler(int kind, void h(int, int)) 95 | { 96 | auto pWndData = BGI__GetWindowDataPtr(); 97 | if (MouseKindInRange(kind)) 98 | pWndData->mouse_handlers[kind - WM_MOUSEFIRST] = h; 99 | } 100 | -------------------------------------------------------------------------------- /WinBGI/dibapi.h: -------------------------------------------------------------------------------- 1 | /* PortTool v2.2 dibapi.h */ 2 | 3 | /* 4 | * dibapi.h 5 | * 6 | * ** Win32 Version ** 7 | * 8 | * Copyright (C) 1991-1996 Microsoft Corporation. All rights reserved 9 | * 10 | * Header file for Device-Independent Bitmap (DIB) API. Provides 11 | * function prototypes and constants for the following functions: 12 | * 13 | * BitmapToDIB() - Creates a DIB from a bitmap 14 | * ChangeBitmapFormat() - Changes a bitmap to a specified DIB format 15 | * ChangeDIBFormat() - Changes a DIB's BPP and/or compression format 16 | * CopyScreenToBitmap() - Copies entire screen to a standard Bitmap 17 | * CopyScreenToDIB() - Copies entire screen to a DIB 18 | * CopyWindowToBitmap() - Copies a window to a standard Bitmap 19 | * CopyWindowToDIB() - Copies a window to a DIB 20 | * CreateDIBPalette() - Creates a palette from a DIB 21 | * CreateDIB() - Creates a new DIB 22 | * DestroyDIB() - Deletes DIB when finished using it 23 | * DIBError() - Displays message box with error message 24 | * DIBHeight() - Gets the DIB height 25 | * DIBNumColors() - Calculates number of colors in the DIB's color table 26 | * DIBToBitmap() - Creates a bitmap from a DIB 27 | * DIBWidth() - Gets the DIB width 28 | * FindDIBBits() - Sets pointer to the DIB bits 29 | * GetSystemPalette() - Gets the current palette 30 | * LoadDIB() - Loads a DIB from a file 31 | * PaintBitmap() - Displays standard bitmap in the specified DC 32 | * PaintDIB() - Displays DIB in the specified DC 33 | * PalEntriesOnDevice() - Gets the number of palette entries 34 | * PaletteSize() - Calculates the buffer size required by a palette 35 | * PrintDIB() - Prints the specified DIB 36 | * PrintScreen() - Prints the entire screen 37 | * PrintWindow() - Prints all or part of a window 38 | * SaveDIB() - Saves the specified dib in a file 39 | * 40 | * See the file DIBAPI.TXT for more information about these functions. 41 | * 42 | */ 43 | 44 | #pragma once 45 | 46 | /* Handle to a DIB */ 47 | #define HDIB HANDLE 48 | 49 | 50 | /* Print Area selection */ 51 | #define PW_WINDOW 1 52 | #define PW_CLIENT 2 53 | 54 | 55 | /* Print Options selection */ 56 | #define PW_BESTFIT 1 57 | #define PW_STRETCHTOPAGE 2 58 | #define PW_SCALE 3 59 | 60 | /* DIB Macros*/ 61 | 62 | // WIDTHBYTES performs DWORD-aligning of DIB scanlines. The "bits" 63 | // parameter is the bit count for the scanline (biWidth * biBitCount), 64 | // and this macro returns the number of DWORD-aligned bytes needed 65 | // to hold those bits. 66 | 67 | #define WIDTHBYTES(bits) (((bits) + 31) / 32 * 4) 68 | 69 | /* Error constants */ 70 | typedef enum DIB_ERR 71 | { 72 | ERR_MIN = 0, // All error #s >= this value 73 | ERR_NOT_DIB = 0, // Tried to load a file, NOT a DIB! 74 | ERR_MEMORY, // Not enough memory! 75 | ERR_READ, // Error reading file! 76 | ERR_LOCK, // Error on a GlobalLock()! 77 | ERR_OPEN, // Error opening a file! 78 | ERR_CREATEPAL, // Error creating palette. 79 | ERR_GETDC, // Couldn't get a DC. 80 | ERR_CREATEDDB, // Error create a DDB. 81 | ERR_STRETCHBLT, // StretchBlt() returned failure. 82 | ERR_STRETCHDIBITS, // StretchDIBits() returned failure. 83 | ERR_SETDIBITSTODEVICE, // SetDIBitsToDevice() failed. 84 | ERR_STARTDOC, // Error calling StartDoc(). 85 | ERR_NOGDIMODULE, // Couldn't find GDI module in memory. 86 | ERR_SETABORTPROC, // Error calling SetAbortProc(). 87 | ERR_STARTPAGE, // Error calling StartPage(). 88 | ERR_NEWFRAME, // Error calling NEWFRAME escape. 89 | ERR_ENDPAGE, // Error calling EndPage(). 90 | ERR_ENDDOC, // Error calling EndDoc(). 91 | ERR_SETDIBITS, // Error calling SetDIBits(). 92 | ERR_FILENOTFOUND, // Error opening file in GetDib() 93 | ERR_INVALIDHANDLE, // Invalid Handle 94 | ERR_DIBFUNCTION, // Error on call to DIB function 95 | ERR_MAX // All error #s < this value 96 | } DIB_ERR; 97 | 98 | 99 | 100 | /* Function prototypes */ 101 | 102 | HDIB BitmapToDIB(HBITMAP, HPALETTE); 103 | HDIB ChangeBitmapFormat(HBITMAP, WORD, DWORD, HPALETTE); 104 | HDIB ChangeDIBFormat(HDIB, WORD, DWORD); 105 | HBITMAP CopyScreenToBitmap(LPRECT); 106 | HDIB CopyScreenToDIB(LPRECT); 107 | HBITMAP CopyWindowToBitmap(HWND, WORD); 108 | HDIB CopyWindowToDIB(HWND, WORD); 109 | HPALETTE CreateDIBPalette(HDIB); 110 | HDIB CreateDIB(DWORD, DWORD, WORD); 111 | WORD DestroyDIB(HDIB); 112 | void DIBError(int); 113 | DWORD DIBHeight(LPSTR); 114 | WORD DIBNumColors(LPSTR); 115 | HBITMAP DIBToBitmap(HDIB, HPALETTE); 116 | DWORD DIBWidth(LPSTR); 117 | LPSTR FindDIBBits(LPSTR); 118 | HPALETTE GetSystemPalette(void); 119 | HDIB LoadDIB(const LPSTR); 120 | BOOL PaintBitmap(HDC, LPRECT, HBITMAP, LPRECT, HPALETTE); 121 | BOOL PaintDIB(HDC, LPRECT, HDIB, LPRECT, HPALETTE); 122 | int PalEntriesOnDevice(HDC); 123 | WORD PaletteSize(LPSTR); 124 | WORD PrintDIB(HDIB, WORD, WORD, WORD, LPSTR); 125 | WORD PrintScreen(LPRECT, WORD, WORD, WORD, LPSTR); 126 | WORD PrintWindow(HWND, WORD, WORD, WORD, WORD, LPSTR); 127 | WORD SaveDIB(HDIB, const char*); 128 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | ### VisualStudio ### 3 | ## Ignore Visual Studio temporary files, build results, and 4 | ## files generated by popular Visual Studio add-ons. 5 | 6 | # User-specific files 7 | *.suo 8 | *.user 9 | *.userosscache 10 | *.sln.docstates 11 | 12 | # User-specific files (MonoDevelop/Xamarin Studio) 13 | *.userprefs 14 | 15 | # Build results 16 | [Dd]ebug/ 17 | [Dd]ebugPublic/ 18 | [Rr]elease/ 19 | [Rr]eleases/ 20 | x64/ 21 | x86/ 22 | bld/ 23 | [Bb]in/ 24 | [Oo]bj/ 25 | [Ll]og/ 26 | [Bb]uild/ 27 | [Bb]uilds/ 28 | [Bb]inaries/ 29 | 30 | 31 | # Visual Studio 2015 cache/options directory 32 | .vs/ 33 | # Uncomment if you have tasks that create the project's static files in wwwroot 34 | #wwwroot/ 35 | 36 | # Visual Studio Code cache/options directory 37 | .vscode/ 38 | 39 | # MSTest test Results 40 | [Tt]est[Rr]esult*/ 41 | [Bb]uild[Ll]og.* 42 | 43 | # NUNIT 44 | *.VisualState.xml 45 | TestResult.xml 46 | 47 | # Build Results of an ATL Project 48 | [Dd]ebugPS/ 49 | [Rr]eleasePS/ 50 | dlldata.c 51 | 52 | # DNX 53 | *.lock.* 54 | *.nuget.props 55 | *.nuget.targets 56 | artifacts/ 57 | 58 | *_i.c 59 | *_p.c 60 | *_i.h 61 | *.ilk 62 | *.meta 63 | *.obj 64 | *.pch 65 | *.pdb 66 | *.pgc 67 | *.pgd 68 | *.rsp 69 | *.sbr 70 | *.tlb 71 | *.tli 72 | *.tlh 73 | *.tmp 74 | *.tmp_proj 75 | *.log 76 | *.vspscc 77 | *.vssscc 78 | .builds 79 | *.pidb 80 | *.svclog 81 | *.scc 82 | 83 | # Chutzpah Test files 84 | _Chutzpah* 85 | 86 | # Visual C++ cache files 87 | ipch/ 88 | *.aps 89 | *.ncb 90 | *.opendb 91 | *.opensdf 92 | *.sdf 93 | *.cachefile 94 | *.VC.db 95 | *.VC.VC.opendb 96 | 97 | # Visual Studio profiler 98 | *.psess 99 | *.vsp 100 | *.vspx 101 | *.sap 102 | 103 | # TFS 2012 Local Workspace 104 | $tf/ 105 | 106 | # Guidance Automation Toolkit 107 | *.gpState 108 | 109 | # ReSharper is a .NET coding add-in 110 | _ReSharper*/ 111 | *.[Rr]e[Ss]harper 112 | *.DotSettings.user 113 | 114 | # JustCode is a .NET coding add-in 115 | .JustCode 116 | 117 | # TeamCity is a build add-in 118 | _TeamCity* 119 | 120 | # DotCover is a Code Coverage Tool 121 | *.dotCover 122 | 123 | # NCrunch 124 | _NCrunch_* 125 | .*crunch*.local.xml 126 | nCrunchTemp_* 127 | 128 | # MightyMoose 129 | *.mm.* 130 | AutoTest.Net/ 131 | 132 | # Web workbench (sass) 133 | .sass-cache/ 134 | 135 | # Installshield output folder 136 | [Ee]xpress/ 137 | 138 | # DocProject is a documentation generator add-in 139 | DocProject/buildhelp/ 140 | DocProject/Help/*.HxT 141 | DocProject/Help/*.HxC 142 | DocProject/Help/*.hhc 143 | DocProject/Help/*.hhk 144 | DocProject/Help/*.hhp 145 | DocProject/Help/Html2 146 | DocProject/Help/html 147 | 148 | # Click-Once directory 149 | publish/ 150 | 151 | # Publish Web Output 152 | *.[Pp]ublish.xml 153 | *.azurePubxml 154 | # TODO: Comment the next line if you want to checkin your web deploy settings 155 | # but database connection strings (with potential passwords) will be unencrypted 156 | *.pubxml 157 | *.publishproj 158 | 159 | # Microsoft Azure Web App publish settings. Comment the next line if you want to 160 | # checkin your Azure Web App publish settings, but sensitive information contained 161 | # in these scripts will be unencrypted 162 | PublishScripts/ 163 | 164 | # NuGet Packages 165 | *.nupkg 166 | # The packages folder can be ignored because of Package Restore 167 | **/packages/* 168 | # except build/, which is used as an MSBuild target. 169 | !**/packages/build/ 170 | # Uncomment if necessary however generally it will be regenerated when needed 171 | #!**/packages/repositories.config 172 | # NuGet v3's project.json files produces more ignoreable files 173 | *.nuget.props 174 | *.nuget.targets 175 | 176 | # Microsoft Azure Build Output 177 | csx/ 178 | *.build.csdef 179 | 180 | # Microsoft Azure Emulator 181 | ecf/ 182 | rcf/ 183 | 184 | # Windows Store app package directories and files 185 | AppPackages/ 186 | BundleArtifacts/ 187 | SubmissionInfo/ 188 | Package.StoreAssociation.xml 189 | _pkginfo.txt 190 | 191 | # Visual Studio cache files 192 | # files ending in .cache can be ignored 193 | *.[Cc]ache 194 | # but keep track of directories ending in .cache 195 | !*.[Cc]ache/ 196 | 197 | # Others 198 | ClientBin/ 199 | ~$* 200 | *~ 201 | *.dbmdl 202 | *.dbproj.schemaview 203 | *.pfx 204 | *.publishsettings 205 | *.ignore.* 206 | orleans.codegen.cs 207 | node_modules/ 208 | bower_components/ 209 | typings/ 210 | jspm_packages/ 211 | 212 | # RIA/Silverlight projects 213 | Generated_Code/ 214 | 215 | # Backup & report files from converting an old project file 216 | # to a newer Visual Studio version. Backup files are not needed, 217 | # because we have git ;-) 218 | _UpgradeReport_Files/ 219 | Backup*/ 220 | UpgradeLog*.XML 221 | UpgradeLog*.htm 222 | 223 | # SQL Server files 224 | *.mdf 225 | *.ldf 226 | 227 | # Business Intelligence projects 228 | *.rdl.data 229 | *.bim.layout 230 | *.bim_*.settings 231 | 232 | # Microsoft Fakes 233 | FakesAssemblies/ 234 | 235 | # GhostDoc plugin setting file 236 | *.GhostDoc.xml 237 | 238 | # Node.js Tools for Visual Studio 239 | .ntvs_analysis.dat 240 | 241 | # Visual Studio 6 build log 242 | *.plg 243 | 244 | # Visual Studio 6 workspace options file 245 | *.opt 246 | 247 | # Visual Studio LightSwitch build output 248 | **/*.HTMLClient/GeneratedArtifacts 249 | **/*.DesktopClient/GeneratedArtifacts 250 | **/*.DesktopClient/ModelManifest.xml 251 | **/*.Server/GeneratedArtifacts 252 | **/*.Server/ModelManifest.xml 253 | _Pvt_Extensions 254 | 255 | # Paket dependency manager 256 | .paket/paket.exe 257 | paket-files/ 258 | 259 | # FAKE - F# Make 260 | .fake/ 261 | 262 | # JetBrains Rider 263 | .idea/ 264 | *.sln.iml 265 | 266 | -------------------------------------------------------------------------------- /WinBGI/winbgitypes.h: -------------------------------------------------------------------------------- 1 | // $Id: winbgitypes.h,v 1.13 2003/07/21 23:14:45 bush Exp $ 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | 11 | #pragma once 12 | 13 | #ifndef STDAFX_H_ 14 | #include "winbgi.h" // Provides default structures 15 | #endif 16 | 17 | // Define maximum pages used for drawing. 18 | #define MAX_PAGES 4 19 | typedef void(*Handler)(int, int); 20 | 21 | // --------------------------------------------------------------------------- 22 | // Structures 23 | // --------------------------------------------------------------------------- 24 | // This structure gives all necessary information to the ThreadInitWindow 25 | // function which creates a new window and processes its messages 26 | struct WindowData 27 | { 28 | int width; // Width of window to create 29 | int height; // Height of window to create 30 | int initleft, inittop; // Initial top and left coordinates on screen 31 | string title; // Title at the top of the window 32 | queue kbd_queue; // Queue of keyboard characters 33 | arccoordstype arcInfo; // Information about the last arc drawn 34 | fillsettingstype fillInfo; // Information about the fill style 35 | char uPattern[8]; // A user-defined fill style 36 | linesettingstype lineInfo; // Information about the line style 37 | textsettingstype textInfo; // Information about the text style 38 | viewporttype viewportInfo; // Information about the viewport 39 | HWND hWnd; // Handle to the window created 40 | HDC hDC[MAX_PAGES]; // Device contexts used for double buffering 41 | HBITMAP hOldBitmap[MAX_PAGES]; // The bitmaps generated with CreateCompatibleBitmap 42 | int VisualPage; // The current device context used for painting the window 43 | int ActivePage; // The current device context used for drawing 44 | bool DoubleBuffer; // Whether the user wants a double buffered window (DOUBLE_BUFFER in initwindow) 45 | bool CloseBehavior; // false (do nothing); true (exit program) 46 | int drawColor; // The current drawing color (That the user gave us) 47 | int bgColor; // The current background color (That the user gave us) 48 | // TODO: Maybe cahnge bgColor to always be the 0 index into the palette 49 | HANDLE key_waiting; // Event signaled when a key is pressed 50 | HANDLE WindowCreated; // Running event 51 | DWORD threadID; // ID of thread 52 | int error_code; // Error code used by graphresult (usually grOk) 53 | int x_aspect_ratio; // Horizontal Aspect Ratio 54 | int y_aspect_ratio; // Vertical Aspect Ratio 55 | HBITMAP hbitmap; // The bitmap of the image the user loaded 56 | POINT ipBitmap; // Location to draw the image 57 | PBITMAPINFO pbmpInfo; // Bitmap header info 58 | int t_scale[4]; // scaling factor for fonts multx, divx, multy, divy 59 | UINT alignment; // current alignment 60 | POINTS mouse; // Current location of the mouse 61 | queue clicks[WM_MOUSELAST - WM_MOUSEFIRST + 1]; // Array to hold the coordinates of the clicks 62 | bool mouse_queuing[WM_MOUSELAST - WM_MOUSEFIRST + 1]; // Array to tell whether mouse events should be queued 63 | Handler mouse_handlers[WM_MOUSELAST - WM_MOUSEFIRST + 1]; // Array of mouse event handlers 64 | bool refreshing; // True if autorefershing should be done after each drawing event 65 | HANDLE hDCMutex; // A mutex so that only one thread at a time can access the hDC array. 66 | }; 67 | // maybe need current position for lines, text, etc. 68 | // palette settings 69 | // graph error result 70 | // lock on window 71 | 72 | 73 | 74 | 75 | 76 | 77 | // --------------------------------------------------------------------------- 78 | // Prototypes 79 | // --------------------------------------------------------------------------- 80 | // The entry point for each new window thread (WindowThread.cpp) 81 | DWORD WINAPI BGI__ThreadInitWindow(LPVOID pThreadData); 82 | 83 | // Returns a DC for the window specified by hWnd. If hWnd is NULL, the 84 | // current window us used (drawing.cpp) 85 | HDC BGI__GetWinbgiDC(HWND hWnd = nullptr); 86 | void BGI__ReleaseWinbgiDC(HWND hWnd = nullptr); 87 | 88 | // Returns a pointer to the window data structure associated with hWnd. 89 | // If hWnd is NULL, the current window is used (drawing.cpp) 90 | WindowData* BGI__GetWindowDataPtr(HWND hWnd = nullptr); 91 | 92 | // Refreshes an area of the window: 93 | void RefreshWindow(RECT* rect); 94 | 95 | // --------------------------------------------------------------------------- 96 | // Global Variables 97 | // --------------------------------------------------------------------------- 98 | extern vector BGI__WindowTable; // WindowThread.cpp 99 | extern int BGI__WindowCount; // Number of windows currently in use, WindowThread.cpp 100 | extern int BGI__CurrentWindow; // Index to current window, WindowThread.cpp 101 | extern COLORREF BGI__Colors[16]; // The RGB values for the Borland 16 colors, misc.cpp 102 | extern HINSTANCE BGI__hInstance; // Handle to the instance of the DLL 103 | // (creating the window class) WindowThread.cpp 104 | -------------------------------------------------------------------------------- /WinBGI/WinBGI.vcxproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | Debug 6 | Win32 7 | 8 | 9 | Release 10 | Win32 11 | 12 | 13 | Debug 14 | x64 15 | 16 | 17 | Release 18 | x64 19 | 20 | 21 | 22 | {C218697F-1F8F-4F5B-8774-32BA17CAE9AD} 23 | Win32Proj 24 | WinBGI 25 | 10.0.10240.0 26 | 27 | 28 | 29 | StaticLibrary 30 | true 31 | v140 32 | MultiByte 33 | 34 | 35 | StaticLibrary 36 | false 37 | v140 38 | true 39 | MultiByte 40 | 41 | 42 | StaticLibrary 43 | true 44 | v140 45 | MultiByte 46 | 47 | 48 | StaticLibrary 49 | false 50 | v140 51 | true 52 | MultiByte 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | Create 76 | Level3 77 | Disabled 78 | WIN32;_DEBUG;_LIB;%(PreprocessorDefinitions) 79 | true 80 | 81 | 82 | Windows 83 | 84 | 85 | 86 | 87 | Create 88 | Level3 89 | Disabled 90 | _DEBUG;_LIB;%(PreprocessorDefinitions) 91 | true 92 | 93 | 94 | Windows 95 | 96 | 97 | 98 | 99 | Level3 100 | Create 101 | MaxSpeed 102 | true 103 | true 104 | WIN32;NDEBUG;_LIB;%(PreprocessorDefinitions) 105 | true 106 | 107 | 108 | Windows 109 | true 110 | true 111 | 112 | 113 | 114 | 115 | Level3 116 | Create 117 | MaxSpeed 118 | true 119 | true 120 | NDEBUG;_LIB;%(PreprocessorDefinitions) 121 | true 122 | 123 | 124 | Windows 125 | true 126 | true 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | -------------------------------------------------------------------------------- /WinBGI/file.cpp: -------------------------------------------------------------------------------- 1 | //******************************************************************* 2 | // 3 | // file.c 4 | // 5 | // Source file for Device-Independent Bitmap (DIB) API. Provides 6 | // the following functions: 7 | // 8 | // SaveDIB() - Saves the specified dib in a file 9 | // LoadDIB() - Loads a DIB from a file 10 | // DestroyDIB() - Deletes DIB when finished using it 11 | // 12 | // Written by Microsoft Product Support Services, Developer Support. 13 | // Copyright (C) 1991-1996 Microsoft Corporation. All rights reserved. 14 | //******************************************************************* 15 | 16 | #include "stdafx.h" 17 | //#include "dibapi.h" 18 | //#include "dibutil.h" 19 | 20 | // DIB Header Marker - used in writing DIBs to files 21 | #define DIB_HEADER_MARKER ((WORD) ('M' << 8) | 'B') 22 | 23 | 24 | /********************************************************************* 25 | * 26 | * Local Function Prototypes 27 | * 28 | *********************************************************************/ 29 | 30 | 31 | HANDLE ReadDIBFile(HANDLE); 32 | BOOL SaveDIBFile(void); 33 | BOOL WriteDIB(LPSTR, HANDLE); 34 | 35 | /************************************************************************* 36 | * 37 | * LoadDIB() 38 | * 39 | * Loads the specified DIB from a file, allocates memory for it, 40 | * and reads the disk file into the memory. 41 | * 42 | * 43 | * Parameters: 44 | * 45 | * LPSTR lpFileName - specifies the file to load a DIB from 46 | * 47 | * Returns: A handle to a DIB, or NULL if unsuccessful. 48 | * 49 | * NOTE: The DIB API were not written to handle OS/2 DIBs; This 50 | * function will reject any file that is not a Windows DIB. 51 | * 52 | *************************************************************************/ 53 | 54 | HDIB LoadDIB(const char* lpFileName) 55 | { 56 | HDIB hDIB; 57 | HANDLE hFile; 58 | 59 | // Set the cursor to a hourglass, in case the loading operation 60 | // takes more than a sec, the user will know what's going on. 61 | 62 | SetCursor(LoadCursor(NULL, IDC_WAIT)); 63 | 64 | if ((hFile = CreateFile(lpFileName, GENERIC_READ, FILE_SHARE_READ, NULL, 65 | OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, 66 | NULL)) != INVALID_HANDLE_VALUE) 67 | { 68 | hDIB = ReadDIBFile(hFile); 69 | CloseHandle(hFile); 70 | SetCursor(LoadCursor(NULL, IDC_ARROW)); 71 | return hDIB; 72 | } 73 | else 74 | { 75 | showerrorbox("File not found"); 76 | SetCursor(LoadCursor(NULL, IDC_ARROW)); 77 | return NULL; 78 | } 79 | } 80 | 81 | 82 | /************************************************************************* 83 | * 84 | * SaveDIB() 85 | * 86 | * Saves the specified DIB into the specified file name on disk. No 87 | * error checking is done, so if the file already exists, it will be 88 | * written over. 89 | * 90 | * Parameters: 91 | * 92 | * HDIB hDib - Handle to the dib to save 93 | * 94 | * LPSTR lpFileName - pointer to full pathname to save DIB under 95 | * 96 | * Return value: 0 if successful, or one of: 97 | * ERR_INVALIDHANDLE 98 | * ERR_OPEN 99 | * ERR_LOCK 100 | * 101 | *************************************************************************/ 102 | 103 | WORD SaveDIB(HDIB hDib, const char* lpFileName) 104 | { 105 | BITMAPFILEHEADER bmfHdr; // Header for Bitmap file 106 | LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure 107 | HANDLE fh; // file handle for opened file 108 | DWORD dwDIBSize; 109 | DWORD dwWritten; 110 | 111 | if (!hDib) 112 | return ERR_INVALIDHANDLE; 113 | 114 | fh = CreateFile(lpFileName, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 115 | FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL); 116 | 117 | if (fh == INVALID_HANDLE_VALUE) 118 | return ERR_OPEN; 119 | 120 | // Get a pointer to the DIB memory, the first of which contains 121 | // a BITMAPINFO structure 122 | 123 | lpBI = (LPBITMAPINFOHEADER)GlobalLock(hDib); 124 | if (!lpBI) 125 | { 126 | CloseHandle(fh); 127 | return ERR_LOCK; 128 | } 129 | 130 | // Check to see if we're dealing with an OS/2 DIB. If so, don't 131 | // save it because our functions aren't written to deal with these 132 | // DIBs. 133 | 134 | if (lpBI->biSize != sizeof(BITMAPINFOHEADER)) 135 | { 136 | GlobalUnlock(hDib); 137 | CloseHandle(fh); 138 | return ERR_NOT_DIB; 139 | } 140 | 141 | // Fill in the fields of the file header 142 | 143 | // Fill in file type (first 2 bytes must be "BM" for a bitmap) 144 | 145 | bmfHdr.bfType = DIB_HEADER_MARKER; // "BM" 146 | 147 | // Calculating the size of the DIB is a bit tricky (if we want to 148 | // do it right). The easiest way to do this is to call GlobalSize() 149 | // on our global handle, but since the size of our global memory may have 150 | // been padded a few bytes, we may end up writing out a few too 151 | // many bytes to the file (which may cause problems with some apps, 152 | // like HC 3.0). 153 | // 154 | // So, instead let's calculate the size manually. 155 | // 156 | // To do this, find size of header plus size of color table. Since the 157 | // first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER contains 158 | // the size of the structure, let's use this. 159 | 160 | // Partial Calculation 161 | 162 | dwDIBSize = *(LPDWORD)lpBI + PaletteSize((LPSTR)lpBI); 163 | 164 | // Now calculate the size of the image 165 | 166 | // It's an RLE bitmap, we can't calculate size, so trust the biSizeImage 167 | // field 168 | 169 | if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4)) 170 | dwDIBSize += lpBI->biSizeImage; 171 | else 172 | { 173 | DWORD dwBmBitsSize; // Size of Bitmap Bits only 174 | 175 | // It's not RLE, so size is Width (DWORD aligned) * Height 176 | 177 | dwBmBitsSize = WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount)) * 178 | lpBI->biHeight; 179 | 180 | dwDIBSize += dwBmBitsSize; 181 | 182 | // Now, since we have calculated the correct size, why don't we 183 | // fill in the biSizeImage field (this will fix any .BMP files which 184 | // have this field incorrect). 185 | 186 | lpBI->biSizeImage = dwBmBitsSize; 187 | } 188 | 189 | 190 | // Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER) 191 | 192 | bmfHdr.bfSize = dwDIBSize + sizeof(BITMAPFILEHEADER); 193 | bmfHdr.bfReserved1 = 0; 194 | bmfHdr.bfReserved2 = 0; 195 | 196 | // Now, calculate the offset the actual bitmap bits will be in 197 | // the file -- It's the Bitmap file header plus the DIB header, 198 | // plus the size of the color table. 199 | 200 | bmfHdr.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) + lpBI->biSize + 201 | PaletteSize((LPSTR)lpBI); 202 | 203 | // Write the file header 204 | 205 | WriteFile(fh, (LPSTR)&bmfHdr, sizeof(BITMAPFILEHEADER), &dwWritten, NULL); 206 | 207 | // Write the DIB header and the bits -- use local version of 208 | // MyWrite, so we can write more than 32767 bytes of data 209 | 210 | WriteFile(fh, (LPSTR)lpBI, dwDIBSize, &dwWritten, NULL); 211 | 212 | GlobalUnlock(hDib); 213 | CloseHandle(fh); 214 | 215 | if (dwWritten == 0) 216 | return ERR_OPEN; // oops, something happened in the write 217 | else 218 | return 0; // Success code 219 | } 220 | 221 | 222 | /************************************************************************* 223 | * 224 | * DestroyDIB () 225 | * 226 | * Purpose: Frees memory associated with a DIB 227 | * 228 | * Returns: Nothing 229 | * 230 | *************************************************************************/ 231 | 232 | WORD DestroyDIB(HDIB hDib) 233 | { 234 | GlobalFree(hDib); 235 | return 0; 236 | } 237 | 238 | 239 | //************************************************************************ 240 | // 241 | // Auxiliary Functions which the above procedures use 242 | // 243 | //************************************************************************ 244 | 245 | 246 | /************************************************************************* 247 | * 248 | * Function: ReadDIBFile (int) 249 | * 250 | * Purpose: Reads in the specified DIB file into a global chunk of 251 | * memory. 252 | * 253 | * Returns: A handle to a dib (hDIB) if successful. 254 | * NULL if an error occurs. 255 | * 256 | * Comments: BITMAPFILEHEADER is stripped off of the DIB. Everything 257 | * from the end of the BITMAPFILEHEADER structure on is 258 | * returned in the global memory handle. 259 | * 260 | * 261 | * NOTE: The DIB API were not written to handle OS/2 DIBs, so this 262 | * function will reject any file that is not a Windows DIB. 263 | * 264 | *************************************************************************/ 265 | 266 | HANDLE ReadDIBFile(HANDLE hFile) 267 | { 268 | BITMAPFILEHEADER bmfHeader; 269 | DWORD dwBitsSize; 270 | UINT nNumColors; // Number of colors in table 271 | HANDLE hDIB; 272 | HANDLE hDIBtmp; // Used for GlobalRealloc() //MPB 273 | LPBITMAPINFOHEADER lpbi; 274 | DWORD offBits; 275 | DWORD dwRead; 276 | 277 | // get length of DIB in bytes for use when reading 278 | 279 | dwBitsSize = GetFileSize(hFile, NULL); 280 | 281 | // Allocate memory for header & color table. We'll enlarge this 282 | // memory as needed. 283 | 284 | hDIB = GlobalAlloc(GMEM_MOVEABLE, (DWORD)(sizeof(BITMAPINFOHEADER) + 285 | 256 * sizeof(RGBQUAD))); 286 | 287 | if (!hDIB) 288 | return NULL; 289 | 290 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 291 | 292 | if (!lpbi) 293 | { 294 | GlobalFree(hDIB); 295 | return NULL; 296 | } 297 | 298 | // read the BITMAPFILEHEADER from our file 299 | 300 | if (!ReadFile(hFile, (LPSTR)&bmfHeader, sizeof(BITMAPFILEHEADER), 301 | &dwRead, NULL)) 302 | goto ErrExit; 303 | 304 | if (sizeof(BITMAPFILEHEADER) != dwRead) 305 | goto ErrExit; 306 | 307 | if (bmfHeader.bfType != 0x4d42) // 'BM' 308 | goto ErrExit; 309 | 310 | // read the BITMAPINFOHEADER 311 | 312 | if (!ReadFile(hFile, (LPSTR)lpbi, sizeof(BITMAPINFOHEADER), &dwRead, 313 | NULL)) 314 | goto ErrExit; 315 | 316 | if (sizeof(BITMAPINFOHEADER) != dwRead) 317 | goto ErrExit; 318 | 319 | // Check to see that it's a Windows DIB -- an OS/2 DIB would cause 320 | // strange problems with the rest of the DIB API since the fields 321 | // in the header are different and the color table entries are 322 | // smaller. 323 | // 324 | // If it's not a Windows DIB (e.g. if biSize is wrong), return NULL. 325 | 326 | if (lpbi->biSize == sizeof(BITMAPCOREHEADER)) 327 | goto ErrExit; 328 | 329 | // Now determine the size of the color table and read it. Since the 330 | // bitmap bits are offset in the file by bfOffBits, we need to do some 331 | // special processing here to make sure the bits directly follow 332 | // the color table (because that's the format we are supposed to pass 333 | // back) 334 | 335 | if (!(nNumColors = (UINT)lpbi->biClrUsed)) 336 | { 337 | // no color table for 24-bit, default size otherwise 338 | 339 | if (lpbi->biBitCount != 24) 340 | nNumColors = 1 << lpbi->biBitCount; // standard size table 341 | } 342 | 343 | // fill in some default values if they are zero 344 | 345 | if (lpbi->biClrUsed == 0) 346 | lpbi->biClrUsed = nNumColors; 347 | 348 | if (lpbi->biSizeImage == 0) 349 | { 350 | lpbi->biSizeImage = ((((lpbi->biWidth * (DWORD)lpbi->biBitCount) + 351 | 31) & ~31) >> 3) * lpbi->biHeight; 352 | } 353 | 354 | // get a proper-sized buffer for header, color table and bits 355 | 356 | GlobalUnlock(hDIB); 357 | hDIBtmp = GlobalReAlloc(hDIB, lpbi->biSize + nNumColors * 358 | sizeof(RGBQUAD) + lpbi->biSizeImage, 0); 359 | 360 | if (!hDIBtmp) // can't resize buffer for loading 361 | goto ErrExitNoUnlock; //MPB 362 | else 363 | hDIB = hDIBtmp; 364 | 365 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 366 | 367 | // read the color table 368 | 369 | ReadFile(hFile, (LPSTR)(lpbi)+lpbi->biSize, 370 | nNumColors * sizeof(RGBQUAD), &dwRead, NULL); 371 | 372 | // offset to the bits from start of DIB header 373 | 374 | offBits = lpbi->biSize + nNumColors * sizeof(RGBQUAD); 375 | 376 | // If the bfOffBits field is non-zero, then the bits might *not* be 377 | // directly following the color table in the file. Use the value in 378 | // bfOffBits to seek the bits. 379 | 380 | if (bmfHeader.bfOffBits != 0L) 381 | SetFilePointer(hFile, bmfHeader.bfOffBits, NULL, FILE_BEGIN); 382 | 383 | if (ReadFile(hFile, (LPSTR)lpbi + offBits, lpbi->biSizeImage, &dwRead, 384 | NULL)) 385 | goto OKExit; 386 | 387 | 388 | ErrExit: 389 | GlobalUnlock(hDIB); 390 | 391 | ErrExitNoUnlock: 392 | GlobalFree(hDIB); 393 | return NULL; 394 | 395 | OKExit: 396 | GlobalUnlock(hDIB); 397 | return hDIB; 398 | } 399 | -------------------------------------------------------------------------------- /WinBGI/text.cpp: -------------------------------------------------------------------------------- 1 | // File: text.cpp 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | // This file contains the code necessary to draw/modify text 12 | // 13 | 14 | #include "stdafx.h" 15 | //#include "winbgi.h" 16 | //#include "winbgitypes.h" 17 | 18 | 19 | /***************************************************************************** 20 | * 21 | * Some very useful arrays -- Same as previous version for consistency 22 | * Also, the exported definition of bgiout. 23 | * 24 | *****************************************************************************/ 25 | ostringstream bgiout; 26 | 27 | static int font_weight[] = 28 | { 29 | FW_BOLD, // DefaultFont 30 | FW_NORMAL, // TriplexFont 31 | FW_NORMAL, // SmallFont 32 | FW_NORMAL, // SansSerifFont 33 | FW_NORMAL, // GothicFont 34 | FW_NORMAL, // ScriptFont 35 | FW_NORMAL, // SimplexFont 36 | FW_NORMAL, // TriplexScriptFont 37 | FW_NORMAL, // ComplexFont 38 | FW_NORMAL, // EuropeanFont 39 | FW_BOLD // BoldFont 40 | }; 41 | static int font_family[] = 42 | { 43 | FIXED_PITCH | FF_DONTCARE, // DefaultFont 44 | VARIABLE_PITCH | FF_ROMAN, // TriplexFont 45 | VARIABLE_PITCH | FF_MODERN, // SmallFont 46 | VARIABLE_PITCH | FF_DONTCARE, // SansSerifFont 47 | VARIABLE_PITCH | FF_SWISS, // GothicFont 48 | VARIABLE_PITCH | FF_SCRIPT, // ScriptFont 49 | VARIABLE_PITCH | FF_DONTCARE, // SimplexFont 50 | VARIABLE_PITCH | FF_SCRIPT, // TriplexScriptFont 51 | VARIABLE_PITCH | FF_DONTCARE, // ComplexFont 52 | VARIABLE_PITCH | FF_DONTCARE, // EuropeanFont 53 | VARIABLE_PITCH | FF_DONTCARE // BoldFont 54 | }; 55 | static char* font_name[] = 56 | { 57 | "Console", // DefaultFont 58 | "Times New Roman", // TriplexFont 59 | "Small Fonts", // SmallFont 60 | "MS Sans Serif", // SansSerifFont 61 | "Arial", // GothicFont 62 | "Script", // ScriptFont 63 | "Times New Roman", // SimplexFont 64 | "Script", // TriplexScriptFont 65 | "Courier New", // ComplexFont 66 | "Times New Roman", // EuropeanFont 67 | "Courier New Bold", // BoldFont 68 | }; 69 | 70 | static struct { int width; int height; } font_metrics[][11] = { 71 | {{0,0},{8,8},{16,16},{24,24},{32,32},{40,40},{48,48},{56,56},{64,64},{72,72},{80,80}}, // DefaultFont 72 | {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexFont 73 | {{0,0},{3,5},{4,6},{4,6},{6,9},{8,12},{10,15},{12,18},{15,22},{18,27},{24,36}}, // SmallFont 74 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SansSerifFont 75 | {{0,0},{13,19},{14,21},{16,24},{22,32},{29,42},{36,53},{44,64},{55,80},{66,96},{88,128}}, // GothicFont 76 | 77 | // These may not be 100% correct 78 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ScriptFont 79 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // SimplexFont 80 | {{0,0},{13,18},{14,20},{16,23},{22,31},{29,41},{36,51},{44,62},{55,77},{66,93},{88,124}}, // TriplexScriptFont 81 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // ComplexFont 82 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}}, // EuropeanFont 83 | {{0,0},{11,19},{12,21},{14,24},{19,32},{25,42},{31,53},{38,64},{47,80},{57,96},{76,128}} // BoldFont 84 | }; 85 | 86 | // horiz LEFT_TEXT 0 left-justify text 87 | // CENTER_TEXT 1 center text 88 | // RIGHT_TEXT 2 right-justify text 89 | // vertical BOTTOM_TEXT 0 bottom-justify text 90 | // CENTER_TEXT 1 center text 91 | // TOP_TEXT 2 top-justify text 92 | static UINT horiz_align[3] = { TA_LEFT, TA_CENTER, TA_RIGHT }; 93 | static UINT vert_align[3] = { TA_BOTTOM, TA_BASELINE, TA_TOP }; 94 | 95 | /***************************************************************************** 96 | * 97 | * Some helper functions 98 | * 99 | *****************************************************************************/ 100 | 101 | // This function 102 | // POSTCONDITION: 103 | // 104 | static void set_align(WindowData* pWndData) 105 | { 106 | auto alignment = pWndData->alignment; 107 | 108 | // if we are vertical, things are swapped. 109 | if (pWndData->textInfo.direction == HORIZ_DIR) 110 | { 111 | alignment |= horiz_align[pWndData->textInfo.horiz]; 112 | alignment |= vert_align[pWndData->textInfo.vert]; 113 | } 114 | else 115 | { 116 | alignment |= horiz_align[pWndData->textInfo.vert]; 117 | alignment |= vert_align[pWndData->textInfo.horiz]; 118 | } 119 | 120 | // set the alignment for all valid pages. 121 | for (auto i = 0; i < MAX_PAGES; i++) 122 | SetTextAlign(pWndData->hDC[i], alignment); 123 | } 124 | 125 | // This function updates the current hdc with the user defined font 126 | // POSTCONDITION: text written to the current hdc will be in the new font 127 | // 128 | static void set_font(WindowData* pWndData) 129 | { 130 | int mindex; 131 | double xscale, yscale; 132 | HFONT hFont; 133 | 134 | // get the scaling factors based on charsize 135 | if (pWndData->textInfo.charsize == 0) 136 | { 137 | xscale = pWndData->t_scale[0] / pWndData->t_scale[1]; 138 | yscale = pWndData->t_scale[2] / pWndData->t_scale[3]; 139 | 140 | // if font zero, only use factors.. else also multiply by 4 141 | if (pWndData->textInfo.font == 0) 142 | mindex = 0; 143 | else 144 | mindex = 4; 145 | } 146 | else 147 | { 148 | xscale = 1.0; 149 | yscale = 1.0; 150 | mindex = pWndData->textInfo.charsize; 151 | } 152 | 153 | // with the scaling decided, make a font. 154 | hFont = CreateFont( 155 | int(font_metrics[pWndData->textInfo.font][mindex].height * yscale), 156 | int(font_metrics[pWndData->textInfo.font][mindex].width * xscale), 157 | pWndData->textInfo.direction * 900, 158 | (pWndData->textInfo.direction & 1) * 900, 159 | font_weight[pWndData->textInfo.font], 160 | FALSE, 161 | FALSE, 162 | FALSE, 163 | DEFAULT_CHARSET, 164 | OUT_DEFAULT_PRECIS, 165 | CLIP_DEFAULT_PRECIS, 166 | DEFAULT_QUALITY, 167 | font_family[pWndData->textInfo.font], 168 | font_name[pWndData->textInfo.font] 169 | ); 170 | 171 | // assign the fonts to each of the hdcs 172 | for (auto i = 0; i < MAX_PAGES; i++) 173 | SelectObject(pWndData->hDC[i], hFont); 174 | } 175 | 176 | 177 | /***************************************************************************** 178 | * 179 | * The actual API calls are implemented below 180 | * 181 | *****************************************************************************/ 182 | // This function fills the textsettingstype structure pointed to by textinfo 183 | // with information about the current text font, direction, size, and 184 | // justification. 185 | // POSTCONDITION: texttypeinfo has been filled with the proper information 186 | // 187 | void gettextsettings(struct textsettingstype *texttypeinfo) 188 | { 189 | // if its null, leave. 190 | if (!texttypeinfo) 191 | return; 192 | 193 | auto pWndData = BGI__GetWindowDataPtr(); 194 | 195 | *texttypeinfo = pWndData->textInfo; 196 | } 197 | 198 | // This function prints textstring to the screen at the current position 199 | // POSTCONDITION: text has been written to the screen using the current font, 200 | // direction, and size. In addition, the current position has 201 | // been modified to reflect the text that was just output. 202 | // 203 | void outtext(char *textstring) 204 | { 205 | auto hDC = BGI__GetWinbgiDC(); 206 | auto pWndData = BGI__GetWindowDataPtr(); 207 | 208 | // so we can clear the screen 209 | POINT cp; 210 | GetCurrentPositionEx(hDC, &cp); 211 | 212 | // check cp alignment 213 | if (pWndData->alignment != TA_UPDATECP) 214 | { 215 | pWndData->alignment = TA_UPDATECP; 216 | set_align(pWndData); 217 | } 218 | 219 | TextOut(hDC, 0, 0, LPCTSTR(textstring), int(strlen(textstring))); 220 | BGI__ReleaseWinbgiDC(); 221 | RefreshWindow(nullptr); 222 | // Todo: Change to refresh only the needed part. 223 | } 224 | 225 | // This function prints textstring to x,y 226 | // POSTCONDITION: text has been written to the screen using the current font, 227 | // direction, and size. If a string is printed with the default 228 | // font using outtext or outtextxy, any part of the string that 229 | // extends outside the current viewport is truncated. 230 | // 231 | void outtextxy(int x, int y, char *textstring) 232 | { 233 | auto hDC = BGI__GetWinbgiDC(); 234 | auto pWndData = BGI__GetWindowDataPtr(); 235 | 236 | // check alignment 237 | if (pWndData->alignment != TA_NOUPDATECP) 238 | { 239 | pWndData->alignment = TA_NOUPDATECP; 240 | set_align(pWndData); 241 | } 242 | 243 | TextOut(hDC, x, y, LPCTSTR(textstring), int(strlen(textstring))); 244 | BGI__ReleaseWinbgiDC(); 245 | 246 | RefreshWindow(nullptr); 247 | // Todo: Change to refresh only the needed part. 248 | } 249 | 250 | 251 | 252 | // This function sets the vertical and horizontal justification based on CP 253 | // POSTCONDITION: Text output is justified around the current position as 254 | // has been specified. 255 | // 256 | void settextjustify(int horiz, int vert) 257 | { 258 | auto pWndData = BGI__GetWindowDataPtr(); 259 | 260 | pWndData->textInfo.horiz = horiz; 261 | pWndData->textInfo.vert = vert; 262 | 263 | WaitForSingleObject(pWndData->hDCMutex, 5000); 264 | set_align(pWndData); 265 | ReleaseMutex(pWndData->hDCMutex); 266 | } 267 | 268 | 269 | // This function sets the font and it's properties that will be used 270 | // by all text output related functions. 271 | // POSTCONDITION: text output after a call to settextstyle should be 272 | // in the newly specified format. 273 | // 274 | void settextstyle(int font, int direction, int charsize) 275 | { 276 | auto pWndData = BGI__GetWindowDataPtr(); 277 | 278 | pWndData->textInfo.font = font; 279 | pWndData->textInfo.direction = direction; 280 | pWndData->textInfo.charsize = charsize; 281 | 282 | WaitForSingleObject(pWndData->hDCMutex, 5000); 283 | set_font(pWndData); 284 | ReleaseMutex(pWndData->hDCMutex); 285 | } 286 | 287 | // This function sets the size of stroked fonts 288 | // POSTCONDITION: these values will be used when charsize is zero in the 289 | // settextstyle assignments. consequently output text will 290 | // be scaled by the appropriate x and y values when output. 291 | // 292 | void setusercharsize(int multx, int divx, int multy, int divy) 293 | { 294 | auto pWndData = BGI__GetWindowDataPtr(); 295 | pWndData->t_scale[0] = multx; 296 | pWndData->t_scale[1] = divx; 297 | pWndData->t_scale[2] = multy; 298 | pWndData->t_scale[3] = divy; 299 | 300 | WaitForSingleObject(pWndData->hDCMutex, 5000); 301 | set_font(pWndData); 302 | ReleaseMutex(pWndData->hDCMutex); 303 | } 304 | 305 | // This function returns the height in pixels of textstring using the current 306 | // text output settings. 307 | // POSTCONDITION: the height of the string in pixels has been returned. 308 | // 309 | int textheight(char *textstring) 310 | { 311 | auto hDC = BGI__GetWinbgiDC(); 312 | SIZE tb; 313 | 314 | GetTextExtentPoint32(hDC, LPCTSTR(textstring), int(strlen(textstring)), &tb); 315 | BGI__ReleaseWinbgiDC(); 316 | 317 | return tb.cy; 318 | } 319 | 320 | // This function returns the width in pixels of textstring using the current 321 | // text output settings. 322 | // POSTCONDITION: the width of the string in pixels has been returned. 323 | // 324 | int textwidth(char *textstring) 325 | { 326 | auto hDC = BGI__GetWinbgiDC(); 327 | SIZE tb; 328 | 329 | GetTextExtentPoint32(hDC, LPCTSTR(textstring), int(strlen(textstring)), &tb); 330 | BGI__ReleaseWinbgiDC(); 331 | 332 | return tb.cx; 333 | } 334 | 335 | void outstreamxy(int x, int y, ostringstream& out) 336 | { 337 | string all, line; 338 | auto startx = x; 339 | 340 | all = out.str(); 341 | out.str(""); 342 | 343 | moveto(x, y); 344 | for (size_t i = 0; i < all.length(); i++) 345 | { 346 | if (all[i] == '\n') 347 | { 348 | if (line.length() > 0) 349 | outtext(const_cast(line.c_str())); 350 | y += textheight("X"); 351 | x = startx; 352 | line.clear(); 353 | moveto(x, y); 354 | } 355 | else 356 | line += all[i]; 357 | } 358 | if (line.length() > 0) 359 | outtext(const_cast(line.c_str())); 360 | } 361 | 362 | void outstream(ostringstream& out) 363 | { 364 | outstreamxy(getx(), gety(), out); 365 | } 366 | -------------------------------------------------------------------------------- /WinBGI/winbgi.h: -------------------------------------------------------------------------------- 1 | // The winbgim library, Version 6.0, August 9, 2004 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // Michael Main (Michael.Main@colorado.edu) 8 | // CSCI 4830/7818: API Programming 9 | // University of Colorado at Boulder, Spring 2003 10 | 11 | 12 | // --------------------------------------------------------------------------- 13 | // Notes 14 | // --------------------------------------------------------------------------- 15 | // * This library is still under development. 16 | // * Please see http://www.cs.colorado.edu/~main/bgi for information on 17 | // * using this library with the mingw32 g++ compiler. 18 | // * This library only works with Windows API level 4.0 and higher (Windows 95, NT 4.0 and newer) 19 | // * This library may not be compatible with 64-bit versions of Windows 20 | // --------------------------------------------------------------------------- 21 | 22 | 23 | #pragma once 24 | 25 | #ifndef STDAFX_H_ 26 | #include // Provides std::ostringstream 27 | #include // Provides INT_MAX 28 | #include // Provides the mouse message types 29 | #endif 30 | 31 | // --------------------------------------------------------------------------- 32 | 33 | // --------------------------------------------------------------------------- 34 | // Definitions 35 | // --------------------------------------------------------------------------- 36 | // Definitions for the key pad extended keys are added here. When one 37 | // of these keys are pressed, getch will return a zero followed by one 38 | // of these values. This is the same way that it works in conio for 39 | // dos applications. 40 | #define KEY_HOME 71 41 | #define KEY_UP 72 42 | #define KEY_PGUP 73 43 | #define KEY_LEFT 75 44 | #define KEY_CENTER 76 45 | #define KEY_RIGHT 77 46 | #define KEY_END 79 47 | #define KEY_DOWN 80 48 | #define KEY_PGDN 81 49 | #define KEY_INSERT 82 50 | #define KEY_DELETE 83 51 | #define KEY_F1 59 52 | #define KEY_F2 60 53 | #define KEY_F3 61 54 | #define KEY_F4 62 55 | #define KEY_F5 63 56 | #define KEY_F6 64 57 | #define KEY_F7 65 58 | #define KEY_F8 66 59 | #define KEY_F9 67 60 | 61 | // Line thickness settings 62 | #define NORM_WIDTH 1 63 | #define THICK_WIDTH 3 64 | 65 | // Character Size and Direction 66 | #define USER_CHAR_SIZE 0 67 | #define HORIZ_DIR 0 68 | #define VERT_DIR 1 69 | 70 | // No mouse event of the current type in getmouseclick 71 | #define NO_CLICK -1 72 | 73 | // Constants for closegraph 74 | #define CURRENT_WINDOW -1 75 | #define ALL_WINDOWS -2 76 | #define NO_CURRENT_WINDOW -3 77 | 78 | // The standard Borland 16 colors 79 | #define MAXCOLORS 15 80 | 81 | enum colors 82 | { 83 | BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, 84 | LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE 85 | }; 86 | 87 | // The standard line styles 88 | enum line_styles { SOLID_LINE, DOTTED_LINE, CENTER_LINE, DASHED_LINE, USERBIT_LINE }; 89 | 90 | // The standard fill styles 91 | enum fill_styles 92 | { 93 | EMPTY_FILL, SOLID_FILL, LINE_FILL, LTSLASH_FILL, SLASH_FILL, 94 | BKSLASH_FILL, LTBKSLASH_FILL, HATCH_FILL, XHATCH_FILL, INTERLEAVE_FILL, 95 | WIDE_DOT_FILL, CLOSE_DOT_FILL, USER_FILL 96 | }; 97 | 98 | // The various graphics drivers 99 | enum graphics_drivers 100 | { 101 | DETECT, CGA, MCGA, EGA, EGA64, EGAMONO, IBM8514, HERCMONO, 102 | ATT400, VGA, PC3270 103 | }; 104 | 105 | // Various modes for each graphics driver 106 | enum graphics_modes 107 | { 108 | CGAC0, CGAC1, CGAC2, CGAC3, CGAHI, 109 | MCGAC0 = 0, MCGAC1, MCGAC2, MCGAC3, MCGAMED, MCGAHI, 110 | EGALO = 0, EGAHI, 111 | EGA64LO = 0, EGA64HI, 112 | EGAMONOHI = 3, 113 | HERCMONOHI = 0, 114 | ATT400C0 = 0, ATT400C1, ATT400C2, ATT400C3, ATT400MED, ATT400HI, 115 | VGALO = 0, VGAMED, VGAHI, 116 | PC3270HI = 0, 117 | IBM8514LO = 0, IBM8514HI 118 | }; 119 | 120 | // Borland error messages for the graphics window. 121 | enum graph_errors 122 | { 123 | grInvalidVersion = -18, grInvalidDeviceNum = -15, grInvalidFontNum, 124 | grInvalidFont, grIOerror, grError, grInvalidMode, grNoFontMem, 125 | grFontNotFound, grNoFloodMem, grNoScanMem, grNoLoadMem, 126 | grInvalidDriver, grFileNotFound, grNotDetected, grNoInitGraph, 127 | grOk 128 | }; 129 | 130 | // Write modes 131 | enum putimage_ops { COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT }; 132 | 133 | // Text Modes 134 | enum horiz { LEFT_TEXT, CENTER_TEXT, RIGHT_TEXT }; 135 | enum vertical { BOTTOM_TEXT, VCENTER_TEXT, TOP_TEXT }; // middle not needed other than as seperator 136 | enum font_names 137 | { 138 | DEFAULT_FONT, TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT, 139 | GOTHIC_FONT, SCRIPT_FONT, SIMPLEX_FONT, TRIPLEX_SCR_FONT, 140 | COMPLEX_FONT, EUROPEAN_FONT, BOLD_FONT 141 | }; 142 | // --------------------------------------------------------------------------- 143 | 144 | 145 | 146 | // --------------------------------------------------------------------------- 147 | // Structures 148 | // --------------------------------------------------------------------------- 149 | // This structure records information about the last call to arc. It is used 150 | // by getarccoords to get the location of the endpoints of the arc. 151 | struct arccoordstype 152 | { 153 | int x, y; // Center point of the arc 154 | int xstart, ystart; // The starting position of the arc 155 | int xend, yend; // The ending position of the arc. 156 | }; 157 | 158 | 159 | // This structure defines the fill style for the current window. Pattern is 160 | // one of the system patterns such as SOLID_FILL. Color is the color to 161 | // fill with 162 | struct fillsettingstype 163 | { 164 | int pattern; // Current fill pattern 165 | int color; // Current fill color 166 | }; 167 | 168 | 169 | // This structure records information about the current line style. 170 | // linestyle is one of the line styles such as SOLID_LINE, upattern is a 171 | // 16-bit pattern for user defined lines, and thickness is the width of the 172 | // line in pixels. 173 | struct linesettingstype 174 | { 175 | int linestyle; // Current line style 176 | unsigned int upattern; // 16-bit user line pattern 177 | int thickness; // Width of the line in pixels 178 | }; 179 | 180 | 181 | // This structure records information about the text settings. 182 | struct textsettingstype 183 | { 184 | int font; // The font in use 185 | int direction; // Text direction 186 | int charsize; // Character size 187 | int horiz; // Horizontal text justification 188 | int vert; // Vertical text justification 189 | }; 190 | 191 | 192 | // This structure records information about the viewport 193 | struct viewporttype 194 | { 195 | int left, top, // Viewport bounding box 196 | right, bottom; 197 | int clip; // Whether to clip image to viewport 198 | }; 199 | 200 | 201 | // This structure records information about the palette. 202 | struct palettetype 203 | { 204 | unsigned char size; 205 | signed char colors[MAXCOLORS + 1]; 206 | }; 207 | // --------------------------------------------------------------------------- 208 | 209 | 210 | 211 | // --------------------------------------------------------------------------- 212 | // API Entries 213 | // --------------------------------------------------------------------------- 214 | #ifdef __cplusplus 215 | extern "C" 216 | { 217 | #endif 218 | 219 | // Drawing Functions 220 | void arc(int x, int y, int stangle, int endangle, int radius); 221 | void bar(int left, int top, int right, int bottom); 222 | void bar3d(int left, int top, int right, int bottom, int depth, int topflag); 223 | void circle(int x, int y, int radius); 224 | void cleardevice(); 225 | void clearviewport(); 226 | void drawpoly(int n_points, int* points); 227 | void ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius); 228 | void fillellipse(int x, int y, int xradius, int yradius); 229 | void fillpoly(int n_points, int* points); 230 | void floodfill(int x, int y, int border); 231 | void line(int x1, int y1, int x2, int y2); 232 | void linerel(int dx, int dy); 233 | void lineto(int x, int y); 234 | void pieslice(int x, int y, int stangle, int endangle, int radius); 235 | void putpixel(int x, int y, int color); 236 | void rectangle(int left, int top, int right, int bottom); 237 | void sector(int x, int y, int stangle, int endangle, int xradius, int yradius); 238 | 239 | // Miscellaneous Functions 240 | int getdisplaycolor(int color); 241 | int converttorgb(int color); 242 | void delay(int msec); 243 | void getarccoords(arccoordstype *arccoords); 244 | int getbkcolor(); 245 | int getcolor(); 246 | void getfillpattern(char *pattern); 247 | void getfillsettings(fillsettingstype *fillinfo); 248 | void getlinesettings(linesettingstype *lineinfo); 249 | int getmaxcolor(); 250 | int getmaxheight(); 251 | int getmaxwidth(); 252 | int getmaxx(); 253 | int getmaxy(); 254 | bool getrefreshingbgi(); 255 | int getwindowheight(); 256 | int getwindowwidth(); 257 | int getpixel(int x, int y); 258 | void getviewsettings(viewporttype *viewport); 259 | int getx(); 260 | int gety(); 261 | void moverel(int dx, int dy); 262 | void moveto(int x, int y); 263 | void refreshbgi(int left, int top, int right, int bottom); 264 | void refreshallbgi(); 265 | void setbkcolor(int color); 266 | void setcolor(int color); 267 | void setfillpattern(char *upattern, int color); 268 | void setfillstyle(int pattern, int color); 269 | void setlinestyle(int linestyle, unsigned int upattern, int thickness); 270 | void setrefreshingbgi(bool value); 271 | void setviewport(int left, int top, int right, int bottom, int clip); 272 | void setwritemode(int mode); 273 | 274 | // Window Creation / Graphics Manipulation 275 | void closegraph(int wid = ALL_WINDOWS); 276 | void detectgraph(int *graphdriver, int *graphmode); 277 | void getaspectratio(int *xasp, int *yasp); 278 | char *getdrivername(); 279 | int getgraphmode(); 280 | int getmaxmode(); 281 | char *getmodename(int mode_number); 282 | void getmoderange(int graphdriver, int *lomode, int *himode); 283 | void graphdefaults(); 284 | char *grapherrormsg(int errorcode); 285 | int graphresult(); 286 | void initgraph(int *graphdriver, int *graphmode, char *pathtodriver); 287 | int initwindow(int width, int height, const char* title = "Windows BGI", int left = 0, int top = 0, bool dbflag = false, bool closeflag = true); 288 | int installuserdriver(char *name, int *fp); // Not available in WinBGI 289 | int installuserfont(char *name); // Not available in WinBGI 290 | int registerbgidriver(void *driver); // Not available in WinBGI 291 | int registerbgifont(void *font); // Not available in WinBGI 292 | void restorecrtmode(); 293 | void setaspectratio(int xasp, int yasp); 294 | unsigned int setgraphbufsize(unsigned int bufsize); // Not available in WinBGI 295 | void setgraphmode(int mode); 296 | void showerrorbox(const char *msg = nullptr); 297 | 298 | // User Interaction 299 | int getch(); 300 | int kbhit(); 301 | 302 | // User-Controlled Window Functions (winbgi.cpp) 303 | int getcurrentwindow(); 304 | void setcurrentwindow(int window); 305 | 306 | // Double buffering support (winbgi.cpp) 307 | int getactivepage(); 308 | int getvisualpage(); 309 | void setactivepage(int page); 310 | void setvisualpage(int page); 311 | void swapbuffers(); 312 | 313 | // Image Functions (drawing.cpp) 314 | unsigned int imagesize(int left, int top, int right, int bottom); 315 | void getimage(int left, int top, int right, int bottom, void *bitmap); 316 | void putimage(int left, int top, void *bitmap, int op); 317 | void printimage( 318 | const char* title = nullptr, 319 | double width_inches = 7, double border_left_inches = 0.75, double border_top_inches = 0.75, 320 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX, 321 | bool active = true, HWND hwnd = nullptr 322 | ); 323 | void readimagefile( 324 | const char* filename = nullptr, 325 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX 326 | ); 327 | void writeimagefile( 328 | const char* filename = nullptr, 329 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX, 330 | bool active = true, HWND hwnd = nullptr 331 | ); 332 | 333 | // Text Functions (text.cpp) 334 | void gettextsettings(struct textsettingstype *texttypeinfo); 335 | void outtext(char *textstring); 336 | void outtextxy(int x, int y, char *textstring); 337 | void settextjustify(int horiz, int vert); 338 | void settextstyle(int font, int direction, int charsize); 339 | void setusercharsize(int multx, int divx, int multy, int divy); 340 | int textheight(char *textstring); 341 | int textwidth(char *textstring); 342 | extern ostringstream bgiout; 343 | void outstream(ostringstream& out = bgiout); 344 | void outstreamxy(int x, int y, ostringstream& out = bgiout); 345 | 346 | // Mouse Functions (mouse.cpp) 347 | void clearmouseclick(int kind); 348 | void clearresizeevent(); 349 | void getmouseclick(int kind, int& x, int& y); 350 | bool ismouseclick(int kind); 351 | bool isresizeevent(); 352 | int mousex(); 353 | int mousey(); 354 | void registermousehandler(int kind, void h(int, int)); 355 | void setmousequeuestatus(int kind, bool status = true); 356 | 357 | // Palette Functions 358 | palettetype *getdefaultpalette(); 359 | void getpalette(palettetype *palette); 360 | int getpalettesize(); 361 | void setallpalette(palettetype *palette); 362 | void setpalette(int colornum, int color); 363 | void setrgbpalette(int colornum, int red, int green, int blue); 364 | 365 | // Color Macros 366 | #define IS_BGI_COLOR(v) ( ((v) >= 0) && ((v) < 16) ) 367 | #define IS_RGB_COLOR(v) ( (v) & 0x03000000 ) 368 | #define RED_VALUE(v) int(GetRValue( converttorgb(v) )) 369 | #define GREEN_VALUE(v) int(GetGValue( converttorgb(v) )) 370 | #define BLUE_VALUE(v) int(GetBValue( converttorgb(v) )) 371 | #undef COLOR 372 | int COLOR(int r, int g, int b); // No longer a macro 373 | #ifdef __cplusplus 374 | } 375 | #endif 376 | // --------------------------------------------------------------------------- 377 | -------------------------------------------------------------------------------- /WinBGI/graphics.h: -------------------------------------------------------------------------------- 1 | // The winbgim library, Version 6.0, August 9, 2004 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // Michael Main (Michael.Main@colorado.edu) 8 | // CSCI 4830/7818: API Programming 9 | // University of Colorado at Boulder, Spring 2003 10 | 11 | 12 | // --------------------------------------------------------------------------- 13 | // Notes 14 | // --------------------------------------------------------------------------- 15 | // * This library is still under development. 16 | // * Please see http://www.cs.colorado.edu/~main/bgi for information on 17 | // * using this library with the mingw32 g++ compiler. 18 | // * This library only works with Windows API level 4.0 and higher (Windows 95, NT 4.0 and newer) 19 | // * This library may not be compatible with 64-bit versions of Windows 20 | // --------------------------------------------------------------------------- 21 | 22 | 23 | // --------------------------------------------------------------------------- 24 | // Macro Guard and Include Directives 25 | // --------------------------------------------------------------------------- 26 | 27 | #pragma once 28 | 29 | #include // Provides std::ostringstream 30 | #include // Provides INT_MAX 31 | #include // Provides the mouse message types 32 | // --------------------------------------------------------------------------- 33 | 34 | using namespace std; 35 | 36 | // --------------------------------------------------------------------------- 37 | // Definitions 38 | // --------------------------------------------------------------------------- 39 | // Definitions for the key pad extended keys are added here. When one 40 | // of these keys are pressed, getch will return a zero followed by one 41 | // of these values. This is the same way that it works in conio for 42 | // dos applications. 43 | #define KEY_HOME 71 44 | #define KEY_UP 72 45 | #define KEY_PGUP 73 46 | #define KEY_LEFT 75 47 | #define KEY_CENTER 76 48 | #define KEY_RIGHT 77 49 | #define KEY_END 79 50 | #define KEY_DOWN 80 51 | #define KEY_PGDN 81 52 | #define KEY_INSERT 82 53 | #define KEY_DELETE 83 54 | #define KEY_F1 59 55 | #define KEY_F2 60 56 | #define KEY_F3 61 57 | #define KEY_F4 62 58 | #define KEY_F5 63 59 | #define KEY_F6 64 60 | #define KEY_F7 65 61 | #define KEY_F8 66 62 | #define KEY_F9 67 63 | 64 | // Line thickness settings 65 | #define NORM_WIDTH 1 66 | #define THICK_WIDTH 3 67 | 68 | // Character Size and Direction 69 | #define USER_CHAR_SIZE 0 70 | #define HORIZ_DIR 0 71 | #define VERT_DIR 1 72 | 73 | // No mouse event of the current type in getmouseclick 74 | #define NO_CLICK -1 75 | 76 | // Constants for closegraph 77 | #define CURRENT_WINDOW -1 78 | #define ALL_WINDOWS -2 79 | #define NO_CURRENT_WINDOW -3 80 | 81 | // The standard Borland 16 colors 82 | #define MAXCOLORS 15 83 | 84 | enum colors 85 | { 86 | BLACK, BLUE, GREEN, CYAN, RED, MAGENTA, BROWN, LIGHTGRAY, DARKGRAY, 87 | LIGHTBLUE, LIGHTGREEN, LIGHTCYAN, LIGHTRED, LIGHTMAGENTA, YELLOW, WHITE 88 | }; 89 | 90 | // The standard line styles 91 | enum line_styles { SOLID_LINE, DOTTED_LINE, CENTER_LINE, DASHED_LINE, USERBIT_LINE }; 92 | 93 | // The standard fill styles 94 | enum fill_styles 95 | { 96 | EMPTY_FILL, SOLID_FILL, LINE_FILL, LTSLASH_FILL, SLASH_FILL, 97 | BKSLASH_FILL, LTBKSLASH_FILL, HATCH_FILL, XHATCH_FILL, INTERLEAVE_FILL, 98 | WIDE_DOT_FILL, CLOSE_DOT_FILL, USER_FILL 99 | }; 100 | 101 | // The various graphics drivers 102 | enum graphics_drivers 103 | { 104 | DETECT, CGA, MCGA, EGA, EGA64, EGAMONO, IBM8514, HERCMONO, 105 | ATT400, VGA, PC3270 106 | }; 107 | 108 | // Various modes for each graphics driver 109 | enum graphics_modes 110 | { 111 | CGAC0, CGAC1, CGAC2, CGAC3, CGAHI, 112 | MCGAC0 = 0, MCGAC1, MCGAC2, MCGAC3, MCGAMED, MCGAHI, 113 | EGALO = 0, EGAHI, 114 | EGA64LO = 0, EGA64HI, 115 | EGAMONOHI = 3, 116 | HERCMONOHI = 0, 117 | ATT400C0 = 0, ATT400C1, ATT400C2, ATT400C3, ATT400MED, ATT400HI, 118 | VGALO = 0, VGAMED, VGAHI, 119 | PC3270HI = 0, 120 | IBM8514LO = 0, IBM8514HI 121 | }; 122 | 123 | // Borland error messages for the graphics window. 124 | enum graph_errors 125 | { 126 | grInvalidVersion = -18, grInvalidDeviceNum = -15, grInvalidFontNum, 127 | grInvalidFont, grIOerror, grError, grInvalidMode, grNoFontMem, 128 | grFontNotFound, grNoFloodMem, grNoScanMem, grNoLoadMem, 129 | grInvalidDriver, grFileNotFound, grNotDetected, grNoInitGraph, 130 | grOk 131 | }; 132 | 133 | // Write modes 134 | enum putimage_ops { COPY_PUT, XOR_PUT, OR_PUT, AND_PUT, NOT_PUT }; 135 | 136 | // Text Modes 137 | enum horiz { LEFT_TEXT, CENTER_TEXT, RIGHT_TEXT }; 138 | enum vertical { BOTTOM_TEXT, VCENTER_TEXT, TOP_TEXT }; // middle not needed other than as seperator 139 | enum font_names 140 | { 141 | DEFAULT_FONT, TRIPLEX_FONT, SMALL_FONT, SANS_SERIF_FONT, 142 | GOTHIC_FONT, SCRIPT_FONT, SIMPLEX_FONT, TRIPLEX_SCR_FONT, 143 | COMPLEX_FONT, EUROPEAN_FONT, BOLD_FONT 144 | }; 145 | // --------------------------------------------------------------------------- 146 | 147 | 148 | 149 | // --------------------------------------------------------------------------- 150 | // Structures 151 | // --------------------------------------------------------------------------- 152 | // This structure records information about the last call to arc. It is used 153 | // by getarccoords to get the location of the endpoints of the arc. 154 | struct arccoordstype 155 | { 156 | int x, y; // Center point of the arc 157 | int xstart, ystart; // The starting position of the arc 158 | int xend, yend; // The ending position of the arc. 159 | }; 160 | 161 | 162 | // This structure defines the fill style for the current window. Pattern is 163 | // one of the system patterns such as SOLID_FILL. Color is the color to 164 | // fill with 165 | struct fillsettingstype 166 | { 167 | int pattern; // Current fill pattern 168 | int color; // Current fill color 169 | }; 170 | 171 | 172 | // This structure records information about the current line style. 173 | // linestyle is one of the line styles such as SOLID_LINE, upattern is a 174 | // 16-bit pattern for user defined lines, and thickness is the width of the 175 | // line in pixels. 176 | struct linesettingstype 177 | { 178 | int linestyle; // Current line style 179 | unsigned int upattern; // 16-bit user line pattern 180 | int thickness; // Width of the line in pixels 181 | }; 182 | 183 | 184 | // This structure records information about the text settings. 185 | struct textsettingstype 186 | { 187 | int font; // The font in use 188 | int direction; // Text direction 189 | int charsize; // Character size 190 | int horiz; // Horizontal text justification 191 | int vert; // Vertical text justification 192 | }; 193 | 194 | 195 | // This structure records information about the viewport 196 | struct viewporttype 197 | { 198 | int left, top, // Viewport bounding box 199 | right, bottom; 200 | int clip; // Whether to clip image to viewport 201 | }; 202 | 203 | 204 | // This structure records information about the palette. 205 | struct palettetype 206 | { 207 | unsigned char size; 208 | signed char colors[MAXCOLORS + 1]; 209 | }; 210 | // --------------------------------------------------------------------------- 211 | 212 | 213 | 214 | // --------------------------------------------------------------------------- 215 | // API Entries 216 | // --------------------------------------------------------------------------- 217 | #ifdef __cplusplus 218 | extern "C" 219 | { 220 | #endif 221 | 222 | // Drawing Functions 223 | void arc(int x, int y, int stangle, int endangle, int radius); 224 | void bar(int left, int top, int right, int bottom); 225 | void bar3d(int left, int top, int right, int bottom, int depth, int topflag); 226 | void circle(int x, int y, int radius); 227 | void cleardevice(); 228 | void clearviewport(); 229 | void drawpoly(int n_points, int* points); 230 | void ellipse(int x, int y, int stangle, int endangle, int xradius, int yradius); 231 | void fillellipse(int x, int y, int xradius, int yradius); 232 | void fillpoly(int n_points, int* points); 233 | void floodfill(int x, int y, int border); 234 | void line(int x1, int y1, int x2, int y2); 235 | void linerel(int dx, int dy); 236 | void lineto(int x, int y); 237 | void pieslice(int x, int y, int stangle, int endangle, int radius); 238 | void putpixel(int x, int y, int color); 239 | void rectangle(int left, int top, int right, int bottom); 240 | void sector(int x, int y, int stangle, int endangle, int xradius, int yradius); 241 | 242 | // Miscellaneous Functions 243 | int getdisplaycolor(int color); 244 | int converttorgb(int color); 245 | void delay(int msec); 246 | void getarccoords(arccoordstype *arccoords); 247 | int getbkcolor(); 248 | int getcolor(); 249 | void getfillpattern(char *pattern); 250 | void getfillsettings(fillsettingstype *fillinfo); 251 | void getlinesettings(linesettingstype *lineinfo); 252 | int getmaxcolor(); 253 | int getmaxheight(); 254 | int getmaxwidth(); 255 | int getmaxx(); 256 | int getmaxy(); 257 | bool getrefreshingbgi(); 258 | int getwindowheight(); 259 | int getwindowwidth(); 260 | int getpixel(int x, int y); 261 | void getviewsettings(viewporttype *viewport); 262 | int getx(); 263 | int gety(); 264 | void moverel(int dx, int dy); 265 | void moveto(int x, int y); 266 | void refreshbgi(int left, int top, int right, int bottom); 267 | void refreshallbgi(); 268 | void setbkcolor(int color); 269 | void setcolor(int color); 270 | void setfillpattern(char *upattern, int color); 271 | void setfillstyle(int pattern, int color); 272 | void setlinestyle(int linestyle, unsigned upattern, int thickness); 273 | void setrefreshingbgi(bool value); 274 | void setviewport(int left, int top, int right, int bottom, int clip); 275 | void setwritemode(int mode); 276 | 277 | // Window Creation / Graphics Manipulation 278 | void closegraph(int wid = ALL_WINDOWS); 279 | void detectgraph(int *graphdriver, int *graphmode); 280 | void getaspectratio(int *xasp, int *yasp); 281 | char *getdrivername(); 282 | int getgraphmode(); 283 | int getmaxmode(); 284 | char *getmodename(int mode_number); 285 | void getmoderange(int graphdriver, int *lomode, int *himode); 286 | void graphdefaults(); 287 | char *grapherrormsg(int errorcode); 288 | int graphresult(); 289 | void initgraph(int *graphdriver, int *graphmode, char *pathtodriver); 290 | int initwindow(int width, int height, const char* title = "Windows BGI", int left = 0, int top = 0, bool dbflag = false, bool closeflag = true); 291 | int installuserdriver(char *name, int *fp); // Not available in WinBGI 292 | int installuserfont(char *name); // Not available in WinBGI 293 | int registerbgidriver(void *driver); // Not available in WinBGI 294 | int registerbgifont(void *font); // Not available in WinBGI 295 | void restorecrtmode(); 296 | void setaspectratio(int xasp, int yasp); 297 | unsigned setgraphbufsize(unsigned bufsize); // Not available in WinBGI 298 | void setgraphmode(int mode); 299 | void showerrorbox(const char *msg = nullptr); 300 | 301 | // User Interaction 302 | int getch(); 303 | int kbhit(); 304 | 305 | // User-Controlled Window Functions (winbgi.cpp) 306 | int getcurrentwindow(); 307 | void setcurrentwindow(int window); 308 | 309 | // Double buffering support (winbgi.cpp) 310 | int getactivepage(); 311 | int getvisualpage(); 312 | void setactivepage(int page); 313 | void setvisualpage(int page); 314 | void swapbuffers(); 315 | 316 | // Image Functions (drawing.cpp) 317 | unsigned imagesize(int left, int top, int right, int bottom); 318 | void getimage(int left, int top, int right, int bottom, void *bitmap); 319 | void putimage(int left, int top, void *bitmap, int op); 320 | void printimage( 321 | const char* title = nullptr, 322 | double width_inches = 7, double border_left_inches = 0.75, double border_top_inches = 0.75, 323 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX, 324 | bool active = true, HWND hwnd = nullptr 325 | ); 326 | void readimagefile( 327 | const char* filename = nullptr, 328 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX 329 | ); 330 | void writeimagefile( 331 | const char* filename = nullptr, 332 | int left = 0, int top = 0, int right = INT_MAX, int bottom = INT_MAX, 333 | bool active = true, HWND hwnd = nullptr 334 | ); 335 | 336 | // Text Functions (text.cpp) 337 | void gettextsettings(struct textsettingstype *texttypeinfo); 338 | void outtext(char *textstring); 339 | void outtextxy(int x, int y, char *textstring); 340 | void settextjustify(int horiz, int vert); 341 | void settextstyle(int font, int direction, int charsize); 342 | void setusercharsize(int multx, int divx, int multy, int divy); 343 | int textheight(char *textstring); 344 | int textwidth(char *textstring); 345 | extern ostringstream bgiout; 346 | void outstream(ostringstream& out = bgiout); 347 | void outstreamxy(int x, int y, ostringstream& out = bgiout); 348 | 349 | // Mouse Functions (mouse.cpp) 350 | void clearmouseclick(int kind); 351 | void clearresizeevent(); 352 | void getmouseclick(int kind, int& x, int& y); 353 | bool ismouseclick(int kind); 354 | bool isresizeevent(); 355 | int mousex(); 356 | int mousey(); 357 | void registermousehandler(int kind, void h(int, int)); 358 | void setmousequeuestatus(int kind, bool status = true); 359 | 360 | // Palette Functions 361 | palettetype *getdefaultpalette(); 362 | void getpalette(palettetype *palette); 363 | int getpalettesize(); 364 | void setallpalette(palettetype *palette); 365 | void setpalette(int colornum, int color); 366 | void setrgbpalette(int colornum, int red, int green, int blue); 367 | 368 | // Color Macros 369 | #define IS_BGI_COLOR(v) ( ((v) >= 0) && ((v) < 16) ) 370 | #define IS_RGB_COLOR(v) ( (v) & 0x03000000 ) 371 | #define RED_VALUE(v) int(GetRValue( converttorgb(v) )) 372 | #define GREEN_VALUE(v) int(GetGValue( converttorgb(v) )) 373 | #define BLUE_VALUE(v) int(GetBValue( converttorgb(v) )) 374 | #undef COLOR 375 | int COLOR(int r, int g, int b); // No longer a macro 376 | #ifdef __cplusplus 377 | } 378 | #endif 379 | // --------------------------------------------------------------------------- 380 | -------------------------------------------------------------------------------- /WinBGI/winthread.cpp: -------------------------------------------------------------------------------- 1 | // File: WindowThread.cpp 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | 12 | #include "stdafx.h" 13 | //#include "winbgi.h" 14 | //#include "winbgitypes.h" 15 | 16 | // This structure is how the user interacts with the window. Upon creation,y 17 | // the user gets the index into this array of the window he created. We will 18 | // use this array for any function which does not deal with the window 19 | // directly, but relies on the current window. 20 | // MGM: hInstance is no longer a handle to the DLL, but instead it is 21 | // a "self" handle, returned by GetCurrentThread( ). 22 | vector BGI__WindowTable; 23 | int BGI__WindowCount = 0; // Number of windows currently in use 24 | int BGI__CurrentWindow = NO_CURRENT_WINDOW; // Index to current window 25 | HINSTANCE BGI__hInstance; // Handle to the instance of the DLL (creating the window class) 26 | 27 | // ID numbers for new options that are added to the system menu: 28 | #define BGI_PRINT_SMALL 1 29 | #define BGI_PRINT_MEDIUM 2 30 | #define BGI_PRINT_LARGE 3 31 | #define BGI_SAVE_AS 4 32 | 33 | // This is the window creation and message processing function. Each new 34 | // window is created in its own thread and handles all its own messages. 35 | // It creates the window, sets the current window of the application to this 36 | // window, and signals the main thread that the window has been created. 37 | DWORD WINAPI BGI__ThreadInitWindow(LPVOID pThreadData) 38 | { 39 | HWND hWindow; // A handle to the window 40 | MSG Message; // A windows event message 41 | HDC hDC; // The device context of the window 42 | HBITMAP hBitmap; // A compatible bitmap of the DC for the Memory DC 43 | HMENU hMenu; // Handle to the system menu 44 | int CaptionHeight, xBorder, yBorder; 45 | 46 | auto pWndData = static_cast(pThreadData); // Thread creation data 47 | 48 | if (pWndData->title.size()) 49 | { 50 | CaptionHeight = GetSystemMetrics(SM_CYCAPTION); // Height of caption 51 | } 52 | else 53 | { 54 | CaptionHeight = 0; // Height of caption 55 | } 56 | xBorder = GetSystemMetrics(SM_CXFIXEDFRAME); // Width of border 57 | yBorder = GetSystemMetrics(SM_CYFIXEDFRAME); // Height of border 58 | 59 | auto height = pWndData->height + CaptionHeight + 2 * yBorder; // Calculate total height 60 | auto width = pWndData->width + 2 * xBorder; // Calculate total width 61 | 62 | auto top = pWndData->inittop; // MGM: Initial top 63 | auto left = pWndData->initleft; // MGM: Initial left 64 | 65 | hWindow = CreateWindowEx(0, // Extended window styles 66 | "BGILibrary", // What kind of window 67 | pWndData->title.c_str(), // Title at top of the window 68 | pWndData->title.size() ? WS_CAPTION | WS_SYSMENU | WS_MINIMIZEBOX | WS_DLGFRAME : WS_POPUP | WS_DLGFRAME, 69 | left, top, width, height, // left top width height 70 | nullptr, // HANDLE to the parent window 71 | nullptr, // HANDLE to the menu 72 | BGI__hInstance, // HANDLE to this program 73 | nullptr); // Address of window-creation data 74 | // Check if the window was created 75 | if (hWindow == nullptr) 76 | { 77 | showerrorbox(); 78 | return 0; 79 | } 80 | 81 | // Add the print options to the system menu, as shown in Chapter 10 (p 460) of Petzold 82 | hMenu = GetSystemMenu(hWindow, FALSE); 83 | AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); 84 | AppendMenu(hMenu, MF_STRING, BGI_SAVE_AS, TEXT("Save image as...")); 85 | AppendMenu(hMenu, MF_STRING, BGI_PRINT_SMALL, TEXT("Print 2\" wide...")); 86 | AppendMenu(hMenu, MF_STRING, BGI_PRINT_MEDIUM, TEXT("Print 4.5\" wide...")); 87 | AppendMenu(hMenu, MF_STRING, BGI_PRINT_LARGE, TEXT("Print 7\" wide...")); 88 | AppendMenu(hMenu, MF_SEPARATOR, 0, nullptr); 89 | 90 | // Store the HANDLE in the structure 91 | pWndData->hWnd = hWindow; 92 | 93 | // Store the address of the WindowData structure in the window's user data 94 | // Uncomment the following line for GCC build pipeline 95 | // SetWindowLong(hWindow, GWL_USERDATA, LONG(pWndData)); 96 | SetWindowLongPtr(hWindow, GWLP_USERDATA, LONG_PTR(pWndData)); 97 | 98 | // Set the default active and visual page. These must be set here in 99 | // addition to setting all the defaults in initwindow because the paint 100 | // method depends on using the correct page. 101 | pWndData->ActivePage = 0; 102 | pWndData->VisualPage = 0; 103 | 104 | // Clear the mouse handler array and turn off queuing 105 | memset(pWndData->mouse_handlers, 0, (WM_MOUSELAST - WM_MOUSEFIRST + 1) * sizeof(Handler)); 106 | memset(pWndData->mouse_queuing, 0, (WM_MOUSELAST - WM_MOUSEFIRST + 1) * sizeof(bool)); 107 | 108 | // Create a memory Device Context used for drawing. The image is copied from here 109 | // to the screen in the paint method. The DC and bitmaps are deleted 110 | // in cls_OnDestroy() 111 | hDC = GetDC(hWindow); 112 | pWndData->hDCMutex = CreateMutex(nullptr, FALSE, nullptr); 113 | WaitForSingleObject(pWndData->hDCMutex, 5000); 114 | for (auto i = 0; i < MAX_PAGES; i++) 115 | { 116 | pWndData->hDC[i] = CreateCompatibleDC(hDC); 117 | // Create a bitmap for the memory DC. This is where the drawn image is stored. 118 | hBitmap = CreateCompatibleBitmap(hDC, pWndData->width, pWndData->height); 119 | pWndData->hOldBitmap[i] = HBITMAP(SelectObject(pWndData->hDC[i], hBitmap)); 120 | } 121 | ReleaseMutex(pWndData->hDCMutex); 122 | // Release the original DC and set up the mutex for the hDC array 123 | ReleaseDC(hWindow, hDC); 124 | 125 | // Make the window visible 126 | ShowWindow(hWindow, SW_SHOWNORMAL); // Make the window visible 127 | UpdateWindow(hWindow); // Flush output buffer 128 | 129 | // Tell the user thread that the window was created successfully 130 | SetEvent(pWndData->WindowCreated); 131 | 132 | // The message loop, which stops when a WM_QUIT message arrives 133 | while (GetMessage(&Message, nullptr, 0, 0)) 134 | { 135 | TranslateMessage(&Message); 136 | DispatchMessage(&Message); 137 | } 138 | 139 | // Free memory used by thread structure 140 | delete pWndData; 141 | return DWORD(Message.wParam); 142 | } 143 | 144 | 145 | // This function handles the WM_CHAR message. This message is sent whenever 146 | // the user presses a key in the window (after a WM_KEYDOWN and WM_KEYUP 147 | // message, a WM_CHAR message is added). It adds the key pressed to the 148 | // keyboard queue for the window. 149 | void cls_OnChar(HWND hWnd, TCHAR ch, int repeat) 150 | { 151 | // This gets the address of the WindowData structure associated with the window 152 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 153 | 154 | pWndData->kbd_queue.push(TCHAR(ch));// Add the key to the queue 155 | SetEvent(pWndData->key_waiting); // Notify the waiting thread, if any 156 | FORWARD_WM_CHAR(hWnd, ch, repeat, DefWindowProc); 157 | } 158 | 159 | static void cls_OnClose(HWND hWnd) 160 | { 161 | // This gets the address of the WindowData structure associated with the window 162 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 163 | 164 | exit(0); 165 | } 166 | 167 | // This function handles the destroy message. It will cause the application 168 | // to send WM_QUIT, which will then terminate the message pump thread. 169 | static void cls_OnDestroy(HWND hWnd) 170 | { 171 | // This gets the address of the WindowData structure associated with the window 172 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 173 | 174 | WaitForSingleObject(pWndData->hDCMutex, 5000); 175 | for (auto i = 0; i < MAX_PAGES; i++) 176 | { 177 | // Delete the pen in the DC's 178 | DeletePen(SelectPen(pWndData->hDC[i], GetStockPen(WHITE_PEN))); 179 | 180 | // Delete the brush in the DC's 181 | DeleteBrush(SelectBrush(pWndData->hDC[i], GetStockBrush(WHITE_BRUSH))); 182 | 183 | // Here we clean up the memory device contexts used by the program. 184 | // This selects the original bitmap back into the memory DC. The SelectObject 185 | // function returns the current bitmap which we then delete. 186 | DeleteObject(SelectObject(pWndData->hDC[i], pWndData->hOldBitmap[i])); 187 | // Finally, we delete the MemoryDC 188 | DeleteObject(pWndData->hDC[i]); 189 | } 190 | ReleaseMutex(pWndData->hDCMutex); 191 | // Clean up the bitmap memory 192 | DeleteBitmap(pWndData->hbitmap); 193 | 194 | // Delete the two events created 195 | CloseHandle(pWndData->key_waiting); 196 | CloseHandle(pWndData->WindowCreated); 197 | 198 | PostQuitMessage(0); 199 | } 200 | 201 | 202 | // This function handles the KEYDOWN message and will translate the virtual 203 | // keys to the keys expected by the user 204 | static void cls_OnKey(HWND hWnd, UINT vk, BOOL down, int repeat, UINT flags) 205 | { 206 | // This gets the address of the WindowData structure associated with the window 207 | // TODO: Set event for each key 208 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 209 | 210 | switch (vk) 211 | { 212 | case VK_CLEAR: 213 | pWndData->kbd_queue.push(TCHAR(0)); 214 | pWndData->kbd_queue.push(TCHAR(KEY_CENTER)); 215 | break; 216 | case VK_PRIOR: 217 | pWndData->kbd_queue.push(TCHAR(0)); 218 | pWndData->kbd_queue.push(TCHAR(KEY_PGUP)); 219 | break; 220 | case VK_NEXT: 221 | pWndData->kbd_queue.push(TCHAR(0)); 222 | pWndData->kbd_queue.push(TCHAR(KEY_PGDN)); 223 | break; 224 | case VK_END: 225 | pWndData->kbd_queue.push(TCHAR(0)); 226 | pWndData->kbd_queue.push(TCHAR(KEY_END)); 227 | break; 228 | case VK_HOME: 229 | pWndData->kbd_queue.push(TCHAR(0)); 230 | pWndData->kbd_queue.push(TCHAR(KEY_HOME)); 231 | break; 232 | case VK_LEFT: 233 | pWndData->kbd_queue.push(TCHAR(0)); 234 | pWndData->kbd_queue.push(TCHAR(KEY_LEFT)); 235 | SetEvent(pWndData->key_waiting); 236 | break; 237 | case VK_UP: 238 | pWndData->kbd_queue.push(TCHAR(0)); 239 | pWndData->kbd_queue.push(TCHAR(KEY_UP)); 240 | SetEvent(pWndData->key_waiting); 241 | break; 242 | case VK_RIGHT: 243 | pWndData->kbd_queue.push(TCHAR(0)); 244 | pWndData->kbd_queue.push(TCHAR(KEY_RIGHT)); 245 | SetEvent(pWndData->key_waiting); 246 | break; 247 | case VK_DOWN: 248 | pWndData->kbd_queue.push(TCHAR(0)); 249 | pWndData->kbd_queue.push(TCHAR(KEY_DOWN)); 250 | SetEvent(pWndData->key_waiting); 251 | break; 252 | case VK_INSERT: 253 | pWndData->kbd_queue.push(TCHAR(0)); 254 | pWndData->kbd_queue.push(TCHAR(KEY_INSERT)); 255 | break; 256 | case VK_DELETE: 257 | pWndData->kbd_queue.push(TCHAR(0)); 258 | pWndData->kbd_queue.push(TCHAR(KEY_DELETE)); 259 | break; 260 | case VK_F1: 261 | pWndData->kbd_queue.push(TCHAR(0)); 262 | pWndData->kbd_queue.push(TCHAR(KEY_F1)); 263 | break; 264 | case VK_F2: 265 | pWndData->kbd_queue.push(TCHAR(0)); 266 | pWndData->kbd_queue.push(TCHAR(KEY_F2)); 267 | break; 268 | case VK_F3: 269 | pWndData->kbd_queue.push(TCHAR(0)); 270 | pWndData->kbd_queue.push(TCHAR(KEY_F3)); 271 | break; 272 | case VK_F4: 273 | pWndData->kbd_queue.push(TCHAR(0)); 274 | pWndData->kbd_queue.push(TCHAR(KEY_F4)); 275 | break; 276 | case VK_F5: 277 | pWndData->kbd_queue.push(TCHAR(0)); 278 | pWndData->kbd_queue.push(TCHAR(KEY_F5)); 279 | break; 280 | case VK_F6: 281 | pWndData->kbd_queue.push(TCHAR(0)); 282 | pWndData->kbd_queue.push(TCHAR(KEY_F6)); 283 | break; 284 | case VK_F7: 285 | pWndData->kbd_queue.push(TCHAR(0)); 286 | pWndData->kbd_queue.push(TCHAR(KEY_F7)); 287 | break; 288 | case VK_F8: 289 | pWndData->kbd_queue.push(TCHAR(0)); 290 | pWndData->kbd_queue.push(TCHAR(KEY_F8)); 291 | break; 292 | case VK_F9: 293 | pWndData->kbd_queue.push(TCHAR(0)); 294 | pWndData->kbd_queue.push(TCHAR(KEY_F9)); 295 | break; 296 | default: break; 297 | } 298 | 299 | FORWARD_WM_KEYDOWN(hWnd, vk, repeat, flags, DefWindowProc); 300 | } 301 | 302 | static void cls_OnPaint(HWND hWnd) 303 | { 304 | PAINTSTRUCT ps; // BeginPaint puts info about the paint request here 305 | HDC hSrcDC; // The device context to copy from 306 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 307 | int width, height; // Area that needs to be redrawn 308 | POINT srcCorner; // Logical coordinates of the source image upper left point 309 | BOOL success; // Is the BitBlt successful? 310 | 311 | WaitForSingleObject(pWndData->hDCMutex, INFINITE); 312 | BeginPaint(hWnd, &ps); 313 | hSrcDC = pWndData->hDC[pWndData->VisualPage]; // The source (memory) DC 314 | 315 | // Get the dimensions of the area that needs to be redrawn. 316 | width = ps.rcPaint.right - ps.rcPaint.left; 317 | height = ps.rcPaint.bottom - ps.rcPaint.top; 318 | 319 | 320 | // The region that needs to be updated is specified in device units (pixels) for the actual DC. 321 | // However, if a viewport is specified, the source image is referenced in logical 322 | // units. Perform the conversion. 323 | // MGM TODO: When is the DPtoLP call needed? 324 | srcCorner.x = ps.rcPaint.left; 325 | srcCorner.y = ps.rcPaint.top; 326 | DPtoLP(hSrcDC, &srcCorner, 1); 327 | 328 | // MGM: Screen BitBlts are not always successful, although I don't know why. 329 | success = BitBlt(ps.hdc, ps.rcPaint.left, ps.rcPaint.top, width, height, hSrcDC, srcCorner.x, srcCorner.y, SRCCOPY); 330 | EndPaint(hWnd, &ps); // Validates the rectangle 331 | ReleaseMutex(pWndData->hDCMutex); 332 | 333 | if (!success) 334 | { 335 | // I would like to invalidate the rectangle again 336 | // since BitBlt wasn't successful, but the recursion seems 337 | // to hang some machines. 338 | //delay(100); 339 | //InvalidateRect( hWnd, &(ps.rcPaint), FALSE ); 340 | //std::cout << "Failure in cls_OnPaint" << std:: endl; 341 | } 342 | } 343 | 344 | // The message-handler function for the window 345 | LRESULT CALLBACK WndProc(HWND hWnd, UINT uiMessage, WPARAM wParam, LPARAM lParam) 346 | { 347 | const queue EMPTY; 348 | auto pWndData = BGI__GetWindowDataPtr(hWnd); 349 | 350 | // If this is a mouse message, set our internal state 351 | if (pWndData && (uiMessage >= WM_MOUSEFIRST) && (uiMessage <= WM_MOUSELAST)) 352 | { 353 | // Type of mouse message 354 | auto type = uiMessage - WM_MOUSEFIRST; 355 | if (!pWndData->mouse_queuing[type] && pWndData->clicks[type].size()) 356 | { 357 | pWndData->clicks[type] = EMPTY; 358 | } 359 | 360 | auto where = MAKEPOINTS(lParam); 361 | 362 | // Set the current position for the event type 363 | pWndData->clicks[type].push(where); 364 | 365 | // Set the current mouse position 366 | pWndData->mouse = where; 367 | 368 | // Registered mouse handler 369 | // If the user has registered a mouse handler, call it now 370 | auto handler = pWndData->mouse_handlers[type]; 371 | if (handler != nullptr) handler(where.x, where.y); 372 | } 373 | 374 | switch (uiMessage) 375 | { 376 | HANDLE_MSG(hWnd, WM_CHAR, cls_OnChar); 377 | HANDLE_MSG(hWnd, WM_DESTROY, cls_OnDestroy); 378 | HANDLE_MSG(hWnd, WM_KEYDOWN, cls_OnKey); 379 | HANDLE_MSG(hWnd, WM_PAINT, cls_OnPaint); 380 | case WM_LBUTTONDBLCLK: 381 | return TRUE; 382 | case WM_NCHITTEST: 383 | { 384 | auto uHitTest = DefWindowProc(hWnd, WM_NCHITTEST, wParam, lParam); 385 | return uHitTest != HTCLIENT && pWndData && pWndData->title.size() == 0 ? HTCAPTION : uHitTest; 386 | } 387 | case WM_CLOSE: 388 | if (pWndData->CloseBehavior) 389 | { 390 | HANDLE_WM_CLOSE(hWnd, wParam, lParam, cls_OnClose); 391 | } 392 | return TRUE; 393 | case WM_SYSCOMMAND: 394 | switch (LOWORD(wParam)) 395 | { 396 | case BGI_SAVE_AS: writeimagefile(nullptr, 0, 0, INT_MAX, INT_MAX, false, hWnd); break; 397 | case BGI_PRINT_SMALL: printimage(nullptr, 2.0, 0.75, 0.75, 0, 0, INT_MAX, INT_MAX, false, hWnd); break; 398 | case BGI_PRINT_MEDIUM: printimage(nullptr, 4.5, 0.75, 0.75, 0, 0, INT_MAX, INT_MAX, false, hWnd); break; 399 | case BGI_PRINT_LARGE: printimage(nullptr, 7.0, 0.75, 0.75, 0, 0, INT_MAX, INT_MAX, false, hWnd); break; 400 | default: break; 401 | } 402 | return 0; 403 | default: break; 404 | } 405 | return DefWindowProc(hWnd, uiMessage, wParam, lParam); 406 | } 407 | -------------------------------------------------------------------------------- /WinBGI/misc.cpp: -------------------------------------------------------------------------------- 1 | // $Id: misc.cpp,v 1.11 2003/05/07 23:41:23 schmidap Exp $ 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | 12 | #include "stdafx.h" 13 | //#include "winbgi.h" 14 | //#include "winbgitypes.h" 15 | 16 | 17 | 18 | /***************************************************************************** 19 | * 20 | * Structures 21 | * 22 | *****************************************************************************/ 23 | struct LinePattern 24 | { 25 | int width; 26 | DWORD pattern[16]; 27 | }; 28 | 29 | 30 | 31 | /***************************************************************************** 32 | * 33 | * Global Variables 34 | * 35 | *****************************************************************************/ 36 | // Solid line: 0xFFFF 37 | // Dotted line: 0011 0011 0011 0011b dot space 38 | // Center line: 0001 1110 0011 1111b dot space dash space 39 | // Dashed line: 0001 1111 0001 1111b dash space 40 | // The numbers in the pattern (of the LinePattern struct) represent the width 41 | // in pixels of the first dash, then the first space, then the next dash, etc. 42 | // A leading space is moved to the end. 43 | // The dash is one longer than specified; the space is one shorter. 44 | // Creating a geometric pen using the predefined constants produces 45 | // poor results. Thus, the above widths have been modified: 46 | // Space: 3 pixels 47 | // Dash: 8 pixels 48 | // Dot: 4 pixels 49 | LinePattern SOLID = { 2, {16, 0} }; // In reality, these are (see note above) 50 | LinePattern DOTTED = { 2, {3, 4} }; // 4, 3 51 | LinePattern CENTER = { 4, {3, 4, 7, 4} }; // 4, 3, 8, 3 52 | LinePattern DASHED = { 2, {7, 4} }; // 8, 3 53 | 54 | // Color format: 55 | // High byte: 0 Color is an index, BGI color 56 | // -- This is necessary since these colors are defined to be 0-15 in BGI 57 | // High byte: 3 Color is an RGB value (page 244 of Win32 book) 58 | // -- Note the internal COLORREF structure has RGB values with a high byte 59 | // of 0, but this conflicts with the BGI color notation. 60 | // We store the value the user gave internally (be it number 4 for RED or 61 | // our RGB encoded value). This is then converted when needed. 62 | 63 | // From http://www.textmodegames.com/articles/coolgame.html 64 | // Then used BGI graphics on my system for slight modification. 65 | COLORREF BGI__Colors[16]; 66 | // These are set in graphdefaults in winbgi.cpp 67 | /* 68 | = { 69 | RGB( 0, 0, 0 ), // Black 70 | RGB( 0, 0, 168), // Blue 71 | RGB( 0, 168, 0 ), // Green 72 | RGB( 0, 168, 168 ), // Cyan 73 | RGB( 168, 0, 0 ), // Red 74 | RGB( 168, 0, 168 ), // Magenta 75 | RGB( 168, 84, 0 ), // Brown 76 | RGB( 168, 168, 168 ), // Light Gray 77 | RGB( 84, 84, 84 ), // Dark Gray 78 | RGB( 84, 84, 252 ), // Light Blue 79 | RGB( 84, 252, 84 ), // Light Green 80 | RGB( 84, 252, 252 ), // Light Cyan 81 | RGB( 252, 84, 84 ), // Light Red 82 | RGB( 252, 84, 252 ), // Light Magenta 83 | RGB( 252, 252, 84 ), // Yellow 84 | RGB( 252, 252, 252 ) // White 85 | }; 86 | */ 87 | 88 | 89 | /***************************************************************************** 90 | * 91 | * Prototypes 92 | * 93 | *****************************************************************************/ 94 | LinePattern CreateUserStyle(); 95 | 96 | 97 | /***************************************************************************** 98 | * 99 | * Helper functions 100 | * 101 | *****************************************************************************/ 102 | 103 | // This function converts a given color (specified by the user) into a format 104 | // native to windows. 105 | // 106 | int converttorgb(int color) 107 | { 108 | // Convert from BGI color to RGB color 109 | if (IS_BGI_COLOR(color)) 110 | color = BGI__Colors[color]; 111 | else 112 | color &= 0x0FFFFFF; 113 | 114 | return color; 115 | } 116 | 117 | // This function creates a new pen in the current drawing color and selects it 118 | // into all the memory DC's. 119 | // 120 | void CreateNewPen() 121 | { 122 | auto pWndData = BGI__GetWindowDataPtr(); 123 | auto color = pWndData->drawColor;; 124 | LinePattern style; 125 | LOGBRUSH lb; 126 | HPEN hPen; 127 | 128 | // Convert from BGI color to RGB color 129 | color = converttorgb(color); 130 | 131 | // Set the color and style of the logical brush 132 | lb.lbColor = color; 133 | lb.lbStyle = BS_SOLID; 134 | 135 | if (pWndData->lineInfo.linestyle == SOLID_LINE) style = SOLID; 136 | if (pWndData->lineInfo.linestyle == DOTTED_LINE) style = DOTTED; 137 | if (pWndData->lineInfo.linestyle == CENTER_LINE) style = CENTER; 138 | if (pWndData->lineInfo.linestyle == DASHED_LINE) style = DASHED; 139 | // TODO: If user specifies a 0 pattern, create a NULL pen. 140 | if (pWndData->lineInfo.linestyle == USERBIT_LINE) style = CreateUserStyle(); 141 | 142 | // Round endcaps are default, set to square 143 | // Use a bevel join 144 | WaitForSingleObject(pWndData->hDCMutex, 5000); 145 | for (auto i = 0; i < MAX_PAGES; i++) 146 | { 147 | hPen = ExtCreatePen(PS_GEOMETRIC | PS_ENDCAP_SQUARE 148 | | PS_JOIN_BEVEL | PS_USERSTYLE, // Pen Style 149 | pWndData->lineInfo.thickness, // Pen Width 150 | &lb, // Logical Brush 151 | style.width, // Bytes in pattern 152 | style.pattern); // Line Pattern 153 | DeletePen(HPEN(SelectObject(pWndData->hDC[i], hPen))); 154 | } 155 | ReleaseMutex(pWndData->hDCMutex); 156 | } 157 | 158 | 159 | // The user style might appear reversed from what you expect. With the 160 | // original Borland graphics, the least significant bit specified the first 161 | // pixel of the line. Thus, if you reverse the bit string, the line is 162 | // drawn as the pixels then appear. 163 | LinePattern CreateUserStyle() 164 | { 165 | auto pWndData = BGI__GetWindowDataPtr(); 166 | auto style = pWndData->lineInfo.upattern; 167 | auto zeroCount = 0; // A count of the number of leading zeros 168 | int i = 0, j, sum = 0; // i is number of dwords, sum is a running count of bits used 169 | LinePattern userPattern; // The pattern 170 | 171 | style &= 0xFFFF; // Only lower 16 bits matter 172 | 173 | if (style == 0) 174 | { 175 | userPattern.pattern[0] = 0; 176 | userPattern.pattern[1] = 16; 177 | userPattern.width = 2; 178 | return userPattern; 179 | } 180 | 181 | // If the pattern starts with a zero, count how many and store until 182 | // later 183 | if ((style & 1) == 0) 184 | { 185 | for (j = 0; !(style & 1); j++) style >>= 1; 186 | zeroCount = j; 187 | sum += j; 188 | } 189 | 190 | // See note above (in Global Variables) for dash being one pixel more, 191 | // space being one pixel less 192 | while (true) 193 | { 194 | // Get a count of the number of ones 195 | for (j = 0; style & 1; j++) style >>= 1; 196 | userPattern.pattern[i++] = j - 1; // Subtract one for dash 197 | sum += j; 198 | 199 | 200 | // Check if the pattern is now zero. 201 | if (style == 0) 202 | { 203 | if (sum != 16) 204 | userPattern.pattern[i++] = 16 - sum + 1; // Add one for space 205 | break; 206 | } 207 | 208 | // Get a count of the number of zeros 209 | for (j = 0; !(style & 1); j++) style >>= 1; 210 | userPattern.pattern[i++] = j + 1; // Add one for space 211 | sum += j; 212 | } 213 | 214 | // If there were leading zeros, put them at the end 215 | if (zeroCount > 0) 216 | { 217 | // If i is even, we ended on a space. Add the leading zeros to the back 218 | // end count. If i is odd, we ended on a dash. Append the leading zeros. 219 | if ((i % 2) == 0) 220 | userPattern.pattern[i - 1] += zeroCount; 221 | else 222 | userPattern.pattern[i++] = zeroCount; 223 | } 224 | else // If there were no leading zeros, check if we need to add a space 225 | { 226 | // If we ended on a dash and there are no more following zeros, put a 227 | // zero-length space. This is necessary since the user may specify 228 | // a style of 0xFFFF. In this case, a solid line is not created unless 229 | // there is a zero-length space at the end. 230 | if ((i % 2) != 0) 231 | userPattern.pattern[i++] = 0; 232 | } 233 | 234 | // Set the with to the number of array indices used 235 | userPattern.width = i; 236 | 237 | return userPattern; 238 | } 239 | 240 | 241 | 242 | 243 | /***************************************************************************** 244 | * 245 | * The actual API calls are implemented below 246 | * 247 | *****************************************************************************/ 248 | 249 | // This function will pause the current thread for the specified number of 250 | // milliseconds 251 | // 252 | void delay(int msec) 253 | { 254 | Sleep(msec); 255 | } 256 | 257 | 258 | // This function returns information about the last call to arc. 259 | // 260 | void getarccoords(arccoordstype *arccoords) 261 | { 262 | auto pWndData = BGI__GetWindowDataPtr(); 263 | *arccoords = pWndData->arcInfo; 264 | } 265 | 266 | 267 | // This function returns the current background color. 268 | // 269 | int getbkcolor() 270 | { 271 | auto pWndData = BGI__GetWindowDataPtr(); 272 | return pWndData->bgColor; 273 | } 274 | 275 | 276 | // This function returns the current drawing color. 277 | // 278 | int getcolor() 279 | { 280 | auto pWndData = BGI__GetWindowDataPtr(); 281 | return pWndData->drawColor; 282 | } 283 | 284 | 285 | // This function returns the user-defined fill pattern in the 8-byte area 286 | // specified by pattern. 287 | // 288 | void getfillpattern(char *pattern) 289 | { 290 | auto pWndData = BGI__GetWindowDataPtr(); 291 | memcpy(pattern, pWndData->uPattern, sizeof(pWndData->uPattern)); 292 | } 293 | 294 | 295 | // This function returns the current fill settings. 296 | // 297 | void getfillsettings(fillsettingstype *fillinfo) 298 | { 299 | auto pWndData = BGI__GetWindowDataPtr(); 300 | *fillinfo = pWndData->fillInfo; 301 | } 302 | 303 | 304 | // This function returns the current line settings. 305 | // 306 | void getlinesettings(linesettingstype *lineinfo) 307 | { 308 | auto pWndData = BGI__GetWindowDataPtr(); 309 | *lineinfo = pWndData->lineInfo; 310 | } 311 | 312 | 313 | // This function returns the highest color possible in the current graphics 314 | // mode. For WinBGI, this is always WHITE (15), even though larger RGB 315 | // colors are possible. 316 | // 317 | int getmaxcolor() 318 | { 319 | return WHITE; 320 | } 321 | 322 | 323 | // This function returns the maximum x screen coordinate. 324 | // 325 | int getmaxx() 326 | { 327 | auto pWndData = BGI__GetWindowDataPtr(); 328 | return pWndData->width - 1; 329 | } 330 | 331 | 332 | // This function returns the maximum y screen coordinate. 333 | int getmaxy() 334 | { 335 | auto pWndData = BGI__GetWindowDataPtr(); 336 | return pWndData->height - 1; 337 | } 338 | 339 | // This function returns the maximum height of a window for the current screen 340 | int getmaxheight() 341 | { 342 | auto CaptionHeight = GetSystemMetrics(SM_CYCAPTION); // Height of caption area 343 | auto yBorder = GetSystemMetrics(SM_CYFIXEDFRAME); // Height of border 344 | auto TotalHeight = GetSystemMetrics(SM_CYSCREEN); // Height of screen 345 | 346 | return TotalHeight - (CaptionHeight + 2 * yBorder); // Calculate max height 347 | } 348 | 349 | // This function returns the maximum width of a window for the current screen 350 | int getmaxwidth() 351 | { 352 | auto xBorder = GetSystemMetrics(SM_CXFIXEDFRAME); // Width of border 353 | auto TotalWidth = GetSystemMetrics(SM_CXSCREEN); // Width of screen 354 | 355 | return TotalWidth - (2 * xBorder); // Calculate max width 356 | } 357 | 358 | // This function returns the total window height, including borders 359 | int getwindowheight() 360 | { 361 | auto pWndData = BGI__GetWindowDataPtr(); 362 | auto CaptionHeight = GetSystemMetrics(SM_CYCAPTION); // Height of caption area 363 | auto yBorder = GetSystemMetrics(SM_CYFIXEDFRAME); // Height of border 364 | 365 | return pWndData->height + CaptionHeight + 2 * yBorder; // Calculate total height 366 | } 367 | 368 | // This function returns the total window width, including borders 369 | int getwindowwidth() 370 | { 371 | auto pWndData = BGI__GetWindowDataPtr(); 372 | auto xBorder = GetSystemMetrics(SM_CXFIXEDFRAME); // Width of border 373 | 374 | return pWndData->width + 2 * xBorder; // Calculate total width 375 | } 376 | 377 | // MGM: Function to convert rgb values to a color that can be 378 | // used with any bgi functions. Numbers 0 to WHITE are the 379 | // original bgi colors. Other colors are 0x03rrggbb. 380 | // This used to be a macro. 381 | int COLOR(int r, int g, int b) 382 | { 383 | auto color = RGB(r, g, b); 384 | 385 | for (auto i = 0; i <= WHITE; i++) 386 | { 387 | if (color == BGI__Colors[i]) 388 | return i; 389 | } 390 | 391 | return (0x03000000 | color); 392 | } 393 | 394 | int getdisplaycolor(int color) 395 | { 396 | auto save = getpixel(0, 0); 397 | int answer; 398 | 399 | putpixel(0, 0, color); 400 | answer = getpixel(0, 0); 401 | putpixel(0, 0, save); 402 | return answer; 403 | } 404 | 405 | int getpixel(int x, int y) 406 | { 407 | auto hDC = BGI__GetWinbgiDC(); 408 | auto color = GetPixel(hDC, x, y); 409 | BGI__ReleaseWinbgiDC(); 410 | 411 | if (color == CLR_INVALID) 412 | return CLR_INVALID; 413 | 414 | // If the color is a BGI color, return the index rather than the RGB value. 415 | for (auto i = 0; i <= WHITE; i++) 416 | { 417 | if (color == BGI__Colors[i]) 418 | return i; 419 | } 420 | 421 | // If we got here, the color didn't match a BGI color. Thus, convert to 422 | // our RGB format. 423 | color |= 0x03000000; 424 | 425 | return color; 426 | } 427 | 428 | 429 | void getviewsettings(viewporttype *viewport) 430 | { 431 | auto pWndData = BGI__GetWindowDataPtr(); 432 | *viewport = pWndData->viewportInfo; 433 | } 434 | 435 | 436 | // This function returns the x-coordinate of the current graphics position. 437 | // 438 | int getx() 439 | { 440 | auto hDC = BGI__GetWinbgiDC(); 441 | POINT cp; 442 | 443 | GetCurrentPositionEx(hDC, &cp); 444 | BGI__ReleaseWinbgiDC(); 445 | return cp.x; 446 | } 447 | 448 | 449 | // This function returns the y-coordinate of the current graphics position. 450 | // 451 | int gety() 452 | { 453 | auto hDC = BGI__GetWinbgiDC(); 454 | POINT cp; 455 | 456 | GetCurrentPositionEx(hDC, &cp); 457 | BGI__ReleaseWinbgiDC(); 458 | return cp.y; 459 | } 460 | 461 | 462 | // This function moves the current position by dx pixels in the x direction and 463 | // dy pixels in the y direction. 464 | // 465 | void moverel(int dx, int dy) 466 | { 467 | auto hDC = BGI__GetWinbgiDC(); 468 | POINT cp; 469 | 470 | // Get the current position 471 | GetCurrentPositionEx(hDC, &cp); 472 | // Move to the new position 473 | MoveToEx(hDC, cp.x + dx, cp.y + dy, nullptr); 474 | BGI__ReleaseWinbgiDC(); 475 | } 476 | 477 | 478 | // This function moves the current point to position (x,y) 479 | // 480 | void moveto(int x, int y) 481 | { 482 | auto hDC = BGI__GetWinbgiDC(); 483 | 484 | MoveToEx(hDC, x, y, nullptr); 485 | BGI__ReleaseWinbgiDC(); 486 | } 487 | 488 | 489 | void setbkcolor(int color) 490 | { 491 | auto pWndData = BGI__GetWindowDataPtr(); 492 | 493 | pWndData->bgColor = color; 494 | 495 | // Convert from BGI color to RGB color 496 | color = converttorgb(color); 497 | 498 | WaitForSingleObject(pWndData->hDCMutex, 5000); 499 | for (auto i = 0; i < MAX_PAGES; i++) 500 | SetBkColor(pWndData->hDC[i], color); 501 | ReleaseMutex(pWndData->hDCMutex); 502 | } 503 | 504 | 505 | void setcolor(int color) 506 | { 507 | auto pWndData = BGI__GetWindowDataPtr(); 508 | 509 | // Update the color in our structure 510 | pWndData->drawColor = color; 511 | 512 | // Convert from BGI color to RGB color 513 | color = converttorgb(color); 514 | 515 | // Use that to set the text color for each page 516 | WaitForSingleObject(pWndData->hDCMutex, 5000); 517 | for (auto i = 0; i < MAX_PAGES; i++) 518 | SetTextColor(pWndData->hDC[i], color); 519 | ReleaseMutex(pWndData->hDCMutex); 520 | 521 | // Create the new drawing pen 522 | CreateNewPen(); 523 | } 524 | 525 | 526 | void setlinestyle(int linestyle, unsigned upattern, int thickness) 527 | { 528 | auto pWndData = BGI__GetWindowDataPtr(); 529 | pWndData->lineInfo.linestyle = linestyle; 530 | pWndData->lineInfo.upattern = upattern; 531 | pWndData->lineInfo.thickness = thickness; 532 | 533 | // Create the new drawing pen 534 | CreateNewPen(); 535 | } 536 | 537 | 538 | // The user calls this function to create a brush with a pattern they create 539 | // 540 | void setfillpattern(char *upattern, int color) 541 | { 542 | auto pWndData = BGI__GetWindowDataPtr(); 543 | HBITMAP hBitmap; 544 | HBRUSH hBrush; 545 | unsigned short pattern[8]; 546 | int i; 547 | 548 | // Copy the pattern to the storage for the window 549 | memcpy(pWndData->uPattern, upattern, sizeof(pWndData->uPattern)); 550 | 551 | // Convert the pattern to create a brush 552 | for (i = 0; i < 8; i++) 553 | pattern[i] = static_cast(~upattern[i]); // Restrict to 8 bits 554 | 555 | // Set the settings for the structure 556 | pWndData->fillInfo.pattern = USER_FILL; 557 | pWndData->fillInfo.color = color; 558 | 559 | // Create the bitmap 560 | hBitmap = CreateBitmap(8, 8, 1, 1, pattern); 561 | // Create a brush for each DC 562 | WaitForSingleObject(pWndData->hDCMutex, 5000); 563 | for (auto i = 0; i < MAX_PAGES; i++) 564 | { 565 | hBrush = CreatePatternBrush(hBitmap); 566 | // Select the new brush into the device context and delete the old one. 567 | DeleteBrush(HBRUSH(SelectBrush(pWndData->hDC[i], hBrush))); 568 | } 569 | ReleaseMutex(pWndData->hDCMutex); 570 | // I'm not sure if it's safe to delete the bitmap here or not, but it 571 | // hasn't caused any problems. The material I've found just says the 572 | // bitmap must be deleted in addition to the brush when finished. 573 | DeleteBitmap(hBitmap); 574 | 575 | } 576 | 577 | // If the USER_FILL pattern is passed, nothing is changed. 578 | // 579 | void setfillstyle(int pattern, int color) 580 | { 581 | // Unsigned char creates a truncation for some reason. 582 | unsigned short Slash[8] = { SC_US(~0xE0), SC_US(~0xC1), SC_US(~0x83), SC_US(~0x07), SC_US(~0x0E), SC_US(~0x1C), SC_US(~0x38), SC_US(~0x70) }; 583 | unsigned short BkSlash[8] = { SC_US(~0x07), SC_US(~0x83), SC_US(~0xC1), SC_US(~0xE0), SC_US(~0x70), SC_US(~0x38), SC_US(~0x1C), SC_US(~0x0E) }; 584 | unsigned short Interleave[8] = { SC_US(~0xCC), SC_US(~0x33), SC_US(~0xCC), SC_US(~0x33), SC_US(~0xCC), SC_US(~0x33), SC_US(~0xCC), SC_US(~0x33) }; 585 | unsigned short WideDot[8] = { SC_US(~0x80), SC_US(~0x00), SC_US(~0x08), SC_US(~0x00), SC_US(~0x80), SC_US(~0x00), SC_US(~0x08), SC_US(~0x00) }; 586 | unsigned short CloseDot[8] = { SC_US(~0x88), SC_US(~0x00), SC_US(~0x22), SC_US(~0x00), SC_US(~0x88), SC_US(~0x00), SC_US(~0x22), SC_US(~0x00) }; 587 | 588 | auto pWndData = BGI__GetWindowDataPtr(); 589 | auto hDC = BGI__GetWinbgiDC(); 590 | HBRUSH hBrush; 591 | HBITMAP hBitmap; 592 | 593 | // Convert from BGI color to RGB color 594 | color = converttorgb(color); 595 | 596 | switch (pattern) 597 | { 598 | case EMPTY_FILL: 599 | hBrush = CreateSolidBrush(converttorgb(pWndData->bgColor)); 600 | break; 601 | case SOLID_FILL: 602 | hBrush = CreateSolidBrush(color); 603 | break; 604 | case LINE_FILL: 605 | hBrush = CreateHatchBrush(HS_HORIZONTAL, color); 606 | break; 607 | case LTSLASH_FILL: 608 | hBrush = CreateHatchBrush(HS_BDIAGONAL, color); 609 | break; 610 | case SLASH_FILL: 611 | // The colors of the monochrome bitmap are drawn using the text color 612 | // and the current background color. 613 | // TODO: We may have to set the text color in every fill function 614 | // and then reset the text color to the user-specified text color 615 | // after the fill-draw routines are complete. 616 | hBitmap = CreateBitmap(8, 8, 1, 1, Slash); 617 | hBrush = CreatePatternBrush(hBitmap); 618 | DeleteBitmap(hBitmap); 619 | break; 620 | case BKSLASH_FILL: 621 | hBitmap = CreateBitmap(8, 8, 1, 1, BkSlash); 622 | hBrush = CreatePatternBrush(hBitmap); 623 | DeleteBitmap(hBitmap); 624 | break; 625 | case LTBKSLASH_FILL: 626 | hBrush = CreateHatchBrush(HS_FDIAGONAL, color); 627 | break; 628 | case HATCH_FILL: 629 | hBrush = CreateHatchBrush(HS_CROSS, color); 630 | break; 631 | case XHATCH_FILL: 632 | hBrush = CreateHatchBrush(HS_DIAGCROSS, color); 633 | break; 634 | case INTERLEAVE_FILL: 635 | hBitmap = CreateBitmap(8, 8, 1, 1, Interleave); 636 | hBrush = CreatePatternBrush(hBitmap); 637 | DeleteBitmap(hBitmap); 638 | break; 639 | case WIDE_DOT_FILL: 640 | hBitmap = CreateBitmap(8, 8, 1, 1, WideDot); 641 | hBrush = CreatePatternBrush(hBitmap); 642 | DeleteBitmap(hBitmap); 643 | break; 644 | case CLOSE_DOT_FILL: 645 | hBitmap = CreateBitmap(8, 8, 1, 1, CloseDot); 646 | hBrush = CreatePatternBrush(hBitmap); 647 | DeleteBitmap(hBitmap); 648 | break; 649 | case USER_FILL: 650 | return; 651 | break; 652 | default: 653 | pWndData->error_code = grError; 654 | return; 655 | } 656 | 657 | // TODO: Modify this so the brush is created in every DC 658 | pWndData->fillInfo.pattern = pattern; 659 | pWndData->fillInfo.color = color; 660 | 661 | // Select the new brush into the device context and delete the old one. 662 | DeleteBrush(HBRUSH(SelectBrush(hDC, hBrush))); 663 | BGI__ReleaseWinbgiDC(); 664 | } 665 | 666 | 667 | void setviewport(int left, int top, int right, int bottom, int clip) 668 | { 669 | auto pWndData = BGI__GetWindowDataPtr(); 670 | HRGN hRGN = nullptr; 671 | 672 | // Store the viewport information in the structure 673 | pWndData->viewportInfo.left = left; 674 | pWndData->viewportInfo.top = top; 675 | pWndData->viewportInfo.right = right; 676 | pWndData->viewportInfo.bottom = bottom; 677 | pWndData->viewportInfo.clip = clip; 678 | 679 | // If the drawing should be clipped at the viewport boundary, create a 680 | // clipping region 681 | if (clip != 0) 682 | hRGN = CreateRectRgn(left, top, right, bottom); 683 | 684 | WaitForSingleObject(pWndData->hDCMutex, 5000); 685 | for (auto i = 0; i < MAX_PAGES; i++) 686 | { 687 | SelectClipRgn(pWndData->hDC[i], hRGN); 688 | 689 | // Set the viewport origin to be the upper left corner 690 | SetViewportOrgEx(pWndData->hDC[i], left, top, nullptr); 691 | 692 | // Move to the new origin 693 | MoveToEx(pWndData->hDC[i], 0, 0, nullptr); 694 | } 695 | ReleaseMutex(pWndData->hDCMutex); 696 | // A copy of the region is used for the clipping region, so it is 697 | // safe to delete the region (p. 369 Win32 API book) 698 | DeleteRgn(hRGN); 699 | } 700 | 701 | 702 | void setwritemode(int mode) 703 | { 704 | auto hDC = BGI__GetWinbgiDC(); 705 | 706 | if (mode == COPY_PUT) 707 | SetROP2(hDC, R2_COPYPEN); 708 | if (mode == XOR_PUT) 709 | SetROP2(hDC, R2_XORPEN); 710 | BGI__ReleaseWinbgiDC(); 711 | } 712 | -------------------------------------------------------------------------------- /WinBGI/winbgi.cpp: -------------------------------------------------------------------------------- 1 | // File: winbgi.cpp 2 | // Written by: 3 | // Grant Macklem (Grant.Macklem@colorado.edu) 4 | // Gregory Schmelter (Gregory.Schmelter@colorado.edu) 5 | // Alan Schmidt (Alan.Schmidt@colorado.edu) 6 | // Ivan Stashak (Ivan.Stashak@colorado.edu) 7 | // CSCI 4830/7818: API Programming 8 | // University of Colorado at Boulder, Spring 2003 9 | // http://www.cs.colorado.edu/~main/bgi 10 | // 11 | 12 | #include "stdafx.h" 13 | //#include "winbgi.h" 14 | //#include "winbgitypes.h" 15 | 16 | // The window message-handling function (in WindowThread.cpp) 17 | LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); 18 | 19 | 20 | // This function is called whenever a process attaches itself to the DLL. 21 | // Thus, it registers itself in the process' address space. 22 | // 23 | BOOL registerWindowClass() 24 | { 25 | WNDCLASSEX wcex; // The main window class that we create 26 | 27 | // Set up the properties of the Windows BGI window class and register it 28 | wcex.cbSize = sizeof(WNDCLASSEX); // Size of the structure 29 | wcex.style = CS_SAVEBITS | CS_DBLCLKS; // Use default class styles 30 | wcex.lpfnWndProc = WndProc; // The message handling function 31 | wcex.cbClsExtra = 0; // No extra memory allocation 32 | wcex.cbWndExtra = 0; 33 | wcex.hInstance = BGI__hInstance; // HANDLE for this program 34 | wcex.hIcon = nullptr; // Use default icon 35 | wcex.hIconSm = nullptr; // Default small icon 36 | wcex.hCursor = LoadCursor(nullptr, IDC_ARROW); // Set mouse cursor 37 | wcex.hbrBackground = GetStockBrush(BLACK_BRUSH); // Background color 38 | wcex.lpszMenuName = nullptr; // Menu identification 39 | wcex.lpszClassName = "BGILibrary"; // a c-string name for the window 40 | 41 | if (RegisterClassEx(&wcex) == 0) 42 | { 43 | showerrorbox(); 44 | return FALSE; 45 | } 46 | return TRUE; 47 | } 48 | 49 | 50 | // This function unregisters the window class so that it can be registered 51 | // again if using LoadLibrary and FreeLibrary 52 | void unregisterWindowClass() 53 | { 54 | UnregisterClass("BGILibrary", BGI__hInstance); 55 | } 56 | 57 | 58 | // This is the entry point for the DLL 59 | // MGM: I changed it to a regular function rather than a DLL entry 60 | // point (since I deleted the DLL). As such, it is now called 61 | // by initwindow. 62 | bool DllMain_MGM( 63 | HINSTANCE hinstDll, // Handle to DLL module 64 | DWORD Reason, // Reason for calling function 65 | LPVOID Reserved // reserved 66 | ) 67 | { 68 | // MGM: Add a static variable so that this work is done but once. 69 | static auto called = false; 70 | if (called) return true; 71 | called = true; 72 | 73 | switch (Reason) 74 | { 75 | case DLL_PROCESS_ATTACH: 76 | BGI__hInstance = hinstDll; // Set the global hInstance variable 77 | return registerWindowClass() == FALSE ? false : true; // Register the window class for this process 78 | // break; 79 | case DLL_PROCESS_DETACH: 80 | unregisterWindowClass(); 81 | break; 82 | default: break; 83 | } 84 | return true; // Ignore other initialization cases 85 | } 86 | 87 | 88 | 89 | void showerrorbox(const char* msg) 90 | { 91 | LPVOID lpMsgBuf; 92 | 93 | if (msg == nullptr) 94 | { 95 | // This code is taken from the MSDN help for FormatMessage 96 | FormatMessage( 97 | FORMAT_MESSAGE_ALLOCATE_BUFFER | 98 | FORMAT_MESSAGE_FROM_SYSTEM | 99 | FORMAT_MESSAGE_IGNORE_INSERTS, // Formatting options 100 | nullptr, // Location of message definition 101 | GetLastError(), // Message ID 102 | MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT), // Default language 103 | LPTSTR(&lpMsgBuf), // Pointer to buffer 104 | 0, // Minimum size of buffer 105 | nullptr); 106 | 107 | MessageBox(nullptr, LPCTSTR(lpMsgBuf), "Error", MB_OK | MB_ICONERROR); 108 | 109 | // Free the buffer 110 | LocalFree(lpMsgBuf); 111 | } 112 | else 113 | MessageBox(nullptr, msg, "Error", MB_OK | MB_ICONERROR); 114 | } 115 | 116 | 117 | /***************************************************************************** 118 | * 119 | * The actual API calls are implemented below 120 | * MGM: Rearranged order of functions by trial-and-error until internal 121 | * error in g++ 3.2.3 disappeared. 122 | *****************************************************************************/ 123 | 124 | 125 | void graphdefaults() 126 | { 127 | auto pWndData = BGI__GetWindowDataPtr(); 128 | HPEN hPen; // The default drawing pen 129 | HBRUSH hBrush; // The default filling brush 130 | HDC hDC; 131 | 132 | #if CUSTOM_COLORS 133 | int bgi_color; // A bgi color number 134 | COLORREF actual_color; // The color that's actually put on the screen 135 | #endif // CUSTOM_COLORS 136 | 137 | // TODO: Do this for each DC 138 | 139 | // Set viewport to the entire screen and move current position to (0,0) 140 | setviewport(0, 0, pWndData->width, pWndData->height, 0); 141 | pWndData->mouse.x = 0; 142 | pWndData->mouse.y = 0; 143 | 144 | // Turn on auto refreshing 145 | pWndData->refreshing = true; 146 | 147 | // MGM: Grant suggested the following colors, but I have changed 148 | // them so that they will be consistent on any 16-color VGA 149 | // display. It's also important to use 255-255-255 for white 150 | // to match some stock tools such as the stock WHITE brush 151 | 152 | #if CUSTOM_COLORS 153 | BGI__Colors[0] = RGB(0, 0, 0); // Black 154 | BGI__Colors[1] = RGB(0, 0, 168); // Blue 155 | BGI__Colors[2] = RGB(0, 168, 0); // Green 156 | BGI__Colors[3] = RGB(0, 168, 168); // Cyan 157 | BGI__Colors[4] = RGB(168, 0, 0); // Red 158 | BGI__Colors[5] = RGB(168, 0, 168); // Magenta 159 | BGI__Colors[6] = RGB(168, 84, 0); // Brown 160 | BGI__Colors[7] = RGB(168, 168, 168); // Light Gray 161 | BGI__Colors[8] = RGB(84, 84, 84); // Dark Gray 162 | BGI__Colors[9] = RGB(84, 84, 252); // Light Blue 163 | BGI__Colors[10] = RGB(84, 252, 84); // Light Green 164 | BGI__Colors[11] = RGB(84, 252, 252); // Light Cyan 165 | BGI__Colors[12] = RGB(252, 84, 84); // Light Red 166 | BGI__Colors[13] = RGB(252, 84, 252); // Light Magenta 167 | BGI__Colors[14] = RGB(252, 252, 84); // Yellow 168 | BGI__Colors[15] = RGB(252, 252, 252); // White 169 | 170 | for (bgi_color = 0; bgi_color <= WHITE; bgi_color++) 171 | { 172 | putpixel(0, 0, bgi_color); 173 | actual_color = GetPixel(hDC, 0, 0); 174 | BGI__Colors[bgi_color] = actual_color; 175 | } 176 | #endif // CUSTOM_COLORS 177 | 178 | 179 | 180 | BGI__Colors[0] = RGB(0, 0, 0); // Black 181 | BGI__Colors[1] = RGB(0, 0, 128); // Blue 182 | BGI__Colors[2] = RGB(0, 128, 0); // Green 183 | BGI__Colors[3] = RGB(0, 128, 128); // Cyan 184 | BGI__Colors[4] = RGB(128, 0, 0); // Red 185 | BGI__Colors[5] = RGB(128, 0, 128); // Magenta 186 | BGI__Colors[6] = RGB(128, 128, 0); // Brown 187 | BGI__Colors[7] = RGB(192, 192, 192); // Light Gray 188 | BGI__Colors[8] = RGB(128, 128, 128); // Dark Gray 189 | BGI__Colors[9] = RGB(128, 128, 255); // Light Blue 190 | BGI__Colors[10] = RGB(128, 255, 128); // Light Green 191 | BGI__Colors[11] = RGB(128, 255, 255); // Light Cyan 192 | BGI__Colors[12] = RGB(255, 128, 128); // Light Red 193 | BGI__Colors[13] = RGB(255, 128, 255); // Light Magenta 194 | BGI__Colors[14] = RGB(255, 255, 0); // Yellow 195 | BGI__Colors[15] = RGB(255, 255, 255); // White 196 | 197 | // Set background color to default (black) 198 | setbkcolor(BLACK); 199 | 200 | // Set drawing color to default (white) 201 | pWndData->drawColor = WHITE; 202 | // Set fill style and pattern to default (white solid) 203 | pWndData->fillInfo.pattern = SOLID_FILL; 204 | pWndData->fillInfo.color = WHITE; 205 | 206 | hDC = BGI__GetWinbgiDC(); 207 | // Reset the pen and brushes for each DC 208 | for (auto i = 0; i < MAX_PAGES; i++) 209 | { 210 | // Using Stock stuff is more efficient. 211 | // Create the default pen for drawing in the window. 212 | hPen = GetStockPen(WHITE_PEN); 213 | // Select this pen into the DC and delete the old pen. 214 | DeletePen(SelectPen(pWndData->hDC[i], hPen)); 215 | 216 | // Create the default brush for painting in the window. 217 | hBrush = GetStockBrush(WHITE_BRUSH); 218 | // Select this brush into the DC and delete the old brush. 219 | DeleteBrush(SelectBrush(pWndData->hDC[i], hBrush)); 220 | 221 | // Set the default text color for each page 222 | SetTextColor(pWndData->hDC[i], converttorgb(WHITE)); 223 | } 224 | ReleaseMutex(pWndData->hDCMutex); 225 | 226 | // Set text font and justification to default 227 | pWndData->textInfo.horiz = LEFT_TEXT; 228 | pWndData->textInfo.vert = TOP_TEXT; 229 | pWndData->textInfo.font = DEFAULT_FONT; 230 | pWndData->textInfo.direction = HORIZ_DIR; 231 | pWndData->textInfo.charsize = 1; 232 | 233 | // set this something that it can never be to force set_align to be called 234 | pWndData->alignment = 2; 235 | 236 | pWndData->t_scale[0] = 1; // mul-x 237 | pWndData->t_scale[1] = 1; // div-x 238 | pWndData->t_scale[2] = 1; // mul-y 239 | pWndData->t_scale[3] = 1; // div-y 240 | 241 | // Set the error code to OK: There is no error 242 | pWndData->error_code = grOk; 243 | 244 | // Line style as well? 245 | pWndData->lineInfo.linestyle = SOLID_LINE; 246 | pWndData->lineInfo.thickness = NORM_WIDTH; 247 | 248 | // Set the default active and visual page 249 | if (pWndData->DoubleBuffer) 250 | { 251 | pWndData->ActivePage = 1; 252 | pWndData->VisualPage = 0; 253 | } 254 | else 255 | { 256 | pWndData->ActivePage = 0; 257 | pWndData->VisualPage = 0; 258 | } 259 | 260 | // Set the aspect ratios. Unless Windows is doing something funky, 261 | // these should not need to be changed by the user to produce geometrically 262 | // correct shapes (circles, squares, etc). 263 | pWndData->x_aspect_ratio = 10000; 264 | pWndData->y_aspect_ratio = 10000; 265 | } 266 | 267 | // The initwindow function is typically the first function called by the 268 | // application. It will create a separate thread for each window created. 269 | // This thread is responsible for creating the window and processing all the 270 | // messages. It returns a positive integer value which the user can then 271 | // use whenever he needs to reference the window. 272 | // RETURN VALUE: If the window is successfully created, a nonnegative integer 273 | // uniquely identifying the window. 274 | // On failure, -1. 275 | // 276 | int initwindow(int width, int height, const char* title, int left, int top, bool dbflag, bool closeflag) 277 | { 278 | HANDLE hThread; // Handle to the message pump thread 279 | int index; // Index of current window in the table 280 | HANDLE objects[2]; // Handle to objects (thread and event) to ensure proper creation 281 | int code; // Return code of thread wait function 282 | 283 | // MGM: Call the DllMain, which used to be the DLL entry point. 284 | if (!DllMain_MGM( 285 | nullptr, 286 | DLL_PROCESS_ATTACH, 287 | nullptr)) 288 | return -1; 289 | 290 | auto pWndData = new WindowData; 291 | // Check if new failed 292 | if (pWndData == nullptr) 293 | return -1; 294 | 295 | // TODO: check to make sure the events are created successfully 296 | pWndData->key_waiting = CreateEvent(nullptr, FALSE, FALSE, nullptr); 297 | pWndData->WindowCreated = CreateEvent(nullptr, FALSE, FALSE, nullptr); 298 | pWndData->width = width; 299 | pWndData->height = height; 300 | pWndData->initleft = left; 301 | pWndData->inittop = top; 302 | pWndData->title = title; // Converts to a string object 303 | 304 | hThread = CreateThread(nullptr, // Security Attributes (use default) 305 | 0, // Stack size (use default) 306 | BGI__ThreadInitWindow, // Start routine 307 | LPVOID(pWndData), // Thread specific parameter 308 | 0, // Creation flags (run immediately) 309 | &pWndData->threadID); // Thread ID 310 | 311 | // Check if the message pump thread was created 312 | if (hThread == nullptr) 313 | { 314 | showerrorbox(); 315 | delete pWndData; 316 | return -1; 317 | } 318 | 319 | // Create an array of events to wait for 320 | objects[0] = hThread; 321 | objects[1] = pWndData->WindowCreated; 322 | // We'll either wait to be signaled that the window was created 323 | // successfully or the thread will terminate and we'll have some problem. 324 | code = WaitForMultipleObjects(2, // Number of objects to wait on 325 | objects, // Array of objects 326 | FALSE, // Whether all objects must be signaled 327 | INFINITE); // How long to wait before timing out 328 | 329 | switch (code) 330 | { 331 | case WAIT_OBJECT_0: 332 | // Thread terminated without creating the window 333 | delete pWndData; 334 | return -1; 335 | // break; 336 | case WAIT_OBJECT_0 + 1: 337 | // Successfully running 338 | break; 339 | default: break; 340 | } 341 | 342 | // Set index to the next available position 343 | index = BGI__WindowCount; 344 | // Increment the count 345 | ++BGI__WindowCount; 346 | // Store the window in the next position of the vector 347 | BGI__WindowTable.push_back(pWndData->hWnd); 348 | // Set the current window to the newly created window 349 | BGI__CurrentWindow = index; 350 | 351 | // Set double-buffering and close behavior 352 | pWndData->DoubleBuffer = dbflag; 353 | pWndData->CloseBehavior = closeflag; 354 | 355 | // Set the bitmap info struct to NULL 356 | pWndData->pbmpInfo = nullptr; 357 | 358 | // Set up the defaults for the window 359 | graphdefaults(); 360 | 361 | // MGM: Draw diagonal line since otherwise BitBlt into window doesn't work. 362 | setcolor(BLACK); 363 | line(0, 0, width - 1, height - 1); 364 | // MGM: The black rectangle is because on my laptop, the background 365 | // is not automatically reset to black when the window opens. 366 | setfillstyle(SOLID_FILL, BLACK); 367 | bar(0, 0, width - 1, height - 1); 368 | // MGM: Reset the color and fillstyle to the default for a new window. 369 | setcolor(WHITE); 370 | setfillstyle(SOLID_FILL, WHITE); 371 | 372 | // Everything went well! Return the window index to the user. 373 | return index; 374 | } 375 | 376 | 377 | void closegraph(int wid) 378 | { 379 | if (wid == CURRENT_WINDOW) 380 | { 381 | closegraph(BGI__CurrentWindow); 382 | } 383 | else if (wid == ALL_WINDOWS) 384 | { 385 | for (auto i = 0; i < BGI__WindowCount; i++) 386 | { 387 | closegraph(i); 388 | } 389 | } 390 | else if (wid >= 0 && wid <= BGI__WindowCount && BGI__WindowTable[wid] != nullptr) 391 | { 392 | // DestroyWindow cannot delete a window created by another thread. 393 | // Thus, use SendMessage to close the requested window. 394 | // Destroying the window causes cls_OnDestroy to be called, 395 | // releasing any dynamic memory that's being used by the window. 396 | // The WindowData structure is released at the end of BGI__ThreadInitWindow, 397 | // which is reached when the message loop of BGI__ThreadInitWindow get WM_QUIT. 398 | SendMessage(BGI__WindowTable[wid], WM_DESTROY, 0, 0); 399 | 400 | // Remove the HWND from the BGI__WindowTable vector: 401 | BGI__WindowTable[wid] = nullptr; 402 | 403 | // Reset the global BGI__CurrentWindow if needed: 404 | if (BGI__CurrentWindow == wid) 405 | { 406 | BGI__CurrentWindow = NO_CURRENT_WINDOW; 407 | } 408 | } 409 | } 410 | 411 | 412 | // This function detects the graphics driver and returns the highest resolution 413 | // mode possible. For WinBGI, this is always VGA/VGAHI 414 | // 415 | void detectgraph(int *graphdriver, int *graphmode) 416 | { 417 | *graphdriver = VGA; 418 | *graphmode = VGAHI; 419 | } 420 | 421 | 422 | // This function returns the aspect ratio of the current window. Unless there 423 | // is something weird going on with Windows resolutions, these quantities 424 | // will be equal and correctly proportioned geometric shapes will result. 425 | // 426 | void getaspectratio(int *xasp, int *yasp) 427 | { 428 | auto pWndData = BGI__GetWindowDataPtr(); 429 | *xasp = pWndData->x_aspect_ratio; 430 | *yasp = pWndData->y_aspect_ratio; 431 | } 432 | 433 | 434 | // This function will return the next character waiting to be read in the 435 | // window's keyboard buffer 436 | // 437 | int getch() 438 | { 439 | char c; 440 | auto pWndData = BGI__GetWindowDataPtr(); 441 | 442 | // TODO: Start critical section 443 | // check queue empty 444 | // end critical section 445 | 446 | if (pWndData->kbd_queue.empty()) 447 | WaitForSingleObject(pWndData->key_waiting, INFINITE); 448 | else 449 | // Make sure the event is not signaled. It will remain signaled until a 450 | // thread is woken up by it. This could cause problems if the queue was 451 | // not empty and we got characters from it, never having to wait. If the 452 | // queue then becomes empty, the WaitForSingleObjectX will immediately 453 | // return since it's still signaled. If no key was pressed, this would 454 | // obviously be an error. 455 | ResetEvent(pWndData->key_waiting); 456 | 457 | // TODO: Start critical section 458 | // access queue 459 | // end critical section 460 | 461 | c = pWndData->kbd_queue.front(); // Obtain the next element in the queue 462 | pWndData->kbd_queue.pop(); // Remove the element from the queue 463 | 464 | return c; 465 | } 466 | 467 | 468 | // This function returns the name of the current driver in use. For WinBGI, 469 | // this is always "EGAVGA" 470 | // 471 | char *getdrivername() 472 | { 473 | return "EGAVGA"; 474 | } 475 | 476 | 477 | // This function gets the current graphics mode. For WinBGI, this is always 478 | // VGAHI 479 | // 480 | int getgraphmode() 481 | { 482 | return VGAHI; 483 | } 484 | 485 | 486 | // This function returns the maximum mode the current graphics driver can 487 | // display. For WinBGI, this is always VGAHI. 488 | // 489 | int getmaxmode() 490 | { 491 | return VGAHI; 492 | } 493 | 494 | 495 | // This function returns a string describing the current graphics mode. It has the format 496 | // "width*height MODE_NAME" For WinBGI, this is the window size followed by VGAHI 497 | // 498 | char *getmodename(int mode_number) 499 | { 500 | static char mode[20]; 501 | auto pWndData = BGI__GetWindowDataPtr(); 502 | 503 | sprintf_s(mode, "%d*%d VGAHI", pWndData->width, pWndData->height); 504 | return mode; 505 | } 506 | 507 | 508 | // This function returns the range of possible graphics modes for the given graphics driver. 509 | // If -1 is given for the driver, the current driver and mode is used. 510 | // 511 | void getmoderange(int graphdriver, int *lomode, int *himode) 512 | { 513 | auto pWndData = BGI__GetWindowDataPtr(); 514 | int graphmode; 515 | 516 | // Use current driver modes 517 | if (graphdriver == -1) 518 | detectgraph(&graphdriver, &graphmode); 519 | 520 | switch (graphdriver) 521 | { 522 | case CGA: 523 | *lomode = CGAC0; 524 | *himode = CGAHI; 525 | break; 526 | case MCGA: 527 | *lomode = MCGAC0; 528 | *himode = MCGAHI; 529 | break; 530 | case EGA: 531 | *lomode = EGALO; 532 | *himode = EGAHI; 533 | break; 534 | case EGA64: 535 | *lomode = EGA64LO; 536 | *himode = EGA64HI; 537 | break; 538 | case EGAMONO: 539 | *lomode = *himode = EGAMONOHI; 540 | break; 541 | case HERCMONO: 542 | *lomode = *himode = HERCMONOHI; 543 | break; 544 | case ATT400: 545 | *lomode = ATT400C0; 546 | *himode = ATT400HI; 547 | break; 548 | case VGA: 549 | *lomode = VGALO; 550 | *himode = VGAHI; 551 | break; 552 | case PC3270: 553 | *lomode = *himode = PC3270HI; 554 | break; 555 | case IBM8514: 556 | *lomode = IBM8514LO; 557 | *himode = IBM8514HI; 558 | break; 559 | default: 560 | *lomode = *himode = -1; 561 | pWndData->error_code = grInvalidDriver; 562 | break; 563 | } 564 | } 565 | 566 | 567 | // This function returns an error string corresponding to the given error code. 568 | // This code is returned by graphresult() 569 | // 570 | char *grapherrormsg(int errorcode) 571 | { 572 | static char *msg[16] 573 | { 574 | "No error", "Graphics not installed", 575 | "Graphics hardware not detected", "Device driver not found", 576 | "Invalid device driver file", "Insufficient memory to load driver", 577 | "Out of memory in scan fill", "Out of memory in flood fill", 578 | "Font file not found", "Not enough memory to load font", 579 | "Invalid mode for selected driver", "Graphics error", 580 | "Graphics I/O error", "Invalid font file", 581 | "Invalid font number", "Invalid device number" 582 | }; 583 | 584 | return errorcode < -16 || errorcode > 0 ? nullptr : msg[-errorcode]; 585 | } 586 | 587 | 588 | // This function returns the error code from the most recent graphics operation. 589 | // It also resets the error to grOk. 590 | // 591 | int graphresult() 592 | { 593 | auto pWndData = BGI__GetWindowDataPtr(); 594 | int code; 595 | 596 | code = pWndData->error_code; 597 | pWndData->error_code = grOk; 598 | return code; 599 | 600 | } 601 | 602 | 603 | // This function uses the information in graphdriver and graphmode to select 604 | // the appropriate size for the window to be created. 605 | // 606 | void initgraph(int *graphdriver, int *graphmode, char *pathtodriver) 607 | { 608 | WindowData *pWndData; 609 | auto width = 0, height = 0; 610 | auto valid = true; 611 | 612 | if (*graphdriver == DETECT) 613 | { 614 | detectgraph(graphdriver, graphmode); 615 | } 616 | 617 | switch (*graphdriver) 618 | { 619 | case MCGA: 620 | switch (*graphmode) 621 | { 622 | case MCGAC0: 623 | case MCGAC1: 624 | case MCGAC2: 625 | case MCGAC3: 626 | width = 320; 627 | height = 200; 628 | break; 629 | case MCGAMED: 630 | width = 640; 631 | height = 200; 632 | break; 633 | case MCGAHI: 634 | width = 640; 635 | height = 480; 636 | break; 637 | default: break; 638 | } 639 | break; 640 | case EGA: 641 | switch (*graphmode) 642 | { 643 | case EGALO: 644 | width = 640; 645 | height = 200; 646 | break; 647 | case EGAHI: 648 | width = 640; 649 | height = 350; 650 | break; 651 | default: break; 652 | } 653 | break; 654 | case EGA64: 655 | switch (*graphmode) 656 | { 657 | case EGALO: 658 | width = 640; 659 | height = 200; 660 | break; 661 | case EGAHI: 662 | width = 640; 663 | height = 350; 664 | break; 665 | default: break; 666 | } 667 | break; 668 | case EGAMONO: 669 | width = 640; 670 | height = 350; 671 | break; 672 | case HERCMONO: 673 | width = 720; 674 | width = 348; 675 | break; 676 | case ATT400: 677 | switch (*graphmode) 678 | { 679 | case ATT400C0: 680 | case ATT400C1: 681 | case ATT400C2: 682 | case ATT400C3: 683 | width = 320; 684 | height = 200; 685 | break; 686 | case ATT400MED: 687 | width = 640; 688 | height = 200; 689 | break; 690 | case ATT400HI: 691 | width = 640; 692 | height = 400; 693 | break; 694 | default: break; 695 | } 696 | break; 697 | case VGA: 698 | switch (*graphmode) 699 | { 700 | case VGALO: 701 | width = 640; 702 | height = 200; 703 | break; 704 | case VGAMED: 705 | width = 640; 706 | height = 350; 707 | break; 708 | case VGAHI: 709 | width = 640; 710 | height = 480; 711 | break; 712 | default: break; 713 | } 714 | break; 715 | case PC3270: 716 | width = 720; 717 | height = 350; 718 | break; 719 | case IBM8514: 720 | switch (*graphmode) 721 | { 722 | case IBM8514LO: 723 | width = 640; 724 | height = 480; 725 | break; 726 | case IBM8514HI: 727 | width = 1024; 728 | height = 768; 729 | break; 730 | default: break; 731 | } 732 | break; 733 | default: 734 | valid = false; 735 | case CGA: 736 | switch (*graphmode) 737 | { 738 | case CGAC0: 739 | case CGAC1: 740 | case CGAC2: 741 | case CGAC3: 742 | width = 320; 743 | height = 200; 744 | break; 745 | case CGAHI: 746 | width = 640; 747 | height = 200; 748 | break; 749 | default: break; 750 | } 751 | break; 752 | } 753 | 754 | // Create the window with the specified dimensions 755 | initwindow(width, height); 756 | if (!valid) 757 | { 758 | pWndData = BGI__GetWindowDataPtr(); 759 | pWndData->error_code = grInvalidDriver; 760 | 761 | } 762 | } 763 | 764 | 765 | // This function does not do any work in WinBGI since the graphics and text 766 | // windows are always both open. 767 | // 768 | void restorecrtmode() 769 | { 770 | 771 | } 772 | 773 | 774 | // This function returns true if there is a character waiting to be read 775 | // from the window's keyboard buffer. 776 | // 777 | int kbhit() 778 | { 779 | // TODO: start critical section 780 | // check queue empty 781 | // end critical section 782 | auto pWndData = BGI__GetWindowDataPtr(); 783 | 784 | return !pWndData->kbd_queue.empty(); 785 | } 786 | 787 | 788 | // This function sets the aspect ratio of the current window. 789 | // 790 | void setaspectratio(int xasp, int yasp) 791 | { 792 | auto pWndData = BGI__GetWindowDataPtr(); 793 | 794 | pWndData->x_aspect_ratio = xasp; 795 | pWndData->y_aspect_ratio = yasp; 796 | } 797 | 798 | 799 | void setgraphmode(int mode) 800 | { 801 | // Reset graphics stuff to default 802 | graphdefaults(); 803 | // Clear the screen 804 | cleardevice(); 805 | } 806 | 807 | 808 | 809 | 810 | /***************************************************************************** 811 | * 812 | * User-Controlled Window Functions 813 | * 814 | *****************************************************************************/ 815 | 816 | // This function returns the current window index to the user. The user can 817 | // use this return value to refer to the window at a later time. 818 | // 819 | int getcurrentwindow() 820 | { 821 | return BGI__CurrentWindow; 822 | } 823 | 824 | 825 | // This function sets the current window to the value specified by the user. 826 | // All future drawing activity will be sent to this window. If the window 827 | // index is invalid, the current window is unchanged 828 | // 829 | void setcurrentwindow(int window) 830 | { 831 | if (window < 0 || window >= BGI__WindowCount || BGI__WindowTable[window] == nullptr) 832 | { 833 | return; 834 | } 835 | 836 | BGI__CurrentWindow = window; 837 | } 838 | 839 | 840 | 841 | 842 | 843 | /***************************************************************************** 844 | * 845 | * Double buffering support 846 | * 847 | *****************************************************************************/ 848 | 849 | // This function returns the current active page for the current window. 850 | // 851 | int getactivepage() 852 | { 853 | auto pWndData = BGI__GetWindowDataPtr(); 854 | return pWndData->ActivePage; 855 | } 856 | 857 | 858 | // This function returns the current visual page for the current window. 859 | // 860 | int getvisualpage() 861 | { 862 | auto pWndData = BGI__GetWindowDataPtr(); 863 | return pWndData->VisualPage; 864 | } 865 | 866 | 867 | // This function changes the active page of the current window to the page 868 | // specified by page. If page refers to an invalid number, the current 869 | // active page is unchanged. 870 | // 871 | void setactivepage(int page) 872 | { 873 | auto pWndData = BGI__GetWindowDataPtr(); 874 | 875 | if (page < 0 || page > MAX_PAGES) 876 | { 877 | return; 878 | } 879 | 880 | pWndData->ActivePage = page; 881 | } 882 | 883 | 884 | // This function changes the visual page of the current window to the page 885 | // specified by page. If page refers to an invalid number, the current 886 | // visual page is unchanged. The graphics window is then redrawn with the 887 | // new page. 888 | // 889 | void setvisualpage(int page) 890 | { 891 | auto pWndData = BGI__GetWindowDataPtr(); 892 | 893 | if (page < 0 || page > MAX_PAGES) 894 | { 895 | return; 896 | } 897 | 898 | pWndData->VisualPage = page; 899 | 900 | // Redraw the entire current window. No need to erase the background as 901 | // the new image is simply copied over the old one. 902 | InvalidateRect(pWndData->hWnd, nullptr, FALSE); 903 | } 904 | 905 | 906 | // This function will swap the buffers if you have created a double-buffered 907 | // window. That is, by having the dbflag true when initwindow was called. 908 | // 909 | void swapbuffers() 910 | { 911 | auto pWndData = BGI__GetWindowDataPtr(); 912 | 913 | if (pWndData->ActivePage == 0) 914 | { 915 | pWndData->VisualPage = 0; 916 | pWndData->ActivePage = 1; 917 | } 918 | else // Active page is 1 919 | { 920 | pWndData->VisualPage = 1; 921 | pWndData->ActivePage = 0; 922 | } 923 | // Redraw the entire current window. No need to erase the background as 924 | // the new image is simply copied over the old one. 925 | InvalidateRect(pWndData->hWnd, nullptr, FALSE); 926 | } 927 | -------------------------------------------------------------------------------- /WinBGI/dibutil.cpp: -------------------------------------------------------------------------------- 1 | //********************************************************************** 2 | // 3 | // dibutil.c 4 | // 5 | // Source file for Device-Independent Bitmap (DIB) API. Provides 6 | // the following functions: 7 | // 8 | // CreateDIB() - Creates new DIB 9 | // FindDIBBits() - Sets pointer to the DIB bits 10 | // DIBWidth() - Gets the width of the DIB 11 | // DIBHeight() - Gets the height of the DIB 12 | // PaletteSize() - Calculates the buffer size required by a palette 13 | // DIBNumColors() - Calculates number of colors in the DIB's color table 14 | // CreateDIBPalette() - Creates a palette from a DIB 15 | // DIBToBitmap() - Creates a bitmap from a DIB 16 | // BitmapToDIB() - Creates a DIB from a bitmap 17 | // PalEntriesOnDevice()- Gets the number of palette entries of a device 18 | // GetSystemPalette() - Returns a handle to the current system palette 19 | // AllocRoomForDIB() - Allocates memory for a DIB 20 | // ChangeDIBFormat() - Changes a DIB's BPP and/or compression format 21 | // ChangeBitmapFormat()- Changes a bitmap to a DIB with specified BPP and 22 | // compression format 23 | // 24 | // Written by Microsoft Product Support Services, Developer Support. 25 | // Copyright (C) 1991-1996 Microsoft Corporation. All rights reserved. 26 | //********************************************************************** 27 | 28 | #include "stdafx.h" 29 | //#include "dibapi.h" 30 | //#include "dibutil.h" 31 | 32 | /************************************************************************* 33 | * 34 | * CreateDIB() 35 | * 36 | * Parameters: 37 | * 38 | * DWORD dwWidth - Width for new bitmap, in pixels 39 | * DWORD dwHeight - Height for new bitmap 40 | * WORD wBitCount - Bit Count for new DIB (1, 4, 8, or 24) 41 | * 42 | * Return Value: 43 | * 44 | * HDIB - Handle to new DIB 45 | * 46 | * Description: 47 | * 48 | * This function allocates memory for and initializes a new DIB by 49 | * filling in the BITMAPINFOHEADER, allocating memory for the color 50 | * table, and allocating memory for the bitmap bits. As with all 51 | * HDIBs, the header, colortable and bits are all in one contiguous 52 | * memory block. This function is similar to the CreateBitmap() 53 | * Windows API. 54 | * 55 | * The colortable and bitmap bits are left uninitialized (zeroed) in the 56 | * returned HDIB. 57 | * 58 | * 59 | ************************************************************************/ 60 | 61 | HDIB CreateDIB(DWORD dwWidth, DWORD dwHeight, WORD wBitCount) 62 | { 63 | BITMAPINFOHEADER bi; // bitmap header 64 | LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER 65 | DWORD dwLen; // size of memory block 66 | HDIB hDIB; 67 | DWORD dwBytesPerLine; // Number of bytes per scanline 68 | 69 | 70 | // Make sure bits per pixel is valid 71 | 72 | if (wBitCount <= 1) 73 | wBitCount = 1; 74 | else if (wBitCount <= 4) 75 | wBitCount = 4; 76 | else if (wBitCount <= 8) 77 | wBitCount = 8; 78 | else if (wBitCount <= 24) 79 | wBitCount = 24; 80 | else 81 | wBitCount = 4; // set default value to 4 if parameter is bogus 82 | 83 | // initialize BITMAPINFOHEADER 84 | 85 | bi.biSize = sizeof(BITMAPINFOHEADER); 86 | bi.biWidth = dwWidth; // fill in width from parameter 87 | bi.biHeight = dwHeight; // fill in height from parameter 88 | bi.biPlanes = 1; // must be 1 89 | bi.biBitCount = wBitCount; // from parameter 90 | bi.biCompression = BI_RGB; 91 | bi.biSizeImage = 0; // 0's here mean "default" 92 | bi.biXPelsPerMeter = 0; 93 | bi.biYPelsPerMeter = 0; 94 | bi.biClrUsed = 0; 95 | bi.biClrImportant = 0; 96 | 97 | // calculate size of memory block required to store the DIB. This 98 | // block should be big enough to hold the BITMAPINFOHEADER, the color 99 | // table, and the bits 100 | 101 | dwBytesPerLine = WIDTHBYTES(wBitCount * dwWidth); 102 | dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + (dwBytesPerLine * dwHeight); 103 | 104 | // alloc memory block to store our bitmap 105 | 106 | hDIB = GlobalAlloc(GHND, dwLen); 107 | 108 | // major bummer if we couldn't get memory block 109 | 110 | if (!hDIB) 111 | return NULL; 112 | 113 | // lock memory and get pointer to it 114 | 115 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 116 | 117 | // use our bitmap info structure to fill in first part of 118 | // our DIB with the BITMAPINFOHEADER 119 | 120 | *lpbi = bi; 121 | 122 | // Since we don't know what the colortable and bits should contain, 123 | // just leave these blank. Unlock the DIB and return the HDIB. 124 | 125 | GlobalUnlock(hDIB); 126 | 127 | //return handle to the DIB 128 | 129 | return hDIB; 130 | } 131 | 132 | 133 | /************************************************************************* 134 | * 135 | * FindDIBBits() 136 | * 137 | * Parameter: 138 | * 139 | * LPSTR lpDIB - pointer to packed-DIB memory block 140 | * 141 | * Return Value: 142 | * 143 | * LPSTR - pointer to the DIB bits 144 | * 145 | * Description: 146 | * 147 | * This function calculates the address of the DIB's bits and returns a 148 | * pointer to the DIB bits. 149 | * 150 | ************************************************************************/ 151 | 152 | LPSTR FindDIBBits(LPSTR lpDIB) 153 | { 154 | return (lpDIB + *(LPDWORD)lpDIB + PaletteSize(lpDIB)); 155 | } 156 | 157 | 158 | /************************************************************************* 159 | * 160 | * DIBWidth() 161 | * 162 | * Parameter: 163 | * 164 | * LPSTR lpDIB - pointer to packed-DIB memory block 165 | * 166 | * Return Value: 167 | * 168 | * DWORD - width of the DIB 169 | * 170 | * Description: 171 | * 172 | * This function gets the width of the DIB from the BITMAPINFOHEADER 173 | * width field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 174 | * width field if it is an OS/2-style DIB. 175 | * 176 | ************************************************************************/ 177 | 178 | 179 | DWORD DIBWidth(LPSTR lpDIB) 180 | { 181 | LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 182 | LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 183 | 184 | // point to the header (whether Win 3.0 and OS/2) 185 | 186 | lpbmi = (LPBITMAPINFOHEADER)lpDIB; 187 | lpbmc = (LPBITMAPCOREHEADER)lpDIB; 188 | 189 | // return the DIB width if it is a Win 3.0 DIB 190 | 191 | if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 192 | return lpbmi->biWidth; 193 | else // it is an OS/2 DIB, so return its width 194 | return (DWORD)lpbmc->bcWidth; 195 | } 196 | 197 | 198 | /************************************************************************* 199 | * 200 | * DIBHeight() 201 | * 202 | * Parameter: 203 | * 204 | * LPSTR lpDIB - pointer to packed-DIB memory block 205 | * 206 | * Return Value: 207 | * 208 | * DWORD - height of the DIB 209 | * 210 | * Description: 211 | * 212 | * This function gets the height of the DIB from the BITMAPINFOHEADER 213 | * height field if it is a Windows 3.0-style DIB or from the BITMAPCOREHEADER 214 | * height field if it is an OS/2-style DIB. 215 | * 216 | ************************************************************************/ 217 | 218 | DWORD DIBHeight(LPSTR lpDIB) 219 | { 220 | LPBITMAPINFOHEADER lpbmi; // pointer to a Win 3.0-style DIB 221 | LPBITMAPCOREHEADER lpbmc; // pointer to an OS/2-style DIB 222 | 223 | // point to the header (whether OS/2 or Win 3.0 224 | 225 | lpbmi = (LPBITMAPINFOHEADER)lpDIB; 226 | lpbmc = (LPBITMAPCOREHEADER)lpDIB; 227 | 228 | // return the DIB height if it is a Win 3.0 DIB 229 | if (lpbmi->biSize == sizeof(BITMAPINFOHEADER)) 230 | return lpbmi->biHeight; 231 | else // it is an OS/2 DIB, so return its height 232 | return (DWORD)lpbmc->bcHeight; 233 | } 234 | 235 | 236 | /************************************************************************* 237 | * 238 | * PaletteSize() 239 | * 240 | * Parameter: 241 | * 242 | * LPSTR lpDIB - pointer to packed-DIB memory block 243 | * 244 | * Return Value: 245 | * 246 | * WORD - size of the color palette of the DIB 247 | * 248 | * Description: 249 | * 250 | * This function gets the size required to store the DIB's palette by 251 | * multiplying the number of colors by the size of an RGBQUAD (for a 252 | * Windows 3.0-style DIB) or by the size of an RGBTRIPLE (for an OS/2- 253 | * style DIB). 254 | * 255 | ************************************************************************/ 256 | 257 | WORD PaletteSize(LPSTR lpDIB) 258 | { 259 | // calculate the size required by the palette 260 | if (IS_WIN30_DIB(lpDIB)) 261 | return (DIBNumColors(lpDIB) * sizeof(RGBQUAD)); 262 | else 263 | return (DIBNumColors(lpDIB) * sizeof(RGBTRIPLE)); 264 | } 265 | 266 | 267 | /************************************************************************* 268 | * 269 | * DIBNumColors() 270 | * 271 | * Parameter: 272 | * 273 | * LPSTR lpDIB - pointer to packed-DIB memory block 274 | * 275 | * Return Value: 276 | * 277 | * WORD - number of colors in the color table 278 | * 279 | * Description: 280 | * 281 | * This function calculates the number of colors in the DIB's color table 282 | * by finding the bits per pixel for the DIB (whether Win3.0 or OS/2-style 283 | * DIB). If bits per pixel is 1: colors=2, if 4: colors=16, if 8: colors=256, 284 | * if 24, no colors in color table. 285 | * 286 | ************************************************************************/ 287 | 288 | WORD DIBNumColors(LPSTR lpDIB) 289 | { 290 | WORD wBitCount; // DIB bit count 291 | 292 | // If this is a Windows-style DIB, the number of colors in the 293 | // color table can be less than the number of bits per pixel 294 | // allows for (i.e. lpbi->biClrUsed can be set to some value). 295 | // If this is the case, return the appropriate value. 296 | 297 | 298 | if (IS_WIN30_DIB(lpDIB)) 299 | { 300 | DWORD dwClrUsed; 301 | 302 | dwClrUsed = ((LPBITMAPINFOHEADER)lpDIB)->biClrUsed; 303 | if (dwClrUsed) 304 | 305 | return (WORD)dwClrUsed; 306 | } 307 | 308 | // Calculate the number of colors in the color table based on 309 | // the number of bits per pixel for the DIB. 310 | 311 | if (IS_WIN30_DIB(lpDIB)) 312 | wBitCount = ((LPBITMAPINFOHEADER)lpDIB)->biBitCount; 313 | else 314 | wBitCount = ((LPBITMAPCOREHEADER)lpDIB)->bcBitCount; 315 | 316 | // return number of colors based on bits per pixel 317 | 318 | switch (wBitCount) 319 | { 320 | case 1: 321 | return 2; 322 | 323 | case 4: 324 | return 16; 325 | 326 | case 8: 327 | return 256; 328 | 329 | default: 330 | return 0; 331 | } 332 | } 333 | 334 | 335 | /************************************************************************* 336 | * 337 | * CreateDIBPalette() 338 | * 339 | * Parameter: 340 | * 341 | * HDIB hDIB - specifies the DIB 342 | * 343 | * Return Value: 344 | * 345 | * HPALETTE - specifies the palette 346 | * 347 | * Description: 348 | * 349 | * This function creates a palette from a DIB by allocating memory for the 350 | * logical palette, reading and storing the colors from the DIB's color table 351 | * into the logical palette, creating a palette from this logical palette, 352 | * and then returning the palette's handle. This allows the DIB to be 353 | * displayed using the best possible colors (important for DIBs with 256 or 354 | * more colors). 355 | * 356 | ************************************************************************/ 357 | 358 | HPALETTE CreateDIBPalette(HDIB hDIB) 359 | { 360 | LPLOGPALETTE lpPal; // pointer to a logical palette 361 | HANDLE hLogPal = NULL; // handle to a logical palette 362 | HPALETTE hPal = NULL; // handle to a palette 363 | int i, wNumColors; // loop index, number of colors in color table 364 | LPSTR lpbi; // pointer to packed-DIB 365 | LPBITMAPINFO lpbmi; // pointer to BITMAPINFO structure (Win3.0) 366 | LPBITMAPCOREINFO lpbmc; // pointer to BITMAPCOREINFO structure (OS/2) 367 | BOOL bWinStyleDIB; // Win3.0 DIB? 368 | 369 | // if handle to DIB is invalid, return NULL 370 | 371 | if (!hDIB) 372 | return NULL; 373 | 374 | // lock DIB memory block and get a pointer to it 375 | 376 | lpbi = (LPSTR)GlobalLock(hDIB); 377 | 378 | // get pointer to BITMAPINFO (Win 3.0) 379 | 380 | lpbmi = (LPBITMAPINFO)lpbi; 381 | 382 | // get pointer to BITMAPCOREINFO (OS/2 1.x) 383 | 384 | lpbmc = (LPBITMAPCOREINFO)lpbi; 385 | 386 | // get the number of colors in the DIB 387 | 388 | wNumColors = DIBNumColors(lpbi); 389 | 390 | // is this a Win 3.0 DIB? 391 | 392 | bWinStyleDIB = IS_WIN30_DIB(lpbi); 393 | if (wNumColors) 394 | { 395 | // allocate memory block for logical palette 396 | 397 | hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + 398 | sizeof(PALETTEENTRY) * wNumColors); 399 | 400 | // if not enough memory, clean up and return NULL 401 | 402 | if (!hLogPal) 403 | { 404 | GlobalUnlock(hDIB); 405 | return NULL; 406 | } 407 | 408 | // lock memory block and get pointer to it 409 | 410 | lpPal = (LPLOGPALETTE)GlobalLock(hLogPal); 411 | 412 | // set version and number of palette entries 413 | 414 | lpPal->palVersion = PALVERSION; 415 | lpPal->palNumEntries = wNumColors; 416 | 417 | // store RGB triples (if Win 3.0 DIB) or RGB quads (if OS/2 DIB) 418 | // into palette 419 | 420 | for (i = 0; i < wNumColors; i++) 421 | { 422 | if (bWinStyleDIB) 423 | { 424 | lpPal->palPalEntry[i].peRed = lpbmi->bmiColors[i].rgbRed; 425 | lpPal->palPalEntry[i].peGreen = lpbmi->bmiColors[i].rgbGreen; 426 | lpPal->palPalEntry[i].peBlue = lpbmi->bmiColors[i].rgbBlue; 427 | lpPal->palPalEntry[i].peFlags = 0; 428 | } 429 | else 430 | { 431 | lpPal->palPalEntry[i].peRed = lpbmc->bmciColors[i].rgbtRed; 432 | lpPal->palPalEntry[i].peGreen = lpbmc->bmciColors[i].rgbtGreen; 433 | lpPal->palPalEntry[i].peBlue = lpbmc->bmciColors[i].rgbtBlue; 434 | lpPal->palPalEntry[i].peFlags = 0; 435 | } 436 | } 437 | 438 | // create the palette and get handle to it 439 | 440 | hPal = CreatePalette(lpPal); 441 | 442 | // if error getting handle to palette, clean up and return NULL 443 | 444 | if (!hPal) 445 | { 446 | GlobalUnlock(hLogPal); 447 | GlobalFree(hLogPal); 448 | return NULL; 449 | } 450 | } 451 | 452 | // clean up 453 | 454 | GlobalUnlock(hLogPal); 455 | GlobalFree(hLogPal); 456 | GlobalUnlock(hDIB); 457 | 458 | // return handle to DIB's palette 459 | return hPal; 460 | } 461 | 462 | 463 | /************************************************************************* 464 | * 465 | * DIBToBitmap() 466 | * 467 | * Parameters: 468 | * 469 | * HDIB hDIB - specifies the DIB to convert 470 | * 471 | * HPALETTE hPal - specifies the palette to use with the bitmap 472 | * 473 | * Return Value: 474 | * 475 | * HBITMAP - identifies the device-dependent bitmap 476 | * 477 | * Description: 478 | * 479 | * This function creates a bitmap from a DIB using the specified palette. 480 | * If no palette is specified, default is used. 481 | * 482 | * NOTE: 483 | * 484 | * The bitmap returned from this function is always a bitmap compatible 485 | * with the screen (e.g. same bits/pixel and color planes) rather than 486 | * a bitmap with the same attributes as the DIB. This behavior is by 487 | * design, and occurs because this function calls CreateDIBitmap to 488 | * do its work, and CreateDIBitmap always creates a bitmap compatible 489 | * with the hDC parameter passed in (because it in turn calls 490 | * CreateCompatibleBitmap). 491 | * 492 | * So for instance, if your DIB is a monochrome DIB and you call this 493 | * function, you will not get back a monochrome HBITMAP -- you will 494 | * get an HBITMAP compatible with the screen DC, but with only 2 495 | * colors used in the bitmap. 496 | * 497 | * If your application requires a monochrome HBITMAP returned for a 498 | * monochrome DIB, use the function SetDIBits(). 499 | * 500 | * Also, the DIBpassed in to the function is not destroyed on exit. This 501 | * must be done later, once it is no longer needed. 502 | * 503 | ************************************************************************/ 504 | 505 | HBITMAP DIBToBitmap(HDIB hDIB, HPALETTE hPal) 506 | { 507 | LPSTR lpDIBHdr, lpDIBBits; // pointer to DIB header, pointer to DIB bits 508 | HBITMAP hBitmap; // handle to device-dependent bitmap 509 | HDC hDC = NULL; // handle to DC 510 | HPALETTE hOldPal = NULL; // handle to a palette 511 | 512 | // if invalid handle, return NULL 513 | 514 | if (!hDIB) 515 | return NULL; 516 | 517 | // lock memory block and get a pointer to it 518 | 519 | lpDIBHdr = (LPSTR)GlobalLock(hDIB); 520 | 521 | // get a pointer to the DIB bits 522 | 523 | lpDIBBits = FindDIBBits(lpDIBHdr); 524 | 525 | // get a DC 526 | 527 | hDC = GetDC(NULL); 528 | if (!hDC) 529 | { 530 | // clean up and return NULL 531 | 532 | GlobalUnlock(hDIB); 533 | return NULL; 534 | } 535 | 536 | // select and realize palette 537 | 538 | if (hPal) 539 | hOldPal = SelectPalette(hDC, hPal, FALSE); 540 | 541 | RealizePalette(hDC); 542 | 543 | // create bitmap from DIB info. and bits 544 | hBitmap = CreateDIBitmap(hDC, (LPBITMAPINFOHEADER)lpDIBHdr, CBM_INIT, 545 | lpDIBBits, (LPBITMAPINFO)lpDIBHdr, DIB_RGB_COLORS); 546 | 547 | // restore previous palette 548 | if (hOldPal) 549 | SelectPalette(hDC, hOldPal, FALSE); 550 | 551 | // clean up 552 | ReleaseDC(NULL, hDC); 553 | GlobalUnlock(hDIB); 554 | 555 | // return handle to the bitmap 556 | return hBitmap; 557 | } 558 | 559 | 560 | /************************************************************************* 561 | * 562 | * BitmapToDIB() 563 | * 564 | * Parameters: 565 | * 566 | * HBITMAP hBitmap - specifies the bitmap to convert 567 | * 568 | * HPALETTE hPal - specifies the palette to use with the bitmap 569 | * 570 | * Return Value: 571 | * 572 | * HDIB - identifies the device-dependent bitmap 573 | * 574 | * Description: 575 | * 576 | * This function creates a DIB from a bitmap using the specified palette. 577 | * 578 | ************************************************************************/ 579 | 580 | HDIB BitmapToDIB(HBITMAP hBitmap, HPALETTE hPal) 581 | { 582 | BITMAP bm; // bitmap structure 583 | BITMAPINFOHEADER bi; // bitmap header 584 | LPBITMAPINFOHEADER lpbi; // pointer to BITMAPINFOHEADER 585 | DWORD dwLen; // size of memory block 586 | HANDLE hDIB, h; // handle to DIB, temp handle 587 | HDC hDC; // handle to DC 588 | WORD biBits; // bits per pixel 589 | 590 | // check if bitmap handle is valid 591 | 592 | if (!hBitmap) 593 | return NULL; 594 | 595 | // fill in BITMAP structure, return NULL if it didn't work 596 | 597 | if (!GetObject(hBitmap, sizeof(bm), (LPSTR)&bm)) 598 | return NULL; 599 | 600 | // if no palette is specified, use default palette 601 | 602 | if (hPal == NULL) 603 | hPal = (HPALETTE)GetStockObject(DEFAULT_PALETTE); 604 | 605 | // calculate bits per pixel 606 | 607 | biBits = bm.bmPlanes * bm.bmBitsPixel; 608 | 609 | // make sure bits per pixel is valid 610 | 611 | if (biBits <= 1) 612 | biBits = 1; 613 | else if (biBits <= 4) 614 | biBits = 4; 615 | else if (biBits <= 8) 616 | biBits = 8; 617 | else // if greater than 8-bit, force to 24-bit 618 | biBits = 24; 619 | 620 | // initialize BITMAPINFOHEADER 621 | 622 | bi.biSize = sizeof(BITMAPINFOHEADER); 623 | bi.biWidth = bm.bmWidth; 624 | bi.biHeight = bm.bmHeight; 625 | bi.biPlanes = 1; 626 | bi.biBitCount = biBits; 627 | bi.biCompression = BI_RGB; 628 | bi.biSizeImage = 0; 629 | bi.biXPelsPerMeter = 0; 630 | bi.biYPelsPerMeter = 0; 631 | bi.biClrUsed = 0; 632 | bi.biClrImportant = 0; 633 | 634 | // calculate size of memory block required to store BITMAPINFO 635 | 636 | dwLen = bi.biSize + PaletteSize((LPSTR)&bi); 637 | 638 | // get a DC 639 | 640 | hDC = GetDC(NULL); 641 | 642 | // select and realize our palette 643 | 644 | hPal = SelectPalette(hDC, hPal, FALSE); 645 | RealizePalette(hDC); 646 | 647 | // alloc memory block to store our bitmap 648 | 649 | hDIB = GlobalAlloc(GHND, dwLen); 650 | 651 | // if we couldn't get memory block 652 | 653 | if (!hDIB) 654 | { 655 | // clean up and return NULL 656 | 657 | SelectPalette(hDC, hPal, TRUE); 658 | RealizePalette(hDC); 659 | ReleaseDC(NULL, hDC); 660 | return NULL; 661 | } 662 | 663 | // lock memory and get pointer to it 664 | 665 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 666 | 667 | /// use our bitmap info. to fill BITMAPINFOHEADER 668 | 669 | *lpbi = bi; 670 | 671 | // call GetDIBits with a NULL lpBits param, so it will calculate the 672 | // biSizeImage field for us 673 | 674 | GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 675 | DIB_RGB_COLORS); 676 | 677 | // get the info. returned by GetDIBits and unlock memory block 678 | 679 | bi = *lpbi; 680 | GlobalUnlock(hDIB); 681 | 682 | // if the driver did not fill in the biSizeImage field, make one up 683 | if (bi.biSizeImage == 0) 684 | bi.biSizeImage = WIDTHBYTES((DWORD)bm.bmWidth * biBits) * bm.bmHeight; 685 | 686 | // realloc the buffer big enough to hold all the bits 687 | 688 | dwLen = bi.biSize + PaletteSize((LPSTR)&bi) + bi.biSizeImage; 689 | 690 | if (h = GlobalReAlloc(hDIB, dwLen, 0)) 691 | hDIB = h; 692 | else 693 | { 694 | // clean up and return NULL 695 | 696 | GlobalFree(hDIB); 697 | hDIB = NULL; 698 | SelectPalette(hDC, hPal, TRUE); 699 | RealizePalette(hDC); 700 | ReleaseDC(NULL, hDC); 701 | return NULL; 702 | } 703 | 704 | // lock memory block and get pointer to it */ 705 | 706 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 707 | 708 | // call GetDIBits with a NON-NULL lpBits param, and actually get the 709 | // bits this time 710 | 711 | if (GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, (LPSTR)lpbi + 712 | (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 713 | DIB_RGB_COLORS) == 0) 714 | { 715 | // clean up and return NULL 716 | 717 | GlobalUnlock(hDIB); 718 | hDIB = NULL; 719 | SelectPalette(hDC, hPal, TRUE); 720 | RealizePalette(hDC); 721 | ReleaseDC(NULL, hDC); 722 | return NULL; 723 | } 724 | 725 | bi = *lpbi; 726 | 727 | // clean up 728 | GlobalUnlock(hDIB); 729 | SelectPalette(hDC, hPal, TRUE); 730 | RealizePalette(hDC); 731 | ReleaseDC(NULL, hDC); 732 | 733 | // return handle to the DIB 734 | return hDIB; 735 | } 736 | 737 | 738 | /************************************************************************* 739 | * 740 | * PalEntriesOnDevice() 741 | * 742 | * Parameter: 743 | * 744 | * HDC hDC - device context 745 | * 746 | * Return Value: 747 | * 748 | * int - number of palette entries on device 749 | * 750 | * Description: 751 | * 752 | * This function gets the number of palette entries on the specified device 753 | * 754 | ************************************************************************/ 755 | 756 | int PalEntriesOnDevice(HDC hDC) 757 | { 758 | int nColors; // number of colors 759 | 760 | // Find out the number of colors on this device. 761 | 762 | nColors = (1 << (GetDeviceCaps(hDC, BITSPIXEL) * GetDeviceCaps(hDC, PLANES))); 763 | 764 | assert(nColors); 765 | return nColors; 766 | } 767 | 768 | 769 | /************************************************************************* 770 | * 771 | * GetSystemPalette() 772 | * 773 | * Parameters: 774 | * 775 | * None 776 | * 777 | * Return Value: 778 | * 779 | * HPALETTE - handle to a copy of the current system palette 780 | * 781 | * Description: 782 | * 783 | * This function returns a handle to a palette which represents the system 784 | * palette. The system RGB values are copied into our logical palette using 785 | * the GetSystemPaletteEntries function. 786 | * 787 | ************************************************************************/ 788 | 789 | HPALETTE GetSystemPalette(void) 790 | { 791 | HDC hDC; // handle to a DC 792 | static HPALETTE hPal = NULL; // handle to a palette 793 | HANDLE hLogPal; // handle to a logical palette 794 | LPLOGPALETTE lpLogPal; // pointer to a logical palette 795 | int nColors; // number of colors 796 | 797 | // Find out how many palette entries we want. 798 | 799 | hDC = GetDC(NULL); 800 | 801 | if (!hDC) 802 | return NULL; 803 | 804 | nColors = PalEntriesOnDevice(hDC); // Number of palette entries 805 | 806 | // Allocate room for the palette and lock it. 807 | 808 | hLogPal = GlobalAlloc(GHND, sizeof(LOGPALETTE) + nColors * 809 | sizeof(PALETTEENTRY)); 810 | 811 | // if we didn't get a logical palette, return NULL 812 | 813 | if (!hLogPal) 814 | return NULL; 815 | 816 | // get a pointer to the logical palette 817 | 818 | lpLogPal = (LPLOGPALETTE)GlobalLock(hLogPal); 819 | 820 | // set some important fields 821 | 822 | lpLogPal->palVersion = PALVERSION; 823 | lpLogPal->palNumEntries = nColors; 824 | 825 | // Copy the current system palette into our logical palette 826 | 827 | GetSystemPaletteEntries(hDC, 0, nColors, 828 | (LPPALETTEENTRY)(lpLogPal->palPalEntry)); 829 | 830 | // Go ahead and create the palette. Once it's created, 831 | // we no longer need the LOGPALETTE, so free it. 832 | 833 | hPal = CreatePalette(lpLogPal); 834 | 835 | // clean up 836 | 837 | GlobalUnlock(hLogPal); 838 | GlobalFree(hLogPal); 839 | ReleaseDC(NULL, hDC); 840 | 841 | return hPal; 842 | } 843 | 844 | 845 | /************************************************************************* 846 | * 847 | * AllocRoomForDIB() 848 | * 849 | * Parameters: 850 | * 851 | * BITMAPINFOHEADER - bitmap info header structure 852 | * 853 | * HBITMAP - handle to the bitmap 854 | * 855 | * Return Value: 856 | * 857 | * HDIB - handle to memory block 858 | * 859 | * Description: 860 | * 861 | * This routine takes a BITMAPINOHEADER, and returns a handle to global 862 | * memory which can contain a DIB with that header. It also initializes 863 | * the header portion of the global memory. GetDIBits() is used to determine 864 | * the amount of room for the DIB's bits. The total amount of memory 865 | * needed = sizeof(BITMAPINFOHEADER) + size of color table + size of bits. 866 | * 867 | ************************************************************************/ 868 | 869 | HANDLE AllocRoomForDIB(BITMAPINFOHEADER bi, HBITMAP hBitmap) 870 | { 871 | DWORD dwLen; 872 | HANDLE hDIB; 873 | HDC hDC; 874 | LPBITMAPINFOHEADER lpbi; 875 | HANDLE hTemp; 876 | 877 | // Figure out the size needed to hold the BITMAPINFO structure 878 | // (which includes the BITMAPINFOHEADER and the color table). 879 | 880 | dwLen = bi.biSize + PaletteSize((LPSTR)&bi); 881 | hDIB = GlobalAlloc(GHND, dwLen); 882 | 883 | // Check that DIB handle is valid 884 | 885 | if (!hDIB) 886 | return NULL; 887 | 888 | // Set up the BITMAPINFOHEADER in the newly allocated global memory, 889 | // then call GetDIBits() with lpBits = NULL to have it fill in the 890 | // biSizeImage field for us. 891 | 892 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 893 | *lpbi = bi; 894 | 895 | hDC = GetDC(NULL); 896 | 897 | GetDIBits(hDC, hBitmap, 0, (UINT)bi.biHeight, NULL, (LPBITMAPINFO)lpbi, 898 | DIB_RGB_COLORS); 899 | ReleaseDC(NULL, hDC); 900 | 901 | // If the driver did not fill in the biSizeImage field, 902 | // fill it in -- NOTE: this is a bug in the driver! 903 | 904 | if (lpbi->biSizeImage == 0) 905 | lpbi->biSizeImage = WIDTHBYTES((DWORD)lpbi->biWidth * 906 | lpbi->biBitCount) * lpbi->biHeight; 907 | 908 | // Get the size of the memory block we need 909 | 910 | dwLen = lpbi->biSize + PaletteSize((LPSTR)&bi) + lpbi->biSizeImage; 911 | 912 | // Unlock the memory block 913 | 914 | GlobalUnlock(hDIB); 915 | 916 | // ReAlloc the buffer big enough to hold all the bits 917 | 918 | if (hTemp = GlobalReAlloc(hDIB, dwLen, 0)) 919 | return hTemp; 920 | else 921 | { 922 | // Else free memory block and return failure 923 | 924 | GlobalFree(hDIB); 925 | return NULL; 926 | } 927 | } 928 | 929 | 930 | /************************************************************************* 931 | * 932 | * ChangeDIBFormat() 933 | * 934 | * Parameter: 935 | * 936 | * HDIB - handle to packed-DIB in memory 937 | * 938 | * WORD - desired bits per pixel 939 | * 940 | * DWORD - desired compression format 941 | * 942 | * Return Value: 943 | * 944 | * HDIB - handle to the new DIB if successful, else NULL 945 | * 946 | * Description: 947 | * 948 | * This function will convert the bits per pixel and/or the compression 949 | * format of the specified DIB. Note: If the conversion was unsuccessful, 950 | * we return NULL. The original DIB is left alone. Don't use code like the 951 | * following: 952 | * 953 | * hMyDIB = ChangeDIBFormat(hMyDIB, 8, BI_RLE4); 954 | * 955 | * The conversion will fail, but hMyDIB will now be NULL and the original 956 | * DIB will now hang around in memory. We could have returned the old 957 | * DIB, but we wanted to allow the programmer to check whether this 958 | * conversion succeeded or failed. 959 | * 960 | ************************************************************************/ 961 | 962 | HDIB ChangeDIBFormat(HDIB hDIB, WORD wBitCount, DWORD dwCompression) 963 | { 964 | HDC hDC; // Handle to DC 965 | HBITMAP hBitmap; // Handle to bitmap 966 | BITMAP Bitmap; // BITMAP data structure 967 | BITMAPINFOHEADER bi; // Bitmap info header 968 | LPBITMAPINFOHEADER lpbi; // Pointer to bitmap info 969 | HDIB hNewDIB = NULL; // Handle to new DIB 970 | HPALETTE hPal, hOldPal; // Handle to palette, previous pal 971 | WORD DIBBPP, NewBPP; // DIB bits per pixel, new bpp 972 | DWORD DIBComp, NewComp;// DIB compression, new compression 973 | 974 | // Check for a valid DIB handle 975 | 976 | if (!hDIB) 977 | return NULL; 978 | 979 | // Get the old DIB's bits per pixel and compression format 980 | 981 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hDIB); 982 | DIBBPP = ((LPBITMAPINFOHEADER)lpbi)->biBitCount; 983 | DIBComp = ((LPBITMAPINFOHEADER)lpbi)->biCompression; 984 | GlobalUnlock(hDIB); 985 | 986 | // Validate wBitCount and dwCompression 987 | // They must match correctly (i.e., BI_RLE4 and 4 BPP or 988 | // BI_RLE8 and 8BPP, etc.) or we return failure 989 | if (wBitCount == 0) 990 | { 991 | NewBPP = DIBBPP; 992 | if ((dwCompression == BI_RLE4 && NewBPP == 4) || 993 | (dwCompression == BI_RLE8 && NewBPP == 8) || 994 | (dwCompression == BI_RGB)) 995 | NewComp = dwCompression; 996 | else 997 | return NULL; 998 | } 999 | else if (wBitCount == 1 && dwCompression == BI_RGB) 1000 | { 1001 | NewBPP = wBitCount; 1002 | NewComp = BI_RGB; 1003 | } 1004 | else if (wBitCount == 4) 1005 | { 1006 | NewBPP = wBitCount; 1007 | if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1008 | NewComp = dwCompression; 1009 | else 1010 | return NULL; 1011 | } 1012 | else if (wBitCount == 8) 1013 | { 1014 | NewBPP = wBitCount; 1015 | if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1016 | NewComp = dwCompression; 1017 | else 1018 | return NULL; 1019 | } 1020 | else if (wBitCount == 24 && dwCompression == BI_RGB) 1021 | { 1022 | NewBPP = wBitCount; 1023 | NewComp = BI_RGB; 1024 | } 1025 | else 1026 | return NULL; 1027 | 1028 | // Save the old DIB's palette 1029 | 1030 | hPal = CreateDIBPalette(hDIB); 1031 | if (!hPal) 1032 | return NULL; 1033 | 1034 | // Convert old DIB to a bitmap 1035 | 1036 | hBitmap = DIBToBitmap(hDIB, hPal); 1037 | if (!hBitmap) 1038 | { 1039 | DeleteObject(hPal); 1040 | return NULL; 1041 | } 1042 | 1043 | // Get info about the bitmap 1044 | GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1045 | 1046 | // Fill in the BITMAPINFOHEADER appropriately 1047 | 1048 | bi.biSize = sizeof(BITMAPINFOHEADER); 1049 | bi.biWidth = Bitmap.bmWidth; 1050 | bi.biHeight = Bitmap.bmHeight; 1051 | bi.biPlanes = 1; 1052 | bi.biBitCount = NewBPP; 1053 | bi.biCompression = NewComp; 1054 | bi.biSizeImage = 0; 1055 | bi.biXPelsPerMeter = 0; 1056 | bi.biYPelsPerMeter = 0; 1057 | bi.biClrUsed = 0; 1058 | bi.biClrImportant = 0; 1059 | 1060 | // Go allocate room for the new DIB 1061 | 1062 | hNewDIB = AllocRoomForDIB(bi, hBitmap); 1063 | if (!hNewDIB) 1064 | return NULL; 1065 | 1066 | // Get a pointer to the new DIB 1067 | 1068 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1069 | 1070 | // Get a DC and select/realize our palette in it 1071 | 1072 | hDC = GetDC(NULL); 1073 | hOldPal = SelectPalette(hDC, hPal, FALSE); 1074 | RealizePalette(hDC); 1075 | 1076 | // Call GetDIBits and get the new DIB bits 1077 | 1078 | if (!GetDIBits(hDC, hBitmap, 0, (UINT)lpbi->biHeight, 1079 | (LPSTR)lpbi + (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), 1080 | (LPBITMAPINFO)lpbi, DIB_RGB_COLORS)) 1081 | { 1082 | GlobalUnlock(hNewDIB); 1083 | GlobalFree(hNewDIB); 1084 | hNewDIB = NULL; 1085 | } 1086 | 1087 | // Clean up and return 1088 | 1089 | SelectPalette(hDC, hOldPal, TRUE); 1090 | RealizePalette(hDC); 1091 | ReleaseDC(NULL, hDC); 1092 | 1093 | // Unlock the new DIB's memory block 1094 | if (hNewDIB) 1095 | GlobalUnlock(hNewDIB); 1096 | 1097 | DeleteObject(hBitmap); 1098 | DeleteObject(hPal); 1099 | 1100 | return hNewDIB; 1101 | } 1102 | 1103 | 1104 | /************************************************************************* 1105 | * 1106 | * ChangeBitmapFormat() 1107 | * 1108 | * Parameter: 1109 | * 1110 | * HBITMAP - handle to a bitmap 1111 | * 1112 | * WORD - desired bits per pixel 1113 | * 1114 | * DWORD - desired compression format 1115 | * 1116 | * HPALETTE - handle to palette 1117 | * 1118 | * Return Value: 1119 | * 1120 | * HDIB - handle to the new DIB if successful, else NULL 1121 | * 1122 | * Description: 1123 | * 1124 | * This function will convert a bitmap to the specified bits per pixel 1125 | * and compression format. The bitmap and it's palette will remain 1126 | * after calling this function. 1127 | * 1128 | ************************************************************************/ 1129 | 1130 | HDIB ChangeBitmapFormat(HBITMAP hBitmap, WORD wBitCount, DWORD dwCompression, 1131 | HPALETTE hPal) 1132 | { 1133 | HDC hDC = NULL; // Screen DC 1134 | HDIB hNewDIB = NULL; // Handle to new DIB 1135 | BITMAP Bitmap; // BITMAP data structure 1136 | BITMAPINFOHEADER bi; // Bitmap info. header 1137 | LPBITMAPINFOHEADER lpbi; // Pointer to bitmap header 1138 | HPALETTE hOldPal = NULL; // Handle to palette 1139 | WORD NewBPP; // New bits per pixel 1140 | DWORD NewComp; // New compression format 1141 | 1142 | // Check for a valid bitmap handle 1143 | 1144 | if (!hBitmap) 1145 | return NULL; 1146 | 1147 | // Validate wBitCount and dwCompression 1148 | // They must match correctly (i.e., BI_RLE4 and 4 BPP or 1149 | // BI_RLE8 and 8BPP, etc.) or we return failure 1150 | 1151 | if (wBitCount == 0) 1152 | { 1153 | NewComp = dwCompression; 1154 | if (NewComp == BI_RLE4) 1155 | NewBPP = 4; 1156 | else if (NewComp == BI_RLE8) 1157 | NewBPP = 8; 1158 | else // Not enough info */ 1159 | return NULL; 1160 | } 1161 | else if (wBitCount == 1 && dwCompression == BI_RGB) 1162 | { 1163 | NewBPP = wBitCount; 1164 | NewComp = BI_RGB; 1165 | } 1166 | else if (wBitCount == 4) 1167 | { 1168 | NewBPP = wBitCount; 1169 | if (dwCompression == BI_RGB || dwCompression == BI_RLE4) 1170 | NewComp = dwCompression; 1171 | else 1172 | return NULL; 1173 | } 1174 | else if (wBitCount == 8) 1175 | { 1176 | NewBPP = wBitCount; 1177 | if (dwCompression == BI_RGB || dwCompression == BI_RLE8) 1178 | NewComp = dwCompression; 1179 | else 1180 | return NULL; 1181 | } 1182 | else if (wBitCount == 24 && dwCompression == BI_RGB) 1183 | { 1184 | NewBPP = wBitCount; 1185 | NewComp = BI_RGB; 1186 | } 1187 | else 1188 | return NULL; 1189 | 1190 | // Get info about the bitmap 1191 | 1192 | GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&Bitmap); 1193 | 1194 | // Fill in the BITMAPINFOHEADER appropriately 1195 | 1196 | bi.biSize = sizeof(BITMAPINFOHEADER); 1197 | bi.biWidth = Bitmap.bmWidth; 1198 | bi.biHeight = Bitmap.bmHeight; 1199 | bi.biPlanes = 1; 1200 | bi.biBitCount = NewBPP; 1201 | bi.biCompression = NewComp; 1202 | bi.biSizeImage = 0; 1203 | bi.biXPelsPerMeter = 0; 1204 | bi.biYPelsPerMeter = 0; 1205 | bi.biClrUsed = 0; 1206 | bi.biClrImportant = 0; 1207 | 1208 | // Go allocate room for the new DIB 1209 | 1210 | hNewDIB = AllocRoomForDIB(bi, hBitmap); 1211 | if (!hNewDIB) 1212 | return NULL; 1213 | 1214 | // Get a pointer to the new DIB 1215 | 1216 | lpbi = (LPBITMAPINFOHEADER)GlobalLock(hNewDIB); 1217 | 1218 | // If we have a palette, get a DC and select/realize it 1219 | 1220 | if (hPal) 1221 | { 1222 | hDC = GetDC(NULL); 1223 | hOldPal = SelectPalette(hDC, hPal, FALSE); 1224 | RealizePalette(hDC); 1225 | } 1226 | 1227 | // Call GetDIBits and get the new DIB bits 1228 | 1229 | if (!GetDIBits(hDC, hBitmap, 0, (UINT)lpbi->biHeight, (LPSTR)lpbi + 1230 | (WORD)lpbi->biSize + PaletteSize((LPSTR)lpbi), (LPBITMAPINFO)lpbi, 1231 | DIB_RGB_COLORS)) 1232 | { 1233 | GlobalUnlock(hNewDIB); 1234 | GlobalFree(hNewDIB); 1235 | hNewDIB = NULL; 1236 | } 1237 | 1238 | // Clean up and return 1239 | 1240 | if (hOldPal) 1241 | { 1242 | SelectPalette(hDC, hOldPal, TRUE); 1243 | RealizePalette(hDC); 1244 | ReleaseDC(NULL, hDC); 1245 | } 1246 | 1247 | // Unlock the new DIB's memory block 1248 | 1249 | if (hNewDIB) 1250 | GlobalUnlock(hNewDIB); 1251 | 1252 | return hNewDIB; 1253 | } 1254 | --------------------------------------------------------------------------------