看《Teach Yourself Game Programming with DirectX in 21 Days》真的快半年了,虽然有很长时间都花在项目上(主要是在对接大厂的SDK,那段时间真的快对接疯了),但至少从开始到现在有半年的时间了,真的看的有点累了,换个心情看起了GameEngine相关视频。最近也会开始将从《Teach Yourself Game Programming with DirectX in 21 Days》学到的内容发到博客上的。
************************************************************************************************************************************
在看GameEngine相关视频时候,看到GLFW库可以在控制台程序中创建Window窗口,就去google了相关资料,发现是可以用控制台程序创建窗口的,就测试了下。
Window创建的代码都封装在CSystem这个class中,其实创建Window窗口的代码都不想贴出来的,因为没啥东西,现在已经都不需要看书,完全能默写下来了╮( ̄▽ ̄)╭:
CSystem.h:
#pragma once
#include <Windows.h>
#include <iostream>
namespace Engine
{
class CSystem
{
public:
CSystem();
~CSystem();
bool Initialize(const char* strName, int iWidth, int iHeight, bool bFullScreen);
void Shutdown();
void Run();
virtual LRESULT CALLBACK MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
private:
std::string m_strAppName;
int m_iWidth, m_iHeight;
bool m_bFullScreen;
HINSTANCE m_appInstance;
HWND m_hwnd;
};
static LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
static CSystem* m_pGlobalSystem = nullptr;
// To be defined in CLIENT
CSystem* CreateSystem();
}
CSystem.cpp:
#include "Engine/CSystem.h"
namespace Engine
{
CSystem::CSystem()
{
m_iWidth = 0;
m_iHeight = 0;
m_bFullScreen = false;
m_appInstance = NULL;
m_hwnd = NULL;
}
CSystem::~CSystem()
{
m_hwnd = NULL;
m_appInstance = NULL;
m_bFullScreen = false;
m_iHeight = 0;
m_iWidth = 0;
}
bool CSystem::Initialize(const char* strName, int iWidth, int iHeight, bool bFullScreen)
{
m_strAppName = strName;
m_iWidth = iWidth;
m_iHeight = iHeight;
m_bFullScreen = bFullScreen;
m_appInstance = GetModuleHandle(NULL);
m_pGlobalSystem = this;
WNDCLASSEX wndClass;
memset(&wndClass, 0, sizeof(wndClass));
wndClass.cbClsExtra = 0;
wndClass.cbSize = sizeof(wndClass);
wndClass.cbWndExtra = 0;
wndClass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
wndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wndClass.hIconSm = wndClass.hIcon;
wndClass.hInstance = m_appInstance;
wndClass.lpfnWndProc = WndProc;
wndClass.lpszClassName = m_strAppName.c_str();
wndClass.lpszMenuName = nullptr;
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
if (!RegisterClassEx(&wndClass))
{
MessageBox(NULL, TEXT("RegisterClassEx function failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
int screenWidth, screenHeight;
int posX, posY;
screenWidth = GetSystemMetrics(SM_CXSCREEN);
screenHeight = GetSystemMetrics(SM_CYSCREEN);
if (m_bFullScreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPanningWidth = screenWidth;
dmScreenSettings.dmPanningWidth = screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN);
m_iWidth = screenWidth;
m_iHeight = screenHeight;
posX = posY = 0;
}
else
{
posX = (screenWidth - m_iWidth) / 2;
posY = (screenHeight - m_iHeight) / 2;
}
m_hwnd = CreateWindowEx(
WS_EX_APPWINDOW,
wndClass.lpszClassName,
wndClass.lpszClassName,
WS_OVERLAPPEDWINDOW,
posX, posY,
m_iWidth, m_iHeight,
NULL,
NULL,
m_appInstance,
nullptr);
if (!m_hwnd)
{
MessageBox(NULL, TEXT("CreateWindowEx function failed"), TEXT("Error"), MB_OK | MB_ICONERROR);
return false;
}
ShowWindow(m_hwnd, SW_SHOW);
UpdateWindow(m_hwnd);
SetFocus(m_hwnd);
ShowCursor(true);
return true;
}
void CSystem::Shutdown()
{
if (m_bFullScreen)
ChangeDisplaySettings(nullptr, 0);
DestroyWindow(m_hwnd);
m_hwnd = NULL;
UnregisterClass(m_strAppName.c_str(), m_appInstance);
m_appInstance = NULL;
m_pGlobalSystem = nullptr;
}
void CSystem::Run()
{
MSG msg;
memset(&msg, 0, sizeof(msg));
bool done = false;
while (!done)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if (WM_QUIT == msg.message)
done = true;
else
{
}
}
}
LRESULT CALLBACK CSystem::MessageHandler(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_CLOSE:
PostQuitMessage(0);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
}
return m_pGlobalSystem->MessageHandler(hwnd, msg, wParam, lParam);
}
}
调用接口在EntryPoint.h:
#pragma once
#include "CSystem.h"
#ifdef ENGINE_PLATFORM_WINDOWS
extern Engine::CSystem* Engine::CreateSystem();
int main(int argc, char** argv)
{
std::cout << "Engine: main begin" << std::endl;
Engine::CSystem* pSystem = Engine::CreateSystem();
pSystem->Run();
pSystem->Shutdown();
delete pSystem;
pSystem = nullptr;
std::cout << "Engine: main end" << std::endl;
return 0;
}
#endif
Engine.h:
#pragma once
// ---Entry Point----------------------
#include "Engine/EntryPoint.h"
// ------------------------------------
如果是application程序的话,就可以直接运行了,但是在看GameEngine视频的时候学到个骚操作:把main函数封装到dll中。但可惜的是动态库不支持STL,一直报这个warning c4251:needs to have dll interface to be used by clients of class,虽然能解决,但是很麻烦,只好改成静态库。
新建一个名称为Test的Project,添加头文件目录和库文件目录:
为了配置方便,主要是多台电脑路径有可能不一样, 不想每次都去修改就将这些都配置到环境变量中去了,包括boost,DirectX9,JsonCpp等库都是这么玩的,方便管理。
添加一个cpp文件,取名为Main.cpp:
#ifdef _DEBUG
#pragma comment(lib, "Debug/Engine.lib")
#else
#pragma comment(lib, "Release/Engine.lib")
#endif
#ifndef ENGINE_PLATFORM_WINDOWS
#define ENGINE_PLATFORM_WINDOWS
#endif
#include <Engine.h>
Engine::CSystem* Engine::CreateSystem()
{
std::cout << "Test Project: CreateSystem begin" << std::endl;
Engine::CSystem* pSystem = new Engine::CSystem();
pSystem->Initialize("Test Project", 600, 480, false);
std::cout << "Test Project: CreateSystem end" << std::endl;
return pSystem;
}
#ifndef ENGINE_PLATFORM_WINDOWS
int main()
{
std::cout << "Test Project: Hello, world" << std::endl;
return 0;
}
#endif
Engine::CSystem* Engine::CreateSystem()方法只是为了可以修改一些参数添加的。其实Main.cpp中什么都不写,只写到#include <Engine.h>都是可以运行的,可以测试下。
可以将#define ENGINE_PLATFORM_WINDOWS这行代码注释掉,就会看到比较好玩的东西:注释掉后调用的是Main.cpp中的main函数,只有一个控制台。取消注释后就是调用静态库中的main函数,显示一个控制台和一个窗口:
哎,差点漏了一个比较重要的东西:GameEngine视频地址,油管上的,有2个系列,我都刚开始看,最新的感觉比较难,好像还在更新中。最重要的是OpenGL的,OpenGL的,OpenGL的,重要的事情要说3遍,虽然没学过OpenGL,应该也有参考价值。