Previous section: https://blog.csdn.net/z736248591/article/details/122658701
Build engine framework
review
In the previous chapter, we created an empty window. In this chapter, we built an engine framework to encapsulate window display and rendering.
Frame introduction
First, let's introduce the four most important global classes:
- Director: responsible for controlling the whole game.
- Graphics: responsible for the rendering part of the game.
- Input: responsible for processing all user inputs.
- Audio: responsible for managing all audio operations globally.
This section mainly introduces the rendering part of Graphics.
establish
Create the header file and source file of the Graphics class.
statement
In graphics The header file of Direct2D is introduced into H.
#include <windows.h> #include <d2d1_3.h> #include <wincodec.h>
d2d1_3 is the header file of direct2d version 1.3 on Windows. You can view the details MSDN Updated content on.
Import STL header file.
#include <memory> #include <string> #include <iostream>
Link Direct2D library files.
#pragma comment(lib, "d2d1.lib")
Declare class member properties.
class Graphics { public: static void Init(int width, int height,const std::wstring &title = L""); static void Render(std::shared_ptr<Scene> scene); static void Dispose(); private: inline static HWND hwnd = NULL; inline static ID2D1Factory* d2dFactory = NULL; inline static ID2D1HwndRenderTarget* renderTarget = NULL; static void InitWindows(int width, int height,const std::wstring& title = L""); static void InitD2D(); };
initialization
The rendering needs to be initialized. The main task is to create a window and initialize Direct2D.
void Graphics::Init(int width, int height, const std::wstring& title) { InitWindows(width, height, title); InitD2D(); }
Window creation is the content of the previous section, which will not be introduced one by one here.
LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); void Graphics::InitWindows(int width, int height, const std::wstring& title) { HINSTANCE hInstance; hInstance = GetModuleHandle(NULL); WNDCLASS wndClass{}; // Set application icon wndClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION); wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW; wndClass.lpfnWndProc = WindowProc; // Set class name wndClass.lpszClassName = L"SGE"; wndClass.hInstance = hInstance; // Specify a unique style wndClass.style = CS_OWNDC; // register RegisterClass(&wndClass); HWND hwnd = CreateWindow( L"SGE", // Class name L"The Seed Game Engine", // Window name WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, 38, 20, width, height, NULL, NULL, hInstance, NULL); if (FAILED(hwnd)) { std::wcout << L"Error creating window!" << std::endl; throw; } Graphics::hwnd = hwnd; // Resize window RECT rc; GetClientRect(hwnd, &rc); MoveWindow(hwnd, 38, 20, width + width - rc.right, height + height - rc.bottom, true); }
Initialize Direct2D.
void Graphics::InitD2D() { HRESULT hr;
Open the debugging visual layer in Debug mode.
D2D1_FACTORY_OPTIONS options{}; #if defined(_DEBUG) // Start the Debug visualization layer options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; #endif
Initialize D2D1Factory class, which will be used to create D2D resource objects in future operations.
hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory); if (FAILED(hr)) { std::wcout << L"establish D2D The factory failed." << std::endl; throw; }
Create a paint render area.
RECT rc; GetClientRect(hwnd, &rc); hr = d2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(),D2D1::HwndRenderTargetProperties(hwnd,D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)),&renderTarget); if (FAILED(hr)) { std::wcout << L"Failed to create render area!" << std::endl; throw; }
Render
The Render function is responsible for rendering the content. The scene parameter is the scene class object, which organizes the content. See the next section for the specific implementation.
void Graphics::Render(std::shared_ptr<Scene> scene) {
Ready to start drawing
renderTarget->BeginDraw();
Only BeginDraw can be called to start drawing.
Use a black background color to empty the drawing area
static D2D1::ColorF blackgroundColor = D2D1::ColorF::Black; renderTarget->Clear(blackgroundColor);
Draw content
scene->Render();
End drawing
HRESULT hr = renderTarget->EndDraw(); if (FAILED(hr)) { std::wcout << L"Drawing error!" << std::endl; throw; }
Destroy
When the game ends running, you need to destroy the previously applied resources.
Here is a macro to safely release resources.
#define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;}
Destroy all requested resources.
void Graphics::Dispose() { SAFE_RELEASE(renderTarget); SAFE_RELEASE(d2dFactory); }
Complete code
Graphics.h
#pragma once #include <windows.h> #include <d2d1_3.h> #include <wincodec.h> #include <memory> #include <string> #include <iostream> #include "Scene.h" #pragma comment(lib, "d2d1.lib") namespace sge { class Graphics { public: static void Init(int width, int height,const std::wstring &title = L""); static void Render(std::shared_ptr<Scene> scene); static void Dispose(); private: inline static HWND hwnd = NULL; inline static ID2D1Factory* d2dFactory = NULL; inline static ID2D1HwndRenderTarget* renderTarget = NULL; static void InitWindows(int width, int height,const std::wstring& title = L""); static void InitD2D(); }; }
Graphics.cpp
#include "Graphics.h" LRESULT CALLBACK WindowProc( HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam ); #define SAFE_RELEASE(P) if(P){P->Release() ; P = NULL ;} namespace sge { void Graphics::Init(int width, int height, const std::wstring& title) { InitWindows(width, height, title); InitD2D(); } void Graphics::Render(std::shared_ptr<Scene> scene) { renderTarget->BeginDraw(); // Empty drawing area static D2D1::ColorF blackgroundColor = D2D1::ColorF::Black; renderTarget->Clear(blackgroundColor); scene->Render(); HRESULT hr = renderTarget->EndDraw(); if (FAILED(hr)) { std::wcout << L"Drawing error!" << std::endl; throw; } } void Graphics::Dispose() { SAFE_RELEASE(renderTarget); SAFE_RELEASE(d2dFactory); } void Graphics::InitWindows(int width, int height, const std::wstring& title) { HINSTANCE hInstance; hInstance = GetModuleHandle(NULL); WNDCLASS wndClass{}; // Set application icon wndClass.hIcon = LoadIcon(hInstance, IDI_APPLICATION); wndClass.hbrBackground = (HBRUSH)COLOR_WINDOW; wndClass.lpfnWndProc = WindowProc; // Set class name wndClass.lpszClassName = L"SGE"; wndClass.hInstance = hInstance; // Specify a unique style wndClass.style = CS_OWNDC; // register RegisterClass(&wndClass); HWND hwnd = CreateWindow( L"SGE", // Class name L"The Seed Game Engine", // Window name WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX | WS_VISIBLE, 38, 20, width, height, NULL, NULL, hInstance, NULL); if (FAILED(hwnd)) { std::wcout << L"Error creating window!" << std::endl; throw; } Graphics::hwnd = hwnd; // Resize window RECT rc; GetClientRect(hwnd, &rc); MoveWindow(hwnd, 38, 20, width + width - rc.right, height + height - rc.bottom, true); } void Graphics::InitD2D() { HRESULT hr; D2D1_FACTORY_OPTIONS options{}; #if defined(_DEBUG) // Start the Debug visualization layer options.debugLevel = D2D1_DEBUG_LEVEL_INFORMATION; #endif hr = D2D1CreateFactory(D2D1_FACTORY_TYPE_SINGLE_THREADED, &d2dFactory); if (FAILED(hr)) { std::wcout << L"establish D2D The factory failed." << std::endl; throw; } // Get drawing area RECT rc; GetClientRect(hwnd, &rc); hr = d2dFactory->CreateHwndRenderTarget(D2D1::RenderTargetProperties(), D2D1::HwndRenderTargetProperties( hwnd, D2D1::SizeU(rc.right - rc.left, rc.bottom - rc.top)), &renderTarget); if (FAILED(hr)) { std::wcout << L"Failed to create render area!" << std::endl; throw; } } }
summary
This section mainly introduces the four main classes of the game engine framework and the preparation of the rendering part. The next section continues with the remaining sections that have not been written.