Created
June 4, 2017 12:50
-
-
Save 0x61726b/524510532d7b6ce63721fb3e3f771c3a to your computer and use it in GitHub Desktop.
Render a full-screen triangle
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//---------------------------------------------------------------------------- | |
// Cef3D | |
// Copyright (C) 2017 arkenthera | |
// This program is free software; you can redistribute it and/or modify | |
// it under the terms of the GNU General Public License as published by | |
// the Free Software Foundation; either version 2 of the License, or | |
// (at your option) any later version. | |
// https://github.com/arkenthera/cef3d | |
//--------------------------------------------------------------------------- | |
#include <d3d11.h> | |
#include <dxgi.h> | |
#include <d3d9.h> | |
#include <DirectXMath.h> | |
#include <d3dcompiler.h> | |
#include <string> // std::string | |
#include <fstream> | |
#include <streambuf> | |
#pragma comment(lib, "dxgi.lib") | |
#pragma comment(lib, "d3d11.lib") | |
#pragma comment(lib, "d3dcompiler.lib") | |
#pragma comment(lib, "windowscodecs.lib") | |
struct SimpleVertex | |
{ | |
DirectX::XMFLOAT3 Point; | |
}; | |
struct VsConstantBuffer | |
{ | |
DirectX::XMFLOAT4X4 ViewProj; | |
DirectX::XMFLOAT4X4 ViewProjInv; | |
DirectX::XMFLOAT3 CamPos; | |
float padding; | |
}; | |
enum ShaderType | |
{ | |
Vertex, | |
Pixel | |
}; | |
std::string ShaderPath = "FSTriangle.hlsl"; // Absolute Shader path here | |
// Some forward declarations | |
bool CompileShader(ShaderType type, unsigned flags, const char* entryPoint, const std::string& source, ID3D10Blob** outBlob); | |
bool CompileFsTrianglePixelShader(unsigned flags); | |
bool CompileFsTriangleVertexShader(unsigned flags); | |
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam); | |
#define D3D_SAFE_RELEASE(p) if (p) { ((IUnknown*)p)->Release(); p = 0; } | |
IDXGISwapChain* SwapChain; | |
ID3D11Device* Device; | |
ID3D11DeviceContext* DeviceContext; | |
ID3D11RenderTargetView* Backbuffer; | |
ID3D11InputLayout* FSTriangleIL; | |
ID3D11VertexShader* FSTriangleVS; | |
ID3D11PixelShader* FSTrianglePS; | |
ID3D11Buffer* VertexBuffer; // the pointer to the vertex buffer | |
ID3D11Buffer* VSConstantBuffer; | |
ID3D11Texture2D* OffscreenTex; | |
ID3D11ShaderResourceView* OffscreenTexSRV; | |
ID3D11SamplerState* OffscreenPSSampler; | |
D3D11_VIEWPORT Viewport; | |
bool Vsync; | |
std::string ReadFile(const std::string & AbsPath) | |
{ | |
std::ifstream str(AbsPath); | |
std::string content; | |
str.seekg(0, std::ios::end); | |
content.reserve(str.tellg()); | |
str.seekg(0, std::ios::beg); | |
content.assign((std::istreambuf_iterator<char>(str)), | |
std::istreambuf_iterator<char>()); | |
return content; | |
} | |
bool InitDirect3D(HWND window, int width, int height) | |
{ | |
if (SwapChain) | |
D3D_SAFE_RELEASE(SwapChain); | |
if (Backbuffer) | |
D3D_SAFE_RELEASE(Backbuffer); | |
if (OffscreenTex) | |
D3D_SAFE_RELEASE(OffscreenTex); | |
if (OffscreenTexSRV) | |
D3D_SAFE_RELEASE(OffscreenTexSRV); | |
if (VSConstantBuffer) | |
D3D_SAFE_RELEASE(VSConstantBuffer); | |
HRESULT hr = S_OK; | |
DXGI_SWAP_CHAIN_DESC scd; | |
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC)); | |
scd.BufferCount = 1; | |
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; | |
scd.BufferDesc.Width = width; | |
scd.BufferDesc.Height = height; | |
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; | |
scd.OutputWindow = window; | |
scd.SampleDesc.Count = 1; | |
scd.Windowed = TRUE; | |
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; | |
if (!Device) | |
{ | |
hr = D3D11CreateDevice( | |
0, | |
D3D_DRIVER_TYPE_HARDWARE, | |
0, | |
D3D11_CREATE_DEVICE_DEBUG, | |
0, | |
0, | |
D3D11_SDK_VERSION, | |
&Device, | |
0, | |
&DeviceContext | |
); | |
if (FAILED(hr)) | |
{ | |
D3D_SAFE_RELEASE(Device); | |
D3D_SAFE_RELEASE(DeviceContext); | |
return false; | |
} | |
} | |
IDXGIDevice* dxgiDevice = 0; | |
Device->QueryInterface(IID_IDXGIDevice, (void**)&dxgiDevice); | |
IDXGIAdapter* dxgiAdapter = 0; | |
dxgiDevice->GetParent(IID_IDXGIAdapter, (void**)&dxgiAdapter); | |
IDXGIFactory* dxgiFactory = 0; | |
dxgiAdapter->GetParent(IID_IDXGIFactory, (void**)&dxgiFactory); | |
hr = dxgiFactory->CreateSwapChain(Device, &scd, &SwapChain); | |
if (FAILED(hr)) | |
{ | |
D3D_SAFE_RELEASE(SwapChain); | |
return false; | |
} | |
dxgiFactory->Release(); | |
dxgiAdapter->Release(); | |
dxgiDevice->Release(); | |
// Debug stuff, not actually necessary | |
ID3D11InfoQueue *d3dInfoQueue = nullptr; | |
Device->QueryInterface(__uuidof(ID3D11InfoQueue), (void**)&d3dInfoQueue); | |
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_CORRUPTION, true); | |
d3dInfoQueue->SetBreakOnSeverity(D3D11_MESSAGE_SEVERITY_ERROR, true); | |
// | |
ID3D11Texture2D *pBackbuffer; | |
SwapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackbuffer); | |
Device->CreateRenderTargetView(pBackbuffer, NULL, &Backbuffer); | |
pBackbuffer->Release(); | |
ZeroMemory(&Viewport, sizeof(D3D11_VIEWPORT)); | |
Viewport.TopLeftX = 0; | |
Viewport.TopLeftY = 0; | |
Viewport.Width = width; | |
Viewport.Height = height; | |
return true; | |
} | |
bool InitResources(int width, int height) | |
{ | |
SimpleVertex v1 = { DirectX::XMFLOAT3(-1.f,-3.f,1.f) }; | |
SimpleVertex v2 = { DirectX::XMFLOAT3(-1.f,1.f,1.f) }; | |
SimpleVertex v3 = { DirectX::XMFLOAT3(3.f,1.f,1.f) }; | |
SimpleVertex vertices[3] = { v1,v2,v3 }; | |
HRESULT hr = S_OK; | |
if (!VertexBuffer) | |
{ | |
// create the vertex buffer | |
D3D11_BUFFER_DESC bd; | |
ZeroMemory(&bd, sizeof(bd)); | |
bd.Usage = D3D11_USAGE_DYNAMIC; | |
bd.ByteWidth = sizeof(SimpleVertex) * 3; | |
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; | |
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; | |
Device->CreateBuffer(&bd, NULL, &VertexBuffer); | |
D3D11_MAPPED_SUBRESOURCE ms; | |
DeviceContext->Map(VertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); | |
memcpy(ms.pData, vertices, sizeof(vertices)); | |
DeviceContext->Unmap(VertexBuffer, NULL); | |
} | |
if (!FSTriangleVS || !FSTrianglePS) | |
{ | |
// load and compile the two shaders | |
unsigned flags = D3DCOMPILE_SKIP_OPTIMIZATION | D3DCOMPILE_DEBUG; | |
if (!CompileFsTriangleVertexShader(flags)) | |
return false; | |
if (!CompileFsTrianglePixelShader(flags)) | |
return false; | |
} | |
DirectX::XMMATRIX V = DirectX::XMMatrixLookAtLH(DirectX::XMVectorSet(0, 0, -5, 0), DirectX::XMVectorSet(0, 0, 0, 0), DirectX::XMVectorSet(0, 1, 0, 0)); | |
DirectX::XMMATRIX P = DirectX::XMMatrixPerspectiveFovLH(DirectX::XMConvertToRadians(60), width / height, 0.1f, 10.0f); | |
DirectX::XMMATRIX VP = DirectX::XMMatrixMultiply(V, P); | |
DirectX::XMVECTOR Det; | |
DirectX::XMMATRIX VPInv = DirectX::XMMatrixInverse(&Det, VP); | |
VsConstantBuffer VsConstData; | |
VsConstData.CamPos = DirectX::XMFLOAT3(0, 0, 0); | |
DirectX::XMStoreFloat4x4(&VsConstData.ViewProj, VP); | |
DirectX::XMStoreFloat4x4(&VsConstData.ViewProjInv, VPInv); | |
D3D11_BUFFER_DESC cbDesc; | |
cbDesc.ByteWidth = sizeof(VsConstantBuffer); | |
cbDesc.Usage = D3D11_USAGE_DYNAMIC; | |
cbDesc.BindFlags = D3D11_BIND_CONSTANT_BUFFER; | |
cbDesc.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; | |
cbDesc.MiscFlags = 0; | |
cbDesc.StructureByteStride = 0; | |
D3D11_SUBRESOURCE_DATA InitData; | |
InitData.pSysMem = &VsConstData; | |
InitData.SysMemPitch = 0; | |
InitData.SysMemSlicePitch = 0; | |
// Create the buffer. | |
hr = Device->CreateBuffer(&cbDesc, &InitData, | |
&VSConstantBuffer); | |
if (FAILED(hr)) | |
return false; | |
return true; | |
} | |
void Render() | |
{ | |
float clearColor[4] = { 0,0,0,0 }; | |
DeviceContext->ClearRenderTargetView(Backbuffer, clearColor); | |
UINT stride = sizeof(SimpleVertex); | |
UINT offset = 0; | |
// Set render target and viewport | |
DeviceContext->OMSetRenderTargets(1, &Backbuffer, NULL); | |
DeviceContext->RSSetViewports(1, &Viewport); | |
// Set input layout | |
DeviceContext->IASetInputLayout(FSTriangleIL); | |
// Set vertex buffers and constant buffers (uniforms) | |
DeviceContext->IASetVertexBuffers(0, 1, &VertexBuffer, &stride, &offset); | |
DeviceContext->VSSetConstantBuffers(0, 1, &VSConstantBuffer); | |
// Set primitive topology | |
DeviceContext->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_TRIANGLELIST); | |
// Set shaders | |
DeviceContext->VSSetShader(FSTriangleVS, 0, 0); | |
DeviceContext->PSSetShader(FSTrianglePS, 0, 0); | |
// Invoke the draw | |
DeviceContext->Draw(3, 0); | |
SwapChain->Present(Vsync ? 1 : 0, 0); | |
} | |
void Shutdown() | |
{ | |
SwapChain->SetFullscreenState(FALSE, NULL); | |
D3D_SAFE_RELEASE(OffscreenPSSampler); | |
D3D_SAFE_RELEASE(OffscreenTex); | |
D3D_SAFE_RELEASE(OffscreenTexSRV); | |
D3D_SAFE_RELEASE(VSConstantBuffer); | |
D3D_SAFE_RELEASE(FSTriangleIL); | |
D3D_SAFE_RELEASE(FSTriangleVS); | |
D3D_SAFE_RELEASE(FSTrianglePS); | |
D3D_SAFE_RELEASE(VertexBuffer); | |
D3D_SAFE_RELEASE(SwapChain); | |
D3D_SAFE_RELEASE(Backbuffer); | |
D3D_SAFE_RELEASE(DeviceContext); | |
D3D_SAFE_RELEASE(Device); | |
} | |
bool CompileShader(ShaderType type, unsigned flags, const char* entryPoint, const std::string& source, ID3D10Blob** outBlob) | |
{ | |
ID3DBlob* errorMsgs = 0; | |
HRESULT hr = D3DCompile(source.c_str(), source.length(), "", 0, 0, | |
entryPoint, type == Vertex ? "vs_5_0" : "ps_5_0", flags, 0, outBlob, &errorMsgs); | |
if (FAILED(hr)) | |
return false; | |
return true; | |
} | |
bool CompileFsTriangleVertexShader(unsigned flags) | |
{ | |
std::string shaderSource = ReadFile(ShaderPath); | |
ID3DBlob* vsBlob = 0; | |
if (!CompileShader(Vertex, flags, "fs_triangle_vs", shaderSource, &vsBlob)) | |
return false; | |
HRESULT hr = Device->CreateVertexShader(vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), NULL, &FSTriangleVS); | |
if (FAILED(hr)) | |
return false; | |
D3D11_INPUT_ELEMENT_DESC ied[] = | |
{ | |
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 } | |
}; | |
hr = Device->CreateInputLayout(ied, 1, vsBlob->GetBufferPointer(), vsBlob->GetBufferSize(), &FSTriangleIL); | |
if (FAILED(hr)) | |
return false; | |
return true; | |
} | |
bool CompileFsTrianglePixelShader(unsigned flags) | |
{ | |
std::string shaderSource = ReadFile(ShaderPath); | |
ID3DBlob* psBlob = 0; | |
if (!CompileShader(Pixel, flags, "fs_triangle_ps", shaderSource, &psBlob)) | |
return false; | |
HRESULT hr = Device->CreatePixelShader(psBlob->GetBufferPointer(), psBlob->GetBufferSize(), NULL, &FSTrianglePS); | |
if (FAILED(hr)) | |
return false; | |
return true; | |
} | |
HWND CreateNativeWindow(int Width, int Height) | |
{ | |
WNDCLASSEX wc; | |
HINSTANCE hInstance = GetModuleHandle(NULL); | |
LPCSTR className = "Cef3DSampleWindow"; | |
ZeroMemory(&wc, sizeof(WNDCLASSEX)); | |
wc.cbSize = sizeof(WNDCLASSEX); | |
wc.style = CS_HREDRAW | CS_VREDRAW; | |
wc.lpfnWndProc = WindowProc; | |
wc.hInstance = hInstance; | |
wc.hCursor = LoadCursor(NULL, IDC_ARROW); | |
wc.lpszClassName = className; | |
RegisterClassEx(&wc); | |
RECT wr = { 0, 0, Width, Height }; | |
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE); | |
HWND Handle = CreateWindowEx(NULL, | |
className, | |
"Cef3D Rendering Window", | |
WS_OVERLAPPEDWINDOW, | |
0, | |
0, | |
wr.right - wr.left, | |
wr.bottom - wr.top, | |
NULL, | |
NULL, | |
hInstance, | |
NULL); | |
ShowWindow(Handle, SW_SHOW); | |
return Handle; | |
} | |
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam) | |
{ | |
return DefWindowProc(hWnd, message, wParam, lParam); | |
} | |
void PumpMessageLoop() | |
{ | |
MSG msg; | |
while (TRUE) | |
{ | |
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) | |
{ | |
TranslateMessage(&msg); | |
DispatchMessage(&msg); | |
if (msg.message == WM_QUIT) | |
break; | |
Render(); | |
} | |
} | |
} | |
int WINAPI WinMain(_In_ HINSTANCE hInInstance, _In_opt_ HINSTANCE hPrevInstance, _In_ char* lpCmdLine, _In_ int nCmdShow) | |
{ | |
UNREFERENCED_PARAMETER(hPrevInstance); | |
UNREFERENCED_PARAMETER(lpCmdLine); | |
// Create the Window | |
int Width = 1024; | |
int Height = 768; | |
HWND Window = CreateNativeWindow(Width, Height); | |
if (!InitDirect3D(Window, Width, Height)) | |
return -1; | |
if (!InitResources(Width, Height)) | |
return -1; | |
PumpMessageLoop(); | |
Shutdown(); | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
struct PS_INPUT | |
{ | |
float4 position : SV_POSITION; | |
float2 tex_coord : TEXCOORD0; | |
float3 view_ray : TEXCOORD1; | |
}; | |
cbuffer camera_vs : register(b0) | |
{ | |
float4x4 vp : packoffset(c0); | |
float4x4 vp_inv : packoffset(c4); | |
float3 camera_pos : packoffset(c8); | |
float pad0 : packoffset(c8.w); | |
} | |
PS_INPUT fs_triangle_vs(in float3 pos : POSITION) | |
{ | |
PS_INPUT outp; | |
float4 position = float4(pos, 1.f); | |
outp.position = position; | |
outp.tex_coord = position.xy * float2(0.5, -0.5) + 0.5; | |
outp.view_ray = mul(vp_inv, position).xyz; | |
return outp; | |
} | |
float4 fs_triangle_ps(PS_INPUT input) : SV_Target | |
{ | |
return float4(input.tex_coord,0,0); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment