《基于 DirectX11 的 3D 图形程序设计案例教程》学习四 D3DTriangle

源程序:

  此次例子的大部分代码均拷贝自上一章 InitD3D 例子程序。

  d3dUtility.h
/*************************************************************************
    > File Name: d3dUtility.h
    > Author: YLD10
    > Mail: [email protected]
    > Created Time: 2018.6.1 21:36
    > Describe: Win32 Application InitD3D.
                《基于 DirectX11 的 3D 图形程序设计案例教程》
                5.2 节程序例子 绘制一个三角形
 ************************************************************************/
#pragma once

#include <Windows.h>

 //////////////////////////////////////////////////////////////////////////
// XNA 数学库相关头文件
//////////////////////////////////////////////////////////////////////////
#include <d3dCompiler.h>
#include <xnamath.h>

//////////////////////////////////////////////////////////////////////////
// DirectX11 相关头文件
//////////////////////////////////////////////////////////////////////////
#include <d3d11.h>
#include <d3dx11.h>

//////////////////////////////////////////////////////////////////////////
// DirectX11 相关库
//////////////////////////////////////////////////////////////////////////
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dx11.lib")

#pragma comment(lib, "d3dCompiler.lib")
#pragma comment(lib, "dxguid.lib")
#pragma comment(lib, "winmm.lib")

namespace d3d  // 定义一个 d3d 命名空间
{
    /*
     * 初始化 D3D
     */
    bool InitD3D(HINSTANCE hInstance,
                 int width, int height,
                 ID3D11RenderTargetView** renderTargerView,  // 目标渲染视图接口
                 ID3D11DeviceContext** immediateContext,     // 执行上下文接口
                 IDXGISwapChain** swapChain,                 // 交换链接口
                 ID3D11Device** device);                     // 设备用接口, 每个 D3D 程序至少有一个设备

    /*
     * 消息循环
     */
    int EnterMsgLoop(bool (*ptr_display)(float timeDelta));

    /*
     * 回调函数
     */
    LRESULT CALLBACK WndProc(HWND,
                             UINT msg,
                             WPARAM,
                             LPARAM lParam);
}
  d3dUtility.cpp
/*************************************************************************
    > File Name: d3dUtility.cpp
    > Author: YLD10
    > Mail: [email protected]
    > Created Time: 2018.6.1 21:36
    > Describe: Win32 Application InitD3D.
                《基于 DirectX11 的 3D 图形程序设计案例教程》
                5.2 节程序例子 绘制一个三角形
 ************************************************************************/
 #include "d3dUtility.h"

/*
 * D3D 初始化
 * 这个函数中包括两个部分: 第一部分: 创建一个窗口; 第二部分: 初始化 D3D
 * 函数参数包括:
 * 1.HINSTANCE   当前应用程序实例的句柄
 * 2.int width   窗口宽
 * 3.int height  窗口高
 * 4.ID3D11RenderTargetView** renderTargetView  目标渲染视图指针
 * 5.ID3D11DeviceContext** immediateContext     立即执行上下文指针
 * 6.IDXGISwapChain** swapChain                 交换链指针
 * 7.ID3D11Device** device                      设备用指针, 每个 D3D 程序至少有一个设备
 */
bool d3d::InitD3D(HINSTANCE hInstance, 
                  int width, int height, 
                  ID3D11RenderTargetView** renderTargerView, 
                  ID3D11DeviceContext** immediateContext, 
                  IDXGISwapChain** swapChain, 
                  ID3D11Device** device)
{
    //************* 第一部分: 创建一个窗口开始 ***************
    // 这部分的代码和 2.2 节中创建窗口代码基本一致
    // 具体参数的注释可以参考 2.2 节程序例子
    // 创建窗口的 4 个步骤: 1 设计一个窗口类; 2 注册窗口类
    //                    3 创建窗口;       4 窗口显示和更新
    // 1 设计一个窗口类
    WNDCLASS wc;
    wc.style            = CS_HREDRAW | CS_VREDRAW;
    wc.lpfnWndProc      = (WNDPROC)d3d::WndProc;
    wc.cbClsExtra       = 0;
    wc.cbWndExtra       = 0;
    wc.hInstance        = hInstance;
    wc.hIcon            = LoadIcon(0, IDI_APPLICATION);
    wc.hCursor          = LoadCursor(0, IDC_ARROW);
    wc.hbrBackground    = (HBRUSH)GetStockObject(WHITE_BRUSH);
    wc.lpszMenuName     = 0;
    wc.lpszClassName    = L"Direct3D11App";

    // 2 注册窗口类
    if (!RegisterClass(&wc))
    {
        ::MessageBox(0, L"RegisterClass() - FAILED", 0, 0);

        return false;
    }

    // 3 创建窗口
    HWND hwnd;
    hwnd = ::CreateWindow(L"Direct3D11App",
                          L"D3D11",
                          WS_OVERLAPPEDWINDOW,
                          CW_USEDEFAULT,
                          CW_USEDEFAULT,
                          width,
                          height,
                          0,
                          0,
                          hInstance,
                          0);
    if (!hwnd)
    {
        ::MessageBox(0, L"CreateWindow() - FAILED", 0, 0);

        return false;
    }

    // 4 窗口显示和更新
    ::ShowWindow(hwnd, SW_SHOW);
    ::UpdateWindow(hwnd);

    //************* 第一部分: 创建一个窗口结束 ***************

    //************* 第二部分: 初始化 D3D 开始 ***************
    // 初始化 D3D 设备主要为以下步骤
    // 1. 描述交换链, 即填充 DXGI_SWAP_CHAIN_DESC 结构
    // 2. 使用 D3D11CreateDeviceAndSwapChain 创建 D3D 设备 (ID3D11Device)
    //    执行上下文接口 (ID3D11DeviceContext), 交换链接口 (IDXGISwapChain)
    // 3. 创建目标渲染视图 (ID3D11RenderTargetView)
    // 4. 设置视口 (View Port)

    // 第一步, 描述交换链, 即填充 DXGI_SWAP_CHAIN_DESC 结构
    DXGI_SWAP_CHAIN_DESC sd;          // 首先声明一个 DXGI_SWAP_CHAIN_DESC 的对象 sd
    ZeroMemory(&sd, sizeof(sd));      // 用 ZeroMemory 对 sd 进行初始化
    sd.BufferCount       = 1;         // 交换链中后台缓存数量, 通常为 1
    sd.BufferDesc.Width  = width;     // 缓存区中的窗口宽
    sd.BufferDesc.Height = height;    // 缓存区中的窗口高
    sd.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;    // 表示红绿蓝 Alpha 各 8 位
    sd.BufferDesc.RefreshRate.Numerator   = 60;           // 刷新频率的分子为 60
    sd.BufferDesc.RefreshRate.Denominator = 1;            // 刷新频率的分母为 1, 即
                                                          // 刷新频率为每秒 60 次
    sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;     // 用来描述后台缓存用法
                                                          // 控制 CPU 对后台缓存的访问
    sd.OutputWindow       = hwnd;     // 指向渲染目标窗口的句柄
    sd.SampleDesc.Count   = 1;        // 多重采样, 本例中不采用多重采样
    sd.SampleDesc.Quality = 0;        // 所以 Count = 1, Quality = 0
    sd.Windowed           = TRUE;     // TRUE 为窗口模式, FALSE 为全屏模式

    // 第二步, 创建设备, 交换链以及立即执行上下文
    // 创建一个数组确定尝试创建 Featurelevel 的顺序
    D3D_FEATURE_LEVEL featureLevels[] =
    {
        D3D_FEATURE_LEVEL_11_0,  // D3D11 所支持的特征, 包括 shader model 5
        D3D_FEATURE_LEVEL_10_1,  // D3D10 所支持的特征, 包括 shader model 4
        D3D_FEATURE_LEVEL_10_0
    };

    // 获取 D3D_FEATURE_LEVEL 数组的元素个数
    UINT numFeatureLevels = ARRAYSIZE(featureLevels);

    // 调用 D3D11CreateDeviceAndSwaoChain 创建交换链、设备和执行上下文
    // 分别存入 swapChain, device, immediateContext
    if (FAILED(D3D11CreateDeviceAndSwapChain(
               NULL,                // 确定显示适配器, NULL 表示默认显示适配器
               D3D_DRIVER_TYPE_HARDWARE,  // 驱动类型, 这里表示使用三维硬件加速
               NULL,                // 只有上一个参数设置为
                                    // D3D_DRIVER_TYPE_SOFTWARE 时才使用该参数
               0,                   // 也可以设置为 D3D11_CREATE_DEVICE_DEBUG 开启调试模式
               featureLevels,       // 前面定义的 D3D_FEATURE_LEVEL 数组
               numFeatureLevels,    // D3D_FEATURE_LEVEL 的元素个数
               D3D11_SDK_VERSION,   // SDK 的版本, 这里为 D3D11
               &sd,                 // 前面定义的 DXGI_SWAP_CHAIN_DESC 对象
               swapChain,           // 返回创建好的交换链指针, InitD3D 函数传递的实参
               device,              // 返回创建好的设备用指针, InitD3D 函数传递到实参
               NULL,                // 返回当前设备支持的 featureLevels 数组中的第一个对象,
                                    // 一般设置为 NULL
               immediateContext)))  // 返回创建好的执行上下文指针,
                                    // InitD3D 函数传递的实参
    {
        ::MessageBox(0, L"CreateDevice - FAILED", 0, 0);

        return false;
    }

    // 第三步, 创建并设置渲染目标视图
    HRESULT hr = 0;                         // COM 要求所有的方法都会返回一个 HRESULT 类型的错误号
    ID3D11Texture2D* pBackBuffer = NULL;    // ID3D11Texture2D 类型的后台缓存指针

    // 调用 GetBuffer() 函数得到后台缓存对象, 并存入 &pBackBuffer 中
    hr = (*swapChain)->GetBuffer(0,         // 缓存索引, 一般设置为 0
                                 __uuidof(ID3D11Texture2D),  // 缓存类型
                                 (LPVOID*)&pBackBuffer);     // 缓存指针
    // 判断 GetBuffer 是否调用成功
    if (FAILED(hr))
    {
        ::MessageBox(0, L"GetBuffer - FAILED", 0, 0);

        return false;
    }

    // 调用 CreateRenderTargetView 创建好渲染目标视图
    // 创建后存入 renderTargetView 中
    hr = (*device)->CreateRenderTargetView(pBackBuffer,        // 上面创建好的后台缓存
                                           NULL,               // 设置为 NULL 得到默认的渲染目标视图
                                           renderTargerView);  // 返回创建好的渲染目标视图
                                                               // InitD3D 函数传递的实参
    pBackBuffer->Release();  // 释放后台缓存

    // 判断 CreateRenderTargetView 是否调用成功
    if (FAILED(hr))
    {
        ::MessageBox(0, L"CreateRender - FAILED", 0, 0);

        return false;
    }

    // 将渲染目标视图绑定到渲染管线
    (*immediateContext)->OMSetRenderTargets(1,                 // 绑定的目标视图的个数
                                            renderTargerView,  // 渲染目标视图
                                            NULL);             // 不绑定深度模版

    // 第四步, 设置视口大小, D3D11 默认不会设置视口, 此步骤必须手动设置
    D3D11_VIEWPORT vp;      // 创建一个视口的对象
    vp.Width    = width;    // 视口的宽
    vp.Height   = height;   // 视口的高
    vp.MinDepth = 0.0f;     // 深度值的下限, 由于深度值是 [0, 1] 所以下限值是 0
    vp.MaxDepth = 1.0f;     // 深度值的上限, 上限值是 1
    vp.TopLeftX = 0;        // 视口左上角的横坐标
    vp.TopLeftY = 0;        // 视口左上角的纵坐标

    // 设置视口
    (*immediateContext)->RSSetViewports(1,      // 视口的个数
                                        &vp);   // 上面创建的视口对象

    return true;

    //************* 第二部分: 初始化 D3D 结束 ***************
}

/*
 * 消息循环函数, 和之前 "Hello World" 程序中 Run() 起到同样的功能
 * bool(*ptr_display)(float timeDelta) 表示传递一个函数指针作为参数
 * 这个函数有一个 float 类型的参数, 有一个 bool 类型的返回
 */
int d3d::EnterMsgLoop(bool(*ptr_display)(float timeDelta))
{
    MSG msg;
    ::ZeroMemory(&msg, sizeof(MSG));                // 初始化内存

    static float lastTime = (float)timeGetTime();   // 第一次获取当前时间

    while (WM_QUIT != msg.message)
    {
        if (::PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
        {
            ::TranslateMessage(&msg);
            ::DispatchMessage(&msg);
        }
        else
        {
            // 第二次获取当前时间
            float currTime  = (float)timeGetTime();

            // 获取两次时间之间的时间差
            float timeDelta = (currTime - lastTime) * 0.001f;

            // 调用显示函数, 这在后面时间图形的变化 (如旋转) 时会用到
            ptr_display(timeDelta);
            lastTime = currTime;
        }
    }

    return msg.wParam;
}
  d3dTriangle.cpp
/*************************************************************************
    > File Name: d3dTriangle.cpp
    > Author: YLD10
    > Mail: [email protected]
    > Created Time: 2018.6.1 21:35
    > Describe: Win32 Application InitD3D.
                《基于 DirectX11 的 3D 图形程序设计案例教程》
                5.2 节程序例子 绘制一个三角形
 ************************************************************************/
#include "d3dUtility.h"

ID3D11Device*           device           = NULL;    // D3D11 设备指针
IDXGISwapChain*         swapChain        = NULL;    // 交换链指针
ID3D11DeviceContext*    immediateContext = NULL;    // 执行上下文指针
ID3D11RenderTargetView* renderTargetView = NULL;    // 渲染目标视图指针
// 新增的两个全局变量
ID3D11VertexShader*     vertexShader;               // 顶点着色器
ID3D11PixelShader*      pixelShader;                // 像素着色器

// 定义一个顶点结构, 这个顶点只需要包含坐标信息
struct Vertex
{
    XMFLOAT3 Pos;
};

//************* 以下为框架函数 ***************
/*
 * 第一步, 创建顶点着色器
 * 第二步, 创建像素着色器
 * 第三步, 创建并设置输入布局
 * 第四步, 创建顶点缓存
 */
bool Setup()
{
    // 第一步, 创建顶点着色器
    // 定义一个着色器编译标识符
    // D3DCOMPILE_ENABLE_STRICTINESS 表示强制严格编译
    // 这样一些已经废弃的语法将不能编译
    DWORD dwShaderFlag = D3DCOMPILE_ENABLE_STRICTNESS;

    // ID3DBlob 接口用于表示任意长度的数据
    // 本例使用该接口声明一个对象来存放编译后的着色器
    ID3DBlob* pVSBlob  = NULL;

    // 从指定文件编译着色器
    if (FAILED(D3DX11CompileFromFile(
               L"Triangle.hlsl",  // 这是我们创建的 hlsl 文件
               NULL,              // 可选项, 指向一个宏定义数组的指针, 一般为 NULL
               NULL,              // 用于处理着色器中的 include 文件, 没有 include 文件则为 NULL
               "VSMain",          // 指定顶点着色器的入口函数
               "vs_5_0",          // 指定顶点着色器版本, 这里是用 5.0 版本
               dwShaderFlag,      // 上面定义的着色器编译标识符
               0,                 // Effect 编译标识符, 如果不是编译 Effect 文件则设置为 0
               NULL,              // 指向 ID3DX11ThreadPump 的指针,
                                  // 设置为 NULL 表示这个函数在完成之前不会返回
               &pVSBlob,          // 指向编译好的顶点着色器的所在内存的指针
               NULL,              // 指向存放在编译中产生错误和警告的指针
               NULL)))            // 一个指向返回值的指针, 如果第八个参数为 NULL,
                                  // 这里也设置为 NULL
    {
        // 如果编译失败, 弹出一个消息框
        MessageBox(NULL, L"Fail to compile vertex shader", L"ERROR", MB_OK);

        return S_FALSE;
    }

    // 用 CreateVertexShader 创建顶点着色器
    device->CreateVertexShader(
            pVSBlob->GetBufferPointer(),  // 指向 pVSBlob 所在内存块的起始地址
            pVSBlob->GetBufferSize(),     // 取得 pVSBlob 的大小
            NULL,                         // 指向 ID3D11ClassLinkage 的指针, 一般为空
            &vertexShader);               // 将创建好的顶点着色器存放到 vertexShader 中

    // 第二步, 创建像素着色器
    // 声明一个 ID3DBlob 对象来存放编译后的像素着色器
    ID3DBlob* pPSBlob  = NULL;
    if (FAILED(D3DX11CompileFromFile(
               L"Triangle.hlsl",  // 这是我们创建的 hlsl 文件
               NULL,              // 可选项, 指向一个宏定义数组的指针, 一般为 NULL
               NULL,              // 用于处理着色器中的 include 文件, 没有 include 文件则为 NULL
               "PSMain",          // 指定像素着色器的入口函数
               "ps_5_0",          // 指定像素着色器版本, 这里是用 5.0 版本
               dwShaderFlag,      // 上面定义的着色器编译标识符
               0,                 // Effect 编译标识符, 如果不是编译 Effect 文件则设置为 0
               NULL,              // 指向 ID3DX11ThreadPump 的指针,
                                  // 设置为 NULL 表示这个函数在完成之前不会返回
               &pPSBlob,          // 指向编译好的像素着色器的所在内存的指针
               NULL,              // 指向存放在编译中产生错误和警告的指针
               NULL)))            // 一个指向返回值的指针, 如果第八个参数为 NULL,
                                  // 这里也设置为 NULL
    {
        MessageBox(NULL, L"Fail to compile pixel shader", L"ERROR", MB_OK);

        return S_FALSE;
    }

    // 用 CreatePixelShader 创建像素着色器
    device->CreatePixelShader(
            pPSBlob->GetBufferPointer(),  // 指向 pPSBlob 所在内存块的起始地址
            pPSBlob->GetBufferSize(),     // 取得 pPSBlob 的大小
            NULL,                         // 指向 ID3D11ClassLinkage 的指针, 一般为空
            &pixelShader);                // 将创建好的像素着色器存放到 pixelShader 中

    // 第三步, 创建并设置输入布局
    // 所谓输入布局, 就是制定顶点结构所包含信息的实际意义
    // D3D11_INPUT_ELEMENT_DESC 用于描述顶点结构的意义
    // 以便让显卡识别所定义的顶点结构
    // 这里定义一个 D3D11_INPUT_ELEMENT_DESC 数组,
    // 由于定义的顶点结构只有位置坐标, 所有这个数组里也只有一个元素
    D3D11_INPUT_ELEMENT_DESC layout[] = 
    {
        {
            "POSITION",  // 语义标识符, 必须和 hlsl 文件中 VSMain 所用的标识符一致
            0,           // 表示第 1 个元素, 注意和数组一样都是从 0 开始计数,
            DXGI_FORMAT_R32G32B32A32_FLOAT,  // 96 位浮点像素, 红绿蓝各 32 位
            0,           // 可以取值 0 - 15, 0 表示绑定顶点缓存到第一个输入槽
            0,           // 可选项, 定义了缓存的对齐方式,
            D3D11_INPUT_PER_VERTEX_DATA,     // 定义输入数据类型为顶点数据
            0            // 本例没有使用实例技术, 所以这里为 0
        }
    };

    // 获取输入布局中元素个数
    UINT numElements   = ARRAYSIZE(layout);

    // 声明一个输入布局对象 pVertexLayout 用于存放创建好的布局
    ID3D11InputLayout* pVertexLayout;

    // 调用 CreateInputLayout 创建输入布局
    device->CreateInputLayout(
            layout,                     // 上面定义的 D3D11_INPUT_ELEMENT_DESC 数组
            numElements,                // D3D11_INPUT_ElEMENT_DESC 数组的元素个数
            pVSBlob->GetBufferPointer(),  // 指向顶点着色器起始位置的指针
            pVSBlob->GetBufferSize(),     // 指向顶点着色器的所在内存大小
            &pVertexLayout);            // 返回生成的输入布局对象

    // 设置生成的输入布局
    immediateContext->IASetInputLayout(pVertexLayout);

    // 第四步, 创建顶点缓存
    // 用我们自己定义的 Vertex 结构创建三角形的三个顶点坐标
    Vertex vertices[] = 
    {
      XMFLOAT3(0.0f, 0.5f, 0.0f),
      XMFLOAT3(0.5f, 0.0f, 0.0f),
      XMFLOAT3(-0.5f, 0.0f, 0.0f)
    };

    // 填充 D3D11_BUFFER_DESC 结构, 这个结构是用来描述顶点缓存的属性
    // 首先声明一个 D3D11_BUFFER_DESC 的对象 bd
    D3D11_BUFFER_DESC bd;
    ZeroMemory(&bd, sizeof(bd));                   // 进行清零操作
    bd.Usage          = D3D11_USAGE_DEFAULT;       // 设置缓存的读写方式, 一般用默认方式
    bd.ByteWidth      = sizeof(Vertex) * 3;        // 设置缓存区域的大小,
                                                   // 由于有三个顶点所以要乘以 3
    bd.BindFlags      = D3D11_BIND_VERTEX_BUFFER;  // 将这个缓存区域绑定到顶点缓存
    bd.CPUAccessFlags = 0;                         // CPU 访问标识符, 0 表示没有 CPU 访问
    bd.MiscFlags      = 0;                         // 其他项标识符, 0 表示不使用该项

    // 声明一个数据用于初始化子资源
    D3D11_SUBRESOURCE_DATA initData;
    ZeroMemory(&initData, sizeof(initData));       // 进行清零操作
    initData.pSysMem  = vertices;                  // 设置需要初始化的数据, 即顶点数组

    // 声明一个 ID3D11Buffer 对象作为顶点缓存
    ID3D11Buffer* vertexBuffer;

    // 调用 CreateBuffer 创建顶点
    device->CreateBuffer(&bd, &initData, &vertexBuffer);
    UINT stride = sizeof(Vertex);     // 获取 Vertex 的大小作为跨度
    UINT offset = 0;                  // 设置偏移量为 0

    // 设置顶点缓存
    immediateContext->IASetVertexBuffers(
                      0,              // 绑定到第一个输入槽
                      1,              // 顶点缓存的个数, 这里为一个
                      &vertexBuffer,  // 创建好的顶点缓存
                      &stride,        // 跨度, 即顶点结构的大小
                      &offset);       // 缓存第一个元素到所用元素的偏移量

    // 指定图元类型, D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST 表示图元为三角形
    immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);

    return true;
}

void Cleanup()
{
    // 释放指针
    if (renderTargetView)
    {
        renderTargetView->Release();
    }
    if (immediateContext)
    {
        immediateContext->Release();
    }
    if (swapChain)
    {
        swapChain->Release();
    }
    if (device)
    {
        device->Release();
    }
    if (vertexShader)
    {
        vertexShader->Release();
    }
    if (pixelShader)
    {
        pixelShader->Release();
    }
}

bool Display(float timeDelta)
{
    if (device)
    {
        // 声明一个数组存放颜色信息, 4 个元素分别表示红, 绿, 蓝以及 alpha
        float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f };

        // 清除渲染目标视图
        immediateContext->ClearRenderTargetView(renderTargetView,
                                                ClearColor);

        // 把创建好的顶点着色器和像素着色器绑定到 immediateContext
        immediateContext->VSSetShader(vertexShader, NULL, 0);
        immediateContext->PSSetShader(pixelShader, NULL, 0);

        // 绘制三角形, 第一个参数表示绘制 3 个点
        // 第二个参数表示从第 0 个点开始绘制
        immediateContext->Draw(3, 0);

        swapChain->Present(0, 0);
    }

    return true;
}
//************* 框架函数编写结束 ***************

/*
* 回调函数
*/
LRESULT CALLBACK d3d::WndProc(HWND hwnd, UINT msg,
                              WPARAM wParam, LPARAM lParam)
{
    switch (msg)
    {
    case WM_DESTROY:
        ::PostQuitMessage(0);
        break;
    case WM_KEYDOWN:
        if (VK_ESCAPE == wParam)
        {
            ::DestroyWindow(hwnd);
        }
        break;
    }

    return ::DefWindowProc(hwnd, msg, wParam, lParam);
}

/*
* 主函数 WinMain
*/
int WINAPI WinMain(HINSTANCE hInstance,
                   HINSTANCE hPreInstance,
                   PSTR pCmdLine,
                   int nShowCmd)
{
    // 初始化
    // 上面声明的 4 个指针, 在这里作为参数传给 InitD3D 函数
    if (!d3d::InitD3D(hInstance,
        800,
        600,
        &renderTargetView,
        &immediateContext,
        &swapChain,
        &device))
    {
        ::MessageBox(0, L"InitD3D() - FAILED", 0, 0);

        return 0;
    }
    if (!Setup())
    {
        ::MessageBox(0, L"Setup() - FAILED", 0, 0);

        return 0;
    }

    // 执行消息循环, 将函数 Display 的指针作为参数传递
    d3d::EnterMsgLoop(Display);

    Cleanup();

    return 0;
}

运行结果:

运行结果

项目工程:https://github.com/YLD10/VisualStudio_Projects/tree/master/DirectX11_3D/D3DTriangle

猜你喜欢

转载自blog.csdn.net/yld10/article/details/80544907
今日推荐