I can initialize win32 window and directx11 fine, but when i try to draw triangle window appears and then it freezes my pc so i have to reboot it.
Here is my WinMain code:
#include "DXApp.h"
#include<DirectXMath.h>
class App : public DXApp {
public:
App(HINSTANCE hInstance);
~App();
bool Init() override;
void Update(float dt) override;
void Render(float dt) override;
};
int WINAPI WinMain(__in HINSTANCE hInstance, __in_opt HINSTANCE hPrevInstance, __in LPSTR lpCmdLine, __in int nShowCmd) {
App app(hInstance);
if (!app.Init()) return 1;
return app.Run();
}
App::App(HINSTANCE hInstance) : DXApp(hInstance)
{
}
App::~App()
{
}
bool App::Init()
{
return DXApp::Init();
}
void App::Update(float dt)
{
}
void App::Render(float dt)
{
immediateContext->ClearRenderTargetView(renderTargetView, DirectX::Colors::CornflowerBlue);
immediateContext->Draw(3, 0);
swapChain->Present(0, 0);
}
And my app header and cpp:
DXApp.h:
#pragma once
#include<Windows.h>
#include<string>
#include"DXUtil.h"
#include<d3dcompiler.h>
#pragma comment(lib, "d3dcompiler.lib")
#define WIN32_LEAN_AND_MEAN
class DXApp
{
public:
DXApp(HINSTANCE hInstance);
void cleanUp();
virtual ~DXApp(void);
//MAIN APPLICATION LOOP
int Run();
//FRAMEWORK METHODS
virtual bool Init();
virtual void Update(float dt) = 0;
virtual void Render(float dt) = 0;
virtual LRESULT MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam);
protected:
HWND hAppWnd;
HINSTANCE hAppInstance;
unsigned int ClientWidth;
unsigned int ClientHeight;
std::string AppTitle;
DWORD WindStyle;
//DIRECTX ATTRIBUTES
ID3D11Device* device;
ID3D11DeviceContext* immediateContext;
IDXGISwapChain* swapChain;
ID3D11RenderTargetView* renderTargetView;
D3D_DRIVER_TYPE driverType;
D3D_FEATURE_LEVEL featureLevel;
D3D11_VIEWPORT viewport;
ID3D11Buffer* triangleVertBuffer;
ID3D11PixelShader* pixelShader;
ID3D11VertexShader* vertexShader;
ID3D10Blob* VSBuffer;
ID3D10Blob* PSBuffer;
ID3D11InputLayout* vertLayout;
protected:
//INITIALZE WIN32 WINDOW
bool windowInit();
//INITIALIZE DIRECTX
bool direct3dInit();
};
DXApp.cpp:
#include "DXApp.h"
namespace {
DXApp * g_pApp = nullptr;
}
LRESULT CALLBACK MainWndProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam) {
if (g_pApp) return g_pApp->MsgProc(hwnd, msg, wParam, lParam);
else return DefWindowProc(hwnd, msg, wParam, lParam);
}
//VERTEX
struct Vertex {
Vertex() {}
Vertex(float x, float y, float z) : pos(x, y, z) {}
DirectX::XMFLOAT3 pos;
};
D3D11_INPUT_ELEMENT_DESC layout[] = {
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
unsigned int numLayoutElements = ARRAYSIZE(layout);
DXApp::DXApp(HINSTANCE hInstance)
{
hAppInstance = hInstance;
hAppWnd = NULL;
ClientWidth = 1280;
ClientHeight = 720;
AppTitle = "DirectX11 Engine";
WindStyle = WS_OVERLAPPEDWINDOW;
g_pApp = this;
//DIRECTX
device = nullptr;
swapChain = nullptr;
immediateContext = nullptr;
renderTargetView = nullptr;
vertexShader = nullptr;
pixelShader = nullptr;
triangleVertBuffer = nullptr;
VSBuffer = nullptr;
PSBuffer = nullptr;
vertLayout = nullptr;
}
void DXApp::cleanUp()
{
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
DXApp::~DXApp()
{
//DIRECTX CLEANUP
if (immediateContext) immediateContext->ClearState();
Memory::SafeRelease(renderTargetView);
Memory::SafeRelease(immediateContext);
Memory::SafeRelease(swapChain);
Memory::SafeRelease(device);
Memory::SafeRelease(vertLayout);
Memory::SafeRelease(PSBuffer);
Memory::SafeRelease(VSBuffer);
Memory::SafeRelease(triangleVertBuffer);
Memory::SafeRelease(pixelShader);
Memory::SafeRelease(vertexShader);
}
int DXApp::Run() {
MSG msg = { 0 };
while (WM_QUIT != msg.message) {
if (PeekMessage(&msg, NULL, NULL, NULL, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
Update(0.0f);
Render(0.0f);
}
}
return static_cast<int>(msg.wParam);
}
bool DXApp::Init()
{
if (!windowInit()) {
return false;
}
if (!direct3dInit()) {
return false;
}
return true;
}
bool DXApp::windowInit()
{
WNDCLASSEX wcex;
ZeroMemory(&wcex, sizeof(WNDCLASSEX));
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.hInstance = hAppInstance;
wcex.lpfnWndProc = MainWndProc;
wcex.hIcon = LoadIcon(NULL, IDI_APPLICATION);
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(NULL_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "DXAPPWNDCLASS";
wcex.hIconSm = LoadIcon(NULL, IDI_APPLICATION);
if (!RegisterClassEx(&wcex)) {
OutputDebugString("\nFAILED TO CREATE WINDOW CLASS!!\n");
return false;
}
RECT r = { 0, 0, ClientWidth, ClientHeight };
AdjustWindowRect(&r, WindStyle, false);
unsigned int width = r.right - r.left;
unsigned int height = r.bottom - r.top;
unsigned int x = GetSystemMetrics(SM_CXSCREEN) / 2 - width / 2;
unsigned int y = GetSystemMetrics(SM_CYSCREEN) / 2 - height / 2;
hAppWnd = CreateWindow("DXAPPWNDCLASS", AppTitle.c_str(), WindStyle, x, y, width, height, NULL, NULL, hAppInstance, NULL);
if (!hAppWnd) {
OutputDebugString("\nFAILED TO CREATE WINDOW!!\n");
return false;
}
ShowWindow(hAppWnd, SW_SHOW);
return true;
}
//DIRECTX INITIALIZATION
bool DXApp::direct3dInit()
{
unsigned int createDeviceFlags = 0;
#ifdef DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif // DEBUG
D3D_DRIVER_TYPE driverTypes[] = {
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE
};
unsigned int numDriverTypes = ARRAYSIZE(driverTypes);
D3D_FEATURE_LEVEL featureLevels[] = {
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
D3D_FEATURE_LEVEL_9_3
};
unsigned int numFeatureLevels = ARRAYSIZE(featureLevels);
DXGI_SWAP_CHAIN_DESC swapDesc;
ZeroMemory(&swapDesc, sizeof(DXGI_SWAP_CHAIN_DESC));
swapDesc.BufferCount = 1;
swapDesc.BufferDesc.Width = ClientWidth;
swapDesc.BufferDesc.Height = ClientHeight;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;
swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = hAppWnd;
swapDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD;
swapDesc.Windowed = true;
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;
swapDesc.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH;
HRESULT result;
for (int i = 0; i < numDriverTypes; ++i) {
result = D3D11CreateDeviceAndSwapChain(NULL, driverTypes[i], NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &swapDesc, &swapChain, &device, &featureLevel, &immediateContext);
if (SUCCEEDED(result)) {
driverType = driverTypes[i];
break;
}
if (FAILED(result)) {
OutputDebugString("FAILED TO CREATE DX11 DEVICE!!");
return false;
}
}
//RENDER TARGET VIEW
ID3D11Texture2D* backBufferTex = 0;
swapChain->GetBuffer(NULL, __uuidof(ID3D11Texture2D), reinterpret_cast<void**>(&backBufferTex));
device->CreateRenderTargetView(backBufferTex, nullptr, &renderTargetView);
//BIND RENDER TARGET VIEW
immediateContext->OMSetRenderTargets(1, &renderTargetView, nullptr);
//COMPILE SHADERS FROM FILE
result = D3DCompileFromFile(L"VertexShader.hlsl", 0, 0, "vertexShader", "vs_4_0", 0, 0, &VSBuffer, &VSBuffer);
result = D3DCompileFromFile(L"PixelShader.hlsl", 0, 0, "pixelShader", "ps_4_0", 0, 0, &PSBuffer, &PSBuffer);
//CREATE SHADER OBJECTS
result = device->CreateVertexShader(VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), 0, &vertexShader);
result = device->CreatePixelShader(PSBuffer->GetBufferPointer(), PSBuffer->GetBufferSize(), 0, &pixelShader);
//SET SHADERS
immediateContext->VSSetShader(vertexShader, 0, 0);
immediateContext->PSSetShader(pixelShader, 0, 0);
//CREATE VERTEX BUFFER
Vertex v[] = {
Vertex(0.0f, 0.5f, 0.5f),
Vertex(0.5f, -0.5f, 0.5f),
Vertex(-0.5f, 0.5f, 0.5f),
};
D3D11_BUFFER_DESC vertexBufferDesc;
ZeroMemory(&vertexBufferDesc, sizeof(D3D11_BUFFER_DESC));
vertexBufferDesc.Usage = D3D11_USAGE_DEFAULT;
vertexBufferDesc.ByteWidth = sizeof(Vertex) * 3;
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
vertexBufferDesc.CPUAccessFlags = 0;
vertexBufferDesc.MiscFlags = 0;
D3D11_SUBRESOURCE_DATA vertexBufferData;
ZeroMemory(&vertexBufferData, sizeof(vertexBufferData));
vertexBufferData.pSysMem = v;
result = device->CreateBuffer(&vertexBufferDesc, &vertexBufferData, &triangleVertBuffer);
//SET VERTEX BUFFER
unsigned int stride = sizeof(Vertex);
unsigned int offset = 0;
immediateContext->IAGetVertexBuffers(0, 1, &triangleVertBuffer, &stride, &offset);
//CREATE INPUT LAYOUT
device->CreateInputLayout(layout, numLayoutElements, VSBuffer->GetBufferPointer(), VSBuffer->GetBufferSize(), &vertLayout);
//SET INPUT LAYOUT
immediateContext->IASetInputLayout(vertLayout);
//SET PRIMITIVE TOPOLOGY
immediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
//VIEWPORT CREATION
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.Width = static_cast<float>(ClientWidth);
viewport.Height = static_cast<float>(ClientHeight);
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
//SET VIEWPORT
immediateContext->RSSetViewports(1, &viewport);
return true;
}
//MESSAGES
LRESULT DXApp::MsgProc(HWND hwnd, unsigned int msg, WPARAM wParam, LPARAM lParam)
{
switch (msg) {
case WM_DESTROY:
PostQuitMessage(0);
return 0;
default:
return DefWindowProc(hwnd, msg, wParam, lParam);
}
}
The first steps in debugging a Direct3D program are:
Make sure you are properly checking all HRESULT values. There are numerous places in your code where you are failing to check the result. If the Direct3D function returns a void, you can ignore error checking. Otherwise you need to use SUCCEEDED, FAILED, or use something like ThrowIfFailed. This is essentially because continuing beyond a failure is going to make it very hard to debug the true cause of the problem.
Enable the Direct3D debug device and look for output. You appear to have that in your debug builds. Do you see any output in the debug window?
It is highly unusual to have a program 'hang' your system, but it is possible if you have a bad driver or faulty hardware. Without more details, however, it's difficult to diagnose since your program is faulty to begin with.
Related
EDIT: Sorry, it's my first time posting here. I've now added the "start_console" files so that you can build it. Sorry for not specifying the problem. My problem is that I expect a triangle to render in the opened window, which it is not.
I've been trying to debug this for a while now but I can't find the problem. Would really appreciate some help :) All the files are posted below except for the eventhandler. I've tried enabling the D3D11_CREATE_DEVICE_DEBUG flag and adding FAILED() functions after each HRESULT but haven't been able to find anything wrong.
main.cpp
//Headers
#define WIN32_LEAN_AND_MEAN
#include "windowCreation.h"
#include "vertex_buffer.h"
#include "shader.h"
#include <comdef.h>
#include "start_console.h"
//hInstance: Used to identify the .exe when it's loaded into memory.
//hPreviousInstance: Always 0.
//pCmdLine: Command-line arguments, convert to argv with CommandLineToArgvW().
//nCmdShow: Flag that says if it should be minimized, maximized or showed normally.
int WINAPI wWinMain(_In_ HINSTANCE hInstance, _In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine, _In_ int nCmdShow) {
RedirectIOToConsole();
HWND D3D_window = InitWindow(hInstance);
if (D3D_window == NULL) {
return 0;
}
assert(D3D_window);
D3D_create(D3D_window);
Create_Vertex_Buffer();
shader_compile_and_layout();
MSG msg = { };
ShowWindow(D3D_window, nCmdShow);
while (msg.message != WM_QUIT) {
if (PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else {
FLOAT background_color[4] = { 1, 1, 1, 0 };
devcon->ClearRenderTargetView(pView, background_color);
devcon->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
devcon->IASetInputLayout(input_layout);
devcon->VSSetShader(vs, NULL, 0);
devcon->PSSetShader(ps, NULL, 0);
devcon->IASetVertexBuffers(0, 1, &Vertex_Buffer, &vertex_strides, &vertex_offset);
devcon->Draw(3, 0);
swapchain->Present(1, 0);
}
}
DestroyWindow(D3D_window);
CleanD3D();
return 0;
}
windowCreation.h
#ifndef WINDOWCREATION_H
#define WINDOWCREATION_H
#include <windows.h> //win32
#include <d3d11.h> //D3D 11
#include <dxgi.h> //Graphics devices and swap chain
#include <assert.h> //for assert()
#include <iostream>
//Libraries
#pragma comment( lib, "user32") //win32
#pragma comment( lib, "gdi32") //Graphics device interface
#pragma comment( lib, "d3d11") //Direct3D 11
#pragma comment( lib, "d3dcompiler.lib") //Shader Compiler
extern unsigned int width;
extern unsigned int height;
extern IDXGISwapChain *swapchain;
extern ID3D11Device *dev;
extern ID3D11DeviceContext *devcon;
extern ID3D11Texture2D* pSwapChainBuffer;
extern ID3D11RenderTargetView* pView;
//Event handler declaration
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
HWND InitWindow(HINSTANCE);
void CleanD3D();
void D3D_create_device_and_swapchain(HWND D3D_window);
void D3D_create_rendertarget();
void D3D_create_rasterizer();
void D3D_create_depth_stencil_state();
void D3D_create_blendstate();
void D3D_create(HWND D3D_window);
#endif
windowCreation.cpp
#include "windowCreation.h"
IDXGISwapChain *swapchain;
ID3D11Device *dev;
ID3D11DeviceContext *devcon;
ID3D11Texture2D* pSwapChainBuffer = 0;
ID3D11RenderTargetView* pView = 0;
unsigned int width = 640;
unsigned int height = 480;
ID3D11RasterizerState *pRSState;
ID3D11DepthStencilState* pDepthStencilState;
ID3D11BlendState* pBlendState;
HWND InitWindow(HINSTANCE hInstance) {
//Declaring the windowclass.
WNDCLASSEX wc = { 0 };
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc; //Pointer to the windowproc-function that handles events.
wc.hInstance = hInstance; //Handle to the application instance.
wc.lpszClassName = L"BasicWindow"; //Identifies the window class
//Registers the window class with the opserating system
if (!RegisterClassEx(&wc)) {
return 0;
}
RECT rc = { 0, 0, width, height };
AdjustWindowRect(&rc, WS_OVERLAPPEDWINDOW, FALSE);
HWND D3D_window = CreateWindow(
L"BasicWindow",
L"BTH BasicWindow",
WS_OVERLAPPEDWINDOW,
//Size and position
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top,
nullptr, //Parent window
nullptr, //Menu
hInstance, //Instance handle
nullptr //Additional application data
);
return D3D_window;
}
void D3D_create_device_and_swapchain(HWND D3D_window) {
DXGI_SWAP_CHAIN_DESC scd;
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
scd.BufferCount = 1;
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
scd.OutputWindow = D3D_window;
scd.SampleDesc.Count = 1;
scd.Windowed = TRUE;
D3D11CreateDeviceAndSwapChain(
NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
D3D11_CREATE_DEVICE_DEBUG,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon
);
}
void D3D_create_rendertarget() {
HRESULT hr = swapchain->GetBuffer( 0,
__uuidof(ID3D11Texture2D),
(void**)&pSwapChainBuffer);
if (FAILED(hr)) {
std::cout << "fail";
}
hr = dev->CreateRenderTargetView( pSwapChainBuffer,
0,
&pView);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->OMSetRenderTargets(1, &pView, nullptr);
auto viewport = CD3D11_VIEWPORT(0.0f, 0.0f,
static_cast<float>(width), static_cast<float>(height)
);
devcon->RSSetViewports(1, &viewport);
}
void D3D_create_rasterizer() {
CD3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
HRESULT hr = dev->CreateRasterizerState(&desc, &pRSState);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->RSGetState(&pRSState);
}
void D3D_create_depth_stencil_state() {
D3D11_DEPTH_STENCIL_DESC desc;
desc.DepthEnable = TRUE;
desc.DepthWriteMask = D3D11_DEPTH_WRITE_MASK_ALL;
desc.DepthFunc = D3D11_COMPARISON_LESS;
desc.StencilEnable = FALSE;
desc.StencilReadMask = D3D11_DEFAULT_STENCIL_READ_MASK;
desc.StencilWriteMask = D3D11_DEFAULT_STENCIL_WRITE_MASK;
desc.FrontFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.FrontFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
desc.BackFace.StencilFailOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilDepthFailOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilPassOp = D3D11_STENCIL_OP_KEEP;
desc.BackFace.StencilFunc = D3D11_COMPARISON_ALWAYS;
HRESULT hr = dev->CreateDepthStencilState(&desc, &pDepthStencilState);
devcon->OMSetDepthStencilState(pDepthStencilState, 1);
}
void D3D_create_blendstate() {
D3D11_RENDER_TARGET_BLEND_DESC render_desc;
render_desc.BlendEnable = TRUE;
render_desc.SrcBlend = D3D11_BLEND_ONE;
render_desc.DestBlend = D3D11_BLEND_ZERO;
render_desc.BlendOp = D3D11_BLEND_OP_ADD;
render_desc.SrcBlendAlpha = D3D11_BLEND_ONE;
render_desc.DestBlendAlpha = D3D11_BLEND_ZERO;
render_desc.BlendOpAlpha = D3D11_BLEND_OP_ADD;
render_desc.RenderTargetWriteMask = D3D11_COLOR_WRITE_ENABLE_ALL;
D3D11_BLEND_DESC desc;
desc.AlphaToCoverageEnable = FALSE;
desc.IndependentBlendEnable = FALSE;
desc.RenderTarget[0] = render_desc;
HRESULT hr = dev->CreateBlendState(&desc, &pBlendState);
if (FAILED(hr)) {
std::cout << "fail";
}
devcon->OMSetBlendState(pBlendState, NULL, NULL);
}
void D3D_create(HWND D3D_window) {
D3D_create_device_and_swapchain(D3D_window);
D3D_create_rendertarget();
D3D_create_rasterizer();
D3D_create_depth_stencil_state();
D3D_create_blendstate();
}
void CleanD3D() {
swapchain->Release();
dev->Release();
devcon->Release();
}
vertex_buffer.h
#pragma once
#ifndef VERTEX_BUFFER_H
#define VERTEX_BUFFER_H
#include <vector>
extern struct ID3D11Buffer* Vertex_Buffer;
extern unsigned int vertex_strides;
extern unsigned int vertex_offset;
void Create_Vertex_Buffer();
#endif
vertex_buffer.cpp
#include "vertex_buffer.h"
#include "windowCreation.h"
#include "directxmath.h"
using namespace DirectX;
struct VERTEX {
XMFLOAT3 pos;
XMFLOAT3 col;
};
ID3D11Buffer* Vertex_Buffer;
unsigned int vertex_strides = sizeof(VERTEX);
unsigned int vertex_offset = 0;
void Create_Vertex_Buffer() {
VERTEX vertex_array[] = {
{XMFLOAT3(10, 10, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(100, 10, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)},
{XMFLOAT3(55, 100, 100), XMFLOAT3(0.0f, 0.0f, 0.0f)}
};
D3D11_BUFFER_DESC buffer_struct;
buffer_struct.ByteWidth = sizeof(VERTEX) * 3;
buffer_struct.Usage = D3D11_USAGE_DEFAULT;
buffer_struct.BindFlags = D3D11_BIND_VERTEX_BUFFER;
buffer_struct.CPUAccessFlags = 0;
buffer_struct.MiscFlags = 0;
buffer_struct.StructureByteStride = sizeof(float);
D3D11_SUBRESOURCE_DATA resource_struct;
resource_struct.pSysMem = vertex_array;
resource_struct.SysMemPitch = 0;
resource_struct.SysMemSlicePitch = 0;
HRESULT hr = dev->CreateBuffer(&buffer_struct, &resource_struct, &Vertex_Buffer);
if (FAILED(hr)) {
std::cout << "fail";
}
}
vertex_pixel_shader.hlsl
struct VS_INPUT
{
float3 vColour : COLOR;
float3 vPosition : POSITION;
};
struct VS_OUTPUT
{
float3 vColour : COLOR;
float4 vPosition : SV_POSITION;
};
VS_OUTPUT VSMain(VS_INPUT input)
{
VS_OUTPUT output;
output.vPosition = float4(input.vPosition.xy, 0.0, 1.0);
output.vColour = input.vColour;
return output;
}
float4 PSMain(VS_OUTPUT input) : SV_TARGET
{
return float4(input.vColour, 1.0);
}
shader.h
#pragma once
#ifndef SHADER_H
#define SHADER_H
#include <d3dcompiler.h>
#include <string>
extern struct ID3D11VertexShader* vs;
extern struct ID3D11PixelShader* ps;
extern struct ID3D11InputLayout* input_layout;
void shader_compile_and_layout();
#endif
shader.cpp
#include "shader.h"
#include "windowCreation.h"
ID3DBlob* blob_vs = nullptr;
ID3DBlob* blob_error_vs = nullptr;
ID3DBlob* blob_ps = nullptr;
ID3DBlob* blob_error_ps = nullptr;
ID3D11VertexShader* vs;
ID3D11PixelShader* ps;
ID3D11InputLayout* input_layout;
void shader_compile_and_layout() {
HRESULT hr = D3DCompileFromFile(
L"vertex_pixel_shader.hlsl",
NULL,
NULL,
"VSMain",
"vs_5_0",
0,
0,
&blob_vs,
&blob_error_vs);
if (FAILED(hr)) {
std::cout << "fail";
}
hr = D3DCompileFromFile(
L"vertex_pixel_shader.hlsl",
NULL,
NULL,
"PSMain",
"ps_5_0",
0,
0,
&blob_ps,
&blob_error_ps);
if (FAILED(hr)) {
std::cout << "fail";
}
dev->CreateVertexShader(blob_vs->GetBufferPointer(), blob_vs->GetBufferSize(), NULL, &vs);
dev->CreatePixelShader(blob_ps->GetBufferPointer(), blob_ps->GetBufferSize(), NULL, &ps);
D3D11_INPUT_ELEMENT_DESC input_element_desc[] = {
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, D3D11_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0}
};
hr = dev->CreateInputLayout(
input_element_desc, ARRAYSIZE(input_element_desc),
blob_vs->GetBufferPointer(),
blob_vs->GetBufferSize(),
&input_layout
);
if (FAILED(hr)) {
std::cout << "fail";
}
}
start_console.h
#pragma once
#ifndef VERTEX_BUFFER_H
#define VERTEX_BUFFER_H
#include <vector>
extern struct ID3D11Buffer* Vertex_Buffer;
extern unsigned int vertex_strides;
extern unsigned int vertex_offset;
void Create_Vertex_Buffer();
#endif
start_console.cpp
#include "start_console.h"
#include "windowCreation.h"
void RedirectIOToConsole()
{
AllocConsole();
HANDLE stdHandle;
int hConsole;
FILE* fp;
stdHandle = GetStdHandle(STD_OUTPUT_HANDLE);
hConsole = _open_osfhandle((long)stdHandle, _O_TEXT);
fp = _fdopen(hConsole, "w");
freopen_s(&fp, "CONOUT$", "w", stdout);
}
For Direct3D, it's critically important that you set all the relevant state.
I don't see you call OMSetRenderTargets to bind the swapchain to the rendering context via your render target view
devcon->OMSetRenderTarget(1, &pView, nullptr);
I don't see a call to RSSetViewports to set the proper pixel rectangle for rendering.
auto viewport = CD3D11_VIEWPORT(0.0f, 0.0f,
static_cast<float>(backBufferWidth),
static_cast<float>(backBufferHeight)
);
devcon->RSSetViewports(1, &viewport);
You don't appear to be setting a render state object via RSSetState which controls the cull-mode. The default if you don't set it Cull mode set to "back-cull" and FrontCounterClockwise is FALSE. You vertex data could be using the wrong winding and end up backface culled. A good place to start would be to create a object with 'Cull None'.
ID3D11RasterizerState *pRSState;
auto desc = CD3D11_RASTERIZER_DESC
D3D11_RASTERIZER_DESC desc = {};
desc.FillMode = D3D11_FILL_SOLID;
desc.CullMode = D3D11_CULL_NONE;
hr = dev->CreateRasterizerState(&desc, &pRSState);
devcon->RSSetState(pRSState);
Another important state is the blend state via OMSetBlendState. It defaults to an opaque setting.
You don't have a depth buffer, but if you do be sure to set OMSetDepthStencilState.
As you are still getting started, you should probably disable MSAA until you get everything else working.
scd.SampleDesc.Count = 1;
I have complete basic render loops and device templates on GitHub you may want to reference.
You should take a look at DirectX Tool Kit as well.
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.
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.
I'm having a hard time figuring out how to draw a circle in directx. I'm able to draw a triangle, so I imagined that I might be able to draw one by just rotating a triangle in a circle. However, I'm absolutely stumped. I've been scouring the net for hours with no luck. Can anyone help me out? Here's my code:
Main.cpp
#include "Engine.h"
#include "Box2D.h"
#include "Triangle2D.h"
class MyApp : public Engine {
public:
Box2D box2D;
Triangle2D triangle2D;
void OnStartup() override {
box2D.New(10.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0x00, 0x00, 0xff));
triangle2D.New(150.0f, 10.0f, 100.0f, 100.0f, D3DCOLOR_ARGB(0xff, 0xff, 0x00, 0x00));
}
void OnShutdown() override {
box2D.Delete();
triangle2D.Delete();
}
void OnDraw() override {
box2D.Draw();
triangle2D.Draw();
}
void OnMouseDown(int x, int y) {
Debug("%d %d\n", x, y);
}
};
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
MyApp app;
app.Run();
return 0;
}
Engine.cpp
#include "Engine.h"
// Initialize the classes static variables
Engine* Engine::_ENGINE = NULL;
// Returns the current instance of this class
Engine* Engine::GetInstance()
{
return _ENGINE;
}
// Constructor
Engine::Engine()
: _exit(false)
, _window(NULL)
, _directx(NULL)
, _device(NULL)
{
_ENGINE = this;
}
// Deconstructor
Engine::~Engine() {
_ENGINE = NULL;
}
// Run the core main event loop, start to finish
bool Engine::Run() {
// Create the Windows class
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(wc));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_VREDRAW | CS_HREDRAW | CS_DBLCLKS | CS_CLASSDC;
wc.lpfnWndProc = _WND_PROC;
wc.hInstance = GetModuleHandle(NULL);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);
wc.lpszClassName = _GetModuleName();
RegisterClassEx(&wc);
// Adjust the window rect for the flags
RECT rect;
SetRect(&rect, 0, 0, _WIDTH, _HEIGHT);
const DWORD windowFlags = WS_OVERLAPPED | WS_CAPTION | WS_CLIPCHILDREN | WS_SYSMENU | WS_MINIMIZEBOX;
AdjustWindowRectEx(&rect, windowFlags, FALSE, 0);
// Create the window
_window = CreateWindowEx(0, _GetModuleName(), _GetModuleName(), windowFlags, 0, 0, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, GetModuleHandle(NULL), NULL);
if (_window == NULL)
return false;
// Move the window to the center of the screen
RECT system;
SystemParametersInfo(SPI_GETWORKAREA, 0, &system, 0);
MoveWindow(_window, (system.right - system.left) / 2 - (rect.right - rect.left) / 2, (system.bottom - system.top) / 2 - (rect.bottom - rect.top) / 2, rect.right - rect.left, rect.bottom - rect.top, TRUE);
// Startup Direct X
if (_DirectXStartup() == false)
return false;
// Call our startup callback
OnStartup();
// Show the window
ShowWindow(_window, SW_SHOWNORMAL);
// Run the event loop
MSG msg;
ULONGLONG timer = GetTickCount64();
while (!_exit) {
// Handle normal system events
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
TranslateMessage(&msg);
DispatchMessage(&msg);
}
// Run the timer at the framerate
if (timer + 1000 / _FPS < GetTickCount64()) {
timer = GetTickCount64();
// Clear the buffer
_device->Clear(0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0x00, 0xff, 0x00), 1.0f, NULL);
// Call our draw callback every frame
OnDraw();
// Render to screen
_device->Present(NULL, NULL, NULL, NULL);
}
}
// Hide the window to avoid flicker
ShowWindow(_window, SW_HIDE);
// Call our shutdown callback
OnShutdown();
// Shutdown Direct X
_DirectXShutdown();
// Cleanup and destroy the window
DestroyWindow(_window);
UnregisterClass(_GetModuleName(), GetModuleHandle(NULL));
return true;
}
// Return the DirectX device, needed by other DirectX objects
LPDIRECT3DDEVICE9 Engine::GetDevice() {
return _device;
}
// Return our width
int Engine::GetWidth() {
return _WIDTH;
}
// Return our height
int Engine::GetHeight() {
return _HEIGHT;
}
// Our own custom debug string
void Engine::Debug(const char* message, ...) {
#if _DEBUG
if (message) {
va_list args;
va_start(args, message);
int size = vsnprintf(NULL, 0, message, args);
if (size > 0) {
char* string = new char[size + 1];
vsnprintf(string, size + 1, message, args);
OutputDebugStringA(string);
delete[] string;
}
va_end(args);
}
#endif
}
// This is the Windows callback
LRESULT CALLBACK Engine::_WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
// If we do not have access to an instance of our engine, do nothing
if (Engine::_ENGINE == NULL)
return DefWindowProc(hwnd, uMsg, wParam, lParam);
// Handle system messages
switch (uMsg) {
case WM_LBUTTONDOWN:
Engine::_ENGINE->OnMouseDown(GET_X_LPARAM(lParam), GET_Y_LPARAM(lParam));
return 0;
case WM_KEYDOWN:
case WM_SYSKEYDOWN:
if ((lParam & (1 << 30)) == 0)
Engine::_ENGINE->OnKeyDown((int)wParam);
return 0;
case WM_CHAR:
if ((int)wParam <= 127 && isprint((int)wParam) && (lParam & (1 << 30)) == 0)
Engine::_ENGINE->OnASCIIDown((char)wParam);
return 0;
case WM_CLOSE:
Engine::_ENGINE->_exit = true;
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
// Custom function for getting our exe name
WCHAR* Engine::_GetModuleName() {
static WCHAR* TITLE = NULL;
static WCHAR BUFFER[MAX_PATH];
if (TITLE != NULL)
return TITLE;
// Remove the path
GetModuleFileName(NULL, BUFFER, MAX_PATH);
TITLE = wcsrchr(BUFFER, '\\');
if (TITLE == NULL) {
wcscpy(BUFFER, L"Application");
TITLE = BUFFER;
return TITLE;
}
TITLE++;
// Remove the extension
WCHAR* ext = wcsrchr(BUFFER, '.');
if (ext)
*ext = 0;
return TITLE;
}
// Startup DirectX here
bool Engine::_DirectXStartup() {
// Startup Direct X
_directx = Direct3DCreate9(D3D_SDK_VERSION);
if (_directx == NULL)
return false;
// Create a Direct X device
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.hDeviceWindow = _window;
d3dpp.BackBufferWidth = _WIDTH;
d3dpp.BackBufferHeight = _HEIGHT;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferFormat = D3DFMT_A8R8G8B8;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D24X8;
d3dpp.SwapEffect = D3DSWAPEFFECT_COPY;
HRESULT result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, _window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &_device);
if (FAILED(result))
result = _directx->CreateDevice(D3DADAPTER_DEFAULT, D3DDEVTYPE_REF, _window, D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &_device);
if (FAILED(result))
return false;
return true;
}
// Shutdown DirectX here
bool Engine::_DirectXShutdown() {
if (_device) {
_device->Release();
_device = NULL;
}
if (_directx) {
_directx->Release();
_directx = NULL;
}
return true;
}
Engine.h
#ifndef _ENGINE_H_
#define _ENGINE_H_
#define _CRT_SECURE_NO_WARNINGS
#include <Windows.h>
#include <windowsx.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>
class Engine {
public:
// Return the current singleton of this Engine class
static Engine* GetInstance();
// Constructor and deconstructor
Engine();
virtual ~Engine();
// Run the Engine class
bool Run();
// Return useful information about the class
LPDIRECT3DDEVICE9 GetDevice();
int GetWidth();
int GetHeight();
// Use for debug output
static void Debug(const char* message, ...);
// Virtual callbacks
virtual void OnStartup() {}
virtual void OnShutdown() {}
virtual void OnMouseDown(int x, int y) {}
virtual void OnKeyDown(int key) {}
virtual void OnASCIIDown(char key) {}
virtual void OnDraw() {}
private:
static Engine* _ENGINE;
static const int _WIDTH = 854;
static const int _HEIGHT = 480;
static const int _FPS = 60;
bool _exit;
HWND _window;
LPDIRECT3D9 _directx;
LPDIRECT3DDEVICE9 _device;
static LRESULT CALLBACK _WND_PROC(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
WCHAR* _GetModuleName();
bool _DirectXStartup();
bool _DirectXShutdown();
};
#endif // _ENGINE_H_
Triangle2D.h
#ifndef _TRIANGLE_2D_H_
#define _TRIANGLE_2D_H_
#include "Engine.h"
class Triangle2D {
public:
Triangle2D();
bool New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);
void Delete();
void Draw();
void Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color);
private:
struct CustomVertex {
FLOAT x, y, z, w;
DWORD color;
};
static const DWORD _FVF = D3DFVF_XYZRHW | D3DFVF_DIFFUSE;
LPDIRECT3DVERTEXBUFFER9 _vb;
};
#endif // _BOX_2D_H_
Triangle2D.cpp
#include "Triangle2D.h"
Triangle2D::Triangle2D()
: _vb(NULL)
{
}
bool Triangle2D::New(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {
if (FAILED(Engine::GetInstance()->GetDevice()->CreateVertexBuffer(sizeof(CustomVertex)* 4, D3DUSAGE_WRITEONLY, _FVF, D3DPOOL_DEFAULT, &_vb, NULL)))
return false;
CustomVertex* vertices;
_vb->Lock(0, 0, (void**)&vertices, 0);
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[0].w = 1.0f;
vertices[0].color = color;
vertices[1].x = x + width;
vertices[1].y = y;
vertices[1].z = 0.0f;
vertices[1].w = 1.0f;
vertices[1].color = color;
vertices[2].x = x;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[2].w = 1.0f;
vertices[2].color = color;
_vb->Unlock();
return true;
}
void Triangle2D::Delete(){
if (_vb) {
_vb->Release();
_vb = NULL;
}
}
void Triangle2D::Draw() {
Engine::GetInstance()->GetDevice()->BeginScene();
Engine::GetInstance()->GetDevice()->SetFVF(_FVF);
Engine::GetInstance()->GetDevice()->SetStreamSource(0, _vb, 0, sizeof(CustomVertex));
Engine::GetInstance()->GetDevice()->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2);
Engine::GetInstance()->GetDevice()->EndScene();
}
void Triangle2D::Draw(FLOAT x, FLOAT y, FLOAT width, FLOAT height, DWORD color) {
CustomVertex* vertices;
_vb->Lock(0, 0, (void**)&vertices, 0);
vertices[0].x = x;
vertices[0].y = y;
vertices[0].z = 0.0f;
vertices[0].w = 1.0f;
vertices[0].color = color;
vertices[1].x = x + width;
vertices[1].y = y;
vertices[1].z = 0.0f;
vertices[1].w = 1.0f;
vertices[1].color = color;
vertices[2].x = x;
vertices[2].y = y + height;
vertices[2].z = 0.0f;
vertices[2].w = 1.0f;
vertices[2].color = color;
_vb->Unlock();
Draw();
}
Direct3D does not draw "circles". It only natively draws three fundamental primitives: points, lines, and triangles. There are lots of options for how it draws those things, but that's all it can draw natively. The same is true of OpenGL (which can sometimes draw 'quads' as well, but you can always draw a quad with two triangles).
Typically drawing circles and other smooth objects is best done through "vector graphics" libraries. These can render high-quality approximations of smooth objects like circles at the correct resolution. This is what the legacy GDI library did, and what Direct2D can do. You can code your own approximation for a circle, but you probably won't do as well as Direct2D. These libraries ultimately generate points, lines, and triangles for the actual drawing operations which are performed by Direct3D.
For this reason, if you are doing 'presentation' graphics, you should look at using Direct2D instead of Direct3D. Most games actually never draw true circles. They draw 2D sprites as two textured triangles with Direct3D using an image of a circle drawn on it by an artist in something like Photoshop or Paint.
If you are insistent on using Direct3D, see the DirectX Tool Kit for Direct3D 11 DebugDraw helper that can draw 'rings' (i.e. line-segment circles in 3D space). This should give you an idea for how this is done. This code always uses 32 segments to form the ring, but a 'vector graphics' library would determine how many segments to break it down to based on exactly how many pixels it's going to cover on the screen:
void XM_CALLCONV DX::DrawRing(PrimitiveBatch<VertexPositionColor>* batch,
FXMVECTOR origin,
FXMVECTOR majorAxis,
FXMVECTOR minorAxis,
GXMVECTOR color)
{
static const size_t c_ringSegments = 32;
VertexPositionColor verts[c_ringSegments + 1];
FLOAT fAngleDelta = XM_2PI / float(c_ringSegments);
// Instead of calling cos/sin for each segment we calculate
// the sign of the angle delta and then incrementally calculate sin
// and cosine from then on.
XMVECTOR cosDelta = XMVectorReplicate(cosf(fAngleDelta));
XMVECTOR sinDelta = XMVectorReplicate(sinf(fAngleDelta));
XMVECTOR incrementalSin = XMVectorZero();
static const XMVECTORF32 s_initialCos =
{
1.f, 1.f, 1.f, 1.f
};
XMVECTOR incrementalCos = s_initialCos.v;
for (size_t i = 0; i < c_ringSegments; i++)
{
XMVECTOR pos = XMVectorMultiplyAdd(majorAxis, incrementalCos, origin);
pos = XMVectorMultiplyAdd(minorAxis, incrementalSin, pos);
XMStoreFloat3(&verts[i].position, pos);
XMStoreFloat4(&verts[i].color, color);
// Standard formula to rotate a vector.
XMVECTOR newCos = incrementalCos * cosDelta - incrementalSin * sinDelta;
XMVECTOR newSin = incrementalCos * sinDelta + incrementalSin * cosDelta;
incrementalCos = newCos;
incrementalSin = newSin;
}
verts[c_ringSegments] = verts[0];
batch->Draw(D3D11_PRIMITIVE_TOPOLOGY_LINESTRIP, verts, c_ringSegments + 1);
}
Direct3D 9 is legacy and unless you are specifically targeting Windows XP, you should be using Direct3D 11 or perhaps Direct2D if you are really doing 2D presentation graphics.
I am learning opengl for the first time, and i am trying to make a simple program. My program runs in two threads, one thread renders the program on the screen, while the other thread updates the data of the program. However, sometimes when i try to close my program i get a nasty error message. I don't understand why, although i feel like it is a concurrency error. Here is my code.
Main.cpp
#define WIN32_LEAN_AND_MEAN
#define WIN32_EXTRA_LEAN
#define GLX_GLXEXT_LEGACY
#include <windows.h>
#include "glwindow.h"
#include "example.h"
#include "util.h"
void updateThread(Example* example);
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR cmdLine, int cmdShow)
{
const int windowWidth = 1024;
const int windowHeight = 768;
const int windowBPP = 16;
const int windowFullscreen = false;
GLWindow programWindow(hInstance);
Example example;
programWindow.attachExample(&example);
if (!programWindow.create(windowWidth, windowHeight, windowBPP, windowFullscreen))
{
MessageBox(NULL, "Unable to create the OpenGL Window", "An error occurred", MB_ICONERROR | MB_OK);
programWindow.destroy();
return 1;
}
if (!example.init())
{
MessageBox(NULL, "Could not initialize the application", "An error occurred", MB_ICONERROR | MB_OK);
programWindow.destroy();
return 1;
}
HANDLE thread = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE) updateThread, &example, 0, 0);
example.setThread(&thread);
while(programWindow.isRunning())
{
programWindow.processEvents();
example.render();
programWindow.swapBuffers();
}
example.shutdown();
programWindow.destroy();
return 0;
}
void updateThread(Example* example)
{
setFPS(2000);
while(true)
{
example->update();
sync();
}
}
Util.cpp
#include "util.h"
int fps;
long timeThen;
void sync()
{
while(fps == 0);
long gapTo = 1000 / fps + timeThen;
long timeNow = time(nullptr);
while (gapTo > timeNow)
{
timeNow = time(nullptr);
}
timeThen = timeNow;
}
void setFPS(int FPS)
{
fps = FPS;
}
glwindow.cpp
#include <ctime>
#include <iostream>
#include <windows.h>
#include <GL/gl.h>
#include "wglext.h"
#include "glwindow.h"
#include "example.h"
typedef HGLRC (APIENTRYP PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int*);
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = NULL;
GLWindow::GLWindow(HINSTANCE hInstance):
m_isRunning(false),
m_example(NULL),
m_hinstance(hInstance),
m_lastTime(0)
{
}
bool GLWindow::create(int width, int height, int bpp, bool fullscreen)
{
DWORD dwExStyle;
DWORD dwStyle;
m_isFullscreen = fullscreen;
m_windowRect.left = (long)0;
m_windowRect.right = (long)width;
m_windowRect.top = (long)0;
m_windowRect.bottom = (long)height;
m_windowClass.cbSize = sizeof(WNDCLASSEX);
m_windowClass.style = CS_HREDRAW | CS_VREDRAW;
m_windowClass.lpfnWndProc = GLWindow::StaticWndProc;
m_windowClass.cbClsExtra = 0;
m_windowClass.cbWndExtra = 0;
m_windowClass.hInstance = m_hinstance;
m_windowClass.hIcon = LoadIcon(NULL, IDI_APPLICATION);
m_windowClass.hCursor = LoadCursor(NULL, IDC_ARROW);
m_windowClass.hbrBackground = NULL;
m_windowClass.lpszMenuName = NULL;
m_windowClass.lpszClassName = "GLClass";
m_windowClass.hIconSm = LoadIcon(NULL, IDI_WINLOGO);
if(!RegisterClassEx(&m_windowClass))
{
return false;
}
if(m_isFullscreen)
{
DEVMODE dmScreenSettings;
memset(&dmScreenSettings, 0, sizeof(dmScreenSettings));
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = width;
dmScreenSettings.dmPelsHeight = height;
dmScreenSettings.dmBitsPerPel = bpp;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
if (ChangeDisplaySettings(&dmScreenSettings, CDS_FULLSCREEN) != DISP_CHANGE_SUCCESSFUL)
{
MessageBox(NULL, "Display mode failed", NULL, MB_OK);
m_isFullscreen = false;
}
}
if (m_isFullscreen)
{
dwExStyle = WS_EX_APPWINDOW;
dwStyle = WS_POPUP;
ShowCursor(false);
}
else
{
dwExStyle = WS_EX_APPWINDOW | WS_EX_WINDOWEDGE;
dwStyle = WS_OVERLAPPEDWINDOW;
}
AdjustWindowRectEx(&m_windowRect, dwStyle, false, dwExStyle);
m_hwnd = CreateWindowEx(NULL, "GLClass", "BOGLGP - Chapter 2 - Simple OpenGL Application", dwStyle | WS_CLIPCHILDREN | WS_CLIPSIBLINGS,
0, 0, m_windowRect.right - m_windowRect.left, m_windowRect.bottom - m_windowRect.top, NULL, NULL, m_hinstance, this);
if (!m_hwnd)
{
MessageBox(NULL, "Window Creation Failed", NULL, MB_OK);
return 1;
}
m_hdc = GetDC(m_hwnd);
ShowWindow(m_hwnd, SW_SHOW);
UpdateWindow(m_hwnd);
m_lastTime = GetTickCount() / 1000.0f;
return true;
}
void GLWindow::destroy()
{
if (m_isFullscreen)
{
ChangeDisplaySettings(NULL, 0);
ShowCursor(true);
}
}
void GLWindow::attachExample(Example* example)
{
m_example = example;
}
bool GLWindow::isRunning()
{
return m_isRunning;
}
void GLWindow::processEvents()
{
MSG msg;
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
void GLWindow::setupPixelFormat(void)
{
int pixelFormat;
PIXELFORMATDESCRIPTOR pfd =
{
sizeof(PIXELFORMATDESCRIPTOR),
1,
PFD_SUPPORT_OPENGL |
PFD_DRAW_TO_WINDOW |
PFD_DOUBLEBUFFER,
PFD_TYPE_RGBA,
32,
0, 0, 0, 0, 0, 0,
0,
0,
0,
0, 0, 0, 0,
16,
0,
0,
PFD_MAIN_PLANE,
0,
0, 0, 0,
};
pixelFormat = ChoosePixelFormat(m_hdc, &pfd);
SetPixelFormat(m_hdc, pixelFormat, &pfd);
}
LRESULT GLWindow::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch(uMsg)
{
case WM_CREATE:
{
m_hdc = GetDC(hWnd);
setupPixelFormat();
int attribs[] = {
WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
WGL_CONTEXT_MINOR_VERSION_ARB, 0,
0};
HGLRC tmpContext = wglCreateContext(m_hdc);
wglMakeCurrent(m_hdc, tmpContext);
wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC) wglGetProcAddress("wglCreateContextAttribsARB");
if (!wglCreateContextAttribsARB)
{
MessageBox(NULL, "Open GL 3.0 Is Not Supported", NULL, MB_OK);
m_hglrc = tmpContext;
DestroyWindow(hWnd);
return 0;
}
else
{
m_hglrc = wglCreateContextAttribsARB(m_hdc, 0, attribs);
wglDeleteContext(tmpContext);
}
wglMakeCurrent(m_hdc, m_hglrc);
m_isRunning = true;
}
break;
case WM_DESTROY:
case WM_CLOSE:
wglMakeCurrent(m_hdc, NULL);
wglDeleteContext(m_hglrc);
m_isRunning = false;
PostQuitMessage(0);
return 0;
break;
case WM_SIZE:
{
int height = HIWORD(lParam);
int width = LOWORD(lParam);
getAttachedExample()->onResize(width, height);
}
break;
case WM_KEYDOWN:
if (wParam == VK_ESCAPE)
{
DestroyWindow(m_hwnd);
}
break;
default:
break;
}
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
LRESULT CALLBACK GLWindow::StaticWndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
GLWindow* window = NULL;
if(uMsg == WM_CREATE)
{
window = (GLWindow*)((LPCREATESTRUCT)lParam)->lpCreateParams;
SetWindowLongPtr(hWnd, GWL_USERDATA, (LONG_PTR)window);
}
else
{
window = (GLWindow*)GetWindowLongPtr(hWnd, GWL_USERDATA);
if(!window)
{
return DefWindowProc(hWnd, uMsg, wParam, lParam);
}
}
return window->WndProc(hWnd, uMsg, wParam, lParam);
}
float GLWindow::getElapsedSeconds()
{
float currentTime = float(GetTickCount()) / 1000.0f;
float seconds = float(currentTime - m_lastTime);
m_lastTime = currentTime;
return seconds;
}
example.cpp
#include <windows.h>
#include <GL/gl.h>
#include <GL/glu.h>
#include "example.h"
Example::Example()
{
m_rotationAngle = 0.0f;
}
bool Example::init()
{
glEnable(GL_DEPTH_TEST);
glDepthFunc(GL_LEQUAL);
return true;
}
void Example::update()
{
const float SPEED = 15.0f;
m_rotationAngle += SPEED;
if (m_rotationAngle > 360.0f)
{
m_rotationAngle -= 360.0f;
}
}
void Example::render()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
glRotatef(m_rotationAngle, 0, 0, 1);
glBegin(GL_TRIANGLES);
glColor4f(1.0f, 0.0f, 0.0f, 1.0f);
glVertex3f(-1.0f, -0.5f, -4.0f);
glColor4f(1.0f, 1.0f, 0.0f, 1.0f);
glVertex3f(1.0f, -0.5f, -4.0f);
glColor4f(0.0f, 0.0f, 1.0f, 1.0f);
glVertex3f(0.0f, 0.5f, -4.0f);
glEnd();
}
void Example::shutdown()
{
TerminateThread(thread, 0);
}
void Example::onResize(int width, int height)
{
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0f, float(width) / float(height), 1.0f, 100.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
}
EDIT
I am convinced that my problem is in the threading with example.cpp and main.cpp however i included all of the code to give more context to the situation.
Here is the error i get.
I don't see how your thread can exit cleanly.
In your while loop you should have something like
while (true) {
...
if (IShouldExit()) break;
}
That can be something simple like a bool or similar.
Then in your main you can set the flag then simply join with your thread, to give it time to exit cleanly.