GDI
GDI has some basic functions and graphical definitions. In short, it is a whole composed of some data structures, functions and macros. All kinds of functions cannot escape a concept - device environment DC
4.2 equipment environment
A device environment is a place in the program where you can draw. That is, the "customer area".
In GDI image output, we only need to care about the type of device environment.
To determine the type of device environment, you can create a handle of the corresponding type. (I have to say that the handle of C + + is well designed)
4.2.2 get HDC (device environment handle)
-
Using BeginPaint and EndPaint
The prototypes of these two functions can be found in Microsoft documents:
HDC BeginPaint( [in] HWND hWnd, [out] LPPAINTSTRUCT lpPaint );
BOOL EndPaint( [in] HWND hWnd, [in] const PAINTSTRUCT *lpPaint );
Window handle and an lpPaint
An example:
HDC g_hdc; // Note the g of the Hungarian nomenclature_ Prefixes denote global variables ... case WM_PAINT: g_hdc = BeginPaint(hwnd, &paintStruct); Game_Paint(); EndPaint(hwnd, &paintStruct); ValidateRect(hwnd, NULL); break; ...
-
Directly use GetDC and release DC
HDC g_hdc; g_hdc = GetDC(hWnd); ... ReleaseDC(hWnd, g_hdc);
4.3
4.4
Write a general framework of GDI program, which is just a framework. Copy and modify the main in GameCore in the previous section to get:
//-------------------[procedure description]------------------- // Program name: GDIdemoCore // Learn from light ink orz // Created by Eke, February 2022 // Description: realize the core program required for GDI game development //-------------------------------------------------- //-----------------[header document]--------------------- // Description: header file that the program depends on //-------------------------------------------------- #include <Windows.h> //-----------------[macro definition]-------------------- // Description: defines auxiliary macros //-------------------------------------------------- #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 constexpr auto WINDOW_TITLE = L"Who's going to fly on the slide? I!"; // In the new version, constexpr is safer than define //----------------[global function declaration]---------------- // Description: global function declaration //-------------------------------------------------- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL Game_Init(HWND hwnd); // Resource initialization VOID Game_Paint(HWND hwnd); // Drawing code writing BOOL Game_CleanUp(HWND hwnd); // Resource cleanup //----------------[global variable declaration]---------------- // Description: global variable declaration //-------------------------------------------------- HDC g_hdc = NULL; //----------------[WinMain() function]----------------- // Description: program main entrance //-------------------------------------------------- int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) // Need to_ In_, _In_opt_ Add according to the function prototype, otherwise a warning will be given But why? { // Trilogy // 1. Design (Oh 11 paras!) WNDCLASSEX wndClass = { 0 }; // Define a window class wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = (HICON)::LoadImage(NULL, L"favicon.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH); // Try the brush without RED\BLUE, qwq wndClass.lpszMenuName = NULL; wndClass.lpszClassName = L"ForTheDreamOfGameDevelop"; // 2. Register if (!RegisterClassEx(&wndClass)) return -1; // 3. Create HWND hwnd = CreateWindow(L"ForTheDreamOfGameDevelop", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); // 4. Move, show and update MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); if (!Game_Init(hwnd)) { MessageBox(hwnd, L"Resource initialization failed", L"news", 0); return FALSE; } // 5. msg loop MSG msg = { 0 }; while (msg.message != WM_QUIT); { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } // 6. unregister UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance); return 0; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT paintStruct; switch (message) { case WM_PAINT: g_hdc = BeginPaint(hwnd, &paintStruct); Game_Paint(hwnd); EndPaint(hwnd, &paintStruct); ValidateRect(hwnd, NULL); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) DestroyWindow(hwnd); break; case WM_DESTROY: Game_CleanUp(hwnd); PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } BOOL Game_Init(HWND hwnd) { g_hdc = GetDC(hwnd); Game_Paint(hwnd); ReleaseDC(hwnd, g_hdc); return TRUE; } VOID Game_Paint(HWND hwnd) { } BOOL Game_CleanUp(HWND hwnd) { return TRUE; }
ok. Keep it for standby
4.5 GDI basic geometric drawing
A seemingly unimportant section.
After browsing, I found some similar interface functions. Not in your notes yet.
(there is no difficulty)
Mainly to find out the brush and brush:
Brush is used to draw lines, shapes, outlines and colors;
Brushes are used to create solid shapes and render text
In other words, the brush determines the color and shape, and the brush "Embroiders" the figure drawn by the brush
4.6 random number
Nothing to see, familiar.
After being familiar with the random, write a sample program GDIdemo1, a demonstration program for the use of brushes and brushes.
There is also the playing of background music, but instead of using the PlaySound() function, MCI:
//-------------------[procedure description]------------------- // Program name: GDIdemoCore // Learn from light ink orz // Created by Eke, February 2022 // Description: realize the core program required for GDI game development //-------------------------------------------------- //-----------------[header document]--------------------- // Description: header file that the program depends on //-------------------------------------------------- #include <Windows.h> #include <time.h> #include <mmsystem.h> #pragma comment (lib, "winmm.lib") / / link to winmm library //-----------------[macro definition]-------------------- // Description: defines auxiliary macros //-------------------------------------------------- #define WINDOW_WIDTH 800 #define WINDOW_HEIGHT 600 constexpr auto WINDOW_TITLE = L"Who's going to fly on the slide? I!"; // In the new version, constexpr is safer than define //----------------[global function declaration]---------------- // Description: global function declaration //-------------------------------------------------- LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam); BOOL Game_Init(HWND hwnd); // Resource initialization VOID Game_Paint(HWND hwnd); // Drawing code writing BOOL Game_CleanUp(HWND hwnd); // Resource cleanup //----------------[global variable declaration]---------------- // Description: global variable declaration //-------------------------------------------------- HDC g_hdc = NULL; HPEN g_hPen[7] = { 0 }; HBRUSH g_hBrush[7] = { 0 }; int g_iPenStyle[7] = { PS_SOLID, PS_DASH, PS_DOT, PS_DASHDOT, PS_DASHDOTDOT, PS_NULL, PS_INSIDEFRAME }; int g_iBrushStyle[6] = { HS_VERTICAL, HS_HORIZONTAL, HS_CROSS, HS_DIAGCROSS, HS_FDIAGONAL, HS_BDIAGONAL }; //----------------[WinMain() function]----------------- // Description: program main entrance //-------------------------------------------------- int WINAPI WinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPSTR lpCmdLine, _In_ int nCmdShow) // Need to_ In_, _In_opt_ Add according to the function prototype, otherwise a warning will be given Why? { // Trilogy // 1. Design (Oh 11 paras!) WNDCLASSEX wndClass = { 0 }; // Define a window class wndClass.cbSize = sizeof(WNDCLASSEX); wndClass.style = CS_HREDRAW | CS_VREDRAW; wndClass.lpfnWndProc = WndProc; wndClass.cbClsExtra = 0; wndClass.cbWndExtra = 0; wndClass.hInstance = hInstance; wndClass.hIcon = (HICON)::LoadImage(NULL, L"favicon.ico", IMAGE_ICON, 0, 0, LR_DEFAULTSIZE | LR_LOADFROMFILE); wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); // Try the brush without RED\BLUE, qwq wndClass.lpszMenuName = NULL; wndClass.lpszClassName = L"ForTheDreamOfGameDevelop"; // 2. Register if (!RegisterClassEx(&wndClass)) return -1; // 3. Create HWND hwnd = CreateWindow(L"ForTheDreamOfGameDevelop", WINDOW_TITLE, WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, WINDOW_WIDTH, WINDOW_HEIGHT, NULL, NULL, hInstance, NULL); // 4. Move, show and update MoveWindow(hwnd, 250, 80, WINDOW_WIDTH, WINDOW_HEIGHT, true); ShowWindow(hwnd, nCmdShow); UpdateWindow(hwnd); /* In this book, PlaySound function is used to play background music. Unfortunately, this function is only supported wav format So I use mci to play sound, which is powerful and supports mp3 */ mciSendString(TEXT("open Make a flower fire.mp3 alias BackMusic"), NULL, 0, NULL); // Turn on music mciSendString(L"play BackMusic repeat", NULL, 0, NULL); // Start playing if (!Game_Init(hwnd)) { MessageBox(hwnd, L"Resource initialization failed", L"news", 0); return FALSE; } // 5. msg loop MSG msg = { 0 }; while (msg.message != WM_QUIT); { if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) { TranslateMessage(&msg); DispatchMessage(&msg); } } mciSendString(L"stop BackMusic", NULL, 0, NULL); // stop playing mciSendString(L"close BackMusic", NULL, 0, NULL); // Turn off music // 6. unregister UnregisterClass(L"ForTheDreamOfGameDevelop", wndClass.hInstance); return 0; } LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam) { PAINTSTRUCT paintStruct; switch (message) { case WM_PAINT: g_hdc = BeginPaint(hwnd, &paintStruct); Game_Paint(hwnd); EndPaint(hwnd, &paintStruct); ValidateRect(hwnd, NULL); break; case WM_KEYDOWN: if (wParam == VK_ESCAPE) DestroyWindow(hwnd); break; case WM_DESTROY: Game_CleanUp(hwnd); PostQuitMessage(0); break; default: return DefWindowProc(hwnd, message, wParam, lParam); } return 0; } BOOL Game_Init(HWND hwnd) { g_hdc = GetDC(hwnd); srand((unsigned)time(NULL)); for (int i = 0; i <= 6; ++i) { g_hPen[i] = CreatePen(g_iPenStyle[i], 1, RGB(rand() % 256, rand() % 256, rand() % 256)); if (i == 6) { g_hBrush[i] = CreateSolidBrush(RGB(rand() % 256, rand() % 256, rand() % 256)); } else { g_hBrush[i] = CreateHatchBrush(g_iBrushStyle[i], RGB(rand() % 256, rand() % 256, rand() % 256)); } } Game_Paint(hwnd); ReleaseDC(hwnd, g_hdc); return TRUE; } VOID Game_Paint(HWND hwnd) { int y = 0; for (int i = 0; i <= 6; ++i) { y = (i + 1) * 70; SelectObject(g_hdc, g_hPen[i]); // Choose a good brush Who is the subject chosen here? g_hdc is our DC MoveToEx(g_hdc, 30, y, NULL); // move cursor to (30, y) LineTo(g_hdc, 100, y); // from pos to (100, y) } /* now y = 420 */ int x1 = 120, x2 = 190; // OK, the brush is ready. Now you need to fill the drawn rectangle with the brush for (int i = 0; i <= 6; ++i) { SelectObject(g_hdc, g_hBrush[i]); Rectangle(g_hdc, x1, 70, x2, y); x1 += 90, x2 += 90; } } BOOL Game_CleanUp(HWND hwnd) { for (int i = 0; i <= 6; ++i) { DeleteObject(g_hPen[i]); DeleteObject(g_hBrush[i]); } return TRUE; }
Effect of a run:
(there should be DAOKO and Ba Ye's BGM on the flower fire...)
4.7 text
The most commonly used text output function: TextOut
Learn about your advanced output function: DrawText
This function writes formatted text in the specified rectangle and formats the text
SetTextColor: sets the color value of the text Note that its parameters are only DC handle and text color (God, doesn't that mean a device environment can only have one color)
SetBkMode: sets the text background mode Usually set to TRANSPARENT. If this function is not called, the default text background is white.
CreateFont: font creation function After the font is created, use SelectObject to select it into the device environment.
The second example program: we only modified the GamePaint function
VOID Game_Paint(HWND hwnd) { HFONT hFont = CreateFont(30, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"Microsoft YaHei "); // Create a font SelectObject(g_hdc, hFont); SetBkMode(g_hdc, TRANSPARENT); wchar_t text1[] = L"Fly to ride the storm of the times and become the eye of the typhoon tonight!"; wchar_t text2[] = L"このWindにFlyびToって,Typhoon tonightのorderとなって!"; wchar_t text3[] = L"------King GNU <Flying boat"; SetTextColor(g_hdc, RGB(50, 255, 50)); TextOut(g_hdc, 30, 150, text1, wcslen(text1)); SetTextColor(g_hdc, RGB(50, 50, 255)); TextOut(g_hdc, 30, 200, text2, wcslen(text2)); SetTextColor(g_hdc, RGB(255, 150, 50)); TextOut(g_hdc, 500, 250, text3, wcslen(text3)); DeleteObject(hFont); }
Operation effect:
4.8 bitmap
Bitmap drawing four steps:
- Load bitmap object from file (give bitmap handle)
- Establish a memory DC compatible with window DC
- Select bitmap object
- Map Paste the contents of the memory DC into the window DC
Load bitmap
Use the LoadImage function Its function is to load a picture into a bitmap handle
Establish compatible DC
Use the CreateCompatibleDC function Its function is to create a memory DC compatible with window DC
The memory DC is released after use. Instead of ReleaseDC(), it calls DleteDC(). Please refer to the following link:
Difference between DeleteDC() and ReleaseDC() - vranger - blog Park (cnblogs.com)
Select bitmap object
SelectObject().
Map
You must be familiar with mapping functions, such as BitBlt(), TransparentBlt(), StrentchBlt()
Next, add these four steps to GameInit(), GamePaint(), and you're done. Don't forget to release. Release in game_ In cleanup()
BOOL Game_Init(HWND hwnd) { g_hdc = GetDC(hwnd); // STEP1 g_hBitmap = (HBITMAP)LoadImage(NULL, L"11.bmp", IMAGE_BITMAP, 800, 600, LR_LOADFROMFILE); // STEP2 g_mdc = CreateCompatibleDC(g_hdc); Game_Paint(hwnd); ReleaseDC(hwnd, g_hdc); return TRUE; }
VOID Game_Paint(HWND hwnd) { // STEP3 SelectObject(g_mdc, g_hBitmap); // STEP4 BitBlt(g_hdc, 0, 0, WINDOW_WIDTH, WINDOW_HEIGHT, g_mdc, 0, 0, NOTSRCCOPY); HFONT hFont = CreateFont(30, 0, 0, 0, 0, 0, 0, 0, GB2312_CHARSET, 0, 0, 0, 0, L"Microsoft YaHei "); // Create a font SelectObject(g_hdc, hFont); SetBkMode(g_hdc, TRANSPARENT); wchar_t text1[] = L"Fly to ride the storm of the times and become the eye of the typhoon tonight!"; wchar_t text2[] = L"このWindにFlyびToって,Typhoon tonightのorderとなって!"; wchar_t text3[] = L"------King GNU <Flying boat"; SetTextColor(g_hdc, RGB(50, 255, 50)); TextOut(g_hdc, 30, 150, text1, wcslen(text1)); SetTextColor(g_hdc, RGB(50, 50, 255)); TextOut(g_hdc, 30, 200, text2, wcslen(text2)); SetTextColor(g_hdc, RGB(255, 150, 50)); TextOut(g_hdc, 500, 250, text3, wcslen(text3)); DeleteObject(hFont); }
BOOL Game_CleanUp(HWND hwnd) { DeleteObject(g_hBitmap); DeleteDC(g_mdc); return TRUE; }
The third example program:
summary
It seems that up to now, it is a series of interfaces + functions. I think that's not the case with GDI development?