How to refresh the graphics to avoid black screen? - c++

When I minimized my directx framework and open up the task manage then go back to the framework. It gives me the black screen. How should I modify my code to fix this flaw?
GraphicsClass.h
#ifndef _GRAPHICSCLASS_H_
#define _GRAPHICSCLASS_H_
//////////////
// INCLUDES //
//////////////
#include <d3dx9.h>
#include <assert.h>
#include <string>
using namespace std;
/////////////
// GLOBALS //
/////////////
const bool FULL_SCREEN = false;
const unsigned int SCREEN_WIDTH = 1280;
const unsigned int SCREEN_HEIGHT = 720;
////////////////////////////////////////////////////////////////////////////////
// Class name: GraphicsClass
////////////////////////////////////////////////////////////////////////////////
class GraphicsClass
{
public:
GraphicsClass( HWND hwnd );
~GraphicsClass();
void SetPath( const string& loadFolder );
void BeginFrame();
void EndFrame();
void Load( IDirect3DTexture9*& texture, string imgName, int imgWidth, int imgHeight );
void setFont(ID3DXFont*& font, char* fontName, int fontHeight);
void SourceRect( RECT& sourceRect, int left, int right, int top, int bottom );
void DrawText( ID3DXFont*& font, LPCSTR string, int charNum, RECT& SourceRect, DWORD format, D3DCOLOR color );
void Draw( IDirect3DTexture9* texture );
void Draw( IDirect3DTexture9* texture, float posX, float posY );
void Draw( IDirect3DTexture9* texture, RECT& sourceRect, float posX, float posY );
private:
string path;
HRESULT result;
ID3DXSprite* pSprite;
IDirect3D9* pDirect3D;
IDirect3DDevice9* pDevice;
};
#endif
GraphicsClass.cpp
#include "GraphicsClass.h"
GraphicsClass::GraphicsClass( HWND hwnd )
{
pDirect3D = Direct3DCreate9( D3D_SDK_VERSION );
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof( d3dpp ) );
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
d3dpp.BackBufferCount = 1;
d3dpp.BackBufferWidth = SCREEN_WIDTH;
d3dpp.BackBufferHeight = SCREEN_HEIGHT;
d3dpp.hDeviceWindow = hwnd;
//d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_ONE;
result = pDirect3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hwnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING, &d3dpp, &pDevice );
assert( !FAILED(result) );
result = D3DXCreateSprite( pDevice, &pSprite );
assert( !FAILED(result) );
}
GraphicsClass::~GraphicsClass()
{
// Release and clean up sprite
pSprite->Release();
pSprite = NULL;
}
void GraphicsClass::SetPath( const string& path )
{
this->path = path;
}
void GraphicsClass::BeginFrame()
{
pDevice->Clear( 0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB( 255, 255, 255 ), 1.0f, 0 );
pDevice->BeginScene();
// Specify alpha blend will ensure that the sprite will render the background with alpha.
pSprite->Begin( D3DXSPRITE_ALPHABLEND );
}
void GraphicsClass::EndFrame()
{
// End sprite drawing
pSprite->End();
pDevice->EndScene();
pDevice->Present( NULL, NULL, NULL, NULL );
}
void GraphicsClass::Load( IDirect3DTexture9*& texture, string imgName, int imgWidth, int imgHeight )
{
string fullPath;
fullPath = path + imgName;
result = D3DXCreateTextureFromFileEx( pDevice, fullPath.c_str(), imgWidth, imgHeight,
D3DX_DEFAULT, NULL, D3DFMT_A8R8G8B8, D3DPOOL_MANAGED,
D3DX_DEFAULT, D3DX_DEFAULT, NULL,
NULL, NULL, &texture );
}
void GraphicsClass::setFont(ID3DXFont*& font, char* fontName, int fontHeight)
{
result = D3DXCreateFont(pDevice, fontHeight, 0, 0, 1, false,
DEFAULT_CHARSET, OUT_TT_ONLY_PRECIS, DEFAULT_QUALITY,
DEFAULT_PITCH | FF_DONTCARE, fontName, &font);
}
void GraphicsClass::SourceRect( RECT& sourceRect, int left, int right, int top, int bottom )
{
sourceRect.left = left;
sourceRect.right = right;
sourceRect.top = top;
sourceRect.bottom = bottom;
}
void GraphicsClass::DrawText( ID3DXFont*& font, LPCSTR string, int charNum, RECT& SourceRect, DWORD format, D3DCOLOR color)
{
font->DrawText(pSprite, string, charNum, &SourceRect, format, color);
}
void GraphicsClass::Draw( IDirect3DTexture9* texture )
{
pSprite->Draw( texture, NULL, NULL, &D3DXVECTOR3( 0, 0, 0 ), D3DCOLOR_XRGB( 255, 255, 255 ) );
}
void GraphicsClass::Draw( IDirect3DTexture9* texture, float posX, float posY )
{
pSprite->Draw( texture, NULL, NULL, &D3DXVECTOR3( posX, posY, 0 ), D3DCOLOR_XRGB( 255, 255, 255 ) );
}
void GraphicsClass::Draw( IDirect3DTexture9* texture, RECT& sourceRect, float posX, float posY )
{
pSprite->Draw( texture, &sourceRect, NULL, &D3DXVECTOR3( posX, posY, 0 ), D3DCOLOR_XRGB( 255, 255, 255 ) );
}
SystemClass.cpp
void SystemClass::InitializeWindows()
{
WNDCLASSEX wc;
DEVMODE dmScreenSettings;
int screenWidth, screenHeight;
int posX, posY;
// Get an external pointer to this object
ApplicationHandle = this;
// Get the instance of this application
m_hinstance = GetModuleHandle( NULL );
// Give the application a name
m_applicationName = "Zero DirectX Framework";
// Setup the windows class with default settings
wc.style = CS_HREDRAW | CS_VREDRAW | CS_OWNDC;
wc.lpfnWndProc = WndProc;
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hInstance = m_hinstance;
wc.hIcon = LoadIcon( NULL, IDI_WINLOGO );
wc.hIconSm = wc.hIcon;
wc.hCursor = LoadCursor( NULL, IDC_ARROW );
wc.hbrBackground = (HBRUSH)GetStockObject( BLACK_BRUSH );
wc.lpszMenuName = NULL;
wc.lpszClassName = m_applicationName;
wc.cbSize = sizeof( WNDCLASSEX );
// Register the window class
RegisterClassEx( &wc );
// Determine the resolution of the clients desktop screen
screenWidth = GetSystemMetrics( SM_CXSCREEN );
screenHeight = GetSystemMetrics( SM_CYSCREEN );
// Setup the screen settings depending on whether it is running in full screen or in windowed mode
if ( FULL_SCREEN )
{
// If full screen set the screen to maximum size of the users desktop and 32bit
memset( &dmScreenSettings, 0, sizeof(dmScreenSettings) );
dmScreenSettings.dmSize = sizeof(dmScreenSettings);
dmScreenSettings.dmPelsWidth = (unsigned long)screenWidth;
dmScreenSettings.dmPelsHeight = (unsigned long)screenHeight;
dmScreenSettings.dmBitsPerPel = 32;
dmScreenSettings.dmFields = DM_BITSPERPEL | DM_PELSWIDTH | DM_PELSHEIGHT;
// Change the display settings to full screen
ChangeDisplaySettings( &dmScreenSettings, CDS_FULLSCREEN );
// Set the position of the window to the top left corner
posX = posY = 0;
// Create the window with the screen settings and get the handle to it
m_hwnd = CreateWindowEx( WS_EX_APPWINDOW, m_applicationName, m_applicationName,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | WS_POPUP,
posX, posY, screenWidth, screenHeight, NULL, NULL, m_hinstance, NULL);
SetMenu( m_hwnd, NULL );
}
else
{
// If windowed then set it to 800x600 resolution
screenWidth = 1280;
screenHeight = 768;
// Place the window in the middle of the screen
posX = ( GetSystemMetrics( SM_CXSCREEN ) - screenWidth ) / 2;
posY = ( GetSystemMetrics( SM_CYSCREEN ) - screenHeight) / 2;
m_hwnd = CreateWindowEx( 0, m_applicationName, m_applicationName, WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU,
posX, posY, screenWidth, screenHeight,
NULL, NULL, m_hinstance, NULL );
}
// Bring the window up on the screen and set it as main focus
ShowWindow( m_hwnd, SW_SHOW );
SetForegroundWindow( m_hwnd );
SetFocus( m_hwnd );
// Hide the mouse cursor
ShowCursor(true);
}

You're not handling situation when device is lost, which is (possibly) what happens in this case.
Basically, BEFORE rendering anything you should test cooperative level, if it returns D3DERR_DEVICELOST, do not do not draw anything. If it returns D3DERR_DEVICENOTRESET, you should reset the device, if it returns 0 (D3DERR_OK or use SUCCEEDED macro), then proceed to draw the frame.
When device is reset, it loses all resources that are not in D3DPOOL_MANAGED, and you'll need to recreate them, or reload them. You can release all shaders and id3dx objects (like ID3DXFont) before calling IDirect3DDevice9::Reset, then recreate them after succesfull reset call.
Failure to handle "lost devices" will mean that you won't be able to alt-tab your game when running in fullscreen, and switching display mode might "break it". IN your situation black screen most likely happens for the same reason.

Related

Why is D2D drawing under D3D11?

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

Is it possible to draw a circle made up of triangles with DirectX 3D 11?

Is there a way to create a circle out of 16 triangles with DirectX 3D 11; kind of like a unit circle? I am currently using the Direct3D 11 Tutorial 02: Rendering a Triangle from the DirectX Sample Browser (June 2010) and modified it a bit to draw the triangle in the center, but I now want to draw a circle using that triangle.
Would I have to create 48 vertices to create it, or is there a easier way? Like using a for loop.
I am also new to C++, and am just learning and getting used to it and DirectX basics.
This is the code for the Tutorial02.cpp:
//--------------------------------------------------------------------------------------
// File: Tutorial02.cpp
//
// This application displays a triangle using Direct3D 11
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include "resource.h"
//--------------------------------------------------------------------------------------
// Structures
//--------------------------------------------------------------------------------------
struct SimpleVertex
{
XMFLOAT3 Pos;
};
//--------------------------------------------------------------------------------------
// Global Variables
//--------------------------------------------------------------------------------------
HINSTANCE g_hInst = NULL;
HWND g_hWnd = NULL;
D3D_DRIVER_TYPE g_driverType = D3D_DRIVER_TYPE_NULL;
D3D_FEATURE_LEVEL g_featureLevel = D3D_FEATURE_LEVEL_11_0;
ID3D11Device* g_pd3dDevice = NULL;
ID3D11DeviceContext* g_pImmediateContext = NULL;
IDXGISwapChain* g_pSwapChain = NULL;
ID3D11RenderTargetView* g_pRenderTargetView = NULL;
ID3D11VertexShader* g_pVertexShader = NULL;
ID3D11PixelShader* g_pPixelShader = NULL;
ID3D11InputLayout* g_pVertexLayout = NULL;
ID3D11Buffer* g_pVertexBuffer = NULL;
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow );
HRESULT InitDevice();
void CleanupDevice();
LRESULT CALLBACK WndProc( HWND, UINT, WPARAM, LPARAM );
void Render();
//--------------------------------------------------------------------------------------
// Entry point to the program. Initializes everything and goes into a message processing
// loop. Idle time is used to render the scene.
//--------------------------------------------------------------------------------------
int WINAPI wWinMain( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR lpCmdLine, int nCmdShow )
{
UNREFERENCED_PARAMETER( hPrevInstance );
UNREFERENCED_PARAMETER( lpCmdLine );
if( FAILED( InitWindow( hInstance, nCmdShow ) ) )
return 0;
if( FAILED( InitDevice() ) )
{
CleanupDevice();
return 0;
}
// Main message loop
MSG msg = {0};
while( WM_QUIT != msg.message )
{
if( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
{
TranslateMessage( &msg );
DispatchMessage( &msg );
}
else
{
Render();
}
}
CleanupDevice();
return ( int )msg.wParam;
}
//--------------------------------------------------------------------------------------
// Register class and create window
//--------------------------------------------------------------------------------------
HRESULT InitWindow( HINSTANCE hInstance, int nCmdShow )
{
// Register class
WNDCLASSEX wcex;
wcex.cbSize = sizeof( WNDCLASSEX );
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = LoadIcon( hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
wcex.hCursor = LoadCursor( NULL, IDC_ARROW );
wcex.hbrBackground = ( HBRUSH )( COLOR_WINDOW + 1 );
wcex.lpszMenuName = NULL;
wcex.lpszClassName = L"TutorialWindowClass";
wcex.hIconSm = LoadIcon( wcex.hInstance, ( LPCTSTR )IDI_TUTORIAL1 );
if( !RegisterClassEx( &wcex ) )
return E_FAIL;
// Create window
g_hInst = hInstance;
RECT rc = { 0, 0, 640, 480 };
AdjustWindowRect( &rc, WS_OVERLAPPEDWINDOW, FALSE );
g_hWnd = CreateWindow( L"TutorialWindowClass", L"Direct3D 11 Tutorial 2: Rendering a Triangle",
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, CW_USEDEFAULT, rc.right - rc.left, rc.bottom - rc.top, NULL, NULL, hInstance,
NULL );
if( !g_hWnd )
return E_FAIL;
ShowWindow( g_hWnd, nCmdShow );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Helper for compiling shaders with D3DX11
//--------------------------------------------------------------------------------------
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut )
{
HRESULT hr = S_OK;
DWORD dwShaderFlags = D3DCOMPILE_ENABLE_STRICTNESS;
#if defined( DEBUG ) || defined( _DEBUG )
// Set the D3DCOMPILE_DEBUG flag to embed debug information in the shaders.
// Setting this flag improves the shader debugging experience, but still allows
// the shaders to be optimized and to run exactly the way they will run in
// the release configuration of this program.
dwShaderFlags |= D3DCOMPILE_DEBUG;
#endif
ID3DBlob* pErrorBlob;
hr = D3DX11CompileFromFile( szFileName, NULL, NULL, szEntryPoint, szShaderModel,
dwShaderFlags, 0, NULL, ppBlobOut, &pErrorBlob, NULL );
if( FAILED(hr) )
{
if( pErrorBlob != NULL )
OutputDebugStringA( (char*)pErrorBlob->GetBufferPointer() );
if( pErrorBlob ) pErrorBlob->Release();
return hr;
}
if( pErrorBlob ) pErrorBlob->Release();
return S_OK;
}
//--------------------------------------------------------------------------------------
// Create Direct3D device and swap chain
//--------------------------------------------------------------------------------------
HRESULT InitDevice()
{
HRESULT hr = S_OK;
RECT rc;
GetClientRect( g_hWnd, &rc );
UINT width = rc.right - rc.left;
UINT height = rc.bottom - rc.top;
UINT createDeviceFlags = 0;
#ifdef _DEBUG
createDeviceFlags |= D3D11_CREATE_DEVICE_DEBUG;
#endif
D3D_DRIVER_TYPE driverTypes[] =
{
D3D_DRIVER_TYPE_HARDWARE,
D3D_DRIVER_TYPE_WARP,
D3D_DRIVER_TYPE_REFERENCE,
};
UINT numDriverTypes = ARRAYSIZE( driverTypes );
D3D_FEATURE_LEVEL featureLevels[] =
{
D3D_FEATURE_LEVEL_11_0,
D3D_FEATURE_LEVEL_10_1,
D3D_FEATURE_LEVEL_10_0,
};
UINT numFeatureLevels = ARRAYSIZE( featureLevels );
DXGI_SWAP_CHAIN_DESC sd;
ZeroMemory( &sd, sizeof( sd ) );
sd.BufferCount = 1;
sd.BufferDesc.Width = width;
sd.BufferDesc.Height = height;
sd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
sd.BufferDesc.RefreshRate.Numerator = 60;
sd.BufferDesc.RefreshRate.Denominator = 1;
sd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
sd.OutputWindow = g_hWnd;
sd.SampleDesc.Count = 1;
sd.SampleDesc.Quality = 0;
sd.Windowed = TRUE;
for( UINT driverTypeIndex = 0; driverTypeIndex < numDriverTypes; driverTypeIndex++ )
{
g_driverType = driverTypes[driverTypeIndex];
hr = D3D11CreateDeviceAndSwapChain( NULL, g_driverType, NULL, createDeviceFlags, featureLevels, numFeatureLevels,
D3D11_SDK_VERSION, &sd, &g_pSwapChain, &g_pd3dDevice, &g_featureLevel, &g_pImmediateContext );
if( SUCCEEDED( hr ) )
break;
}
if( FAILED( hr ) )
return hr;
// Create a render target view
ID3D11Texture2D* pBackBuffer = NULL;
hr = g_pSwapChain->GetBuffer( 0, __uuidof( ID3D11Texture2D ), ( LPVOID* )&pBackBuffer );
if( FAILED( hr ) )
return hr;
hr = g_pd3dDevice->CreateRenderTargetView( pBackBuffer, NULL, &g_pRenderTargetView );
pBackBuffer->Release();
if( FAILED( hr ) )
return hr;
g_pImmediateContext->OMSetRenderTargets( 1, &g_pRenderTargetView, NULL );
// Setup the viewport
D3D11_VIEWPORT vp;
vp.Width = (FLOAT)width;
vp.Height = (FLOAT)height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;
g_pImmediateContext->RSSetViewports( 1, &vp );
// Compile the vertex shader
ID3DBlob* pVSBlob = NULL;
hr = CompileShaderFromFile( L"Tutorial02.fx", "VS", "vs_4_0", &pVSBlob );
if( FAILED( hr ) )
{
MessageBox( NULL,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the vertex shader
hr = g_pd3dDevice->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &g_pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return hr;
}
// Define the input layout
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = ARRAYSIZE( layout );
// Create the input layout
hr = g_pd3dDevice->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &g_pVertexLayout );
pVSBlob->Release();
if( FAILED( hr ) )
return hr;
// Set the input layout
g_pImmediateContext->IASetInputLayout( g_pVertexLayout );
// Compile the pixel shader
ID3DBlob* pPSBlob = NULL;
hr = CompileShaderFromFile( L"Tutorial02.fx", "PS", "ps_4_0", &pPSBlob );
if( FAILED( hr ) )
{
MessageBox( NULL,
L"The FX file cannot be compiled. Please run this executable from the directory that contains the FX file.", L"Error", MB_OK );
return hr;
}
// Create the pixel shader
hr = g_pd3dDevice->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &g_pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return hr;
// Create vertex buffer
SimpleVertex vertices[] =
{
XMFLOAT3(-0.1f, 0.8f, 0.5f),
XMFLOAT3(0.1f, 0.8f, 0.5f),
XMFLOAT3(0.0f, 0.0f, 0.5f),
};
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 3;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = g_pd3dDevice->CreateBuffer( &bd, &InitData, &g_pVertexBuffer );
if( FAILED( hr ) )
return hr;
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
g_pImmediateContext->IASetVertexBuffers( 0, 1, &g_pVertexBuffer, &stride, &offset );
// Set primitive topology
g_pImmediateContext->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Clean up the objects we've created
//--------------------------------------------------------------------------------------
void CleanupDevice()
{
if( g_pImmediateContext ) g_pImmediateContext->ClearState();
if( g_pVertexBuffer ) g_pVertexBuffer->Release();
if( g_pVertexLayout ) g_pVertexLayout->Release();
if( g_pVertexShader ) g_pVertexShader->Release();
if( g_pPixelShader ) g_pPixelShader->Release();
if( g_pRenderTargetView ) g_pRenderTargetView->Release();
if( g_pSwapChain ) g_pSwapChain->Release();
if( g_pImmediateContext ) g_pImmediateContext->Release();
if( g_pd3dDevice ) g_pd3dDevice->Release();
}
//--------------------------------------------------------------------------------------
// Called every time the application receives a message
//--------------------------------------------------------------------------------------
LRESULT CALLBACK WndProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
PAINTSTRUCT ps;
HDC hdc;
switch( message )
{
case WM_PAINT:
hdc = BeginPaint( hWnd, &ps );
EndPaint( hWnd, &ps );
break;
case WM_DESTROY:
PostQuitMessage( 0 );
break;
default:
return DefWindowProc( hWnd, message, wParam, lParam );
}
return 0;
}
//--------------------------------------------------------------------------------------
// Render a frame
//--------------------------------------------------------------------------------------
void Render()
{
// Clear the back buffer
float ClearColor[4] = { 0.0f, 0.125f, 0.3f, 1.0f }; // red,green,blue,alpha
g_pImmediateContext->ClearRenderTargetView( g_pRenderTargetView, ClearColor );
// Render a triangle
g_pImmediateContext->VSSetShader( g_pVertexShader, NULL, 0 );
g_pImmediateContext->PSSetShader( g_pPixelShader, NULL, 0 );
g_pImmediateContext->Draw( 3, 0 );
// Present the information rendered to the back buffer to the front buffer (the screen)
g_pSwapChain->Present( 0, 0 );
}
If you want to draw a circle using 16 triangles, you need 17 vertices; one for each corner of your circle and one for the center. Then you have to use 48 indices to tell D3D how it should connect those vertices. Then you can call DrawIndexed to draw the triangles. You can also use a triangle strip which is a different primitive topology and uses slightly less indices.
See this tutorial on how to create vertex and index buffers.
Use a for loop, as you say. Let's say you want 10 triangles. There are 2pi radians in a circle, so 2pi/10 is the angle for each triangle. Let's calculate:
int n = 10; // number of triangles
SimpleVertex* vertices = malloc(sizeof(SimpleVertex) * 10 * 3); // 10 triangles, 3 verticies per triangle
float deltaTheta = 2*pi / n; // Change in theta for each vertex
for( int i = 0; i < n; i++ ) {
int theta = i * deltaTheta; // Theta is the angle for that triangle
int index = 3 * i;
vertices[index + 0] = SimpleVertex(0, 0, 0);
// Given an angle theta, cosine [cos] will give you the x coordinate,
// and sine [sin] will give you the y coordinate.
// #include <math.h>
vertices[index + 1] = SimpleVertex(cos(theta), sin(theta), 0);
vertices[index + 2] = SimpleVertex(cos(theta + deltaTheta), sin(theta + deltaTheta), 0);
}
Note:
As you can imagine, many of the vertices will overlap. (0, 0, 0) is always the same, and the last vertex of one triangle equals the 2nd vertical of the next triangle. I'll leave you up to the optimization, first get it working so you understand what's happening. If you aren't familiar with trig, look up the unit circle. Or just accept that cos/sin are defined to be the x and y coordinates of a circle given degrees (Or rather, radians). You will have to wait until your tutorial goes over how to specify what vertices each triangle uses first.

glutKeyboardFunc error [closed]

This question is unlikely to help any future visitors; it is only relevant to a small geographic area, a specific moment in time, or an extraordinarily narrow situation that is not generally applicable to the worldwide audience of the internet. For help making this question more broadly applicable, visit the help center.
Closed 10 years ago.
I have an opengl c++ code for reading .ply file. I want to read keyboard arrow keys(up,down,right,left) for move a point on the screen. I used glutKeyboardFunc function but i have an error:
Unhandled exception at 0x1000bb1e in opengl3.exe: 0xC0000005: Access violation reading location 0x00000070.
On this line:
glutKeyboardFunc(keyPressed);
#include <windows.h>
#include <gl/gl.h>
#include <gl/glu.h>
#include <gl/glut.h>
#include <iostream>
#include <stdio.h>
#include <string.h>
#include <cmath>
#include <string>
#include <conio.h>
HWND hWnd;
HDC hDC;
HGLRC hRC;
// Set up pixel format for graphics initialization
void SetupPixelFormat()
{
PIXELFORMATDESCRIPTOR pfd, *ppfd;
int pixelformat;
ppfd = &pfd;
ppfd->nSize = sizeof(PIXELFORMATDESCRIPTOR);
ppfd->nVersion = 1;
ppfd->dwFlags = PFD_DRAW_TO_WINDOW | PFD_SUPPORT_OPENGL | PFD_DOUBLEBUFFER;
ppfd->dwLayerMask = PFD_MAIN_PLANE;
ppfd->iPixelType = PFD_TYPE_COLORINDEX;
ppfd->cColorBits = 16;
ppfd->cDepthBits = 16;
ppfd->cAccumBits = 0;
ppfd->cStencilBits = 0;
pixelformat = ChoosePixelFormat(hDC, ppfd);
SetPixelFormat(hDC, pixelformat, ppfd);
}
void InitGraphics()
{
hDC = GetDC(hWnd);
SetupPixelFormat();
hRC = wglCreateContext(hDC);
wglMakeCurrent(hDC, hRC);
glClearColor(0, 0, 0, 0.5);
glClearDepth(1.0);
glEnable(GL_DEPTH_TEST);
}
// Resize graphics to fit window
void ResizeGraphics()
{
// Get new window size
RECT rect;
int width, height;
GLfloat aspect;
GetClientRect(hWnd, &rect);
width = rect.right;
height = rect.bottom;
aspect = (GLfloat)width / height;
// Adjust graphics to window size
glViewport(0, 0, width, height);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluPerspective(45.0, aspect, 1.0, 100.0);
glMatrixMode(GL_MODELVIEW);
}
// Draw frame
void DrawGraphics()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Set location in front of camera
glLoadIdentity();
glTranslated(0, 0, -10);
// Draw a square
glBegin(GL_QUADS);
glColor3d(100, 200, 30);
/*
glVertex3d(-2, 2, 0);
glVertex3d(2, 2, 0);
glVertex3d(2, -2, 0);
glVertex3d(-2, -2, 0);
*/
//FILE * file = fopen("D:\\dart.ply","r");
FILE * file = fopen("mosalas.ply","r");
if (file!=NULL)
{
fseek(file,0,SEEK_END);
long fileSize = ftell(file);
float* Vertex_Buffer;
try
{
Vertex_Buffer = (float*) malloc (ftell(file));
}
catch (char* )
{
//return -1;
}
//if (Vertex_Buffer == NULL) return -1;
fseek(file,0,SEEK_SET);
//Faces_Triangles = (float*) malloc(fileSize*sizeof(float));
//Normals = (float*) malloc(fileSize*sizeof(float));
if (file)
{
int i = 0;
int temp = 0;
int quads_index = 0;
int triangle_index = 0;
int normal_index = 0;
char buffer[1000];
fgets(buffer,300,file); // ply
// READ HEADER
// -----------------
int TotalConnectedPoints;
// Find number of vertexes
while ( strncmp( "element vertex", buffer,strlen("element vertex")) != 0 )
{
fgets(buffer,300,file); // format
}
strcpy(buffer, buffer+strlen("element vertex"));
sscanf(buffer,"%i", &TotalConnectedPoints);
int TotalFaces;
// Find number of face
fseek(file,0,SEEK_SET);
while ( strncmp( "element face", buffer,strlen("element face")) != 0 )
{
fgets(buffer,300,file); // format
}
strcpy(buffer, buffer+strlen("element face"));
sscanf(buffer,"%i", &TotalFaces);
// go to end_header
while ( strncmp( "end_header", buffer,strlen("end_header")) != 0 )
{
fgets(buffer,300,file); // format
}
i =0;
float* ver0,ver1,ver2,ver3;
//char* key[100];
for (int iterator = 0; iterator < TotalConnectedPoints; iterator++)
{
fgets(buffer,300,file);
//sscanf(buffer,"%f %f %f", &Vertex_Buffer[i], &Vertex_Buffer[i+1], &Vertex_Buffer[i+2]);
sscanf(buffer,"%f %f %f", &ver1, &ver2, &ver3);
glNormal3f(ver1, ver2, ver3);
glVertex3d(ver1, ver2, ver3);
//glVertex3f(ver1, ver2, ver3);
i += 3;
}
}
}
glPushMatrix();
glBegin;
glTranslatef(-10,5,0);
glColor3f(1,1,1);
glRotatef(90,0,1,0);
glutSolidCone(0.25, 15, 20, 20);
glEnd();
glPopMatrix();
//glutMouseFunc(0,0,0);
/*
glVertex3d(1.000000, 1.000000, 6);
glVertex3d(3.000000, 0.000000, 4);
glVertex3d(0.000000, 0.000000, 4);
glVertex3d(0.000000, 3.000000, 4);
glVertex3d(1.500000, 0.500000, 0);*/
glEnd();
// Show the new scene
SwapBuffers(hDC);/**/
}
void keyPressed (unsigned char key, int x, int y) {
}
// Handle window events and messages
LONG WINAPI MainWndProc (HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_SIZE:
ResizeGraphics();
break;
case WM_CLOSE:
DestroyWindow(hWnd);
break;
case WM_DESTROY:
PostQuitMessage(0);
break;
// Default event handler
default:
return DefWindowProc (hWnd, uMsg, wParam, lParam);
break;
}
return 1;
}
int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow)
{
const LPCWSTR appname = TEXT("OpenGL Sample");
WNDCLASS wndclass;
MSG msg;
// Define the window class
wndclass.style = 0;
wndclass.lpfnWndProc = (WNDPROC)MainWndProc;
wndclass.cbClsExtra = 0;
wndclass.cbWndExtra = 0;
wndclass.hInstance = hInstance;
wndclass.hIcon = LoadIcon(hInstance, appname);
wndclass.hCursor = LoadCursor(NULL,IDC_ARROW);
wndclass.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wndclass.lpszMenuName = appname;
wndclass.lpszClassName = appname;
// Register the window class
if (!RegisterClass(&wndclass)) return FALSE;
// Create the window
hWnd = CreateWindow(
appname,
appname,
WS_OVERLAPPEDWINDOW | WS_CLIPSIBLINGS | WS_CLIPCHILDREN,
CW_USEDEFAULT,
CW_USEDEFAULT,
800,
600,
NULL,
NULL,
hInstance,
NULL);
if (!hWnd) return FALSE;
// Initialize OpenGL
InitGraphics();
// Display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
DrawGraphics();
// Event loop
int key;
int asgh = 0;
POINT pt;
/**/while (1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE) == TRUE)
{
if (!GetMessage(&msg, NULL, 0, 0))
return TRUE;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
glutKeyboardFunc(keyPressed);
DrawGraphics();
}
wglDeleteContext(hRC);
ReleaseDC(hWnd, hDC);
}
The program you posted lacks a call to glutInit().
Furthermore you're doing all of the platform-specific window management and context creation that GLUT is supposed abstract away.
Bottom line: If you want to use GLUT, use GLUT. If you want to use Win32, use Win32. Don't try to mix-and-match.

Strange thing in D3D9 2D animation -- high FPS while still not smooth

The animation is quite simple: display a picture full-screen and move the picture out of the screen horizontally in 1 second, just like the slide show switching effect in MS PowerPoint.
I'm using the D3D9 surface to realize the animation, because I want the program to be compatible with Windows XP and I might also need some 3D effects of displaying pictures.
When I turn on the VSYNC(d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT), the fps stays at 60 but I can still see the picture moving discontinuously(very obvious). When I turn off the VSYNC, the fps stays around 1600, the picture moves more smoothly(but still lags a little).
The strange part for both cases is that I can see a zig-zag border of the picture and rupture in the picture:
##########
##########
#########
#########
########
I have no exprience in either DX or 2D-animation, so I need your help.
The key part of the code is as follows:
D3DPRESENT_PARAMETERS d3dpp = {0};
d3dpp.BackBufferCount = 3;
d3dpp.Windowed = TRUE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferFormat = D3DFMT_UNKNOWN;
d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_IMMEDIATE; //VSYNC off
// d3dpp.PresentationInterval = D3DPRESENT_INTERVAL_DEFAULT; //VSYNC
......
if(FAILED(D3DXLoadSurfaceFromFile(g_pSurface, NULL, NULL, PICPATH, NULL, D3DX_FILTER_NONE, 0, NULL)))
return E_FAIL;
......
while(1)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
break ;
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else DxRender();
}
VOID DxRender()
{
LPDIRECT3DSURFACE9 pBackBuffer = NULL;
g_pd3dDevice->Clear(0, NULL, D3DCLEAR_TARGET, D3DCOLOR_XRGB(0,0,0), 1.0f, 0 );
static int offs = 0;
static float StartTime = timeGetTime() * 0.001f;
float CurTime = timeGetTime() * 0.001f;
offs = CurTime - StartTime * g_cxClient / ANIMATION_TIME_S;
// ANIMATION_TIME_S = 1.0f
if(offs >= g_cxClient)
{
StartTime = CurTime;
offs -= g_cxClient;
}
RECT srcrect1 = {0,0,g_cxClient-1-offs,g_cyClient-1};
POINT dstpt1 = {offs,0};
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
if(FAILED(g_pd3dDevice->GetBackBuffer(0,0, D3DBACKBUFFER_TYPE_MONO, &pBackBuffer)))
{
MessageBox(NULL, TEXT("GetBackBuffer"), TEXT("Error"), MB_OK);
}
g_pd3dDevice->UpdateSurface(g_pSurface, &srcrect1, pBackBuffer, &dstpt1);
ShowFPS();
g_pd3dDevice->EndScene();
}
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
if(pBackBuffer != NULL)
pBackBuffer->Release();
}
That your animation isn't smooth can be caused by an insufficient resolution of timeGetTime(). This can cause these problems (see MSDN of timeGetTime()), because at high FPS a frame can be shorter than a millisecond. You can try QueryPerformanceCounter() to get a timer with a higher frequency (MSDN to QueryPerformanceCounter()). Then it shouldn't lag. I can't imagine, why there are zig-zags at 60 FPS, but with D3DPRESENT_INTERVAL_IMMEDIATE ruptures are normal, because the screen cannot keep up refreshing.
I have a solution which use the world matrix to translate the texture, the key steps as below
Create texuture from file
Display the texute
Update the the world matrix
if elapsed time less then 2 seconds, display the texture
else translate the texture to right until it out of screen, the translate
matrix was based on the time, you can just upate the matrix._41 filed.
full code as below, you should replace the texture file with your local file to see the effect, please see the code in function SetupMatrix for details of the translation.
#include <d3dx9.h>
LPDIRECT3D9 g_pD3D = NULL ; // Used to create the D3DDevice
LPDIRECT3DDEVICE9 g_pd3dDevice = NULL ; // Our rendering device
LPDIRECT3DVERTEXBUFFER9 g_pVB = NULL ; // Vertex buffer
LPDIRECT3DTEXTURE9 g_pTexture = NULL ; // Texture
D3DXMATRIX g_worldMatrix ;
float g_ShowTimeInterval = 2.0f; // How long will the picture displays.
float g_totalShowTime = 0.0f; // Time elapsed since the picture start to display.
#define SAFE_RELEASE(P) if(P){ P->Release(); P = NULL;}
struct Vertex
{
float x, y, z ; // Vertex position
float u, v ; // Texture coordinates
};
#define VertexFVF D3DFVF_XYZ | D3DFVF_TEX1
HRESULT InitD3D( HWND hWnd )
{
DWORD ScreenW = 0;
DWORD ScreenH = 0;
DEVMODE devMode ;
devMode.dmSize = sizeof(devMode) ;
DWORD iModeNum = 0 ;
DWORD r = 1 ;
while(r != 0)
{
r = EnumDisplaySettings(NULL, iModeNum, &devMode) ;
// Store the maximum resolution currently
if(devMode.dmPelsWidth >= ScreenW && devMode.dmPelsHeight >= ScreenH)
{
ScreenW = devMode.dmPelsWidth ;
ScreenH = devMode.dmPelsHeight ;
}
//OutputModeInfo(iModeNum, devMode) ;
iModeNum++ ;
}
// Create the D3D object.
if( NULL == ( g_pD3D = Direct3DCreate9( D3D_SDK_VERSION ) ) )
return E_FAIL;
// Set up the structure used to create the D3DDevice
D3DPRESENT_PARAMETERS d3dpp;
ZeroMemory( &d3dpp, sizeof(d3dpp) );
d3dpp.Windowed = FALSE;
d3dpp.SwapEffect = D3DSWAPEFFECT_DISCARD;
d3dpp.BackBufferWidth = ScreenW;
d3dpp.BackBufferHeight = ScreenH;
d3dpp.BackBufferFormat = D3DFMT_X8R8G8B8;
// Create device
if( FAILED( g_pD3D->CreateDevice( D3DADAPTER_DEFAULT, D3DDEVTYPE_HAL, hWnd,
D3DCREATE_SOFTWARE_VERTEXPROCESSING,
&d3dpp, &g_pd3dDevice ) ) )
{
MessageBoxA(NULL, "Create D3D9 device failed!", "Error", 0) ;
return E_FAIL;
}
// Disable lighting, since we didn't specify color for vertex
g_pd3dDevice->SetRenderState( D3DRS_LIGHTING , FALSE );
D3DXMatrixIdentity(&g_worldMatrix);
// Create Texture
HRESULT hr ;
hr = D3DXCreateTextureFromFile(g_pd3dDevice, "../Common/Media/chessboard.jpg", &g_pTexture) ;
if (FAILED(hr))
{
MessageBoxA(NULL, "Create Texture failed!", "Error", 0) ;
}
return S_OK;
}
// Prepare vertex buffer
void InitVB()
{
Vertex Quad[] =
{
{-5.0f, 5.0f, 0, 0, 0}, // 1
{ 5.0f, 5.0f, 0, 1.0f, 0}, // 2
{-5.0f, -5.0f, 0, 0, 1.0f}, // 4
{ 5.0f, -5.0f, 0, 1.0f, 1.0f}, // 3
} ;
// Create vertex buffer
HRESULT hr ;
hr = g_pd3dDevice->CreateVertexBuffer(6 * sizeof(Vertex), D3DUSAGE_WRITEONLY,
VertexFVF, D3DPOOL_MANAGED, &g_pVB, NULL) ;
if (FAILED(hr))
{
MessageBoxA(NULL, "Create vertex buffer failed!", "Error", 0) ;
}
// Copy data
Vertex* v ;
g_pVB->Lock(0, 0, (void**)&v, 0) ;
memcpy(v, Quad, 6 * sizeof(Vertex)) ;
g_pVB->Unlock() ;
}
VOID Cleanup()
{
SAFE_RELEASE(g_pTexture) ;
SAFE_RELEASE(g_pVB) ;
SAFE_RELEASE(g_pd3dDevice) ;
SAFE_RELEASE(g_pD3D) ;
}
void SetupMatrix(float timeDelta)
{
g_totalShowTime += timeDelta;
if(g_totalShowTime > g_ShowTimeInterval)
{
g_worldMatrix._41 += timeDelta * 10;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix) ;
}
else
{
D3DXMatrixTranslation(&g_worldMatrix, 0.0f, 0.0f, 0.0f) ;
g_pd3dDevice->SetTransform(D3DTS_WORLD, &g_worldMatrix) ;
}
// set view
D3DXVECTOR3 eyePt(0.0f, 0.0f, -15.0f) ;
D3DXVECTOR3 upVec(0.0f, 1.0f, 0.0f) ;
D3DXVECTOR3 lookCenter(0.0f, 0.0f, 0.0f) ;
D3DXMATRIX view ;
D3DXMatrixLookAtLH(&view, &eyePt, &lookCenter, &upVec) ;
g_pd3dDevice->SetTransform(D3DTS_VIEW, &view) ;
// set projection
D3DXMATRIX proj ;
D3DXMatrixPerspectiveFovLH(&proj, D3DX_PI / 4, 1.0f, 1.0f, 1000.0f) ;
g_pd3dDevice->SetTransform(D3DTS_PROJECTION, &proj) ;
}
void SetupTexture()
{
// Create Texture
HRESULT hr ;
hr = D3DXCreateTextureFromFile(g_pd3dDevice, "../Common/Media/crate.jpg", &g_pTexture) ;
if (FAILED(hr))
{
MessageBoxA(NULL, "Create Texture failed!", "Error", 0) ;
}
// Setup texture
g_pd3dDevice->SetTexture(0, g_pTexture) ;
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MAGFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MINFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState(0, D3DSAMP_MIPFILTER, D3DTEXF_LINEAR);
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSU, D3DTADDRESS_WRAP );
g_pd3dDevice->SetSamplerState( 0, D3DSAMP_ADDRESSV, D3DTADDRESS_WRAP );
}
void RenderQuad()
{
SetupTexture();
// Set stream source
g_pd3dDevice->SetStreamSource(0, g_pVB, 0, sizeof(Vertex) );
g_pd3dDevice->SetFVF(VertexFVF) ;
g_pd3dDevice->DrawPrimitive(D3DPT_TRIANGLESTRIP, 0, 2) ;
}
VOID Render(float timeDelta)
{
SetupMatrix(timeDelta) ;
g_pd3dDevice->Clear( 0, NULL, D3DCLEAR_TARGET, 0, 1.0f, 0 );
// Begin the scene
if( SUCCEEDED( g_pd3dDevice->BeginScene() ) )
{
RenderQuad() ;
// End the scene
g_pd3dDevice->EndScene();
}
// Present the back-buffer contents to the display
g_pd3dDevice->Present( NULL, NULL, NULL, NULL );
}
LRESULT WINAPI MsgProc( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
{
switch( msg )
{
case WM_KEYDOWN:
{
switch( wParam )
{
case VK_ESCAPE:
SendMessage( hWnd, WM_CLOSE, 0, 0 );
break ;
default:
break ;
}
}
break ;
case WM_DESTROY:
Cleanup();
PostQuitMessage( 0 );
return 0;
}
return DefWindowProc( hWnd, msg, wParam, lParam );
}
INT WINAPI wWinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPWSTR szCmdLine, int iCmdShow)
{
WNDCLASSEX winClass ;
winClass.lpszClassName = "ScreenQuad";
winClass.cbSize = sizeof(WNDCLASSEX);
winClass.style = CS_HREDRAW | CS_VREDRAW;
winClass.lpfnWndProc = MsgProc;
winClass.hInstance = hInstance;
winClass.hIcon = NULL ;
winClass.hIconSm = NULL ;
winClass.hCursor = LoadCursor(NULL, IDC_ARROW) ; // to avoid busy cursor
winClass.hbrBackground = NULL ;
winClass.lpszMenuName = NULL ;
winClass.cbClsExtra = 0;
winClass.cbWndExtra = 0;
RegisterClassEx (&winClass) ;
HWND hWnd = CreateWindowEx(NULL,
winClass.lpszClassName, // window class name
"ScreenQuad", // window caption
WS_OVERLAPPEDWINDOW, // window style
32, // initial x position
32, // initial y position
600, // initial window width
600, // initial window height
NULL, // parent window handle
NULL, // window menu handle
hInstance, // program instance handle
NULL) ; // creation parameters
// Create window failed
if(hWnd == NULL)
{
MessageBoxA(hWnd, "Create Window failed!", "Error", 0) ;
return -1 ;
}
// Initialize Direct3D
if( SUCCEEDED(InitD3D(hWnd)))
{
InitVB() ;
// Show the window
ShowWindow( hWnd, SW_SHOWDEFAULT );
UpdateWindow( hWnd );
// Enter the message loop
MSG msg ;
ZeroMemory( &msg, sizeof(msg) );
PeekMessage( &msg, NULL, 0U, 0U, PM_NOREMOVE );
static DWORD lastTime = timeGetTime();
while (msg.message != WM_QUIT)
{
if( PeekMessage(&msg, NULL, 0U, 0U, PM_REMOVE) != 0)
{
TranslateMessage (&msg) ;
DispatchMessage (&msg) ;
}
else // Render the game if there is no message to process
{
DWORD currentTime = timeGetTime();
float timeDelta = (currentTime - lastTime) * 0.001f;
Render(timeDelta) ;
lastTime = currentTime;
}
}
}
UnregisterClass(winClass.lpszClassName, hInstance) ;
return 0;
}

Multiple full-screen windows with DirectX 9.0

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 );
}