首先,我已经有一定的D3D11的基础,《Introduction to 3D Game Programming with Direct3D 11》,我已经具备D3D11入门水平了,我决定用D3D11龙书和http://www.rastertek.com/tutindex.html 给的教程一路做下来,主要学习方式打算是这样:看D3D11龙书,但实现是在http://www.rastertek.com/tutindex.html的教程下,这样两个相结合吧.
(1)入门级别的C++基础
(2)最好拥有win32的基础,了解win32窗口的创建和消息的运行机制。
(1)负责图形渲染的类
GraphicsClass.h
#pragma once
#ifndef _GRAPHICS_CLASS_H
#define _GRAPHICS_CLASS_H
#include
//全局变量
const bool FULL_SCREEN = false;
const bool VSYNC_ENABLE = true;
const float SCREEN_DEPTH = 1000.0f; //视截体远裁面
const float SCREEN_NEAR = 0.1f; //视截体近裁面
class GraphicsClass
{
private:
bool Render();
public:
GraphicsClass();
GraphicsClass(const GraphicsClass&);
~GraphicsClass();
public:
bool Initialize(int ScreenWidth, int ScreenHeight, HWND hwnd);
void Shutdown();
bool Frame();
};
#endif // !_GRAPHICS_CLASS_H
GraphicsClass.cpp
#include"GraphicsClass.h"
GraphicsClass::GraphicsClass()
{
}
GraphicsClass::~GraphicsClass()
{
}
GraphicsClass::GraphicsClass(const GraphicsClass&other)
{
}
bool GraphicsClass::Initialize(int ScreenWidth, int ScreenHeight, HWND hwnd)
{
return true;
}
void GraphicsClass::Shutdown()
{
}
bool GraphicsClass::Frame()
{
return true;
}
bool GraphicsClass::Render()
{
return true;
}
(2)负责输入输出的类
InputClass.h
#pragma once
#ifndef _INPUT_CLASS_H
#define _INPUT_CLASS_H
class InputClass
{
private:
//对应的键是否被按下
bool mKey[256];
public:
InputClass();
InputClass(const InputClass&);
~InputClass();
public:
void Initialize();
void KeyDown(unsigned int wParam);
void KeyUp(unsigned int wParam);
bool IsKeyDown(unsigned int wParam);
};
#endif
InputClass.CPP
#include"InputClass.h"
InputClass::InputClass()
{
}
InputClass::InputClass(const InputClass& inputclass)
{
}
InputClass::~InputClass()
{
}
void InputClass::Initialize()
{
for (int i = 0; i < 256; ++i)
{
mKey[i] = false;
}
}
void InputClass::KeyDown(unsigned int input)
{
mKey[input] = true;
}
void InputClass::KeyUp(unsigned int input)
{
mKey[input] = false;
}
bool InputClass::IsKeyDown(unsigned int key)
{
return mKey[key];
}
(3)控制整个渲染系统的类
SystemClass.h
#pragma once
#ifndef _SYSTEM_CLASS_H
#define _SYSTEM_CLASS_H
#define WIN32_LEAN_AND_MEAN //这个宏可以减少Win32头文件的大小
#include"InputClass.h"
#include
#include"GraphicsClass.h"
class SystemClass
{
private:
LPCWSTR mApplicationName; //应用名字
HINSTANCE mHinstance; //应用实例句柄
HWND mHwnd; //应用窗口句柄
private:
InputClass* m_Input; //输入类
GraphicsClass* m_Graphics; //图形类
private:
//帧函数
bool Frame();
//初始化窗口函数
void InitializeWindow(int&, int&);
//关闭窗口函数
void ShutdownWindow();
public:
/*构造函数*/
SystemClass();
/*拷贝构造函数*/
SystemClass(const SystemClass&);
/*析构函数*/
~SystemClass();
/*初始化函数*/
bool Initialize();
/*关闭应用函数*/
void Shutdown();
/*运行函数*/
void Run();
/*消息操作函数,这里这个函数接受的消息很多传递给全局静态函数WndProc处理,这个回调函数有些特殊,请注意*/
LRESULT CALLBACK MessageHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam);
};
#endif
SystemClass.cpp
#include"SystemClass.h"
//全局变量
static SystemClass* D3DAPP = NULL;
//接受SystemClass类对象的全局回调函数
LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
PostQuitMessage(0); //发送WM_QUIT消息到消息队列 接收到WM_QUIT跳出消息循环
return 0;
}
case WM_CLOSE:
{
PostQuitMessage(0);
return 0;
}
//将其它消息传送到D3DAPP的MessageHandler函数
default:
return D3DAPP->MessageHandler(hwnd, message, wParam, lParam);
}
}
SystemClass::SystemClass()
{
m_Graphics = NULL;
m_Input = NULL;
}
SystemClass::SystemClass(const SystemClass& sys)
{
}
/*不在析构函数中回收内存的一点原因是谨慎对待内存的回收问题*/
SystemClass::~SystemClass()
{
}
/*系统类初始化函数*/
bool SystemClass::Initialize()
{
int ScreenWidth, ScreenHeight;
bool result;
/*初始化屏幕宽度和高度*/
ScreenWidth = 0;
ScreenHeight = 0;
/*初始化系统类的窗口*/
InitializeWindow(ScreenWidth, ScreenHeight);
/*创建输入类对象*/
m_Input = new InputClass();
if (!m_Input)
{
return false;
}
/*初始化输入对象*/
m_Input->Initialize();
/*创建图形类对象*/
m_Graphics = new GraphicsClass();
if (!m_Graphics)
{
return false;
}
/*初始化图形对象,发生在窗口初始化之后,因为窗口初始化之后,窗口句柄才被建立*/
result=m_Graphics->Initialize(ScreenWidth, ScreenHeight, mHwnd);
if (!result)
{
return false;
}
return true;
}
void SystemClass::Shutdown()
{
/*释放图形类对象*/
if (m_Graphics)
{
m_Graphics->Shutdown();
delete m_Graphics;
m_Graphics = NULL;
}
/*释放输入类对象*/
if (m_Input)
{
delete m_Input;
m_Input = NULL;
}
/*关闭窗口*/
this->ShutdownWindow();
}
void SystemClass::Run()
{
MSG msg = { 0 };
bool done, result;
/*循环直到收到来自窗口的或者使用者的quit消息*/
done = false;
while (!done)
{
//操作窗口消息
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
{
done = true;
}
TranslateMessage(&msg);
DispatchMessage(&msg); //把消息发送到WindProc()中
}
else
{
result = Frame(); //Frame运行的函数可能造成游戏退出
if (!result)
{
done = true;
}
}
}
}
bool SystemClass::Frame()
{
bool result;
//你按下了退出函数,则退出这个应用(按键的宏刚好相对应)
if (m_Input->IsKeyDown(VK_ESCAPE))
{
return false;
}
//进行图形对象的帧函数
result = m_Graphics->Frame();
if (!result)
{
return false;
}
return true;
}
LRESULT CALLBACK SystemClass::MessageHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
//确认一个键已经在键盘上按下
case WM_KEYDOWN:
{
//如果一个键被按下,则将这个键的信息送到input object,为了可以记录这个状态
m_Input->KeyDown((unsigned int)wParam);
return 0;
}
//确认一个键被释放
case WM_KEYUP:
{
//如果一个键被释放,则将这个键的信息送到input object,为了可以取消这个状态
m_Input->KeyUp((unsigned int)wParam);
return 0;
}
//其它的消息被送到默认处理消息函数
default:
{
return DefWindowProc(hwnd, message, wParam, lParam); //为全局静态函数
}
}
}
void SystemClass::InitializeWindow(int& ScrrenWidth, int &ScrrenHeight)
{
WNDCLASSEX wc;
DEVMODE dmScrrenSettings;
int posX, posY;
//获取一个额外的指向这个对象的指针
D3DAPP = this;
//获取应用实例句柄
mHinstance = GetModuleHandle(NULL);
//给予应用一个名字
mApplicationName = L"Engine";
//设定要创建的类的属性
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = mHinstance;
wc.hIcon = LoadIcon(NULL, IDI_WINLOGO);
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.lpszMenuName = NULL;
wc.lpszClassName = mApplicationName;
wc.cbSize = sizeof(WNDCLASSEX);
//注册这个类
RegisterClassEx(&wc);
//获取屏幕分辨率的宽度和高度
ScrrenWidth = GetSystemMetrics(SM_CXSCREEN);
ScrrenHeight= GetSystemMetrics(SM_CYSCREEN);
//取决于是否为全屏幕
if (FULL_SCREEN)
{
//如果为全屏幕,则设定屏幕为用户桌面的最大化并且为32bit
memset(&dmScrrenSettings, 0, sizeof(dmScrrenSettings));
dmScrrenSettings.dmSize = sizeof(dmScrrenSettings);
dmScrrenSettings.dmPelsWidth = (unsigned long)ScrrenWidth;
dmScrrenSettings.dmPelsHeight = (unsigned long)ScrrenHeight;
dmScrrenSettings.dmBitsPerPel = 32;
dmScrrenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
//改变显示设定,设置为全屏幕
ChangeDisplaySettings(&dmScrrenSettings, CDS_FULLSCREEN);
//设定窗口左上角的位置
posX = posY = 0;
}
else
{
//如果窗口化,设定为800*600分辨率
ScrrenWidth = 800;
ScrrenHeight = 600;
//窗口位于屏幕稍微的左上方
posX = (GetSystemMetrics(SM_CXSCREEN) - ScrrenWidth) / 2-200;
posY = (GetSystemMetrics(SM_CYSCREEN) - ScrrenHeight) / 2-100;
}
//创建窗口,并且获取窗口的句柄
mHwnd = CreateWindowEx(WS_EX_APPWINDOW, mApplicationName, mApplicationName,
WS_OVERLAPPEDWINDOW,
posX, posY, ScrrenWidth, ScrrenHeight, NULL, NULL, mHinstance, NULL);
//将窗口显示于屏幕之上,并设定该窗口为主要集中点
ShowWindow(mHwnd, SW_SHOW);
SetForegroundWindow(mHwnd);
SetFocus(mHwnd);
//隐藏鼠标光标
//ShowCursor(false);
}
void SystemClass::ShutdownWindow()
{
//显示鼠标光标
//ShowCursor(true);
//如果离开全屏幕模式,恢复显示设定
if (FULL_SCREEN)
{
ChangeDisplaySettings(NULL, 0);
}
//移除(破坏)窗口
DestroyWindow(mHwnd);
mHwnd = NULL;
//移除程序实例
UnregisterClass(mApplicationName, mHinstance);
mHinstance = NULL;
//置空应用类对象
D3DAPP = NULL;
}
(4)入口函数
main.cpp
#include"SystemClass.h"
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
SystemClass* System=NULL;
bool result;
//创建SystemClass类
System = new SystemClass;
if (!System)
{
return 0;
}
//初始化和运行系统对象
result = System->Initialize();
if (result)
{
System->Run();
}
//关闭systemclass对象
System->Shutdown();
delete System;
System = NULL;
return 0;
}
(1) 这个框架值得注意的一点是: 窗口的回调函数不是类内的,而是全局的消息回调函数LRESULT CALLBACK WndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam),在类内定义一个LRESULT CALLBACK MessageHandler(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)接受来自全局函数回调WndProc函数的消息,避免了类内定义回调函数直接作为创建窗口的回调函数会出现的问题,这是封装win32回调函数经常会出现的问题。