OpenGL 4 core profile, shaders and MFC - c++

I'm trying to get shaders to work in an MFC app with an OpenGL 4 core profile.
I did this in a Win32 app to make sure it works (it does, drawing a triangle in the lower part of the window):
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HWND hWnd;
hInst = hInstance; // Store instance handle in our global variable
hWnd = CreateWindow(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
m_hDC = ::GetDC(hWnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 32;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat(m_hDC, &pfd);
if (nPixelFormat == 0) return false;
BOOL bResult = SetPixelFormat(m_hDC, nPixelFormat, &pfd);
if (!bResult) return false;
HGLRC tempContext = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, tempContext);
GLenum err = glewInit();
if (GLEW_OK != err)
{
MessageBox(hWnd, (LPCWSTR)L"Glew not initialized", (LPCWSTR)L"Error", MB_ICONEXCLAMATION);
}
//Get a GL 4,2 context
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 4,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_FLAGS_ARB, 0,
0
};
if (wglewIsSupported("WGL_ARB_create_context") == 1)
{
m_hRC = wglCreateContextAttribsARB(m_hDC, 0, attribs);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(tempContext);
wglMakeCurrent(m_hDC, m_hRC);
}
else
{ //It's not possible to make a GL 4.x context. Use the old style context (GL 2.1 and before)
m_hRC = tempContext;
}
if (!m_hRC) return false;
static const char * vs_source[] =
{
"#version 420 core \n"
" \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 2.25, -2.25, 0.5, 1.0), \n"
" vec4(-2.25, -2.25, 0.5, 1.0), \n"
" vec4( 2.25, 2.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 420 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(1.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
const GLfloat green[] = { 0.0f, 0.25f, 0.0f, 1.0f };
//
// FUNCTION: WndProc(HWND, UINT, WPARAM, LPARAM)
//
// PURPOSE: Processes messages for the main window.
//
// WM_COMMAND - process the application menu
// WM_PAINT - Paint the main window
// WM_DESTROY - post a quit message and return
//
//
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
int wmId, wmEvent;
PAINTSTRUCT ps;
HDC hdc;
switch (message)
{
case WM_COMMAND:
wmId = LOWORD(wParam);
wmEvent = HIWORD(wParam);
// Parse the menu selections:
switch (wmId)
{
case IDM_ABOUT:
DialogBox(hInst, MAKEINTRESOURCE(IDD_ABOUTBOX), hWnd, About);
break;
case IDM_EXIT:
DestroyWindow(hWnd);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
break;
case WM_PAINT:
//hdc = BeginPaint(hWnd, &ps);
// TODO: Add any drawing code here...
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);
SwapBuffers(m_hDC);
//EndPaint(hWnd, &ps);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}
Then I did the same in an MFC MDI program and although the background gets cleared to the same color as the Win32 app, the shaders don't draw anything.
For completion, here's the relevant code in my MFC MDI view class (it's different from the code in the Win32 app because I've been trying to figure out what's wrong, but it was once the same as the Win32 app code and it didn't work):
int CMFCApplication2View::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: Add your specialized creation code here
m_hDC = ::GetDC(m_hWnd);
PIXELFORMATDESCRIPTOR pfd;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.iLayerType = PFD_MAIN_PLANE;
int nPixelFormat = ChoosePixelFormat(m_hDC, &pfd);
if (nPixelFormat == 0) return false;
BOOL bResult = SetPixelFormat(m_hDC, nPixelFormat, &pfd);
if (!bResult) return false;
HGLRC tempContext = wglCreateContext(m_hDC);
wglMakeCurrent(m_hDC, tempContext);
glewExperimental = GL_TRUE;
GLenum err = glewInit();
if (GLEW_OK != err)
{
AfxMessageBox(_T("GLEW is not initialized!"));
}
//This is a modern pixel format attribute list.
//It has an extensible structure. Just add in more argument pairs
//befroe the null to request more features.
const int attribList[] =
{
WGL_DRAW_TO_WINDOW_ARB, GL_TRUE,
WGL_SUPPORT_OPENGL_ARB, GL_TRUE,
WGL_ACCELERATION_ARB, WGL_FULL_ACCELERATION_ARB,
WGL_DOUBLE_BUFFER_ARB, GL_TRUE,
WGL_PIXEL_TYPE_ARB, WGL_TYPE_RGBA_ARB,
WGL_COLOR_BITS_ARB, 32,
WGL_DEPTH_BITS_ARB, 24,
WGL_STENCIL_BITS_ARB, 8,
0, 0 //End
};
unsigned int numFormats;
int pixelFormat;
memset(&pfd, 0, sizeof(PIXELFORMATDESCRIPTOR));
//Select a pixel format number
wglChoosePixelFormatARB(m_hDC, attribList, NULL, 1, &pixelFormat, &numFormats);
//Optional: Get the pixel format's description. We must provide a
//description to SetPixelFormat(), but its contents mean little.
//According to MSDN:
// The system's metafile component uses this structure to record the logical
// pixel format specification. The structure has no other effect upon the
// behavior of the SetPixelFormat function.
//DescribePixelFormat(m_pDC->GetSafeHdc(), pixelFormat, sizeof(PIXELFORMATDESCRIPTOR), &pfd);
//Set it as the current
if (FALSE == SetPixelFormat(m_hDC, pixelFormat, &pfd))
{
}
//Get a GL 4,4 context
int attribs[] =
{
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 2,
WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
//WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_COMPATIBILITY_PROFILE_BIT_ARB,
0, 0 //End
};
if (wglewIsSupported("WGL_ARB_create_context") == 1)
{
m_hRC = wglCreateContextAttribsARB(m_hDC, 0, attribs);
wglMakeCurrent(NULL, NULL);
wglDeleteContext(tempContext);
wglMakeCurrent(m_hDC, m_hRC);
}
else
{ //It's not possible to make a GL 4.x context. Use the old style context (GL 2.1 and before)
m_hRC = tempContext;
}
if (!m_hRC) return false;
static const char * vs_source[] =
{
"#version 150 core \n"
" \n"
"void main(void) \n"
"{ \n"
" const vec4 vertices[] = vec4[](vec4( 2.25, -2.25, 0.5, 1.0), \n"
" vec4(-2.25, -2.25, 0.5, 1.0), \n"
" vec4( 2.25, 2.25, 0.5, 1.0)); \n"
" \n"
" gl_Position = vertices[gl_VertexID]; \n"
"} \n"
};
static const char * fs_source[] =
{
"#version 150 core \n"
" \n"
"out vec4 color; \n"
" \n"
"void main(void) \n"
"{ \n"
" color = vec4(1.0, 0.8, 1.0, 1.0); \n"
"} \n"
};
program = glCreateProgram();
GLuint fs = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fs, 1, fs_source, NULL);
glCompileShader(fs);
GLuint vs = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vs, 1, vs_source, NULL);
glCompileShader(vs);
glAttachShader(program, vs);
glAttachShader(program, fs);
glLinkProgram(program);
glGenVertexArrays(1, &vao);
glBindVertexArray(vao);
wglMakeCurrent(NULL, NULL);
return 0;
}
void CMFCApplication2View::OnDraw(CDC*/* pDC*/)
{
CMFCApplication2Doc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: add draw code for native data here
// Make the rendering context current
wglMakeCurrent(m_hDC, m_hRC);
// TODO: add draw code for native data here
static const GLfloat green[] = { 1.0f, 0.0f, 0.0f, 1.0f };
glClearBufferfv(GL_COLOR, 0, green);
glUseProgram(program);
glDrawArrays(GL_TRIANGLES, 0, 3);
SwapBuffers(m_hDC);
// Allow other rendering contexts to coexist
wglMakeCurrent(NULL, NULL);
}
I ran both executables through AMD's GPU Perfstudio. The Win32 frame debug show everything is ok. The MFC frame debug shows the frame buffer with a size of 0 (the frame buffer size of the win32 app is the size of the window). Both apps API traces are the same.
Any idea on what might be going on?

Apparently OpenGL in MFC, when using a core profile, needs to have a view port set, via glViewport.
Handling WM_SIZE and doing glViewport(0, 0, (GLsizei)cx, (GLsizei)cy) solved the issue.
As a note, Andon was correct in saying that I shouldn't specify the pixel format twice. It didn't give any error, which is strange, but when I removed it everything kept on working.

Related

Unable to glTranslate() light source

I am having a problem translating the light source.
I have coded a program that accepts up, down, left, and right keys to increase/decrease the x, y, and z values to reposition the light source. But the problem right now is the x, y, and z value does change but the light source remains in the same place. I believe the problem shall be somewhere inside the void lighting() function.
below is my code:
#include <Windows.h>
#include <gl/GL.h>
#include <math.h>
#include <gl/GLU.h>
#pragma comment (lib, "OpenGL32.lib") //link library
#pragma comment(lib, "Winmm.lib")
#define WINDOW_TITLE "Lighting"
bool isOrtho = true;
float ONear = -10.0, OFar = 10.0; //Ortho Near & Far
float PNear = 1.0, PFar = 21.0; //Perspective Near & Far
float exeDif[3] = { 1.0,0.0,0.0 }; //Red diffuse light
float x =6 , y=0, z=0;
float exePosD[3] = { 6,0,0 };
float exeDifM[3] = { 1.0,0.0,0.0 };
bool isLightOn = false; //is light on?
LRESULT WINAPI WindowProcedure(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);//quit application
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE) PostQuitMessage(0);
else if (wParam == VK_SPACE) {
isLightOn = !isLightOn;
}
else if (wParam == VK_UP) {
y = y + 1.0;
}
else if (wParam == VK_DOWN) {
y = y - 1.0;
}
else if (wParam == VK_LEFT) {
x = x - 1.0;
}
else if (wParam == VK_RIGHT) {
x = x + 1.0;
}
else if (wParam == 'Q') {
z = z - 1.0;
}
else if (wParam == 'E') {
z = z + 1.0;
}
break;
default:
break;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}
bool initPixelFormat(HDC hdc)
{
PIXELFORMATDESCRIPTOR pfd;
ZeroMemory(&pfd, sizeof(PIXELFORMATDESCRIPTOR));
pfd.cAlphaBits = 8;
pfd.cColorBits = 32;
pfd.cDepthBits = 24;
pfd.cStencilBits = 0;
pfd.dwFlags = PFD_DOUBLEBUFFER | PFD_SUPPORT_OPENGL | PFD_DRAW_TO_WINDOW;
pfd.iLayerType = PFD_MAIN_PLANE;
pfd.iPixelType = PFD_TYPE_RGBA;
pfd.nSize = sizeof(PIXELFORMATDESCRIPTOR);
pfd.nVersion = 1;
// choose pixel format returns the number most similar pixel format available
int n = ChoosePixelFormat(hdc, &pfd);
// set pixel format returns whether it sucessfully set the pixel format
if (SetPixelFormat(hdc, n, &pfd))
{
return true;
}
else
{
return false;
}
}
void lighting() {
if (isLightOn) {
glEnable(GL_LIGHTING); //Turon on lighting for the whole scene
}
else {
//Turn off lighting for the whole screen
glDisable(GL_LIGHTING);
}
glPushMatrix();
glTranslatef(x, y, z);
glLightfv(GL_LIGHT0, GL_POSITION, exePosD);
glPopMatrix();
glLightfv(GL_LIGHT0, GL_DIFFUSE, exeDif);
glEnable(GL_LIGHT0);
}
void projection() {
glMatrixMode(GL_PROJECTION); //refer to projection matrix
glLoadIdentity(); //reset projection matrix
if (isOrtho) {
//Ortho View
glOrtho(-10.0, 10.0, -10.0, 10.0, ONear, OFar); //Ortho view
}
else {
//Perspective view
gluPerspective(20, 1.0, -1.0, 1.0);
glFrustum(-10.0, 10.0, -10.0, 10.0, PNear, PFar);
}
}
void drawSphere(double r) {
GLUquadricObj* sphere = NULL;
sphere = gluNewQuadric();
gluQuadricDrawStyle(sphere, GLU_FILL);
gluSphere(sphere, r, 30, 30);
gluDeleteQuadric(sphere);
}
void display()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
projection(); //projection
lighting();
glMatrixMode(GL_MODELVIEW); //refer to modelview matrix
glLoadIdentity(); //reset
drawSphere(3.0);
//red color diffuse
glMaterialfv(GL_FRONT, GL_DIFFUSE, exeDifM);
glColor3f(0.0, 0.0, 1.0); //blue
drawSphere(3.0);
}
int WINAPI WinMain(HINSTANCE hInst, HINSTANCE, LPSTR, int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.hInstance = GetModuleHandle(NULL);
wc.lpfnWndProc = WindowProcedure;
wc.lpszClassName = WINDOW_TITLE;
wc.style = CS_HREDRAW | CS_VREDRAW;
if (!RegisterClassEx(&wc)) return false;
HWND hWnd = CreateWindow(WINDOW_TITLE, WINDOW_TITLE, WS_OVERLAPPEDWINDOW,
720, 10, 300, 300,
NULL, NULL, wc.hInstance, NULL);
//--------------------------------
// Initialize window for OpenGL
//--------------------------------
HDC hdc = GetDC(hWnd);
// initialize pixel format for the window
initPixelFormat(hdc);
// get an openGL context
HGLRC hglrc = wglCreateContext(hdc);
// make context current
if (!wglMakeCurrent(hdc, hglrc)) return false;
//--------------------------------
// End initialization
//--------------------------------
ShowWindow(hWnd, nCmdShow);
MSG msg;
ZeroMemory(&msg, sizeof(msg));
while (true)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
display();
SwapBuffers(hdc);
}
UnregisterClass(WINDOW_TITLE, wc.hInstance);
return true;
}
This is the output screen:
The light position is transformed with the modelview matrix, but not with the projection matrix. Therefore you need to switch to the modelview matrix after projection() and before lighting():
projection(); //projection
glMatrixMode(GL_MODELVIEW); //refer to modelview matrix
glLoadIdentity();
lighting();

Why is D2D drawing under D3D11?

My intuition is that if X is drawn before Y then X will be under Y. However, my code seems to always draw things drawn by D2D under things drawn by D3D11. This happens regardless of whether I'm using a depth buffer or not. Why is it doing this and how can I make D2D draw over D3D11 so that I can use D2D to create a GUI overlay?
Here is the smallest reproducible sample I could make:
#include <Windows.h>
#include <string>
#include <d3d11.h>
#include <d2d1.h>
#include <wrl.h>
#include <d3dcompiler.h>
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d2d1.lib")
#pragma comment(lib, "d3dcompiler.lib")
using namespace std;
using namespace Microsoft::WRL;
// Globals
HWND g_hWnd;
// D3D11
ComPtr<ID3D11Device> g_device;
ComPtr<ID3D11DeviceContext> g_context;
ComPtr<IDXGISwapChain> g_swapChain;
ComPtr<ID3D11RenderTargetView> g_renderTarget;
ComPtr<ID3D11Buffer> g_triangleVertexBuffer;
// D2D
ComPtr<ID2D1RenderTarget> g_renderTarget2D;
ComPtr<ID2D1Factory> g_factory2D;
// Utilities
constexpr const char* VERTEX_SHADER_CODE =
R"(
float4 main(float2 pos : POSITION) : SV_Position
{
return float4(pos, 0.0f, 1.0f);
}
)";
constexpr const char* PIXEL_SHADER_CODE =
R"(
float4 main() : SV_Target
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
)";
struct Vector2f
{
float x, y;
Vector2f() : x(0.0f), y(0.0f) { }
Vector2f(float x, float y) : x(x), y(y) { }
};
void AssertHResult(HRESULT hr, string errorMsg)
{
if (FAILED(hr))
throw std::exception(errorMsg.c_str());
}
void CompileShaderFromString(string code, string shaderType, ID3DBlob** output)
{
AssertHResult(D3DCompile(
code.c_str(),
code.length(),
nullptr,
nullptr,
nullptr,
"main",
shaderType.c_str(),
#ifdef _DEBUG
D3DCOMPILE_DEBUG |
#else
D3DCOMPILE_OPTIMIZATION_LEVEL3 |
#endif
D3DCOMPILE_ENABLE_STRICTNESS,
NULL,
output,
nullptr
), "Failed to compile shader");
}
// Graphics stuff
void InitializeD2D()
{
// Get swap chain surface
ComPtr<IDXGISurface> surface;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(IDXGISurface),
static_cast<void**>(&surface)
), "Failed to get surface of swap chain");
// Create factory
AssertHResult(D2D1CreateFactory<ID2D1Factory>(
D2D1_FACTORY_TYPE_SINGLE_THREADED,
&g_factory2D
), "Failed to create factory");
// Create render target
D2D1_RENDER_TARGET_PROPERTIES rtDesc = D2D1::RenderTargetProperties(
D2D1_RENDER_TARGET_TYPE_HARDWARE,
D2D1::PixelFormat(DXGI_FORMAT_UNKNOWN, D2D1_ALPHA_MODE_PREMULTIPLIED)
);
AssertHResult(g_factory2D->CreateDxgiSurfaceRenderTarget(
surface.Get(),
&rtDesc,
&g_renderTarget2D
), "Failed to create D2D render target");
}
void InitializeD3D()
{
// Get window dimensions
RECT rect{};
GetClientRect(g_hWnd, &rect);
float width = static_cast<float>(rect.right - rect.left);
float height = static_cast<float>(rect.bottom - rect.top);
// Create device, context, and swapchain
DXGI_SWAP_CHAIN_DESC scDesc{};
scDesc.BufferCount = 1;
scDesc.BufferDesc.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
scDesc.BufferDesc.Width = static_cast<UINT>(width);
scDesc.BufferDesc.Height = static_cast<UINT>(height);
scDesc.BufferDesc.RefreshRate.Numerator = 0;
scDesc.BufferDesc.RefreshRate.Denominator = 0;
scDesc.BufferDesc.Scaling = DXGI_MODE_SCALING_UNSPECIFIED;
scDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;
scDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scDesc.Flags = NULL;
scDesc.OutputWindow = g_hWnd;
scDesc.SampleDesc.Count = 1;
scDesc.SampleDesc.Quality = 0;
scDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
scDesc.Windowed = true;
AssertHResult(D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
#ifdef _DEBUG
D3D11_CREATE_DEVICE_DEBUG |
#endif
D3D11_CREATE_DEVICE_BGRA_SUPPORT,
nullptr,
NULL,
D3D11_SDK_VERSION,
&scDesc,
&g_swapChain,
&g_device,
nullptr,
&g_context
), "Failed to create device and swapchain");
// Create render target
ComPtr<ID3D11Resource> backBuffer;
AssertHResult(g_swapChain->GetBuffer(
0,
__uuidof(ID3D11Resource),
static_cast<void**>(&backBuffer)
), "Failed to get back buffer of swapchain");
AssertHResult(g_device->CreateRenderTargetView(
backBuffer.Get(),
nullptr,
&g_renderTarget
), "Failed to create render target view");
// Bind render target
g_context->OMSetRenderTargets(
1,
g_renderTarget.GetAddressOf(),
nullptr
);
// Bind viewport
D3D11_VIEWPORT viewport{};
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = width;
viewport.Height = height;
g_context->RSSetViewports(
1,
&viewport
);
}
void InitializeD3DTriangle()
{
// Create vertex buffer
Vector2f vertices[3] =
{
Vector2f(-0.5f, -0.5f),
Vector2f(0.0f, 0.5f),
Vector2f(0.5f, -0.5f)
};
D3D11_BUFFER_DESC vbDesc{};
vbDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vbDesc.ByteWidth = static_cast<UINT>(sizeof(Vector2f) * 3);
vbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
vbDesc.MiscFlags = NULL;
vbDesc.StructureByteStride = sizeof(Vector2f);
vbDesc.Usage = D3D11_USAGE_DYNAMIC;
D3D11_SUBRESOURCE_DATA vbData{};
vbData.pSysMem = vertices;
AssertHResult(g_device->CreateBuffer(
&vbDesc,
&vbData,
&g_triangleVertexBuffer
), "Failed to create vertex buffer");
// Bind vertex buffer
const UINT offset = 0;
const UINT stride = sizeof(Vector2f);
g_context->IASetVertexBuffers(
0,
1,
g_triangleVertexBuffer.GetAddressOf(),
&stride,
&offset
);
// Create and bind vertex shader
ComPtr<ID3DBlob> vsBlob;
ComPtr<ID3D11VertexShader> vertexShader;
CompileShaderFromString(
VERTEX_SHADER_CODE,
"vs_4_0",
&vsBlob
);
AssertHResult(g_device->CreateVertexShader(
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
nullptr,
&vertexShader
), "Failed to create vertex shader");
g_context->VSSetShader(
vertexShader.Get(),
nullptr,
NULL
);
// Create and bind pixel shader
ComPtr<ID3DBlob> pxBlob;
ComPtr<ID3D11PixelShader> pixelShader;
CompileShaderFromString(
PIXEL_SHADER_CODE,
"ps_4_0",
&pxBlob
);
AssertHResult(g_device->CreatePixelShader(
pxBlob->GetBufferPointer(),
pxBlob->GetBufferSize(),
nullptr,
&pixelShader
), "Failed to create pixel shader");
g_context->PSSetShader(
pixelShader.Get(),
nullptr,
NULL
);
// Set topology
g_context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY::D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Create input layout
ComPtr<ID3D11InputLayout> inputLayout;
D3D11_INPUT_ELEMENT_DESC ilDesc{};
ilDesc.AlignedByteOffset = 0;
ilDesc.Format = DXGI_FORMAT_R32G32_FLOAT;
ilDesc.SemanticName = "POSITION";
ilDesc.SemanticIndex = 0;
ilDesc.InputSlot = 0;
ilDesc.InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
ilDesc.InstanceDataStepRate = 0;
AssertHResult(g_device->CreateInputLayout(
&ilDesc,
1,
vsBlob->GetBufferPointer(),
vsBlob->GetBufferSize(),
&inputLayout
), "Failed to create input layout");
// Bind input layout
g_context->IASetInputLayout(inputLayout.Get());
}
// Windows
LRESULT CALLBACK WndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch (msg)
{
case WM_DESTROY:
PostQuitMessage(0);
break;
default:
return DefWindowProcW(hWnd, msg, wParam, lParam);
}
return 0;
}
void InitializeWindow(HINSTANCE hInst, int width, int height)
{
// Register window class
WNDCLASSEXW wc{};
wc.cbSize = sizeof(WNDCLASSEXW);
wc.hCursor = LoadCursorW(NULL, IDC_ARROW);
wc.hInstance = hInst;
wc.lpfnWndProc = WndProc;
wc.lpszClassName = L"MainWindow";
wc.style = CS_OWNDC;
RegisterClassExW(&wc);
// Adjust width and height to be client area instead of window area
RECT rc{};
rc.left = 0;
rc.top = 0;
rc.right = width;
rc.bottom = height;
constexpr auto ws = WS_OVERLAPPEDWINDOW;
AdjustWindowRectEx(
&rc,
ws,
false,
NULL
);
// Instantiate and show window
g_hWnd = CreateWindowExW(
NULL,
L"MainWindow",
L"Window Title",
ws,
CW_USEDEFAULT,
CW_USEDEFAULT,
static_cast<int>(rc.right - rc.left),
static_cast<int>(rc.bottom - rc.top),
NULL,
NULL,
hInst,
nullptr
);
ShowWindow(g_hWnd, SW_SHOW);
}
// Driver code
void Update()
{
// Begin frame
g_renderTarget2D->BeginDraw();
// Clear screen to black
D2D1_COLOR_F bgColour = { 0.0f, 0.0f, 0.0f, 1.0f };
g_renderTarget2D->Clear(bgColour);
// Draw D3D triangle
g_context->Draw(
3,
0
);
// Draw D2D rectangle
D2D_RECT_F rect{};
rect.bottom = 500;
rect.top = 300;
rect.left = 100;
rect.right = 700;
D2D1_COLOR_F rectColour = { 0.0f, 1.0f, 0.0f, 1.0f };
ComPtr<ID2D1SolidColorBrush> brush;
g_renderTarget2D->CreateSolidColorBrush(
rectColour,
&brush
);
g_renderTarget2D->FillRectangle(
rect,
brush.Get()
);
// End frame
AssertHResult(g_swapChain->Present(
1,
NULL
), "Failed to present swapchain");
g_renderTarget2D->EndDraw();
}
int APIENTRY wWinMain(HINSTANCE hInst, HINSTANCE prevInst, LPWSTR cmdArgs, int cmdShow)
{
InitializeWindow(hInst, 800, 600);
InitializeD3D();
InitializeD2D();
InitializeD3DTriangle();
// Run message loop
while (true)
{
// Handle windows messages
MSG msg{};
PeekMessageW(&msg, NULL, 0, 0, PM_REMOVE);
TranslateMessage(&msg);
DispatchMessageW(&msg);
if (msg.message == WM_QUIT)
break;
// Quit is escape is pressed
if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
break;
// Do frame
Update();
}
return 0;
}
If you want to control the draw order, then you shouldn't be drawing both at the same time. Call Draw, then BeginDraw / EndDraw. Don't mix them as you have no idea when Direct2D is actually flushing commands to the context in your code, and you have no explicit indication of when Direct3D is done drawing to the render target.
You can of course call Direct3D's Flush which will force all work on the GPU to complete, but it's horribly inefficient to call it every frame.

D3D11 shaders compiles successfully, but I get a white screen

I'm setting up d3d11 to learn the basics, but I'm having some trouble. I have no errors and everything compiles fine, but ending up with a white window. Am I missing something here? there should be a colored quad in the window. Sorry for any mistakes in asking the question. This is my first post here.
CPP FILE:
#include <Windows.h>
#include <d3d11.h>
#include <d3dcompiler.h>
#include <iostream>
struct Vec3
{
float x, y, z;
};
struct Vertex
{
Vec3 position;
Vec3 color;
};
bool running = true;
HWND hwndApp;
LRESULT CALLBACK AppWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (uMsg == WM_DESTROY)
{
running = false;
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
int main()
{
WNDCLASSEX appWndClass = { };
appWndClass.lpfnWndProc = AppWndProc;
appWndClass.cbSize = sizeof(WNDCLASSEX);
appWndClass.cbClsExtra = NULL;
appWndClass.cbWndExtra = NULL;
appWndClass.hbrBackground = (HBRUSH)COLOR_WINDOW;
appWndClass.hCursor = LoadCursor(NULL, IDC_ARROW);
appWndClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
appWndClass.style = NULL;
appWndClass.hInstance = GetModuleHandle(NULL);
appWndClass.lpszClassName = "AppWndClass";
appWndClass.lpszMenuName = "";
RegisterClassEx(&appWndClass);
hwndApp = CreateWindowEx(
WS_EX_OVERLAPPEDWINDOW,
appWndClass.lpszClassName,
"AppWndClass",
WS_CAPTION | WS_SYSMENU,
CW_USEDEFAULT, CW_USEDEFAULT, 1024, 768,
NULL,
NULL,
GetModuleHandle(NULL),
NULL
);
ShowWindow(hwndApp, SW_SHOW);
UpdateWindow(hwndApp);
ID3D11Device* d3dDevice = nullptr;
ID3D11DeviceContext* d3dDeviceContext = nullptr;
IDXGIDevice* dxgiDevice = nullptr;
IDXGIAdapter* dxgiAdapter = nullptr;
IDXGIFactory* dxgiFactory = nullptr;
IDXGISwapChain* dxgiSwapChain = nullptr;
ID3D11RenderTargetView* renderTargetView = nullptr;
D3D_FEATURE_LEVEL featureLevel;
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0
};
D3D11CreateDevice(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
0,
featureLevels,
ARRAYSIZE(featureLevels),
D3D11_SDK_VERSION,
&d3dDevice,
&featureLevel,
&d3dDeviceContext
);
if (d3dDevice == nullptr) return -1;
if (d3dDeviceContext == nullptr) return -1;
d3dDevice->QueryInterface(__uuidof(IDXGIDevice), (void**)& dxgiDevice);
dxgiDevice->GetAdapter(&dxgiAdapter);
dxgiAdapter->GetParent(__uuidof(IDXGIFactory), (void**)& dxgiFactory);
RECT rc;
GetClientRect(hwndApp, &rc);
DXGI_SWAP_CHAIN_DESC swapChainDescription;
ZeroMemory(&swapChainDescription, sizeof(swapChainDescription));
swapChainDescription.BufferCount = 1;
swapChainDescription.BufferDesc.Width = rc.right - rc.left;
swapChainDescription.BufferDesc.Height = rc.bottom - rc.top;
swapChainDescription.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapChainDescription.BufferDesc.RefreshRate.Numerator = 60;
swapChainDescription.BufferDesc.RefreshRate.Denominator = 1;
swapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapChainDescription.OutputWindow = hwndApp;
swapChainDescription.SampleDesc.Count = 1;
swapChainDescription.SampleDesc.Quality = 0;
swapChainDescription.Windowed = TRUE;
dxgiFactory->CreateSwapChain(d3dDevice, &swapChainDescription, &dxgiSwapChain);
ID3D11Texture2D* buffer = nullptr;
dxgiSwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)& buffer);
if (buffer == nullptr) return -1;
d3dDevice->CreateRenderTargetView(buffer, nullptr, &renderTargetView);
buffer->Release();
if (renderTargetView == nullptr) return -1;
Vertex vertices[] =
{
{ -0.5f, -0.5f, 0.0f, 0, 0, 0 },
{ -0.5f, 0.5f, 0.0f, 1, 1, 0 },
{ 0.5f, -0.5f, 0.0f, 0, 0, 1 },
{ 0.5f, 0.5f, 0.0f, 1, 1, 1 }
};
UINT sizeVertices = ARRAYSIZE(vertices);
D3D11_INPUT_ELEMENT_DESC inputElementDescription[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA , 0 },
{ "COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
UINT sizeInputElementDescription = ARRAYSIZE(inputElementDescription);
D3D11_BUFFER_DESC bufferDescription = {};
bufferDescription.Usage = D3D11_USAGE_DEFAULT;
bufferDescription.ByteWidth = sizeof(Vertex) * sizeVertices;
bufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bufferDescription.CPUAccessFlags = 0;
bufferDescription.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA initialData = {};
initialData.pSysMem = vertices;
ID3D11Buffer* vertexBuffer;
d3dDevice->CreateBuffer(&bufferDescription, &initialData, &vertexBuffer);
void* shaderByteCode = nullptr;
size_t byteCodeLength = 0;
ID3DBlob* blobCode = nullptr;
ID3DBlob* blobErrorMsgs = nullptr;
//D3DCompileFromFile( L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs );
if (!SUCCEEDED(D3DCompileFromFile(L"VertexShader.hlsl", nullptr, nullptr, "vsmain", "vs_5_0", 0, 0, &blobCode, &blobErrorMsgs)))
{
if (blobErrorMsgs) blobErrorMsgs->Release();
std::cout << "ERROR COMPILING VERTEXSHADER" << std::endl;
return false;
}
shaderByteCode = blobCode->GetBufferPointer();
byteCodeLength = blobCode->GetBufferSize();
ID3D11VertexShader* vertexShader;
d3dDevice->CreateVertexShader(shaderByteCode, byteCodeLength, nullptr, &vertexShader);
vertexShader->Release();
ID3D11InputLayout* inputLayout;
d3dDevice->CreateInputLayout(inputElementDescription, sizeInputElementDescription, shaderByteCode, byteCodeLength, &inputLayout);
blobCode->Release();
void* shaderByteCode2 = nullptr;
size_t byteCodeLength2 = 0;
ID3DBlob* blobCode2 = nullptr;
ID3DBlob* blobErrorMsgs2 = nullptr;
//D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2);
if (!SUCCEEDED(D3DCompileFromFile(L"PixelShader.hlsl", nullptr, nullptr, "psmain", "ps_5_0", 0, 0, &blobCode2, &blobErrorMsgs2)))
{
if (blobErrorMsgs2) blobErrorMsgs2->Release();
std::cout << "ERROR COMPILING PIXELSHADER" << std::endl;
return false;
}
shaderByteCode2 = blobCode2->GetBufferPointer();
byteCodeLength2 = blobCode2->GetBufferSize();
ID3D11PixelShader* pixelShader;
d3dDevice->CreatePixelShader(shaderByteCode2, byteCodeLength2, nullptr, &pixelShader);
pixelShader->Release();
blobCode2->Release();
FLOAT clearColor[] = { 0.0, 0.0, 0.0, 1.0 };
while (running)
{
d3dDeviceContext->ClearRenderTargetView(renderTargetView, clearColor);
d3dDeviceContext->OMSetRenderTargets(1, &renderTargetView, NULL);
GetClientRect(hwndApp, &rc);
D3D11_VIEWPORT vp = {};
vp.Width = rc.right - rc.left;
vp.Height = rc.bottom - rc.top;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
d3dDeviceContext->RSSetViewports(1, &vp);
d3dDeviceContext->VSSetShader(vertexShader, nullptr, 0);
d3dDeviceContext->PSSetShader(pixelShader, nullptr, 0);
UINT stride = sizeof(Vertex);
UINT offset = 0;
d3dDeviceContext->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
d3dDeviceContext->IASetInputLayout(inputLayout);
d3dDeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLESTRIP);
d3dDeviceContext->Draw(sizeVertices, 0);
dxgiSwapChain->Present(true, NULL);
MSG msg = { 0 };
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE) > 0)
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
renderTargetView->Release();
inputLayout->Release();
vertexBuffer->Release();
dxgiDevice->Release();
dxgiAdapter->Release();
dxgiFactory->Release();
d3dDeviceContext->Release();
d3dDevice->Release();
return 0;
}
VertexShader
struct VS_INPUT
{
float4 position: POSITION;
float3 color: COLOR;
};
struct VS_OUTPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
VS_OUTPUT vsmain(VS_INPUT input)
{
VS_OUTPUT output = (VS_OUTPUT)0;
output.position = input.position;
output.color = input.color;
return output;
}
PixelShader
struct PS_INPUT
{
float4 position: SV_POSITION;
float3 color: COLOR;
};
float4 psmain(PS_INPUT input) : SV_TARGET
{
return float4(input.color,1.0f);
}
I expect the window to show a multicolored quad, but the window is all white.
Shaders was released and then used later in code.
vertexShader->Release();
pixelShader->Release();
moving the release of shaders to the end of the program solved it.

DirectX 11. Hello Triangle not rendering

I've been debugging this for about a day now and everything seems okay. Im trying to get a simple tringle to render, but nothing is showing up. I have a Pixel Shader and a Vertex Shader which is compiling okay.
I will supply all of the code, any help would be greatly appreciated.
Main C++ File:
#include <windows.h>
#include <D3D11_1.h>
static int ScreenWidth = 1280;
static int ScreenHeight = 720;
static bool GlobalRunning;
static ID3D11Device *Device;
static ID3D11DeviceContext *DeviceContext;
static IDXGISwapChain1 *SwapChain;
static ID3D11RenderTargetView *RenderTargetView;
#define Assert(Expression) if(!(Expression)) { *(int *)0 = 0;}
struct vec3
{
float X;
float Y;
float Z;
};
struct vec4
{
float X;
float Y;
float Z;
float W;
};
struct vertex
{
vec3 Position;
vec4 Color;
};
static int
SafeTruncateUInt64(LONG Value)
{
Assert(Value <= 0xFFFFFFFF);
int Result = (int)Value;
return(Result);
}
struct read_file_result
{
void *Contents;
int ContentsSize;
};
static read_file_result
Win32LoadEntireFile(char *Filename)
{
read_file_result Result = {};
HANDLE File = CreateFileA(Filename, GENERIC_READ, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
if(File != INVALID_HANDLE_VALUE)
{
LARGE_INTEGER FileSize;
if(GetFileSizeEx(File, &FileSize))
{
int FileSize32 = SafeTruncateUInt64(FileSize.QuadPart);
Result.Contents = VirtualAlloc(0, FileSize32, MEM_RESERVE|MEM_COMMIT, PAGE_READWRITE);
if(Result.Contents)
{
DWORD BytesRead;
if(ReadFile(File, Result.Contents, FileSize32, &BytesRead, 0) && BytesRead == FileSize32)
{
Result.ContentsSize = FileSize32;
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
return(Result);
}
static LRESULT CALLBACK
Win32MainWindowCallback(HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
LRESULT Result = 0;
switch(Message)
{
case WM_ACTIVATEAPP:
{
// TODO(zak): Handle this
} break;
case WM_SIZE:
{
ScreenWidth = LOWORD(LParam);
ScreenHeight = HIWORD(LParam);
RenderTargetView->Release();
SwapChain->ResizeBuffers(0, ScreenWidth, ScreenHeight, DXGI_FORMAT_UNKNOWN, 0);
ID3D11Texture2D *BackBuffer;
if(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void **)&BackBuffer) == S_OK)
{
Device->CreateRenderTargetView(BackBuffer, 0, &RenderTargetView);
BackBuffer->Release();
}
} break;
case WM_QUIT:
{
GlobalRunning = false;
} break;
case WM_DESTROY:
{
GlobalRunning = false;
} break;
default:
{
Result = DefWindowProcA(Window, Message, WParam, LParam);
}
}
return(Result);
}
int CALLBACK
WinMain(HINSTANCE Instance,
HINSTANCE PrevInstance,
LPSTR CommandLine,
int ShowCode)
{
WNDCLASSA WindowClass = {};
WindowClass.style = CS_HREDRAW|CS_VREDRAW;
WindowClass.lpfnWndProc = Win32MainWindowCallback;
WindowClass.hInstance = Instance;
WindowClass.lpszClassName = "DXPlaygroundWindowClass";
if(RegisterClassA(&WindowClass))
{
RECT WindowRect;
WindowRect.top = 0;
WindowRect.bottom = ScreenHeight;
WindowRect.left = 0;
WindowRect.right = ScreenWidth;
AdjustWindowRect(&WindowRect, WS_OVERLAPPEDWINDOW, 0);
HWND Window =
CreateWindowExA(0,
WindowClass.lpszClassName,
"D3D Playground",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT,
WindowRect.right - WindowRect.left,
WindowRect.bottom - WindowRect.top,
0, 0, Instance, 0);
if(Window)
{
D3D_FEATURE_LEVEL FeatureLevelsRequested[3]
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
D3D_FEATURE_LEVEL FeatureLevelReturned;
if(D3D11CreateDevice(0,
D3D_DRIVER_TYPE_HARDWARE,
0,
0,
FeatureLevelsRequested,
3,
D3D11_SDK_VERSION,
&Device,
&FeatureLevelReturned,
&DeviceContext) == S_OK)
{
IDXGIFactory2 *Factory;
if(CreateDXGIFactory(__uuidof(IDXGIFactory2), (void **)&Factory) == S_OK)
{
DXGI_SWAP_CHAIN_DESC1 SwapChainDescription = {};
SwapChainDescription.Width = ScreenWidth;
SwapChainDescription.Height = ScreenHeight;
SwapChainDescription.Format = DXGI_FORMAT_B8G8R8A8_UNORM;
DXGI_SAMPLE_DESC SampleDescription = {};
SampleDescription.Count = 1;
SampleDescription.Quality = 0;
SwapChainDescription.SampleDesc = SampleDescription;
SwapChainDescription.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDescription.BufferCount = 2;
SwapChainDescription.Scaling = DXGI_SCALING_STRETCH;
SwapChainDescription.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
if(Factory->CreateSwapChainForHwnd(Device, Window,
&SwapChainDescription,
0, 0, &SwapChain) == S_OK)
{
ID3D11Texture2D *BackBuffer;
if(SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D),
(void **)&BackBuffer) == S_OK)
{
Device->CreateRenderTargetView(BackBuffer, 0, &RenderTargetView);
BackBuffer->Release();
}
ShowWindow(Window, SW_SHOWNORMAL);
read_file_result VertexShaderFile = Win32LoadEntireFile("shaders/testvertex.fxo");
read_file_result PixelShaderFile = Win32LoadEntireFile("shaders/testpixel.fxo");
ID3D11VertexShader *VertexShader;
ID3D11PixelShader *PixelShader;
Device->CreateVertexShader(VertexShaderFile.Contents,
VertexShaderFile.ContentsSize, 0, &VertexShader);
Device->CreatePixelShader(PixelShaderFile.Contents,
PixelShaderFile.ContentsSize, 0, &PixelShader);
DeviceContext->VSSetShader(VertexShader, 0, 0);
DeviceContext->PSSetShader(PixelShader, 0, 0);
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
ID3D11InputLayout *Layout;
Device->CreateInputLayout(ied, 2, VertexShaderFile.Contents, VertexShaderFile.ContentsSize, &Layout);
DeviceContext->IASetInputLayout(Layout);
vertex OurVerticies[3] = {};
OurVerticies[0].Position.Y = 0.5f;
OurVerticies[0].Color.X = 1.0f;
OurVerticies[0].Color.W = 1.0f;
OurVerticies[1].Position.X = 0.45f;
OurVerticies[1].Position.Y = -0.5f;
OurVerticies[1].Color.Y = 1.0f;
OurVerticies[1].Color.W = 1.0f;
OurVerticies[2].Position.X = -0.45f;
OurVerticies[2].Position.Y = -0.5f;
OurVerticies[2].Color.Z = 1.0f;
OurVerticies[2].Color.W = 1.0f;
ID3D11Buffer *VertexBuffer = 0;
D3D11_BUFFER_DESC BufferDescription = {};
BufferDescription.Usage = D3D11_USAGE_DYNAMIC;
BufferDescription.ByteWidth = sizeof(vertex) * 3;
BufferDescription.BindFlags = D3D11_BIND_VERTEX_BUFFER;
BufferDescription.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
Device->CreateBuffer(&BufferDescription, 0, &VertexBuffer);
D3D11_MAPPED_SUBRESOURCE MappedSubresource;
DeviceContext->Map(VertexBuffer, 0, D3D11_MAP_WRITE_DISCARD, 0, &MappedSubresource);
CopyMemory(MappedSubresource.pData, OurVerticies, sizeof(OurVerticies));
DeviceContext->Unmap(VertexBuffer, 0);
GlobalRunning = true;
while(GlobalRunning)
{
MSG Message;
while(PeekMessageA(&Message, 0, 0, 0, PM_REMOVE))
{
TranslateMessage(&Message);
DispatchMessageA(&Message);
}
FLOAT ClearColor[] = {0.0f, 0.0f, 1.0f, 1.0f};
DeviceContext->ClearRenderTargetView(RenderTargetView, ClearColor);
DeviceContext->OMSetRenderTargets(1, &RenderTargetView, 0);
UINT Stride = sizeof(vertex);
UINT Offset = 0;
DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &Stride, &Offset);
DeviceContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
DeviceContext->Draw(3, 0);
SwapChain->Present(1, 0);
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
}
else
{
// TODO(zak): Logging
}
return(0);
}
Pixel Shader
float4 main(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}
Vertex Shader
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut main(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
The code you've posted is missing error checking of the HRESULT on most of the Direct3D calls. If a COM call returns a void you don't have to handle the error, otherwise you do. You can do this with the SUCCEEDED macro, the FAILED macro, or with the ThrowIfFailed helper. I'd bet at least one of your calls is failing and you don't notice because you aren't checking for a failure result.
Second, you should enable the Debug device by passing D3D11_CREATE_DEVICE_DEBUG as the 4th parameter. Then look for ERROR or CORRUPTION messages in your debug output. See this post.
Not sure where you got your original "hello world" tutorial, but you should take a look at the Direct3D Game VS Templates and the DirectX Tool Kit.

Problems when drawing text using the SpriteFont class

I'm using the SpriteFont/SpriteBatch classes to render text onto my game because quite frankly, i am tired of using Direct2D and DirectWrite... But everytime I draw text using SpriteFont, I get the text written on the screen, but it is written on a black background... The black background blocks the entire scene of my game.. is there any way to remove the black background and only keep the text?
Down below is my implementation of SpriteFont..
void RenderText(int FPS)
{
std::unique_ptr<DirectX::SpriteFont> Sprite_Font(new DirectX::SpriteFont(device, L"myfile.spritefont"));
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch(new DirectX::SpriteBatch(DevContext));
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), L"FPS: ", DirectX::XMFLOAT2(200,200));
Sprite_Batch->End();
}
It seems to me that the black background is drawn because of the values that I specified in the function ClearRenderTargetView().
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor); //This is where the black background gets drawn over my entire scene
Everytime i change BackgroundColor[4] to different values, the background color changes as well, respectably. How can I remove the black background from my game and only include the text?
Here is my entire code.
#include <Windows.h>
#include <SpriteFont.h>
#include <SpriteBatch.h>
#include <d3dcompiler.h>
#include <SimpleMath.h>
#pragma comment (lib, "dinput8.lib")
#pragma comment (lib, "D3D11.lib")
#pragma comment (lib, "d3dcompiler.lib")
LRESULT CALLBACK WindowProcedure(HWND, unsigned int, WPARAM, LPARAM);
void Create_Window(HINSTANCE&);
void Initialize_Direct3D11(HINSTANCE);
void Initialize_Rendering_Pipeline();
void Initialize_Sprites();
void Render_Frame();
void Render_Text();
void Create_Vertex_Buffer_for_triangle();
HWND MainWindow;
IDXGISwapChain * SwapChain;
ID3D11Device * device;
ID3D11DeviceContext * DevContext;
ID3D11RenderTargetView * RenderTarget;
ID3D11Buffer * VertexBuffer;
ID3D10Blob * VertexShader;
ID3D10Blob * PixelShader;
ID3D11VertexShader * VS;
ID3D11PixelShader * PS;
ID3D11InputLayout * inputLayout;
std::unique_ptr<DirectX::SpriteFont> Sprite_Font;
std::unique_ptr<DirectX::SpriteBatch> Sprite_Batch;
DirectX::SimpleMath::Vector2 m_fontPos;
const wchar_t* output = L"Hello World";
struct Vertex_Buffer
{
float Positions[3];
Vertex_Buffer(float x, float y, float z)
{
Positions[0] = x;
Positions[1] = y;
Positions[2] = z;
};
};
int WINAPI WinMain(HINSTANCE CurrentInstance, HINSTANCE PrevInstance, LPSTR ignore, int WindowShow)
{
MSG message;
HRESULT status;
Create_Window(CurrentInstance);
Initialize_Direct3D11(CurrentInstance);
Initialize_Sprites();
Initialize_Rendering_Pipeline();
Create_Vertex_Buffer_for_triangle();
while (true)
{
if (PeekMessage(&message, MainWindow, 0, 0, PM_REMOVE))
{
TranslateMessage(&message);
DispatchMessage(&message);
}
else
{
Render_Frame();
Render_Text();
SwapChain->Present(0, 0);
}
}
}
void Initialize_Sprites()
{
Sprite_Font.reset(new DirectX::SpriteFont(device, L"myfile.spritefont"));
Sprite_Batch.reset(new DirectX::SpriteBatch(DevContext));
m_fontPos.x = 200;
m_fontPos.y = 200;
}
void Create_Window(HINSTANCE &CurrentInstance)
{
WNDCLASSEX windowclass;
ZeroMemory(&windowclass, sizeof(WNDCLASSEX));
windowclass.cbSize = sizeof(WNDCLASSEX);
windowclass.lpszClassName = L"Window Class";
windowclass.hInstance = CurrentInstance;
windowclass.lpfnWndProc = WindowProcedure;
windowclass.hIcon = LoadIcon(NULL, IDI_WINLOGO);
windowclass.hCursor = LoadCursor(NULL, IDC_ARROW);
RegisterClassEx(&windowclass);
MainWindow = CreateWindowEx(
0,
L"Window Class",
L"The Empire of Anatoria",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
CurrentInstance,
NULL
);
ShowWindow(MainWindow, SW_SHOW);
}
void Render_Text()
{
DirectX::SimpleMath::Vector2 origin = Sprite_Font->MeasureString(output);
Sprite_Batch->Begin();
Sprite_Font->DrawString(Sprite_Batch.get(), output,
m_fontPos, DirectX::Colors::White, 0.f, origin);
Sprite_Batch->End();
}
void Initialize_Direct3D11(HINSTANCE instance)
{
DXGI_MODE_DESC BackBufferDesc;
DXGI_SWAP_CHAIN_DESC SwapChainDesc;
ZeroMemory(&BackBufferDesc, sizeof(DXGI_MODE_DESC));
BackBufferDesc.Width = 400;
BackBufferDesc.Height = 400;
BackBufferDesc.RefreshRate.Numerator = 60;
BackBufferDesc.RefreshRate.Denominator = 1;
BackBufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
ZeroMemory(&SwapChainDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
SwapChainDesc.BufferDesc = BackBufferDesc;
SwapChainDesc.BufferCount = 1;
SwapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
SwapChainDesc.SampleDesc.Count = 1;
SwapChainDesc.SampleDesc.Quality = 0;
SwapChainDesc.OutputWindow = MainWindow;
SwapChainDesc.Windowed = TRUE;
SwapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&SwapChainDesc,
&SwapChain,
&device,
NULL,
&DevContext
);
ID3D11Texture2D * BackBuffer;
SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (void**)&BackBuffer);
device->CreateRenderTargetView(BackBuffer, NULL, &RenderTarget);
DevContext->OMSetRenderTargets(
1,
&RenderTarget,
NULL
);
BackBuffer->Release();
DevContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
}
void Initialize_Rendering_Pipeline()
{
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "main", "vs_5_0", 0, 0, &VertexShader, 0);
D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "Pixel_Shader", "ps_5_0", 0, 0, &PixelShader, 0);
device->CreateVertexShader(VertexShader->GetBufferPointer(), VertexShader->GetBufferSize(), NULL, &VS);
device->CreatePixelShader(PixelShader->GetBufferPointer(), PixelShader->GetBufferSize(), NULL, &PS);
DevContext->VSSetShader(VS, 0, 0);
DevContext->PSSetShader(PS, 0, 0);
D3D11_VIEWPORT Raster;
ZeroMemory(&Raster, sizeof(D3D11_VIEWPORT));
Raster.MinDepth = 0.0f;
Raster.MaxDepth = 1.0f;
Raster.Width = 400;
Raster.Height = 400;
DevContext->RSSetViewports(1, &Raster);
D3D11_INPUT_ELEMENT_DESC InputLayout[1];
ZeroMemory(&InputLayout[0], sizeof(D3D11_INPUT_ELEMENT_DESC));
InputLayout[0].SemanticName = "POSITION";
InputLayout[0].Format = DXGI_FORMAT_R32G32B32_FLOAT;
InputLayout[0].InputSlot = 0;
InputLayout[0].AlignedByteOffset = 0;
InputLayout[0].InputSlotClass = D3D11_INPUT_PER_VERTEX_DATA;
device->CreateInputLayout(
InputLayout,
1,
VertexShader->GetBufferPointer(),
VertexShader->GetBufferSize(),
&inputLayout
);
DevContext->IASetInputLayout(inputLayout);
}
void Render_Frame()
{
float BackgroundColor[4] = {0.0f, 0.0f, 0.0f, 1.0f};
DevContext->ClearRenderTargetView(RenderTarget, BackgroundColor);
DevContext->Draw(3, 0);
}
void Create_Vertex_Buffer_for_triangle()
{
D3D11_BUFFER_DESC VertexBufferDesc;
D3D11_SUBRESOURCE_DATA VertexData;
UINT stride = sizeof(Vertex_Buffer);
UINT offset = 0;
ZeroMemory(&VertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
VertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
VertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
VertexBufferDesc.CPUAccessFlags = 0;
VertexBufferDesc.ByteWidth = sizeof(Vertex_Buffer) * 3;
Vertex_Buffer VerticesData[] =
{
Vertex_Buffer(0.0f, 0.5f, 0.5f),
Vertex_Buffer(0.5f, -0.5f, 0.5f),
Vertex_Buffer(-0.5f, -0.5f, 0.5f)
};
ZeroMemory(&VertexData, sizeof(D3D11_SUBRESOURCE_DATA));
VertexData.pSysMem = VerticesData;
device->CreateBuffer(
&VertexBufferDesc,
&VertexData,
&VertexBuffer);
DevContext->IASetVertexBuffers(
0,
1,
&VertexBuffer,
&stride,
&offset
);
}
LRESULT CALLBACK WindowProcedure(HWND handle, unsigned int message, WPARAM ignore1, LPARAM ignore2)
{
switch (message)
{
case WM_CREATE:
return 0;
case WM_CLOSE:
DestroyWindow(handle);
return 0;
default:
return DefWindowProc(handle, message, ignore1, ignore2);
}
}
Here is the VertexShader.hlsl file
float4 main( float4 pos : POSITION ) : SV_POSITION
{
return pos;
}
float4 Pixel_Shader() : SV_TARGET
{
return float4(1.0f, 0.0f, 0.0f, 1.0f);
}
First, if your code snippet is accurate, you should not be creating the SpriteFont and SpriteBatch instance every frame. You only have to create them when the device changes.
By default, SpriteFont is drawing using pre-multiplied alpha blending modes, so if you are getting a fully "background color" image then something else is amiss in your pipeline state. It is likely that you are leaving some state in effect in the rendering between the clear and RenderText that is affecting the SpriteBatch renderer that you should reset.
It might also be the color you are using for the background clear which has the alpha set to 0 rather than 1. Try using:
float BackgroundColor[4] = { 0.0f, 0.0f, 0.0f, 1.0f };
Try working through a few of the DirectX Tool Kit tutorials to make sure things are working in isolation and so you understand how the classes work, specifically Drawing text.
You and me have the same problem with SpriteFont. We forgot to reset the VertexBuffers and all other rendering states after the call to SpriteFont. See my post and the solution from Chuck Walbourn: DirectX::SpriteFont/SpriteBatch prevents 3D scene from drawing.
To quote Chuck:
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.
See my question for additional links providing more information.