app.h
#pragma once
#include "MyWindow.h"
#include "MyTimer.h"
class App
{
public:
int Go();//初始化游戏逻辑,包含消息循环,
private:
void DoFrame();//处理每一帧的游戏逻辑, 在每次消息循环结束时调用
private:
Window wnd{600,400,L"iiii"};
MyTimer timer;
};
app.cpp
#include "App.h"
#include <sstream>
#include <iomanip>
int App::Go()
{
MSG msg;
BOOL getResult;
while (true)
{
getResult =PeekMessage(&msg, nullptr, 0, 0,PM_REMOVE);
if (msg.message == WM_QUIT)
{
return 0;
}
TranslateMessage(&msg);
DispatchMessage(&msg);
DoFrame();
}
}
void App::DoFrame()
{
const float t = timer.Peek();
std::wostringstream oss;
oss << "Time elapsed:" << std::setprecision(1)<<std::fixed << t << 's';
wnd.SetTitle(oss.str());
wnd.GetGraphics().ClearBuffer(1.0f,1.0f, 1.0f);
wnd.GetGraphics().EndFrame();
}
MyWindow.h部分
class Window
{
//······
public:
Graphic* pG = nullptr; //添加
//······
}
Window::Window(int width, int height, const wchar_t* name) noexcept
:width{width},height{height}
{
//······
ShowWindow(hWnd, SW_SHOWDEFAULT);
pGfx = new Graphic{hWnd}; //创建
}
Graphic.h
#pragma once
#include<d3d11.h>
class Graphic //图形输出
{
public:
Graphic(HWND hWnd); //创建d3d设备,必须要窗口的 Handle,
Graphic(const Graphic&) = delete;
Graphic& operator=(const Graphic&) = delete;
~Graphic();
void EndFrame();
private:
ID3D11Device* pDevice = nullptr; //分配内存和创建资源
IDXGISwapChain* pSwap = nullptr;
ID3D11DeviceContext* pContext = nullptr; //发布渲染命令
ID3D11RenderTargetView* pTarget = nullptr;
};
Graphic.cpp
#include"Graphic.h"
//
// #pragma comment(lib, "d3d11.lib")
// #pragma comment(lib, "dxgi.lib")
// #pragma comment(lib, "dxguid.lib")
// #pragma comment(lib, "D3DCompiler.lib")
// #pragma comment(lib, "winmm.lib")
Graphic::Graphic(HWND hWnd)
{
DXGI_SWAP_CHAIN_DESC sd{}; //
sd.BufferDesc.Width = 0; //描述缓存显示模式//缓存宽,若为零则输出窗口的宽
sd.BufferDesc.Height = 0; //缓存高
sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM; //缓存格式
sd.BufferDesc.RefreshRate.Numerator = 0; //刷新率单位频率率//UINT最大帧率
sd.BufferDesc.RefreshRate.Denominator = 0; //UINT最小帧率
sd.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED; //扫描线的模式,图像区域与窗口client的缩放关系
sd.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;//扫描线的enum从屏幕的何处开始扫描
sd.SampleDesc.Count = 1; //多采样参数//多重采样数
sd.SampleDesc.Quality = 0; //图像质量级别
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; //将交换链用作渲染目标
sd.BufferCount = 1; //缓冲区数量,一个自动设置的前缓冲和1个后缓冲
sd.OutputWindow = hWnd; //需要一个窗口
sd.Windowed = TRUE; //窗口模式
sd.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; //交换效果,此处表示交换后,丢弃原有的图像
sd.Flags = 0;
D3D11CreateDeviceAndSwapChain(
nullptr, //视频适配,NULL代表默认
D3D_DRIVER_TYPE_HARDWARE, //设备类型,enum,此处:硬件驱动
nullptr, //实现光栅的DLL的句柄,特定值
0, //标签,调试层,线程
nullptr, //特征等级:若为NULL,则默认的等级数组
0, //上个数组的元素数量
D3D11_SDK_VERSION, //SDK版本
&sd, //交换链的参数结构体
&pSwap, //后四个用作输出 //交换链输出,传入空指针pSwap, 返回IDXGISwapChain对象地址
&pDevice, //设备,ID3D11Device
nullptr, //特征等级输出,该函数运行完成后,设备实际使用的特征等级,此处用不到该信息,
&pContext //设备上下文, ID3D11DeviceContext
);
//获取交换链的后缓存,用于创建渲染目标
ID3D11Resource* pBackBuffer{ nullptr };
pSwap->GetBuffer(0, __uuidof(ID3D11Resource),reinterpret_cast<void**>(&pBackBuffer));//参数: 后缓存的索引,操作缓存的接口类型,后缓存接口指针
pDevice->CreateRenderTargetView(pBackBuffer,nullptr,&pTarget); //创建渲染目标视图 参数: 后缓存指针,默认设置,
pBackBuffer->Release();//使用渲染目标视图,不再需要后缓存,减少引用计数
}
Graphic::~Graphic()
{
if (pDevice != nullptr)
{
pDevice->Release();
}
if (pSwap != nullptr)
{
pSwap->Release();
}
if (pContext != nullptr)
{
pContext->Release();
}
}
void Graphic::EndFrame()
{
pSwap->Present(1u, 0u); //交换前后缓存, 在消息循环的 App::DoFrame()调用 参数:同步间隔,标签
}
Window类:
内部类WindowClass单例,用于注册窗口类
Window类:
内部类WindowClass单例 构造函数用于注册 窗口类,
构造函数,创建窗口,
消息处理函数,kbd 按键输入和缓冲
pGfx:指针延迟构造(保证先获取hWnd后,再实例化对象),图像输出
App类:
Window类,
Go函数:消息循环
DoFrame:在每次消息循环结束时调用
Graphic类:
构造:创建设备和交换链
析构:释放资源
EndFrame:使用Present() 交换 前后缓存 在Doframe结束时调用