DirectX::SpriteFont/SpriteBatch 阻止 3D 场景绘制

问题描述 投票:0回答:2

我在使用

DirectX::SpriteFont
/
DirectX::SpriteBatch
时遇到问题(来自 DirectXTK;与此处讨论的问题完全相同:使用 SpriteFont 类绘制文本时出现问题)。

void DrawScene(void)
{
    HRESULT hr;
    
    float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };

    g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);
    g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);
    XMVECTOR pos = XMLoadFloat3(&g_camera._pos);
    XMVECTOR target = XMLoadFloat3(&g_camera._target);
    XMVECTOR up = XMLoadFloat3(&g_camera._up);
    XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);
    XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));
    XMMATRIX wvp = worldBox2 * cameraView * cameraProj;
    XMMATRIX transposeWvp = XMMatrixTranspose(wvp);
    XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);
    g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);
    g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);

    g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);
    g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);

    // box
    g_pDeviceContext->DrawIndexed(36, 0, 0);
        
    wchar_t buffer[32];
    swprintf_s(buffer, 32, L"%.2f", g_fps._fps);

    //g_pSpriteBatch->Begin();
    //g_pSpriteFont->DrawString(g_pSpriteBatch, buffer, XMFLOAT2(30, 30));
    //g_pSpriteBatch->End();
    
    // Present the backbuffer to the screen
    hr = g_pSwapChain->Present(0, 0);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot present without error.");
    }
}

如果没有调用

SpriteBatch::Begin()
SpriteFont::DrawString
SpriteBatch::End()
,您将看到一个在空间中旋转的纹理立方体(笼子)。通过调用所描述的函数,您将只能看到左上角的每秒帧数,而看不到旋转的立方体。

我遵循了 github DirectXTK 上的 Chuck Walbourn 的教程,并结合了 2 个教程:使用

SpriteFont
绘制字符串并渲染原始 3D 对象(一个简单的三角形)。在此示例中,我将看到测试字符串绘制在三角形上。但我不明白为什么在使用 DirectXTK 的
SpriteFont
类绘制文本字符串时,我的示例中的旋转立方体不可见,我什至找不到根本原因。

像素着色器文件(PixelShader.hlsl):

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
    float2 TexCoord : TEXCOORD;
};

Texture2D ObjTexture;
SamplerState ObjSamplerState;

float4 PS( VS_OUTPUT input ) : SV_TARGET
{
    float4 diffuse = ObjTexture.Sample(ObjSamplerState, input.TexCoord);
    clip(diffuse.a - 0.25);
    return diffuse;
}

顶点着色器文件(VertexShader.hlsl):

cbuffer constantBufferPerObject
{
    float4x4 WVP;
    float ColorAdjust;
    int Mode;
    int Pad[2];
};

struct VS_OUTPUT
{
    float4 Pos : SV_POSITION;
    float4 Color : COLOR;
    float2 TexCoord : TEXCOORD;
};

VS_OUTPUT VS( float4 pos : POSITION, float4 color : COLOR_ZERO, float4 color2 : COLOR_ONE, float2 texCoord : TEXCOORD )
{
    VS_OUTPUT output;
    float4 temp;
    output.Pos = mul(pos, WVP);  
    temp = color;
    output.Color.r = temp.r * color2.r * (1.0f - ColorAdjust);
    output.Color.g = temp.g * color2.g * (1.0f - ColorAdjust);
    output.Color.b = temp.b * color2.b * (1.0f - ColorAdjust);
    output.Color.a = color.a * color2.a;
    output.TexCoord = texCoord;
    return output;
}

重现问题:我正在使用 Visual Studio 2015 Community Edition。我将 DirectXTK (.lib) 和 DirectXTex (

WICTextureLoader
.cpp/.h,
DDSTextureLoader
.cpp/.h, .lib) 添加到我的项目中。立方体的图像是带 alpha 的 .png。

c++ 3d directx-11 spritefont
2个回答
5
投票

首先,由于您使用的是 DirectXTK,因此不需要 DirectXTex。 DirectXTex 旨在用于纹理处理工具,而 DirectXTK 纹理加载器更适合在应用程序中使用。请参阅此博文

第二,不要使用古老的

timeGetTime
功能。您可以使用
GetTickCount
,尽管
GetTickCount64
更好,因为它可以避免溢出问题。然而,对于帧计时来说,这些还不够精确。您应该查看 DirectX Tool Kit 教程中使用的 StepTimer.h

第三,你应该考虑使用

Microsoft::WRL::ComPtr
而不是所有
SAFE_RELEASE
宏东西。详情请参阅此页

您的代码还包括

xinput.h
。您应该考虑使用 DirectX 工具套件的 GamePad,它有很多好处。如果不出意外的话,它使用 XInput 的能力比您想象的要强大。

综上所述,您的问题非常简单:您在

InitScene
中为场景设置渲染状态,但是绘制任何东西都会更改状态,这正是
SpriteBatch
所做的。我在 wiki 上记录了 DirectX Toolkit 中每个对象的渲染状态。

如果您进行多次绘制,则需要设置绘制所需的每一帧的所有状态,而不是假设它永远设置。

void DrawScene(void)
{
    HRESULT hr;

    float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };

    g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);
    g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

//>>>> THESE WERE MOVED FROM INITSCENE ABOVE!
    // Set Vertex and Pixel Shaders
    g_pDeviceContext->VSSetShader(g_pVertexShader, 0, 0);
    g_pDeviceContext->PSSetShader(g_pPixelShader, 0, 0);

    // Set the vertex buffer
    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;
    g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pTriangleVertexBuffer, &stride, &offset);

    g_pDeviceContext->IASetIndexBuffer(g_pSquareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Set the Input Layout
    g_pDeviceContext->IASetInputLayout(g_pVertexLayout);

    // Set Primitive Topology
    g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 3 vertices per triangle
                                                                                     //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); // 1 vertex per point
                                                                                     //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); // 2 vertices per line

                                                                                     // Create the Viewport

    g_pDeviceContext->RSSetState(g_pNoCullSolid);
//THESE WERE MOVED FROM INITSCENE ABOVE! <<<<

    XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);
    XMVECTOR pos = XMLoadFloat3(&g_camera._pos);
    XMVECTOR target = XMLoadFloat3(&g_camera._target);
    XMVECTOR up = XMLoadFloat3(&g_camera._up);
    XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);
    XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));
    XMMATRIX wvp = worldBox2 * cameraView * cameraProj;
    XMMATRIX transposeWvp = XMMatrixTranspose(wvp);
    XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);
    g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);
    g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);

    g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);
    g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);

    // box
    g_pDeviceContext->DrawIndexed(36, 0, 0);

    wchar_t buffer[32];
    swprintf_s(buffer, 32, L"%.2f", g_fps._fps);

    g_pSpriteBatch->Begin();
    g_pSpriteFont->DrawString(g_pSpriteBatch, buffer, XMFLOAT2(30, 30));
    g_pSpriteBatch->End();

    // Present the backbuffer to the screen
    hr = g_pSwapChain->Present(0, 0);
//>>>> This behavior means the app crashes if you hit a DEVICE_REMOVED or DEVICE_RESET.
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot present without error.");
    }
}

您通常可以为视口状态“设置它并忘记它”

RSSetViewports
,这也隐式设置剪刀状态,但更好的用法是在执行初始
Clear
时在每帧开始时设置它。这是我在 Direct3D 游戏模板中使用的模式。


0
投票

完整代码如下:

#include <Windows.h>
#include <stdio.h>
#include <Xinput.h>
#include <DirectXMath.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <DirectXTex.h>
#include <SpriteFont.h>

#include "DDSTextureLoader.h"
#include "WICTextureLoader.h"

using namespace DirectX;

#define CAMERA_ROTATION_SPEED (110.0f)
#define CAMERA_TARGET_DISTANCE (3.0f)
#define CAMERA_TARGET_VIEW_Y_START (-15.0f)
#define CAMERA_TARGET_VIEW_XZ_START (0.0f)
#define CAMERA_TARGET_START (XMVectorSet(0.0f, 0.0f, 0.0f, 0.0f))
#define CAMERA_UP_START (XMVectorSet(0.0f, 1.0f, 0.0f, 0.0f))
#define CAMERA_POS_START (XMVectorSet(0.0f, 0.0f, 3.0f, 0.0f))

#define PLAYER_MOVEMENT_SPEED (5.0f)

#define SAFE_DELETE(p) if (p) { delete (p); (p) = NULL; }
#define SAFE_RELEASE(p) if (p) { (p)->Release(); (p) = NULL; }

#ifdef _DEBUG
#define ErrorBoxW(msg) MessageBox(NULL, (msg), L"Error", MB_OK | MB_ICONERROR)
#else // _DEBUG
#define ErrorBox(msg)
#endif // _DEBUG

#define NORMALIZE_ANGLE(ang) { while ((ang) > 360.0f) { (ang) -= 360.0f; } while ((ang) < -360.0f) { (ang) += 360.0f; } }
#define LIMIT_ANGLE(ang, val) { if ((ang) > (val)) { (ang) = (val); } if ((ang) < -(val)) { (ang) = -(val); } }
#define CHECK_CHANGE_F(curr, prev, flag) { (flag) = (curr) != (prev); }

typedef struct _Camera
{
    XMFLOAT3 _target;
    XMFLOAT3 _pos;
    XMFLOAT3 _up;
    float _viewRotXZ;
    float _viewRotY;
    XMFLOAT4X4 _cameraProjection;
} Camera;

typedef struct _FPS
{
    _FPS(void)
        : _elapsedTime(0.0f), _frames(0), _fps(0.0f) {}
    void Calc(float timeDelta)
    {
        _elapsedTime += timeDelta;
        _frames++;

        if (_elapsedTime >= 1.0f)
        {
            _fps = (float)_frames / _elapsedTime;

            _elapsedTime = 0.0f;
            _frames = 0;

#ifdef _DEBUG
            wchar_t buffer[32];
            swprintf_s(buffer, 32, L"FPS: %.2f\n", _fps);
            OutputDebugString(buffer);
#endif // _DEBUG
        }
    }

    float _fps;
    float _elapsedTime;
    int _frames;
} FPS;

typedef struct _Player
{
    _Player(void)
        : _moveX(0.0f), _moveY(0.0f), _moveZ(0.0f) {}

    float _moveX;
    float _moveY;
    float _moveZ;
} Player;

using namespace DirectX;

typedef struct _SimpleVertex
{
    _SimpleVertex() {}
    _SimpleVertex(float x, float y, float z, float cr, float cg, float cb, float ca, float cr2, float cg2, float cb2, float ca2, float u, float v)
        : _pos(x, y, z), _color0(cr, cg, cb, ca), _color1(cr2, cg2, cb2, ca2), _tex(u, v) {}

    XMFLOAT3 _pos;
    XMFLOAT4 _color0;
    XMFLOAT4 _color1;
    XMFLOAT2 _tex;
} SimpleVertex;

// sizeof(ConstantBufferPerObject) = 80; multiple of 16
typedef struct _ConstantBufferPerObject
{
    XMFLOAT4X4 _wvp; // sizeof(XMFLOAT4X4) = 64
    float _colorAdjust; // sizeof(float) = 4; 68
    int _mode; // sizeof(int) = 4; 72
    int _pad[2]; // 2 * sizeof(int) = 8; 80
} ConstantBufferPerObject;

LPWSTR const g_windowClassName = L"dx11demo";
LPWSTR const g_windowTitle = L"DirectX11Demo";
HWND g_hwnd = NULL;
HINSTANCE g_hinstance = NULL;
const int g_width = 800;
const int g_height = 600;
IDXGISwapChain *g_pSwapChain = NULL;
ID3D11Device *g_pDevice = NULL;
ID3D11DeviceContext *g_pDeviceContext = NULL;
ID3D11RenderTargetView *g_pRenderTargetView = NULL;
ID3D11Buffer *g_pTriangleVertexBuffer = NULL;
ID3D11Buffer *g_pSquareIndexBuffer = NULL;
ID3D11VertexShader *g_pVertexShader = NULL;
ID3D11PixelShader *g_pPixelShader = NULL;
ID3DBlob *g_pVertexShaderBuffer = NULL;
ID3DBlob *g_pPixelShaderBuffer = NULL;
ID3D11DepthStencilView *g_pDepthStencilView = NULL;
ID3D11Buffer *g_pConstantBufferPerObject = NULL;
ID3D11Texture2D *g_pDepthStencilBuffer = NULL;
ID3D11InputLayout *g_pVertexLayout = NULL;
ID3D11ShaderResourceView *g_pCageTexture = NULL;
ID3D11ShaderResourceView *g_pBrickTexture = NULL;
ID3D11SamplerState *g_pCubeTextureSamplerState = NULL;
bool g_solid = true;
float g_rotBox2 = 0.0f;
ID3D11RasterizerState *g_pNoCullSolid = NULL;
ID3D11RasterizerState *g_pNoCullWireframe = NULL;
ID3D11RasterizerState *g_pCWCullSolid = NULL;
ID3D11RasterizerState *g_pCCWCullSolid = NULL;
ID3D11BlendState *g_pTransparency = NULL;
SpriteBatch *g_pSpriteBatch = NULL;
SpriteFont *g_pSpriteFont = NULL;
D3D11_INPUT_ELEMENT_DESC g_layout_a[] =
{
    { "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR_ZERO", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "COLOR_ONE", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 28, D3D11_INPUT_PER_VERTEX_DATA, 0 },
    { "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 44, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT g_numElements = ARRAYSIZE(g_layout_a);
bool g_isMoving = true;
ConstantBufferPerObject g_constantBufferPerObject;
bool g_enableDraw = true;
Player g_player;
Camera g_camera;
FPS g_fps;

void CleanUp(void);
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd);
bool InitD3D11(void);
bool InitScene(void);
void DrawScene(void);
void UpdateScene(float);

void UpdateScene(float timeDelta)
{
    g_rotBox2 += 20.0f * timeDelta;
    NORMALIZE_ANGLE(g_rotBox2);
}

void DrawScene(void)
{
    HRESULT hr;

    float bgColor_a[4] = { 0.0f, 0.4f, 0.8f, 0.0f };

    g_pDeviceContext->ClearRenderTargetView(g_pRenderTargetView, bgColor_a);
    g_pDeviceContext->ClearDepthStencilView(g_pDepthStencilView, D3D11_CLEAR_DEPTH | D3D11_CLEAR_STENCIL, 1.0f, 0);

    XMMATRIX cameraProj = XMLoadFloat4x4(&g_camera._cameraProjection);
    XMVECTOR pos = XMLoadFloat3(&g_camera._pos);
    XMVECTOR target = XMLoadFloat3(&g_camera._target);
    XMVECTOR up = XMLoadFloat3(&g_camera._up);
    XMMATRIX cameraView = XMMatrixLookAtLH(pos, target, up);
    XMMATRIX worldBox2 = XMMatrixIdentity() * (XMMatrixTranslation(2.0f, 0.0f, 0.0f) * XMMatrixRotationY(XMConvertToRadians(g_rotBox2)));
    XMMATRIX wvp = worldBox2 * cameraView * cameraProj;
    XMMATRIX transposeWvp = XMMatrixTranspose(wvp);
    XMStoreFloat4x4(&g_constantBufferPerObject._wvp, transposeWvp);
    g_pDeviceContext->UpdateSubresource(g_pConstantBufferPerObject, 0, NULL, &g_constantBufferPerObject, 0, 0);
    g_pDeviceContext->VSSetConstantBuffers(0, 1, &g_pConstantBufferPerObject);

    g_pDeviceContext->PSSetShaderResources(0, 1, &g_pCageTexture);
    g_pDeviceContext->PSSetSamplers(0, 1, &g_pCubeTextureSamplerState);

    // box
    g_pDeviceContext->DrawIndexed(36, 0, 0);

    wchar_t buffer[32];
    swprintf_s(buffer, 32, L"%.2f", g_fps._fps);

    //g_pSpriteBatch->Begin();
    //g_pSpriteFont->DrawString(g_pSpriteBatch, buffer, XMFLOAT2(30, 30));
    //g_pSpriteBatch->End();

    // Present the backbuffer to the screen
    hr = g_pSwapChain->Present(0, 0);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot present without error.");
    }
}

bool InitScene(void)
{
    HRESULT hr;
    ID3DBlob *pErrorBlob = NULL;
    UINT flags = D3DCOMPILE_ENABLE_STRICTNESS;
#ifdef _DEBUG
    flags |= D3DCOMPILE_DEBUG;
#endif // _DEBUG

    const D3D_SHADER_MACRO defines_a[] =
    {
        { NULL, NULL }
    };

    // Compile Shaders from shader file
    // https://msdn.microsoft.com/de-de/library/windows/desktop/hh968107(v=vs.85).aspx
    hr = D3DCompileFromFile(L"VertexShader.hlsl", defines_a, D3D_COMPILE_STANDARD_FILE_INCLUDE, "VS", "vs_5_0", flags, 0, &g_pVertexShaderBuffer, &pErrorBlob);
    if (FAILED(hr))
    {
        SAFE_RELEASE(pErrorBlob);
        ErrorBoxW(L"Cannot compile vertex shader VS vs_5_0.");
        return false;
    }

    hr = D3DCompileFromFile(L"PixelShader.hlsl", defines_a, D3D_COMPILE_STANDARD_FILE_INCLUDE, "PS", "ps_5_0", flags, 0, &g_pPixelShaderBuffer, &pErrorBlob);
    if (FAILED(hr))
    {
        SAFE_RELEASE(pErrorBlob);
        ErrorBoxW(L"Cannot compile pixel shader PS ps_5_0.");
        return false;
    }

    // Create the Shader Objects
    hr = g_pDevice->CreateVertexShader(g_pVertexShaderBuffer->GetBufferPointer(), g_pVertexShaderBuffer->GetBufferSize(), NULL, &g_pVertexShader);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create vertex shader.");
        return false;
    }

    hr = g_pDevice->CreatePixelShader(g_pPixelShaderBuffer->GetBufferPointer(), g_pPixelShaderBuffer->GetBufferSize(), NULL, &g_pPixelShader);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create pixel shader.");
        return false;
    }

    // Set Vertex and Pixel Shaders
    g_pDeviceContext->VSSetShader(g_pVertexShader, 0, 0);
    g_pDeviceContext->PSSetShader(g_pPixelShader, 0, 0);

    // Create the vertex buffer (vertices must be in clock-wise order)
    SimpleVertex vertices_a[] =
    {
        // Front Face
        /* 11 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 12 */ SimpleVertex(-1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 13 */ SimpleVertex(1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 14 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Back Face
        /* 15 */ SimpleVertex(-1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
        /* 16 */ SimpleVertex(1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 17 */ SimpleVertex(1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 18 */ SimpleVertex(-1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),

        // Top Face
        /* 19 */ SimpleVertex(-1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 20 */ SimpleVertex(-1.0f, 1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 21 */ SimpleVertex(1.0f, 1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 22 */ SimpleVertex(1.0f, 1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Bottom Face
        /* 23 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
        /* 24 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 25 */ SimpleVertex(1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 26 */ SimpleVertex(-1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),

        // Left Face
        /* 27 */ SimpleVertex(-1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 28 */ SimpleVertex(-1.0f,  1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 29 */ SimpleVertex(-1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 30 */ SimpleVertex(-1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),

        // Right Face
        /* 31 */ SimpleVertex(1.0f, -1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 3.0f),
        /* 32 */ SimpleVertex(1.0f,  1.0f, -1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 0.0f, 0.0f),
        /* 33 */ SimpleVertex(1.0f,  1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 0.0f),
        /* 34 */ SimpleVertex(1.0f, -1.0f,  1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 3.0f, 3.0f),
    };

    D3D11_BUFFER_DESC vertexBufferDesc;
    ZeroMemory(&vertexBufferDesc, sizeof(vertexBufferDesc));

    vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    vertexBufferDesc.ByteWidth = sizeof(SimpleVertex) * 24;
    vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
    vertexBufferDesc.CPUAccessFlags = 0;
    vertexBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA vertexBufferData;
    ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
    vertexBufferData.pSysMem = vertices_a;
    hr = g_pDevice->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &g_pTriangleVertexBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create triangle buffer.");
        return false;
    }

    // Set the vertex buffer
    UINT stride = sizeof(SimpleVertex);
    UINT offset = 0;
    g_pDeviceContext->IASetVertexBuffers(0, 1, &g_pTriangleVertexBuffer, &stride, &offset);

    DWORD indices_a[] =
    {
        // Front Face
        /*  5 */ 0,  1,  2,
        /*  6 */ 0,  2,  3,

        // Back Face
        /*  7 */ 4,  5,  6,
        /*  8 */ 4,  6,  7,

        // Top Face
        /*  9 */ 8,  9, 10,
        /* 10 */ 8, 10, 11,

        // Bottom Face
        /* 11 */ 12, 13, 14,
        /* 12 */ 12, 14, 15,

        // Left Face
        /* 13 */ 16, 17, 18,
        /* 14 */ 16, 18, 19,

        // Right Face
        /* 15 */ 20, 21, 22,
        /* 16 */ 20, 22, 23,
    };

    D3D11_BUFFER_DESC indexBufferDesc;
    ZeroMemory(&indexBufferDesc, sizeof(indexBufferDesc));

    indexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    indexBufferDesc.ByteWidth = sizeof(DWORD) * 12 * 3;
    indexBufferDesc.BindFlags = D3D11_BIND_INDEX_BUFFER;
    indexBufferDesc.CPUAccessFlags = 0;
    indexBufferDesc.MiscFlags = 0;

    D3D11_SUBRESOURCE_DATA iinitData;
    ZeroMemory(&iinitData, sizeof(D3D11_SUBRESOURCE_DATA));
    iinitData.pSysMem = indices_a;
    hr = g_pDevice->CreateBuffer(&indexBufferDesc, &iinitData, &g_pSquareIndexBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create index buffer.");
        return false;
    }

    g_pDeviceContext->IASetIndexBuffer(g_pSquareIndexBuffer, DXGI_FORMAT_R32_UINT, 0);

    // Create the Input Layout
    hr = g_pDevice->CreateInputLayout(g_layout_a, g_numElements, g_pVertexShaderBuffer->GetBufferPointer(), g_pVertexShaderBuffer->GetBufferSize(), &g_pVertexLayout);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create input layout.");
        return false;
    }

    // Set the Input Layout
    g_pDeviceContext->IASetInputLayout(g_pVertexLayout);

    // Set Primitive Topology
    g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST); // 3 vertices per triangle
    //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_POINTLIST); // 1 vertex per point
    //g_pDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_LINELIST); // 2 vertices per line

    // Create the Viewport
    D3D11_VIEWPORT viewport;
    ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));

    viewport.TopLeftX = 0;
    viewport.TopLeftY = 0;
    viewport.Width = g_width; // divide by 4 to only use 1/4 of client area (width)
    viewport.Height = g_height; // divide by 4 to only use 1/4 of client area (height)
    viewport.MinDepth = 0.0f;
    viewport.MaxDepth = 1.0f;

    //Set the Viewport
    g_pDeviceContext->RSSetViewports(1, &viewport);

    // Create the buffer to send to the cbuffer in effect file
    D3D11_BUFFER_DESC constantBufferDesc;
    ZeroMemory(&constantBufferDesc, sizeof(D3D11_BUFFER_DESC));

    constantBufferDesc.Usage = D3D11_USAGE_DEFAULT;
    constantBufferDesc.ByteWidth = sizeof(ConstantBufferPerObject);
    constantBufferDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
    constantBufferDesc.CPUAccessFlags = 0;
    constantBufferDesc.MiscFlags = 0;

    hr = g_pDevice->CreateBuffer(&constantBufferDesc, NULL, &g_pConstantBufferPerObject);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create constant buffer.");
        return false;
    }

    D3D11_RASTERIZER_DESC rasterizerDesc;
    ZeroMemory(&rasterizerDesc, sizeof(D3D11_RASTERIZER_DESC));

    rasterizerDesc.FillMode = D3D11_FILL_SOLID;
    rasterizerDesc.CullMode = D3D11_CULL_NONE;
    rasterizerDesc.FrontCounterClockwise = true;
    hr = g_pDevice->CreateRasterizerState(&rasterizerDesc, &g_pNoCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create rasterizer state (no culling, solid).");
        return false;
    }

    rasterizerDesc.FillMode = D3D11_FILL_WIREFRAME;
    hr = g_pDevice->CreateRasterizerState(&rasterizerDesc, &g_pNoCullWireframe);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create rasterizer state (no culling, wireframe).");
        return false;
    }

    g_pDeviceContext->RSSetState(g_pNoCullSolid);

    hr = CreateWICTextureFromFile(g_pDevice, L"tcage.png", NULL, &g_pCageTexture);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create shader resource view (cage).");
        return false;
    }

    D3D11_SAMPLER_DESC sampDesc;
    ZeroMemory(&sampDesc, sizeof(sampDesc));

    sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
    sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
    sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
    sampDesc.MinLOD = 0;
    sampDesc.MaxLOD = D3D11_FLOAT32_MAX;

    hr = g_pDevice->CreateSamplerState(&sampDesc, &g_pCubeTextureSamplerState);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create sampler state.");
        return false;
    }

    D3D11_BLEND_DESC blendDesc; // Define the Blending Equation
    ZeroMemory(&blendDesc, sizeof(blendDesc));

    D3D11_RENDER_TARGET_BLEND_DESC rtbd;
    ZeroMemory(&rtbd, sizeof(rtbd));

    rtbd.BlendEnable = true;
    rtbd.SrcBlend = D3D11_BLEND_SRC_COLOR;
    rtbd.DestBlend = D3D11_BLEND_BLEND_FACTOR;
    rtbd.BlendOp = D3D11_BLEND_OP_ADD;
    rtbd.SrcBlendAlpha = D3D11_BLEND_ONE;
    rtbd.DestBlendAlpha = D3D11_BLEND_ZERO;
    rtbd.BlendOpAlpha = D3D11_BLEND_OP_ADD;
    rtbd.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;

    blendDesc.AlphaToCoverageEnable = false;
    blendDesc.RenderTarget[0] = rtbd;

    hr = g_pDevice->CreateBlendState(&blendDesc, &g_pTransparency);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create blend state.");
        return false;
    }

    // Create the Counter Clockwise and Clockwise Culling States
    D3D11_RASTERIZER_DESC cmdesc;
    ZeroMemory(&cmdesc, sizeof(D3D11_RASTERIZER_DESC));

    cmdesc.FillMode = D3D11_FILL_SOLID;
    cmdesc.CullMode = D3D11_CULL_BACK;
    cmdesc.FrontCounterClockwise = true;
    hr = g_pDevice->CreateRasterizerState(&cmdesc, &g_pCCWCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create ccw cull mode.");
        return false;
    }

    cmdesc.FrontCounterClockwise = false;
    hr = g_pDevice->CreateRasterizerState(&cmdesc, &g_pCWCullSolid);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create cw cull mode.");
        return false;
    }

    g_pSpriteBatch = new SpriteBatch(g_pDeviceContext);
    if (!g_pSpriteBatch)
    {
        ErrorBoxW(L"Cannot create sprite batch.");
        return false;
    }

    g_pSpriteFont = new SpriteFont(g_pDevice, L"arial.font");
    if (!g_pSpriteFont)
    {
        ErrorBoxW(L"Cannot create sprite font.");
        return false;
    }

    XMStoreFloat3(&g_camera._target, CAMERA_TARGET_START);
    XMStoreFloat3(&g_camera._pos, CAMERA_POS_START);
    XMStoreFloat3(&g_camera._up, CAMERA_UP_START);
    g_camera._viewRotXZ = CAMERA_TARGET_VIEW_XZ_START;
    g_camera._viewRotY = CAMERA_TARGET_VIEW_Y_START;

    // Set the Projection matrix
    XMStoreFloat4x4(&g_camera._cameraProjection, XMMatrixPerspectiveFovLH(XMConvertToRadians(45.0f), (float)g_width / (float)g_height, 0.1f, 1000.0f));

    return true;
}

bool InitD3D11(void)
{   
    HRESULT hr;

    DXGI_MODE_DESC bufferDesc; // Describe our Buffer
    ZeroMemory(&bufferDesc, sizeof(DXGI_MODE_DESC));

    bufferDesc.Width = g_width;
    bufferDesc.Height = g_height;
    bufferDesc.RefreshRate.Numerator = 60;
    bufferDesc.RefreshRate.Denominator = 1;
    bufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
    bufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
    bufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;

    DXGI_SWAP_CHAIN_DESC swapChainDesc; // Describe our SwapChain
    ZeroMemory(&swapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));

    swapChainDesc.BufferDesc = bufferDesc;
    swapChainDesc.SampleDesc.Count = 1;
    swapChainDesc.SampleDesc.Quality = 0;
    swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
    swapChainDesc.BufferCount = 1;
    swapChainDesc.OutputWindow = g_hwnd;
    swapChainDesc.Windowed = TRUE;
    swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;

    //Create our SwapChain
    hr = D3D11CreateDeviceAndSwapChain(
        NULL,
        D3D_DRIVER_TYPE_HARDWARE,
        NULL,
        D3D11_CREATE_DEVICE_DEBUG,
        NULL,
        NULL,
        D3D11_SDK_VERSION,
        &swapChainDesc,
        &g_pSwapChain,
        &g_pDevice,
        NULL,
        &g_pDeviceContext);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create swap chain, device and device context.");
        return false;
    }

    ID3D11Texture2D* backBuffer; // Create our BackBuffer
    hr = g_pSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&backBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create back buffer.");
        return false;
    }

    // Create our Render Target
    hr = g_pDevice->CreateRenderTargetView(backBuffer, NULL, &g_pRenderTargetView);
    SAFE_RELEASE(backBuffer); // release back buffer in any case
    if (FAILED(hr))
    {   
        ErrorBoxW(L"Cannot create render target view.");
        return false;
    }

    D3D11_TEXTURE2D_DESC depthStencilDesc; // Describe our Depth/Stencil Buffer
    ZeroMemory(&depthStencilDesc, sizeof(D3D11_TEXTURE2D_DESC));

    depthStencilDesc.Width = g_width;
    depthStencilDesc.Height = g_height;
    depthStencilDesc.MipLevels = 1;
    depthStencilDesc.ArraySize = 1;
    depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
    depthStencilDesc.SampleDesc.Count = 1;
    depthStencilDesc.SampleDesc.Quality = 0;
    depthStencilDesc.Usage = D3D11_USAGE_DEFAULT;
    depthStencilDesc.BindFlags = D3D11_BIND_DEPTH_STENCIL;
    depthStencilDesc.CPUAccessFlags = 0;
    depthStencilDesc.MiscFlags = 0;

    // Create the Depth/Stencil View
    hr = g_pDevice->CreateTexture2D(&depthStencilDesc, NULL, &g_pDepthStencilBuffer);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create depth stencil buffer.");
        return false;
    }

    hr = g_pDevice->CreateDepthStencilView(g_pDepthStencilBuffer, NULL, &g_pDepthStencilView);
    if (FAILED(hr))
    {
        ErrorBoxW(L"Cannot create depth stencil view.");
        return false;
    }

    // Set our Render Target
    g_pDeviceContext->OMSetRenderTargets(1, &g_pRenderTargetView, g_pDepthStencilView);

    return true;
}

void CleanUp(void)
{
    SAFE_RELEASE(g_pDevice);
    SAFE_RELEASE(g_pDeviceContext);
    SAFE_RELEASE(g_pPixelShader);
    SAFE_RELEASE(g_pPixelShaderBuffer);
    SAFE_RELEASE(g_pRenderTargetView);
    SAFE_RELEASE(g_pSwapChain);
    SAFE_RELEASE(g_pTriangleVertexBuffer);
    SAFE_RELEASE(g_pVertexLayout);
    SAFE_RELEASE(g_pVertexShader);
    SAFE_RELEASE(g_pVertexShaderBuffer);
    SAFE_RELEASE(g_pSquareIndexBuffer);
    SAFE_RELEASE(g_pDepthStencilBuffer);
    SAFE_RELEASE(g_pDepthStencilView);
    SAFE_RELEASE(g_pConstantBufferPerObject);
    SAFE_RELEASE(g_pNoCullSolid);
    SAFE_RELEASE(g_pNoCullWireframe);
    SAFE_RELEASE(g_pCageTexture);
    SAFE_RELEASE(g_pBrickTexture);
    SAFE_RELEASE(g_pCubeTextureSamplerState);
    SAFE_RELEASE(g_pTransparency);
    SAFE_RELEASE(g_pCWCullSolid);
    SAFE_RELEASE(g_pCCWCullSolid);
    SAFE_DELETE(g_pSpriteBatch);
    SAFE_DELETE(g_pSpriteFont);
}

LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
    // Check message
    switch (msg)
    {
    case WM_KEYDOWN:
        // if escape key was pressed, display popup box         
        if (wParam == VK_ESCAPE)
        {
            if (MessageBox(0, L"Are you sure you want to exit?", L"Really?", MB_YESNO | MB_ICONQUESTION) == IDYES)
            {
                // Release the windows allocated memory  
                DestroyWindow(hwnd);
            }
        }
        return 0;

    case WM_DESTROY:
        // if x button in top right was pressed
        PostQuitMessage(0);
        return 0;
    }

    // return the message for windows to handle it
    return DefWindowProc(hwnd, msg, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd)
{
    UNREFERENCED_PARAMETER(lpCmdLine);
    UNREFERENCED_PARAMETER(hPrevInstance);

    g_hinstance = hInstance;

    WNDCLASSEX wc; // Create a new extended windows class
    ZeroMemory(&wc, sizeof(WNDCLASSEX));

    wc.cbSize = sizeof(WNDCLASSEX); // Size of our windows class
    wc.style = CS_HREDRAW | CS_VREDRAW; // class styles
    wc.lpfnWndProc = WndProc; // Default windows procedure function
    wc.cbClsExtra = NULL; // Extra bytes after our wc structure
    wc.cbWndExtra = NULL; // Extra bytes after our windows instance
    wc.hInstance = hInstance; // Instance to current application
    wc.hIcon = LoadIcon(NULL, IDI_WINLOGO); // Title bar Icon
    wc.hCursor = LoadCursor(NULL, IDC_ARROW); // Default mouse Icon
    wc.hbrBackground = (HBRUSH)(COLOR_WINDOW + 2); // Window bg color
    wc.lpszMenuName = NULL; // Name of the menu attached to our window
    wc.lpszClassName = g_windowClassName; // Name of our windows class
    wc.hIconSm = LoadIcon(NULL, IDI_WINLOGO); // Icon in your taskbar

    if (!RegisterClassEx(&wc)) // Register our windows class
    {
        ErrorBoxW(L"Error registering class");
        return 1;
    }

    // Create our Extended Window
    g_hwnd = CreateWindowEx(
        NULL, // Extended style
        g_windowClassName, // Name of our windows class
        g_windowTitle, // Name in the title bar of our window
        WS_OVERLAPPEDWINDOW ^ (WS_THICKFRAME | WS_MINIMIZEBOX | WS_MAXIMIZEBOX), // style of our window
        CW_USEDEFAULT, CW_USEDEFAULT, // Top left corner of window
        g_width, // Width of our window
        g_height, // Height of our window
        NULL, // Handle to parent window
        NULL, // Handle to a Menu
        hInstance, // Specifies instance of current program
        NULL // used for an MDI client window
        );

    // Make sure our window has been created
    if (!g_hwnd)
    {
        ErrorBoxW(L"Error creating window");
        return 1;
    }

    ShowWindow(g_hwnd, nShowCmd); // Shows our window
    UpdateWindow(g_hwnd); // Its good to update our window

    bool result;
    result = InitD3D11();
    if (result)
    {
        result = InitScene();
        if (result)
        {
            MSG msg; // Create a new message structure
            ZeroMemory(&msg, sizeof(MSG));

            DWORD timeLast = timeGetTime();
            DWORD timeCurr = timeLast;
            float timeDelta = 0.0f;
            bool run = true;
            //float elapsed = 0.0f;
            //float frameLimit = 1.0f / 60.0f;

            while (run)
            {
                // if there was a windows message
                while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
                {
                    // if the message was WM_QUIT
                    if (msg.message == WM_QUIT)
                    {
                        run = false; // Exit the message loop
                    }

                    TranslateMessage(&msg); // Translate the message
                    DispatchMessage(&msg); // Send the message to default windows procedure
                }

                timeCurr = timeGetTime();
                timeDelta = (float)(timeCurr - timeLast) / 1000.0f;

                //elapsed += timeDelta;
                //if (elapsed >= frameLimit)
                //{
                g_fps.Calc(timeDelta);

                UpdateScene(timeDelta);
                DrawScene();

                //elapsed = 0.0f;
                //}

                timeLast = timeCurr;
            }
        }
    }

    CleanUp();

    return 0; // return the message
}

Scene without SpriteFont

Scene with SpriteFont

© www.soinside.com 2019 - 2024. All rights reserved.