Sign in to follow this  

First steps of initialising D3D10

This topic is 3115 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi, Just getting back into Direct3D, been away for a number of years and forgotten a lot of what I'd previously learnt ( use to use DX9 ). I've created a main app which basically creates a window and has a wndproc, from within the WinMain function I create an object of a class I've done which basically sets up D3D10.
class CDXMainApp
{
private:
        CDXMainApp(HWND hWnd) { m_hWnd = hWnd; }

	HWND m_hWnd;
	
	ID3D10Device*			m_pD3DDevice;
	IDXGISwapChain*			m_pSwapChain;
	ID3D10RenderTargetView*		m_pRenderTargetView;
	D3D10_VIEWPORT			m_viewPort;
	
	D3DXMATRIX m_viewMatrix;
	D3DXMATRIX m_projectionMatrix;
 
public:
        virtual void RenderScene();

        void Initialise();
 
        virtual void OnResize();

// etc...
};

The CDXMainApp::Initialise function sets up the swap chain and the render target view. The CDXMainApp::OnResize function sets up the viewport along with the view and projection matrix and is called when the window is resized. The CDXMainApp::RenderScene function basically will render the scene / clear render target and flip the buffers. Is this an ok way to start off? Seems that the swap chain initialisation is pretty standard. Your input is much appreciated. Regards, Steve

Share this post


Link to post
Share on other sites
A point worth noting is that D3D10 doesn't create a Z buffer automatically. You'd have to create one yourself.

Share this post


Link to post
Share on other sites
Hi,

Thanks for that, yes, you are correct :-)

Will add ID3D10DepthStencilView into the class.

Then in my OnResize I would reset the viewport and add:


m_pD3DDevice->OMSetRenderTargets(1, &m_pRenderTargetView, mDepthStencilView);

m_vp.TopLeftX = 0;
m_vp.TopLeftY = 0;
m_vp.Width = mClientWidth;
m_vp.Height = mClientHeight;
m_vp.MinDepth = 0.0f;
m_vp.MaxDepth = 1.0f;

m_pD3DDevice->RSSetViewports(1, &vp);



I guess I would also need to add the depth/stencil buffer in here before the call to OMSetRenderTargets?


D3D10_TEXTURE2D_DESC depthStencilDesc;
depthStencilDesc.Width = mClientWidth;
depthStencilDesc.Height = mClientHeight;
depthStencilDesc.MipLevels = 1;
depthStencilDesc.ArraySize = 1;
depthStencilDesc.Format = DXGI_FORMAT_D24_UNORM_S8_UINT;
depthStencilDesc.SampleDesc.Count = 1; // multisampling must match
depthStencilDesc.SampleDesc.Quality = 0; // swap chain values.
depthStencilDesc.Usage = D3D10_USAGE_DEFAULT;
depthStencilDesc.BindFlags = D3D10_BIND_DEPTH_STENCIL;
depthStencilDesc.CPUAccessFlags = 0;
depthStencilDesc.MiscFlags = 0;

m_pD3DDevice->CreateTexture2D(&depthStencilDesc, 0, &m_pDepthStencilBuffer));
m_pD3DDevice->CreateDepthStencilView(m_pDepthStencilBuffer, 0, &mDepthStencilView));



Would I also need to resize the swap chain buffers in here?

Going to make the CDXMainApp class a singleton as I believe there should ever only be once instance of this.

Regards,
Steve

Share this post


Link to post
Share on other sites
Hi,

My new class in its first stage now looks like:

Header:

#ifndef _D3DAPP
#define _D3DAPP

#include<d3d10.h>
#include<d3dx10.h>

#pragma once

class CD3DApp
{
public:
static CD3DApp* Instance();

bool InitializeD3D10(HWND hWnd);

virtual void ResizeD3D10Window(int,int);
virtual void RenderScene();

private:
CD3DApp();
virtual ~CD3DApp();

HWND m_hWnd;

ID3D10Device *m_d3dDevice;
IDXGISwapChain *m_swapChain;
ID3D10RenderTargetView *m_renderTargetView;

//projection and view matrices
D3DXMATRIX m_viewMatrix;
D3DXMATRIX m_projectionMatrix;


static CD3DApp* m_pInstance;

};


#endif



CPP:


#include "D3DApp.h"
#include <windows.h>

#include "D3DApp.h"

#pragma comment(lib, "d3d10.lib")
#pragma comment(lib, "d3dx10.lib")

#define WINDOW_WIDTH 800
#define WINDOW_HEIGHT 600

CD3DApp* CD3DApp::m_pInstance = NULL;

CD3DApp::CD3DApp() : m_d3dDevice(NULL), m_swapChain(NULL), m_renderTargetView(NULL)
{
}

CD3DApp::~CD3DApp()
{
}

CD3DApp* CD3DApp::Instance()
{
if(!m_pInstance)
{
m_pInstance = new CD3DApp();
}
return m_pInstance;
}

bool CD3DApp::InitializeD3D10(HWND hwnd)
{
DXGI_SWAP_CHAIN_DESC swapDesc;
ZeroMemory(&swapDesc, sizeof(swapDesc));

// A swap chain needs to be created first. Once created
// we can create a rendering target that can allow us to
// actually draw to the swap chain (the window).

swapDesc.BufferCount = 2;
swapDesc.BufferDesc.Width = WINDOW_WIDTH;
swapDesc.BufferDesc.Height = WINDOW_HEIGHT;
swapDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
swapDesc.BufferDesc.ScanlineOrdering = DXGI_MODE_SCANLINE_ORDER_UNSPECIFIED;

swapDesc.BufferDesc.RefreshRate.Numerator = 60;
swapDesc.BufferDesc.RefreshRate.Denominator = 1;

swapDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT;
swapDesc.OutputWindow = hwnd;
swapDesc.Windowed = TRUE;

// no multisampling
swapDesc.SampleDesc.Count = 1;
swapDesc.SampleDesc.Quality = 0;

HRESULT hr = S_OK;
unsigned int flags = 0;

// This next flag gives us debug information
// during development. Not used in release versions.

#ifdef _DEBUG
flags |= D3D10_CREATE_DEVICE_DEBUG;
#endif

D3D10_DRIVER_TYPE driverType = D3D10_DRIVER_TYPE_NULL;

D3D10_DRIVER_TYPE driverTypes[] =
{
D3D10_DRIVER_TYPE_HARDWARE,
D3D10_DRIVER_TYPE_REFERENCE,
};

unsigned int numDriverTypes = sizeof(driverTypes) /
sizeof(driverTypes[0]);

for(unsigned int i = 0; i < numDriverTypes; i++)
{
driverType = driverTypes[i];

hr = D3D10CreateDeviceAndSwapChain(NULL, driverType, NULL,
flags, D3D10_SDK_VERSION,
&swapDesc, &m_swapChain,
&m_d3dDevice);
if(SUCCEEDED(hr))
break;
}

if(FAILED(hr))
return false;

// Get the back buffer from the rendering swap chain so we
// can create a destination rendering target from it.

ID3D10Texture2D *buffer = NULL;
hr = m_swapChain->GetBuffer(0, __uuidof(ID3D10Texture2D),
(LPVOID*)&buffer);

// Check for problems creating the previous object.
if(FAILED(hr))
return false;

// Create the default render destination for the drawing calls.
hr = m_d3dDevice->CreateRenderTargetView(buffer, NULL,
&m_renderTargetView);

// No longer need this once the render target viw is created.
buffer->Release();

if(FAILED(hr))
return false;

// Set default render target. Can be set during the rendering
// but since there is only 1 render target it can be set once.
m_d3dDevice->OMSetRenderTargets(1, &m_renderTargetView, NULL);

// Ensure window is ready to be drawn to.
ResizeD3D10Window(WINDOW_WIDTH, WINDOW_HEIGHT);

return true;
}


void CD3DApp::ResizeD3D10Window(int width, int height)
{
if(m_d3dDevice == NULL)
return;

// STILL TODO:
// 1. RESIZE SWAP CHAIN AND RECREATE RENDER VIEW
// 2. CREATE DEPTH/STENCIL BUFFER AND VIEW AND BIND RENDER TARGET
// AND DEPTH/STENCIL VIEW TO PL

D3D10_VIEWPORT vp;

vp.Width = width;
vp.Height = height;
vp.MinDepth = 0.0f;
vp.MaxDepth = 1.0f;
vp.TopLeftX = 0;
vp.TopLeftY = 0;

m_d3dDevice->RSSetViewports(1, &vp);


// view matrix

D3DXMatrixLookAtLH(&m_viewMatrix, new D3DXVECTOR3(0.0f, 0.0f, -5.0f),
new D3DXVECTOR3(0.0f, 0.0f, 1.0f),
new D3DXVECTOR3(0.0f, 1.0f, 0.0f));

// projection matrix

D3DXMatrixPerspectiveFovLH(&m_projectionMatrix, (float)D3DX_PI * 0.5f,
width/(FLOAT)height, 0.1f, 100.0f);
}


////////////////////////////////////////////////////////////////////////////////
// Render the scene
////////////////////////////////////////////////////////////////////////////////
void CD3DApp::RenderScene()
{
float col[4] = { 0, 0, 0, 0 };
m_d3dDevice->ClearRenderTargetView(m_renderTargetView, col);
m_swapChain->Present(0, 0);
}



To use the class, I just do:



CD3DApp* pD3DApp = CD3DApp::Instance();

// in winmain:
pD3DApp->InitializeD3D10(hwnd);

// and in message pump

while(1)
{
if(PeekMessage(&msg, 0, 0, 0, PM_REMOVE))
{
if(msg.message == WM_QUIT) break;
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
pD3DApp->RenderScene();
}
}




In my winproc I catch the WM_SIZE message and just do:


pD3DApp->ResizeD3D10Window(width, height);




All very basic and obviously missing lots out ( depth/stencil for instance ).

Is this ok so far?

Regards,
Steve

Share this post


Link to post
Share on other sites
I am very anti-singleton.

I say you are setting yourself up for a world of hurt down the road. Almost every object in your engine is going to hold references of one type or another dependent on your singleton's data. You have zero control over the destruction order of static and global objects, including the singleton.

So, all it takes is one static, global, or another singleton that attempts to interact with this singleton and you will be debugging for months, trying to find something that doesn't even appear in your call stack.

You'd be surprised how many times this happens in a large project. Especially, when other libraries become involved.

I think people over-use the singleton pattern. It just makes us look smart and tells others we have heard of the gang of four. In practice, I'd rather hand references down to objects that need them.

Is your main app really the best place for matrices?
Seeing how it is most likely for a game engine, I'd bet you are going to have a camera class.

You are probably going to have game states as well.
You are probably going to have a render queue eventually too.
You might even end up with multiple render targets.

Depends how detailed you want to get. When I see "MainApp" I usually think of something that handles the DX inititialization and hands a reference to the device and swapchain to other objects. I doubt it would do any actual rendering or contain any data that is specific to rendering.

I'd sit down with visio or a UML program or even Word and get a rough outline of what objects you are going to make and what they are responsible for.

It doesn't look like you are allowing any screen fullscreen/windowed transitions, or using DXGI either, which is recommended. What do you want to happend when the user hits alt-enter or alt-tab?

It is also a good idea to enumerate devices instead of assuming it can handle 600x800 at 60 hz. It probably does, but isn't guarenteed. You are going to need device info down the road anyway eventually.






Share this post


Link to post
Share on other sites
Hi,

Thanks for your input.

Must admit, I'm not against using design patterns when they are needed, I'll be using a lot of others when I get further on with this. Singleton - you need be careful if the app is going to be multi-threaded, I've not put cover in for this, but it's just a simple mutex.

You are correct with what you are saying with the mainapp not rendering stuff, I envision a base object that other game objects derive from, this base object would have a couple of pure virtual functions in them of which would be render, translate etc...I guess each game object would have a world matrix associated with it etc... BTW, I love template based classes and the game objects would be based around these for obvious reasons.

Another object to manage the game objects, and yep, a camera class, a terrain rendering class, the list would go on and on - definitely be a scene manager object.

Alt/tab, I don't think that is difficult to handle in DX10 :-)

Global objects, well, I've got a pointer to the singleton, wouldn't be using anymore.

Again, thanks for your input, it is appreciated.

Regards,
Steve

Share this post


Link to post
Share on other sites

This topic is 3115 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this