I have a problem using DirectX::SpriteFont
/DirectX::SpriteBatch
(from DirectXTK; exactly the same problem as discussed here: Problems when drawing text
Here is the complete code:
#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
First, as you are using DirectXTK, you don't need DirectXTex. DirectXTex is intended for texture processing tools, while DirectXTK texture loaders are more suited to use in applications. See this blog post.
Second, don't use the ancient timeGetTime
function. You can use GetTickCount
, although GetTickCount64
is better as it avoids overflow problems. For frame timing, however, these are not really precise enough. You should take a look at the StepTimer.h used in the DirectX Tool Kit tutorials.
Third, you should look at using Microsoft::WRL::ComPtr
rather than all the SAFE_RELEASE
macro stuff. See this page for details.
Your code was including
xinput.h
as well. You should take a look at using DirectX Tool Kit's GamePad instead which has a number of benefits. If nothing else, it uses XInput more robustly than you likely would.
With all that said, your problem is quite simple: You set the render state up for your scene in InitScene
, but drawing anything else changes the state which is exactly what SpriteBatch
does. I document which render states each object in DirectX Toolkit manipulates on the wiki.
You need to set all the state your Draw requires each frame, not assume it is set forever, if you do more than a single draw.
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.");
}
}
You can generally 'set it and forget it' for the viewport state RSSetViewports
which also implicitly sets the scissors state, but a better usage is to set it at the start of each frame when you do your initial Clear
. This is the pattern I use in the Direct3D Game Templates.