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 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.
I'm currently writting a 3D visualization tool for a scientific application and I am facing a performance problem.
I have a relatively large grid (~ 1000 rows x 1000 columns) and for each point of this grid I have a physical value that I want to represent as height (for instance: temperature).
Here is an example of what I am trying to draw with white gaussian noise:
http://i.stack.imgur.com/KM23m.jpg
I am using DirectX 9 to draw my scene. I basiclaly draw a bunch of triangles with the (X,Y) coordinate being a point on the grid, and the Z coordinate being the physical measurement at that point.
Here are the operations that I do on each frame:
I create a vertex buffer (CreateVertexBuffer()) and an index buffer (CreateIndexBuffer()) (the data changes on each frame, but the size of the data does not)
I lock them
I fill the two buffers properly, including assigning a color depending on the value (high value are red, low value are blue)
I unlock them
I set the stream source (SetStreamSource()), set the indices (SetIndices()) and draw the triangles (as a triangle strip)
I release the two buffers
My problem is that the frame rate is not as high as expected.
I achieve ~30fps for ~2 millions triangles drawn on a Nvidia GTX 770 (& Intel Core i7 4770k if that matters) when I want to have at least 60fps.
Is there a better way to do what I am doing or my problem is that the number of triangle is too large ?
Will I get better performance if I use DirectX 11 ?
Thank you for your help.
Edit here is a stand-alone simplified code:
#include <windows.h>
#define _USE_MATH_DEFINES
#include <math.h>
#include <windowsx.h>
#include <d3d9.h>
#include <vector>
#include <random>
#include <fcntl.h>
#include <io.h>
#define SCREEN_WIDTH 800
#define SCREEN_HEIGHT 600
#define COLORMAPSIZE 256
#pragma comment (lib, "d3d9.lib")
#define DEG2RAD(x) (x* (float)M_PI/180.0f)
#define CUSTOMFVF (D3DFVF_XYZ | D3DFVF_DIFFUSE)
std::default_random_engine randGenerator;
// global declarations
LPDIRECT3D9 d3d;
LPDIRECT3DDEVICE9 d3ddev;
const int Nrows = 1000, Ncols = 2000;
float indexAz=DEG2RAD(90), indexEl = DEG2RAD(60), distance=80;
const float dataAmplitude = 5.f;
std::vector<float> dataBuffer;
typedef struct D3DXVECTOR3 : public D3DVECTOR
{
public:
FLOAT x,y,z;
D3DXVECTOR3() {};
D3DXVECTOR3( FLOAT xx, FLOAT yy, FLOAT zz ) : x(xx), y(yy), z(zz) {};
} D3DXVECTOR3, *LPD3DXVECTOR3;
typedef struct {
float x, y, z;
D3DCOLOR color;
} Vertex;
void initD3D(HWND hWnd);
void resetD3D(HWND hWnd);
void render_frame(void);
void cleanD3D(void);
void draw_graphics(void);
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
void CreateConsole() {
CONSOLE_SCREEN_BUFFER_INFO consoleInfo;
int consoleHandleR, consoleHandleW ;
long stdioHandle;
FILE *fptr;
AllocConsole();
std::wstring strW = L"Dev Console";
SetConsoleTitleW( strW.c_str() );
EnableMenuItem(GetSystemMenu(GetConsoleWindow(), FALSE), SC_CLOSE , MF_GRAYED);
DrawMenuBar(GetConsoleWindow());
GetConsoleScreenBufferInfo( GetStdHandle(STD_OUTPUT_HANDLE), &consoleInfo );
stdioHandle = (long)GetStdHandle( STD_INPUT_HANDLE );
consoleHandleR = _open_osfhandle( stdioHandle, _O_TEXT );
fptr = _fdopen( consoleHandleR, "r" );
*stdin = *fptr;
setvbuf( stdin, NULL, _IONBF, 0 );
stdioHandle = (long) GetStdHandle( STD_OUTPUT_HANDLE );
consoleHandleW = _open_osfhandle( stdioHandle, _O_TEXT );
fptr = _fdopen( consoleHandleW, "w" );
*stdout = *fptr;
setvbuf( stdout, NULL, _IONBF, 0 );
stdioHandle = (long)GetStdHandle( STD_ERROR_HANDLE );
*stderr = *fptr;
setvbuf( stderr, NULL, _IONBF, 0 );
}
// Generate a random number following a uniform distribution
double rand(const double inf=0, const double sup=1) {
std::uniform_real_distribution<double> distribution(inf,sup);
return distribution(randGenerator);
}
// Update the buffer with new data
void UpdateDataBuffer()
{
static bool firstCall = true;
if (firstCall) //fill the whole buffer
{
for(unsigned k = 0 ; k < Nrows*Ncols ; k++)
dataBuffer[k] = (float)rand(0,dataAmplitude);
firstCall = false;
} else { // remove the first column, shift the whole buffer and update the last column
memmove(&dataBuffer[0], &dataBuffer[Nrows], (Ncols-1)*Nrows*sizeof(float));
for(unsigned k= Nrows*(Ncols-1) ; k < Nrows*Ncols ; k++)
dataBuffer[k] = (float)rand(0,dataAmplitude);
}
}
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
CreateConsole();
randGenerator.seed( GetTickCount() );
dataBuffer.resize(Nrows * Ncols);
HWND hWnd;
WNDCLASSEX wc;
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 = "WindowClass";
RegisterClassEx(&wc);
hWnd = CreateWindowEx(NULL, "WindowClass", "Our Direct3D Program",
WS_OVERLAPPEDWINDOW, 0, 0, SCREEN_WIDTH, SCREEN_HEIGHT,
NULL, NULL, hInstance, NULL);
ShowWindow(hWnd, nCmdShow);
initD3D(hWnd);
MSG msg;
LARGE_INTEGER frequency;
LARGE_INTEGER t1, t2;
float fps = 0.f;
float NFramAvg = 1.0f/10.0f, totalElapsedTime = 0.0f;
QueryPerformanceFrequency(&frequency);
while(TRUE)
{
while(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
if(msg.message == WM_QUIT)
break;
UpdateDataBuffer();
QueryPerformanceCounter(&t1);
render_frame();
QueryPerformanceCounter(&t2);
fps = fps - NFramAvg*fps + NFramAvg* frequency.QuadPart / (t2.QuadPart - t1.QuadPart);
totalElapsedTime += (t2.QuadPart - t1.QuadPart)*1000.0f / frequency.QuadPart;;
if (totalElapsedTime > 1000) {
printf("FPS = %g\n", fps);
totalElapsedTime = 0.0;
}
}
cleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
static int clickX, clickY;
static bool down = false;
switch(message)
{
case WM_LBUTTONDOWN:
if (!down)
{
clickX = GET_X_LPARAM(lParam);
clickY = GET_Y_LPARAM(lParam);
}
down = true;
break;
case WM_LBUTTONUP:
down = false;
break;
case WM_MOUSEMOVE:
if (down)
{
int dx = GET_X_LPARAM(lParam) - clickX;
int dy = GET_Y_LPARAM(lParam) - clickY;
indexAz += dx*DEG2RAD(0.5f);
if (indexEl + dy*DEG2RAD(0.5f) < M_PI_2 && indexEl + dy*DEG2RAD(0.5f) > -M_PI_2)
indexEl += dy*DEG2RAD(0.5f);
clickX += dx;
clickY += dy;
}
break;
case WM_MOUSEWHEEL:
{
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam); //scroll power
distance -= 2*zDelta/120.f;
distance = max(1.0f, distance);
break;
}
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
case WM_SIZE:
if (d3ddev)
resetD3D(hWnd);
break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void initD3D(HWND hWnd)
{
d3d = Direct3DCreate9(D3D_SDK_VERSION);
D3DPRESENT_PARAMETERS d3dpp;
RECT rect;
GetClientRect(hWnd, &rect);
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = rect.right - rect.left;
d3dpp.BackBufferHeight = rect.bottom -rect.top;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3d->CreateDevice(D3DADAPTER_DEFAULT,
D3DDEVTYPE_HAL,
hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp,
&d3ddev);
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // turn off culling
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
}
void resetD3D(HWND hWnd)
{
D3DPRESENT_PARAMETERS d3dpp;
RECT rect;
GetClientRect(hWnd, &rect);
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.hDeviceWindow = hWnd;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = rect.right - rect.left;
d3dpp.BackBufferHeight = rect.bottom -rect.top;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
if (d3dpp.BackBufferWidth && d3dpp.BackBufferHeight)
{
d3ddev->Reset(&d3dpp);
PAINTSTRUCT ps;
BeginPaint(hWnd, &ps);
EndPaint(hWnd, &ps);
InvalidateRect(hWnd, NULL, FALSE);
}
d3ddev->SetRenderState(D3DRS_LIGHTING, FALSE); // turn off the 3D lighting
d3ddev->SetRenderState(D3DRS_CULLMODE, D3DCULL_NONE); // turn off culling
d3ddev->SetRenderState(D3DRS_ZENABLE, TRUE); // turn on the z-buffer
}
D3DXVECTOR3 *D3DVec3Subtract(D3DXVECTOR3 *pOut, const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
pOut->x = pV1->x - pV2->x;
pOut->y = pV1->y - pV2->y;
pOut->z = pV1->z - pV2->z;
return pOut;
}
D3DXVECTOR3* D3DVec3Normalize(D3DXVECTOR3 *pOut,const D3DXVECTOR3 *pV)
{
FLOAT norm = sqrt( pV->x * pV->x + pV->y * pV->y + pV->z * pV->z );
pOut->x = pV->x / norm;
pOut->y = pV->y / norm;
pOut->z = pV->z / norm;
return pOut;
}
D3DXVECTOR3* D3DVec3Cross(D3DXVECTOR3 *pOut,const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
pOut->x = pV1->y*pV2->z - pV1->z*pV2->y;
pOut->y = pV1->z*pV2->x - pV1->x*pV2->z;
pOut->z = pV1->x*pV2->y - pV1->y*pV2->x;
return pOut;
}
FLOAT D3DVec3Dot(const D3DXVECTOR3 *pV1,const D3DXVECTOR3 *pV2)
{
return pV1->x * pV2->x + pV1->y * pV2->y + pV1->z * pV2->z;
}
D3DMATRIX* D3DMatrixLookAtLH(D3DMATRIX *pOut,const D3DXVECTOR3 *pEye,const D3DXVECTOR3 *pAt,const D3DXVECTOR3 *pUp)
{
D3DXVECTOR3 right, rightn, up, upn, vec, vec2;
D3DVec3Subtract(&vec2, pAt, pEye);
D3DVec3Normalize(&vec, &vec2);
D3DVec3Cross(&right, pUp, &vec);
D3DVec3Cross(&up, &vec, &right);
D3DVec3Normalize(&rightn, &right);
D3DVec3Normalize(&upn, &up);
pOut->m[0][0] = rightn.x;
pOut->m[1][0] = rightn.y;
pOut->m[2][0] = rightn.z;
pOut->m[3][0] = -D3DVec3Dot(&rightn,pEye);
pOut->m[0][1] = upn.x;
pOut->m[1][1] = upn.y;
pOut->m[2][1] = upn.z;
pOut->m[3][1] = -D3DVec3Dot(&upn, pEye);
pOut->m[0][2] = vec.x;
pOut->m[1][2] = vec.y;
pOut->m[2][2] = vec.z;
pOut->m[3][2] = -D3DVec3Dot(&vec, pEye);
pOut->m[0][3] = 0.0f;
pOut->m[1][3] = 0.0f;
pOut->m[2][3] = 0.0f;
pOut->m[3][3] = 1.0f;
return pOut;
}
D3DMATRIX* D3DXMatrixPerspectiveFovLH(D3DMATRIX *pOut, const FLOAT fovy, const FLOAT Aspect, const FLOAT zn, const FLOAT zf)
{
FLOAT yScale = tanf((float)M_PI_2 - fovy/2);
FLOAT xScale = yScale /Aspect;
memset(pOut,0, sizeof(*pOut));
pOut->_11 = xScale;
pOut->_22 = yScale;
pOut->_33 = zf/(zf-zn);
pOut->_34 = 1;
pOut->_43 = -zn*zf/(zf-zn);
return pOut;
}
long GetColor(const float x, const float inf, const float sup)
{
BYTE c =(BYTE)( 255 * (x-inf)/(sup-inf) );
return D3DCOLOR_XRGB(c,c,c);
}
// this is the function that puts the 3D models into video RAM
void draw_graphics(void)
{
static long colorTab[COLORMAPSIZE] = {0,};
static std::vector<Vertex> tmp;
static LPDIRECT3DVERTEXBUFFER9 v_buffer = NULL;
static LPDIRECT3DINDEXBUFFER9 i_buffer = NULL;
static unsigned NVertex = 0;
// Create empty IDirect3DTexture9
const unsigned MN = Nrows*Ncols;
unsigned k=0;
if (MN > tmp.size())
tmp.resize( MN );
if (colorTab[0] == 0) // if colortab empty, fill it
{
for(int i=0 ; i < COLORMAPSIZE ;i++)
colorTab[i] = GetColor((float)i, (float)0, (float)(COLORMAPSIZE-1));
}
if (!v_buffer)
d3ddev->CreateVertexBuffer(MN*sizeof(Vertex), 0,D3DFVF_XYZ | D3DFVF_DIFFUSE,D3DPOOL_MANAGED,&v_buffer,NULL);
float factor = (COLORMAPSIZE-1.0f)/dataAmplitude;
for (k=0 ; k < MN ; k++)
{
if (dataBuffer[k] >= dataAmplitude)
tmp[k].color = colorTab[COLORMAPSIZE-1];
else if (dataBuffer[k] <= 0)
tmp[k].color = colorTab[0];
else
tmp[k].color = colorTab[(int)( ( dataBuffer[k])*factor )];
}
float M_2 = Nrows/2.0f, N_2 = Ncols/2.0f;
k=0;
for (unsigned n=0 ; n < Ncols ; n++)
{
for (unsigned m=0 ; m < Nrows ; m++, k++)
{
tmp[k].x = M_2 - m;
tmp[k].z = n - N_2;
tmp[k].y = dataBuffer[k];
}
}
Vertex* pVoid;
v_buffer->Lock(0, 0, (void**)&pVoid, 0);
memcpy(pVoid, &tmp[0], MN*sizeof(Vertex));
v_buffer->Unlock();
if (!i_buffer)
d3ddev->CreateIndexBuffer(3*2*(Nrows-1)*(Ncols-1)*sizeof(DWORD), 0, D3DFMT_INDEX32, D3DPOOL_MANAGED,&i_buffer,NULL);
DWORD *indices;
i_buffer->Lock(0, 0, (void**)&indices, 0);
k=0;
for (unsigned n=0 ; n < Ncols-1 ; n++)
{
if (n!=0)
indices[k++] = n*Nrows;
for (unsigned m=0 ; m < Nrows-1 ; m++)
{
indices[k++] = m + n*Nrows;
indices[k++] = m + (n+1)*Nrows;
}
indices[k++] = Nrows-2 + (n+1)*Nrows;
}
NVertex = k;
i_buffer->Unlock();
d3ddev->SetStreamSource(0, v_buffer, 0, sizeof(Vertex));
d3ddev->SetIndices(i_buffer);
d3ddev->DrawIndexedPrimitive(D3DPT_TRIANGLESTRIP, 0, 0, MN, 0, NVertex-2);
//printf("%d triangle drawn\n", NVertex-2);
//i_buffer->Release();
//v_buffer->Release();
}
// this is the function used to render a single frame
void render_frame(void)
{
d3ddev->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->Clear(0, NULL, D3DCLEAR_ZBUFFER, D3DCOLOR_XRGB(0, 0, 0), 1.0f, 0);
d3ddev->BeginScene();
d3ddev->SetFVF(CUSTOMFVF);
// set the view transform
D3DMATRIX matView; // the view transform matrix
float R = distance*25;
D3DMatrixLookAtLH(&matView,
&D3DXVECTOR3 (R*sin(indexAz)*cos(indexEl), R*sin(indexEl),R*cos(indexAz)*cos(indexEl)), // the camera position
&D3DXVECTOR3 (0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3 (0.0f, 1.0f, 0.0f)); // the up direction
d3ddev->SetTransform(D3DTS_VIEW, &matView); // set the view transform to matView
// set the projection transform
D3DMATRIX matProjection; // the projection transform matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
DEG2RAD(45), // the horizontal field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
0.001f, // the near view-plane
100000.f); // the far view-plane
d3ddev->SetTransform(D3DTS_PROJECTION, &matProjection); // set the projection
indexAz += DEG2RAD(0.1f);
draw_graphics();
d3ddev->EndScene();
d3ddev->Present(NULL, NULL, NULL, NULL);
}
// this is the function that cleans up Direct3D and COM
void cleanD3D(void)
{
d3ddev->Release();
d3d->Release();
}
Well, because you say you're IO bound, the best thing would be to reduce the amount of data you send to the GPU every update.
If you're targeting SM 3.0 or higher you can use vertex texture fetching to sample the height from a texture that you update every frame. This is a lot easier on the input assembler and on BW.
To do this most easily, you might want to change your vertex data, instead of supplying a float3 with xyz, you might want to supply a uint2 with just xz, this way you can directly fetch from the texture without doing a float to int conversion in your shader.
as a side note, there is very little reason for you to write a vertex's color to your VB if it can be trivially derived from its position, it would be less bw to calculate it in the shader with a lerp or some other blending operation.
I've done this very thing for a project of mine, and the speedup is massive on my GTX 480. Brought me from spending 50ms on rendering heightmaps to around 1ms.
Unless I am missing something you don't need to lock your index buffer and update it, you are setting it to the same values anyways. That will get rid of that 1000x2000 loop.
Also I wouldn't update the vertex buffer everyframe if the data isn't changing everyframe. Just update it whenever the data is actually updated.
I'm trying to create a window that uses directx to draw opaque content on top of a transparent view (i.e. the desktop shows through). With DirectX11 I'm trying to do the following, but it's not making the background transparent. In fact, any opacity value I put in gives me the exact same results.
What I'm doing:
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
Working repro code (main.cpp):
#include <Windows.h>
#include <windowsx.h>
#pragma comment (lib, "Winmm.lib")
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "D3DCompiler.lib")
#include <dwmapi.h>
#pragma comment (lib, "Dwmapi.lib")
// Globals
IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *deviceContext;
ID3D11RenderTargetView *backBuffer;
ID3D11InputLayout *inputLayout; // the pointer to the input layout
ID3D11VertexShader *vertexShader; // the pointer to the vertex shader
ID3D11PixelShader *pixelShader; // the pointer to the pixel shader
ID3D11Buffer *vertexBuffer; // the pointer to the vertex buffer
void InitializeDirectX(HWND hWnd);
void LoadTriangle();
struct Vertex {
float x, y, z;
float color[4];
};
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Globals
const LPCWSTR ClassName = L"className";
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
// the handle for the window, filled by a function
HWND hWnd;
// this struct holds information for the window class
WNDCLASSEX wc;
// Pick out window size
int windowHeight = 400;
int windowWidth = 400;
// clear out the window class for use
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ClassName;
// register the window class
RegisterClassEx(&wc);
// Window style
DWORD exStyle = WS_EX_LAYERED | WS_EX_TOPMOST;
DWORD style = WS_POPUP;
// create the window and use the result as the handle
hWnd = CreateWindowEx(
exStyle, // extended styles
ClassName, // name of the window class
L"TestOverlay", // title of the window
style, // window style
0, // x-position of the window
0, // y-position of the window
400, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
SetWindowPos(hWnd,
HWND_TOPMOST,
0, 0,
windowWidth, windowHeight,
SWP_SHOWWINDOW);
// Show the window
ShowWindow(hWnd, SW_SHOWDEFAULT);
UpdateWindow(hWnd);
// Make the window transparent
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED);
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 255, LWA_ALPHA | LWA_COLORKEY);
// NOTE: If I uncomment DwmExtendFrameIntoClientArea then it becomes transparent, otherwise its a black screen
MARGINS dwmMargin = { -1 };
//DwmExtendFrameIntoClientArea(hWnd, &dwmMargin);
// DirectX
InitializeDirectX(hWnd);
LoadTriangle();
// enter the main loop:
MSG msg;
BOOL gotMessage;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
// DirectX stuff
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
// Draw triangle
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(0, 0);
}
}
return msg.wParam;
}
void InitializeDirectX(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapChain,
&device,
NULL,
&deviceContext);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
pBackBuffer->Release();
// set the render target as the back buffer
deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);
// Set the viewport size
RECT cRect;
GetClientRect(hWnd, &cRect);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = cRect.right - cRect.left;
viewport.Height = cRect.bottom - cRect.top;
deviceContext->RSSetViewports(1, &viewport);
// Initialize pipeline stuff
ID3D10Blob *VS, *PS;
// compile shader
D3DCompileFromFile(L"shaders.shader", 0, 0, "VShader", "vs_4_0", 0, 0, &VS, 0);
D3DCompileFromFile(L"shaders.shader", 0, 0, "PShader", "ps_4_0", 0, 0, &PS, 0);
// encapsulate both shaders into shader objects
device->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &vertexShader);
device->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pixelShader);
deviceContext->VSSetShader(vertexShader, 0, 0);
deviceContext->PSSetShader(pixelShader, 0, 0);
// create input layout object
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 },
};
device->CreateInputLayout(ied, 2, VS->GetBufferPointer(), VS->GetBufferSize(), &inputLayout);
deviceContext->IASetInputLayout(inputLayout);
}
void LoadTriangle()
{
// create a triangle using the VERTEX struct
Vertex OurVertices[] =
{
{ 0.0f, 0.5f, 0.0f, { 1.0f, 0.0f, 0.0f, 1.0f } },
{ 0.45f, -0.5, 0.0f, { 0.0f, 1.0f, 0.0f, 1.0f } },
{ -0.45f, -0.5f, 0.0f, { 0.0f, 0.0f, 1.0f, 1.0f } }
};
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC; // write access access by CPU and GPU
bd.ByteWidth = sizeof(Vertex)* 3; // size is the VERTEX struct * 3
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER; // use as a vertex buffer
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE; // allow CPU to write in buffer
device->CreateBuffer(&bd, NULL, &vertexBuffer); // create the buffer
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
deviceContext->Map(vertexBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, OurVertices, sizeof(OurVertices)); // copy the data
deviceContext->Unmap(vertexBuffer, NULL); // unmap the buffer
}
Shader file (shaders.shader):
struct VOut
{
float4 position : SV_POSITION;
float4 color : COLOR;
};
VOut VShader(float4 position : POSITION, float4 color : COLOR)
{
VOut output;
output.position = position;
output.color = color;
return output;
}
float4 PShader(float4 position : SV_POSITION, float4 color : COLOR) : SV_TARGET
{
return color;
}
If you uncomment the DwmExtendFrameIntoClientArea call on line 119ish, then it gets the effect I'm looking for. I'm wondering if there's a way to get the same effect without the use of dwm (for reasons I won't go into).
Any ideas?
Edit: Added full source code of working example. Found out that if I make a call to DwmExtendFrameIntoClientArea, then I get the effect I want. But I'd still like to know if its possible to do it without using dwm apis.
You can't make a Window transparent with DirectX only, The following code only clear the background color to black.
float color[4] = { 0.0f, 0.0f, 0.0f, 0.0f };
To achieve transparent effect of your window, you need to involve some win32 stuff, SetLayeredWindowAttributes is your choice.
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 100, LWA_ALPHA);
UPDATE:
Workable code draw nothing but make the window transparent in green color.
#include <Windows.h>
#include <windowsx.h>
#pragma comment (lib, "Winmm.lib")
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#include <d3dcompiler.h>
#pragma comment(lib, "D3DCompiler.lib")
#include <dwmapi.h>
#pragma comment (lib, "Dwmapi.lib")
// Globals
IDXGISwapChain *swapChain;
ID3D11Device *device;
ID3D11DeviceContext *deviceContext;
ID3D11RenderTargetView *backBuffer;
void InitializeDirectX(HWND hWnd);
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch (message)
{
case WM_DESTROY:
{
// close the application entirely
PostQuitMessage(0);
return 0;
}
}
return DefWindowProc(hWnd, message, wParam, lParam);
}
// Globals
const LPCWSTR ClassName = L"className";
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
// fill in the struct with the needed information
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hbrBackground = (HBRUSH)COLOR_WINDOW;
wc.lpszClassName = ClassName;
// register the window class
RegisterClassEx(&wc);
// create the window and use the result as the handle
HWND hWnd = CreateWindowEx(
NULL, // extended styles
ClassName, // name of the window class
L"TestOverlay", // title of the window
WS_OVERLAPPEDWINDOW, // window style
0, // x-position of the window
0, // y-position of the window
400, // width of the window
400, // height of the window
NULL, // we have no parent window, NULL
NULL, // we aren't using menus, NULL
hInstance, // application handle
NULL); // used with multiple windows, NULL
// display the window on the screen
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
// Make the window transparent
SetWindowLong(hWnd, GWL_EXSTYLE, WS_EX_LAYERED) ;
SetLayeredWindowAttributes(hWnd, RGB(0, 0, 0), 128, LWA_ALPHA);
// DirectX
InitializeDirectX(hWnd);
// enter the main loop:
MSG msg;
BOOL gotMessage;
while (TRUE)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if (msg.message == WM_QUIT)
break;
// DirectX stuff
float color[4] = { 0.0f, 1.0f, 0.0f, 0.0f };
deviceContext->ClearRenderTargetView(backBuffer, color);
swapChain->Present(0, 0);
}
}
return msg.wParam;
}
void InitializeDirectX(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapChain,
&device,
NULL,
&deviceContext);
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapChain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
device->CreateRenderTargetView(pBackBuffer, NULL, &backBuffer);
pBackBuffer->Release();
// set the render target as the back buffer
deviceContext->OMSetRenderTargets(1, &backBuffer, NULL);
// Set the viewport size
RECT cRect;
GetClientRect(hWnd, &cRect);
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0;
viewport.TopLeftY = 0;
viewport.Width = cRect.right - cRect.left;
viewport.Height = cRect.bottom - cRect.top;
deviceContext->RSSetViewports(1, &viewport);
}
This is a bit of an edge case but I am developing a game which uses multiple monitors. For reasons outside the scope of this question, I am using a 'multi-device method' rather than swap chains. My code is similar to the following sample:
http://www.codesampler.com/dx9src/dx9src_1.htm#dx9_multiple_devices
What I'm struggling with, and what I can find no documentation about, is whether it's possible to run both windows in true full-screen (i.e d3dpp.Windowed = FALSE;). Currently I'm getting an 'invalid params' HRESULT when calling CreateDevice the second time. It works fine if one of the windows is full-screen, but not both. I'm hoping there's a setting to make this work though...
Cheers in advance
According to the Direct3D 9 documentation (Working with Multiple Monitor Systems): "The practical implication is that a multiple monitor application can place several devices in full-screen mode, but only if all these devices are for different adapters, were created by the same Direct3D9 object, and all share the same focus window."
You'll notice that there are two window handles per device initialization; the presentation window, and the focus window. The focus window (passed in to IDirect3D9::CreateDevice) is used for handling events such as switching from foreground to background, or Alt+Tab. The presentation window is passed in to the D3DPRESENT_PARAMETERS structure and is used solely as a canvas for Direct3D.
You should mark one of the windows you create (probably the first one) as the focus window. Share the focus window across devices but keep the "canvas" (presentation) windows separate.
EDIT: This may help you as well.
create a focus window for both devices.
(optionally) create a device window for the first adapter.
create a device window for the second adapter.
create a direct3d9 context.
use this to create both devices.
create the first fullscreen device using the shared focus window and (optionally) the first device window.
create the second fullscreen device using the shared focus window and the second device window.
reset the first device.
the shared focus window is passed directly as a parameter to CreateDevice.
the device windows are passed in the presentation parameters structure.
Q> Currently I'm getting an 'invalid params' HRESULT when calling CreateDevice the second time. It works fine if one of the windows is
full-screen, but not both.
Because you were creating two different devices using a same adapter id 0. Use the adater id as 1 for the second create device call !
Important step to be done after the creation of device 2 or 3 or 4... is to reset the device one (default device id 0).
Create Device 1
Create Device 2
........
........
Create Device n
Reset Device 1
For to make your and another's life easier I have added a working code for supporting Multiple Monitors in Full Screen (Directx 9). Please note that I have added/changed few lines of code from the sample code took from the web link you have mentioned in your question.
#define STRICT
#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <mmsystem.h>
#include <stdio.h>
#include <d3d9.h>
#include <d3dx9.h>
#include "resource.h"
// define the screen resolution
#define SCREEN_WIDTH 1920
#define SCREEN_HEIGHT 1080
//-----------------------------------------------------------------------------
// GLOBALS
//-----------------------------------------------------------------------------
LPDIRECT3D9 g_pD3D = NULL;
HWND g_hWnd_0 = NULL; // Handle to the first window
HWND g_hWnd_1 = NULL; // Handle to the second window
LPDIRECT3DDEVICE9 g_pd3dDevice_0 = NULL; // Direct3d device for the first window
LPDIRECT3DDEVICE9 g_pd3dDevice_1 = NULL; // Direct3d device for the second window
LPD3DXMESH g_pTeapotMesh_0 = NULL; // The two devices can't share resources, so we'll
LPD3DXMESH g_pTeapotMesh_1 = NULL; // have to create two meshes... one for each device
D3DMATERIAL9 g_teapotMtrl;
D3DLIGHT9 g_pLight0;
LPD3DXFONT g_pd3dxFont = NULL;
DWORD g_dwBackBufferWidth = 0;
DWORD g_dwBackBufferHeight = 0;
bool windowed = false;
float g_fSpinX = 0.0f;
float g_fSpinY = 0.0f;
double g_dElpasedFrameTime = 0.0f;
double g_dElpasedAppTime = 0.0f;
double g_dCurrentTime = 0.0f;
double g_dLastTime = 0.0f;
struct Vertex
{
float x, y, z; // Position of vertex in 3D space
float nx, ny, nz; // Normal for lighting calculations
DWORD diffuse; // Diffuse color of vertex
enum FVF
{
FVF_Flags = D3DFVF_XYZ | D3DFVF_NORMAL | D3DFVF_DIFFUSE
};
};
#define TWO
//-----------------------------------------------------------------------------
// PROTOTYPES
//-----------------------------------------------------------------------------
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,
LPSTR lpCmdLine, int nCmdShow);
LRESULT CALLBACK WindowProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam);
void CreateFont(void);
void init_0(void);
void init_1(void);
void shutDown_0(void);
void shutDown_1(void);
void render_0(void);
void render_1(void);
void LoadModels(void);
void ResetDevice(void);
//-----------------------------------------------------------------------------
// Name: WinMain()
// Desc: The application's entry point
//-----------------------------------------------------------------------------
int WINAPI WinMain( HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow )
{
WNDCLASSEX winClass;
MSG uMsg;
bool deviceReset = FALSE;
memset(&uMsg,0,sizeof(uMsg));
winClass.lpszClassName = "MY_WINDOWS_CLASS";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = WindowProc;
winClass.hInstance = hInstance;
winClass.hIcon = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
winClass.hIconSm = LoadIcon(hInstance, (LPCTSTR)IDI_DIRECTX_ICON);
winClass.hCursor = LoadCursor(NULL, IDC_ARROW);
winClass.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
winClass.lpszMenuName = NULL;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
if(!RegisterClassEx( &winClass) )
return E_FAIL;
//
// Create window #0...
//
g_hWnd_0 = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",
"Direct3D (DX9) - Multiple Devices (Window #0)",
WS_EX_TOPMOST | WS_POPUP, // fullscreen values /* WS_OVERLAPPEDWINDOW | WS_VISIBLE,*/
0, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );
if( g_hWnd_0 == NULL )
return E_FAIL;
ShowWindow( g_hWnd_0, nCmdShow );
UpdateWindow( g_hWnd_0 );
#ifdef TWO
//
// Create window #1...
//
g_hWnd_1 = CreateWindowEx( NULL, "MY_WINDOWS_CLASS",
"Direct3D (DX9) - Multiple Devices (Window #1)",
WS_EX_TOPMOST | WS_POPUP, // fullscreen values /* WS_OVERLAPPEDWINDOW | WS_VISIBLE,*/
1920, 0, SCREEN_WIDTH, SCREEN_HEIGHT, NULL, NULL, hInstance, NULL );
if( g_hWnd_1 == NULL )
return E_FAIL;
ShowWindow( g_hWnd_1, nCmdShow );
UpdateWindow( g_hWnd_1 );
#endif
//
// Init Direct3D usage on both windows...
//
init_0();
#ifdef TWO
init_1();
#endif
ResetDevice(); // Important !!!
LoadModels();
while( uMsg.message != WM_QUIT )
{
if( PeekMessage( &uMsg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &uMsg );
DispatchMessage( &uMsg );
}
else
{
g_dCurrentTime = timeGetTime();
g_dElpasedFrameTime = g_dCurrentTime - g_dLastTime; // How much time has passed since the last frame?
g_dElpasedAppTime += g_dElpasedFrameTime; // How much time has passed overall for the application?
g_dLastTime = g_dCurrentTime;
render_0();
#ifdef TWO
render_1();
#endif
}
}
//
// Cleanup Direct3D usage on both windows...
//
#ifdef TWO
shutDown_1();
#endif
shutDown_0();
UnregisterClass( "MY_WINDOWS_CLASS", winClass.hInstance );
return uMsg.wParam;
}
void ResetDevice(void)
{
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory(&d3dpp, sizeof(d3dpp));
d3dpp.Windowed = windowed;
d3dpp.hDeviceWindow = g_hWnd_0;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH; // set the width of the buffer
d3dpp.BackBufferHeight = SCREEN_HEIGHT; // set the height of the buffer
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
g_pd3dDevice_0->Reset(&d3dpp);
}
void LoadModels(void)
{
D3DXMATRIX matProj;
D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(45.0f), 1920.0f / 1080.0f, 0.1f, 100.0f );
g_pd3dDevice_0->SetTransform( D3DTS_PROJECTION, &matProj );
g_pd3dDevice_0->SetRenderState( D3DRS_ZENABLE, TRUE );
g_pd3dDevice_0->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pd3dDevice_0->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
// Setup a material for the teapot
ZeroMemory( &g_teapotMtrl, sizeof(D3DMATERIAL9) );
g_teapotMtrl.Diffuse.r = 1.0f;
g_teapotMtrl.Diffuse.g = 1.0f;
g_teapotMtrl.Diffuse.b = 1.0f;
g_teapotMtrl.Diffuse.a = 1.0f;
// Setup a simple directional light and some ambient...
g_pLight0.Type = D3DLIGHT_DIRECTIONAL;
g_pLight0.Direction = D3DXVECTOR3( 1.0f, 0.0f, 1.0f );
g_pLight0.Diffuse.r = 1.0f;
g_pLight0.Diffuse.g = 1.0f;
g_pLight0.Diffuse.b = 1.0f;
g_pLight0.Diffuse.a = 1.0f;
g_pLight0.Specular.r = 1.0f;
g_pLight0.Specular.g = 1.0f;
g_pLight0.Specular.b = 1.0f;
g_pLight0.Specular.a = 1.0f;
g_pd3dDevice_0->SetLight( 0, &g_pLight0 );
g_pd3dDevice_0->LightEnable( 0, TRUE );
g_pd3dDevice_0->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( 0.2f, 0.2f, 0.2f, 1.0f ) );
// Load up the teapot mesh...
D3DXLoadMeshFromX( "teapot.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice_0, NULL, NULL, NULL, NULL, &g_pTeapotMesh_0 );
CreateFont();
#ifndef TWO
return;
#endif
D3DXMatrixPerspectiveFovLH( &matProj, D3DXToRadian(45.0f), 1920.0f / 1080.0f, 0.1f, 100.0f );
g_pd3dDevice_1->SetTransform( D3DTS_PROJECTION, &matProj );
g_pd3dDevice_1->SetRenderState( D3DRS_ZENABLE, TRUE );
g_pd3dDevice_1->SetRenderState( D3DRS_LIGHTING, TRUE );
g_pd3dDevice_1->SetRenderState( D3DRS_SPECULARENABLE, TRUE );
// Setup a material for the teapot
ZeroMemory( &g_teapotMtrl, sizeof(D3DMATERIAL9) );
g_teapotMtrl.Diffuse.r = 1.0f;
g_teapotMtrl.Diffuse.g = 1.0f;
g_teapotMtrl.Diffuse.b = 1.0f;
g_teapotMtrl.Diffuse.a = 1.0f;
// Setup a simple directional light and some ambient...
g_pLight0.Type = D3DLIGHT_DIRECTIONAL;
g_pLight0.Direction = D3DXVECTOR3( 1.0f, 0.0f, 1.0f );
g_pLight0.Diffuse.r = 1.0f;
g_pLight0.Diffuse.g = 1.0f;
g_pLight0.Diffuse.b = 1.0f;
g_pLight0.Diffuse.a = 1.0f;
g_pLight0.Specular.r = 1.0f;
g_pLight0.Specular.g = 1.0f;
g_pLight0.Specular.b = 1.0f;
g_pLight0.Specular.a = 1.0f;
g_pd3dDevice_1->SetLight( 0, &g_pLight0 );
g_pd3dDevice_1->LightEnable( 0, TRUE );
g_pd3dDevice_1->SetRenderState( D3DRS_AMBIENT, D3DCOLOR_COLORVALUE( 0.2f, 0.2f, 0.2f, 1.0f ) );
// Load up the teapot mesh...
D3DXLoadMeshFromX( "teapot.x", D3DXMESH_SYSTEMMEM, g_pd3dDevice_1, NULL, NULL, NULL, NULL, &g_pTeapotMesh_1 );
}
//-----------------------------------------------------------------------------
// Name: WindowProc()
// Desc: The window's message handler
//-----------------------------------------------------------------------------
LRESULT CALLBACK WindowProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
static POINT ptLastMousePosit;
static POINT ptCurrentMousePosit;
static bool bMousing;
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
PostQuitMessage(0);
break;
}
}
break;
case WM_LBUTTONDOWN:
{
ptLastMousePosit.x = ptCurrentMousePosit.x = LOWORD (lParam);
ptLastMousePosit.y = ptCurrentMousePosit.y = HIWORD (lParam);
bMousing = true;
}
break;
case WM_LBUTTONUP:
{
bMousing = false;
}
break;
case WM_MOUSEMOVE:
{
ptCurrentMousePosit.x = LOWORD (lParam);
ptCurrentMousePosit.y = HIWORD (lParam);
if( bMousing )
{
g_fSpinX -= (ptCurrentMousePosit.x - ptLastMousePosit.x);
g_fSpinY -= (ptCurrentMousePosit.y - ptLastMousePosit.y);
}
ptLastMousePosit.x = ptCurrentMousePosit.x;
ptLastMousePosit.y = ptCurrentMousePosit.y;
}
break;
case WM_CLOSE:
{
PostQuitMessage(0);
}
case WM_DESTROY:
{
PostQuitMessage(0);
}
break;
default:
{
return DefWindowProc( hWnd, msg, wParam, lParam );
}
break;
}
return 0;
}
void CreateFont( void )
{
HRESULT hr;
HDC hDC;
//HFONT hFont;
int nHeight;
int nPointSize = 9;
//char strFontName[] = "Arial";
hDC = GetDC( NULL );
nHeight = -( MulDiv( nPointSize, GetDeviceCaps(hDC, LOGPIXELSY), 72 ) );
ReleaseDC( NULL, hDC );
// Create a font for statistics and help output
hr = D3DXCreateFont( g_pd3dDevice_0, nHeight, 0, FW_BOLD, 0, FALSE, DEFAULT_CHARSET, OUT_DEFAULT_PRECIS, DEFAULT_QUALITY, DEFAULT_PITCH | FF_DONTCARE, TEXT("Arial"), &g_pd3dxFont );
if( FAILED( hr ) ) MessageBox(NULL, "Call to D3DXCreateFont failed!", "ERROR", MB_OK | MB_ICONEXCLAMATION);
}
//-----------------------------------------------------------------------------
// Name: init_0()
// Desc:
//-----------------------------------------------------------------------------
void init_0( void )
{
g_pD3D = Direct3DCreate9( D3D_SDK_VERSION );
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = windowed;
d3dpp.hDeviceWindow = g_hWnd_0;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH; // set the width of the buffer
d3dpp.BackBufferHeight = SCREEN_HEIGHT; // set the height of the buffer
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, g_hWnd_0, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice_0 );
}
//-----------------------------------------------------------------------------
// Name: init_1()
// Desc:
//-----------------------------------------------------------------------------
void init_1( void )
{
HWND window;
if(!windowed)
{
window = g_hWnd_0;
}
else
{
window = g_hWnd_1;
}
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = windowed;
d3dpp.hDeviceWindow = window;
d3dpp.SwapEffect = D3DSWAPEFFECT_FLIP;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferWidth = SCREEN_WIDTH; // set the width of the buffer
d3dpp.BackBufferHeight = SCREEN_HEIGHT; // set the height of the buffer
d3dpp.BackBufferCount = 1;
d3dpp.EnableAutoDepthStencil = TRUE;
d3dpp.AutoDepthStencilFormat = D3DFMT_D16;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
g_pD3D->CreateDevice( 1, D3DDEVTYPE_HAL, window, D3DCREATE_HARDWARE_VERTEXPROCESSING, &d3dpp, &g_pd3dDevice_1 );
}
//-----------------------------------------------------------------------------
// Name: shutDown()
// Desc:
//-----------------------------------------------------------------------------
void shutDown_0( void )
{
if( g_pTeapotMesh_0 != NULL )
g_pTeapotMesh_0->Release();
if( g_pd3dDevice_0 != NULL )
g_pd3dDevice_0->Release();
if( g_pD3D != NULL )
g_pD3D->Release();
}
//-----------------------------------------------------------------------------
// Name: shutDown()
// Desc:
//-----------------------------------------------------------------------------
void shutDown_1( void )
{
if( g_pTeapotMesh_1 != NULL )
g_pTeapotMesh_1->Release();
if( g_pd3dDevice_1 != NULL )
g_pd3dDevice_1->Release();
}
//-----------------------------------------------------------------------------
// Name: render_0()
// Desc:
//-----------------------------------------------------------------------------
void render_0( void )
{
D3DXMATRIX matView;
D3DXMATRIX matWorld;
D3DXMATRIX matRotation;
D3DXMATRIX matTranslation;
static int nFrameCount = 0;
static double nTimeOfLastFPSUpdate = 0.0;
static char fpsString[50] = "Frames Per Second = ";
RECT destRect;
// Now we can clear just view-port's portion of the buffer to red...
g_pd3dDevice_0->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE( 1.0f, 0.0f, 0.0f, 1.0f ), 1.0f, 0 );
g_pd3dDevice_0->BeginScene();
// For the left view-port, leave the view at the origin...
D3DXMatrixIdentity( &matView );
g_pd3dDevice_0->SetTransform( D3DTS_VIEW, &matView );
// ... and use the world matrix to spin and translate the teapot
// out where we can see it...
D3DXMatrixRotationYawPitchRoll( &matRotation, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f );
D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, 5.0f );
matWorld = matRotation * matTranslation;
g_pd3dDevice_0->SetTransform( D3DTS_WORLD, &matWorld );
g_pd3dDevice_0->SetMaterial( &g_teapotMtrl );
g_pTeapotMesh_0->DrawSubset(0);
g_pd3dDevice_0->EndScene();
// Report frames per second and the number of objects culled...
++nFrameCount;
if( g_dElpasedAppTime - nTimeOfLastFPSUpdate > 1000 ) // Update once a second
{
sprintf( fpsString, "Frames Per Second = %4.2f", nFrameCount*1000.0/(g_dElpasedAppTime - nTimeOfLastFPSUpdate) );
nTimeOfLastFPSUpdate = g_dElpasedAppTime;
nFrameCount = 0;
}
SetRect( &destRect, 5, 5, 0, 0 );
g_pd3dxFont->DrawText( NULL, fpsString, -1, &destRect, DT_NOCLIP, D3DXCOLOR( 1.0f, 1.0f, 1.0f, 1.0f ) );
g_pd3dDevice_0->Present( NULL, NULL, NULL, NULL );
}
//-----------------------------------------------------------------------------
// Name: render_1()
// Desc:
//-----------------------------------------------------------------------------
void render_1( void )
{
D3DXMATRIX matView;
D3DXMATRIX matWorld;
D3DXMATRIX matRotation;
D3DXMATRIX matTranslation;
// Now we can clear just view-port's portion of the buffer to green...
g_pd3dDevice_1->Clear( 0, NULL, D3DCLEAR_TARGET | D3DCLEAR_ZBUFFER, D3DCOLOR_COLORVALUE( 0.0f, 1.0f, 0.0f, 1.0f ), 1.0f, 0 );
g_pd3dDevice_1->BeginScene();
// For the left view-port, leave the view at the origin...
D3DXMatrixIdentity( &matView );
g_pd3dDevice_1->SetTransform( D3DTS_VIEW, &matView );
// ... and use the world matrix to spin and translate the teapot
// out where we can see it...
D3DXMatrixRotationYawPitchRoll( &matRotation, D3DXToRadian(g_fSpinX), D3DXToRadian(g_fSpinY), 0.0f );
D3DXMatrixTranslation( &matTranslation, 0.0f, 0.0f, 5.0f );
matWorld = matRotation * matTranslation;
g_pd3dDevice_1->SetTransform( D3DTS_WORLD, &matWorld );
g_pd3dDevice_1->SetMaterial( &g_teapotMtrl );
g_pTeapotMesh_1->DrawSubset(0);
g_pd3dDevice_1->EndScene();
// We're done! Now, we just call Present()
g_pd3dDevice_1->Present( NULL, NULL, NULL, NULL );
}