我们定义一个DirectX11的类
头文件的定义:
#pragma once
#ifndef __DIRECT3DCLASS_H_
#define __DIRECT3DCLASS_H_
#pragma comment(lib, "dxgi.lib")
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")
#pragma comment(lib, "d3dx10.lib")
#pragma comment(lib, "dxerr.lib")
#pragma comment(lib, "legacy_stdio_definitions.lib")
#include<d3d11.h>
#include<D3DX11.h>
#include<DxErr.h>
class DIrect3DClass
{
public:
DIrect3DClass();
virtual ~DIrect3DClass(); //在子类中被重写
bool initialize(HINSTANCE hInstance, HWND hwnd); //初始化函数
void shutdown(); //释放在开始时创建的Direct3D对象
virtual bool LoadContent(); //提供一方式载入具体Demo内容
virtual void UnLoadContent(); //提供卸载具体Demo内容的方式
virtual void Update(float dt) = 0; //提供每帧更新具体Demo的能力
virtual void Render() = 0; //提供可重写的具体Demo的渲染函数
protected:
HINSTANCE hInstance_;
HWND hwnd_;
D3D_DRIVER_TYPE driverType_; //驱动类型
D3D_FEATURE_LEVEL featureLevel_; //特征性等级
ID3D11Device* d3dDevice_; //设备类
ID3D11DeviceContext* d3dContext_; //环境渲染类
IDXGISwapChain* swapChain_; //交换链
ID3D11RenderTargetView* backBufferTarget_; //渲染目标视图
};
#endif
源文件:
#include "DIrect3DClass.h"
DIrect3DClass::DIrect3DClass()
{
}
DIrect3DClass::~DIrect3DClass()
{
shutdown(); //每个析构函数有自己独特的关闭内容
}
bool DIrect3DClass::LoadContent() {
return true; //调用内容
}
void DIrect3DClass::UnLoadContent() {
//根据不同的内容进行重写
}
//初始内容
void DIrect3DClass::shutdown() {
//释放内容:
UnLoadContent();
//释放指针对象
if (backBufferTarget_) backBufferTarget_->Release();
if (swapChain_)swapChain_->Release();
if (d3dContext_)d3dContext_->Release();
if (d3dDevice_)d3dDevice_->Release();
backBufferTarget_ = 0;
swapChain_ = 0;
d3dContext_ = 0;
d3dDevice_ = 0;
}
bool DIrect3DClass::initialize(HINSTANCE hInstance, HWND hwnd) {
HRESULT result; //检测是否生成成功
hInstance_ = hInstance;
hwnd_ = hwnd;
//生成驱动和特性等级//
RECT dimensions;
GetClientRect(hwnd, &dimensions);
unsigned int Width = dimensions.right - dimensions.left;
unsigned int height = dimensions.bottom - dimensions.top;
D3D_DRIVER_TYPE driverTypes[] = { //四种驱动类型,选择最合适的驱动类型
D3D_DRIVER_TYPE_HARDWARE, D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE, D3D_DRIVER_TYPE_SOFTWARE
};
unsigned int totalDriverTypes = ARRAYSIZE(driverTypes); //得出类型数
D3D_FEATURE_LEVEL featureLeverls[] = { //三种版本依赖 迭代选择最合适的版本依赖
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0
};
unsigned int totalFeatureLevels = ARRAYSIZE(featureLeverls); //得出版本数
//生成交换链//:
DXGI_SWAP_CHAIN_DESC swapChainDesc;
ZeroMemory(&swapChainDesc, sizeof(swapChainDesc));
swapChainDesc.BufferCount = 1; //缓存页的数量
swapChainDesc.BufferDesc.Width = Width; //宽度
swapChainDesc.BufferDesc.Height = height; //高度
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; //缓存格式
swapChainDesc.BufferDesc.RefreshRate.Numerator = 60; //刷新率
swapChainDesc.BufferDesc.RefreshRate.Denominator = 1; //使用60/1表示60Hz的刷新率
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; //交换链中的缓存用法,能够用于输出以及渲染
swapChainDesc.OutputWindow = hwnd; //窗口句柄
swapChainDesc.Windowed = true; //是全屏还是原来的尺寸resize?
swapChainDesc.SampleDesc.Count = 1; //取样描述:数量
swapChainDesc.SampleDesc.Quality = 0; //取样描述:质量
//测试并选择驱动和特征级别//:
//创建渲染环境//
unsigned int creationFlags = 0;
#ifndef _DEBUG
creationFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
for (unsigned int driver = 0; driver < totalDriverTypes; ++driver) {
result = D3D11CreateDeviceAndSwapChain(0, driverTypes[driver], 0, creationFlags, featureLeverls, totalFeatureLevels, D3D11_SDK_VERSION, &swapChainDesc, &swapChain_,
&d3dDevice_, &featureLevel_, &d3dContext_);
if (SUCCEEDED(result)) {
driverType_ = driverTypes[driver];
break;
}
}
if (FAILED(result))
{
DXTRACE_MSG("Failed to create the Direct3D device!");
return false;
}
//获取后置内存指针//
ID3D11Texture2D* backBufferTexture;
result = swapChain_->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&backBufferTexture);
if (FAILED(result)) {
DXTRACE_MSG("Failed to get the swap chain back buffer");
return false;
}
//创建渲染目标视图//
result = d3dDevice_->CreateRenderTargetView(backBufferTexture, 0, &backBufferTarget_);
//释放贴图
if (backBufferTexture) {
backBufferTexture->Release(); //释放内容
}
if (FAILED(result)) {
DXTRACE_MSG("FAILED To Create the render target view!");
return false;
}
//创建视口//
D3D11_VIEWPORT viewport;
viewport.Width = static_cast<float>(Width);
viewport.Height = static_cast<float>(height);
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
d3dContext_->RSSetViewports(1, &viewport);
//返回//
return LoadContent();
}
然后创建一个demo类 继承DirectX11类
头文件:
#pragma once
#ifndef __BLAMLDEMO_H_
#define __BLAMLDEMO_H_
#include "DIrect3DClass.h"
class BlamlDemo :
public DIrect3DClass
{
public:
BlamlDemo();
virtual ~BlamlDemo();
//重写函数
bool LoadContent();
void UnLoadContent();
void Update(float dt);
void Render();
};
#endif
#include "BlamlDemo.h"
BlamlDemo::BlamlDemo()
{
}
BlamlDemo::~BlamlDemo()
{
}
bool BlamlDemo::LoadContent()
{
return true;
}
void BlamlDemo::UnLoadContent(){
}
void BlamlDemo::Update(float dt) {
}
void BlamlDemo::Render() {
if (d3dContext_ == 0)
return;
float clearColor[4] = { 0.0f, 0.0f, 0.25f, 1.0f };
d3dContext_->ClearRenderTargetView(backBufferTarget_, clearColor);
swapChain_->Present(0, 0);
}
窗口文件(winmain入口定义):
#include<iostream>
#include<memory>
#include "BlamlDemo.h"
using namespace std;
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); //用来处理消息队列
//wWinMain 和 WinMain的区别 可以解决Unicode和ANSI之间的切换问题
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ LPWSTR lpCmdLine, _In_ int nShowCmd)
{
//四个参数:
//hInstance:当前应用的句柄
//hprevious instance:上一个应用的句柄 通常设为NULL
//LPSTR cmdLine:用户和窗体之间的交互
UNREFERENCED_PARAMETER(hPrevInstance); //告诉编译器已经使用了这个变量
UNREFERENCED_PARAMETER(lpCmdLine); //告诉编译器已经使用了该变量
WNDCLASSEX wndClass = { 0 };
wndClass.cbSize = sizeof(WNDCLASSEX); //窗体类的大小,可以用sizeof来获取
wndClass.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC; //窗体的风格
wndClass.lpfnWndProc = WndProc; //窗口函数处理指针
wndClass.cbClsExtra = 0; //指定紧跟在窗口类结构后的附加字数
wndClass.cbWndExtra = 0; //指定紧跟在窗口类结构后的附加字节数
wndClass.hInstance = hInstance; //本模块的实例句柄
wndClass.hIcon = LoadIcon(NULL, IDI_WINLOGO); //图标的句柄
wndClass.hCursor = LoadCursor(NULL, IDC_ARROW); //光标的句柄
wndClass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH); //背景画刷的句柄
wndClass.lpszMenuName = NULL; //指向菜单的指针
wndClass.lpszClassName = TEXT("DX11BookWindowClass"); //指向类名称的指针
wndClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO); //和窗口关联的小图标
//提交注册表单
if (!RegisterClassEx(&wndClass)) {
MessageBox(NULL, TEXT("Register Window failed!"), TEXT("Warning"), MB_OK);
return -1;
}
//设置窗体的大小
RECT rc = { 0, 0, 1024, 768 }; //窗口规模 左上角坐标 宽度 高度
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
//创建一个标准的窗体
HWND hwnd = CreateWindowEx(WS_EX_APPWINDOW, "DX11BookWindowClass", "BLACK WIN32 Window", WS_OVERLAPPED, CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left,
rc.bottom - rc.top, NULL, NULL, hInstance, NULL);
//参数说明:
//(1)窗口类名:这里有个坑 这里填写的类名必须与上面注册的类名一致
//(2)窗体标题
//(3)窗体风格
//(4)坐标x
//(5)坐标y
//(6)宽度
//(7)高度
//(8)父类窗体的句柄
//(9)lpParam--
if (!hwnd) {
MessageBox(NULL, TEXT("Register Window failed!"), TEXT("Warning"), MB_OK);
return -1;
}
ShowWindow(hwnd, nShowCmd);
//初始化对象//
auto_ptr<DIrect3DClass> Demo(new BlamlDemo());
bool result = Demo->initialize(hInstance, hwnd); //传入当前窗口的句柄
if (result == false) {
MessageBox(hwnd, TEXT("DX3d Initialize error!"), TEXT("eror"), MB_OK);
return -1;
}
//窗体创建完毕后 开始消息循环
MSG msg = { 0 };
while (msg.message != WM_QUIT) //如果不退出的话 则一直循环
{
if (PeekMessage(&msg, 0, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg); //获取新的消息
DispatchMessage(&msg); //派遣消息
}
else {
//更新
Demo->Update(0.0f);
//渲染
Demo->Render();
}
}
Demo->shutdown(); //关闭实例
return static_cast<int>(msg.wParam); //把expression转换为type-id
}
//消息队列
//每当消息循环获取到新消息后 开始处理消息
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) {
PAINTSTRUCT ps;
HDC hdc;
switch (message) //选择消息类型进行处理
{
case WM_PAINT: { //窗体绘制
hdc = BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
}break;
case WM_CLOSE: { //窗体关闭
PostQuitMessage(0);
DestroyWindow(hWnd);
}break;
case WM_DESTROY: {
PostQuitMessage(0);
break;
}
default: {
return DefWindowProc(hWnd, message, wParam, lParam); //确保每个消息都得到处理
}
}
}