We also want this object to be updatable and have all the goodies we have in our RC3DBaseObject, so we will also derive from that class, you RC3DBaseDrawableObject.h file should look like this now
#pragma once
#include "interfaces.h"
#include "RC3DBaseObject.h"
class RC3DBaseDrawableObject : public RC3DBaseObject, public IDrawable
{
public:
RC3DBaseDrawableObject(void);
~RC3DBaseDrawableObject(void);
};
#include "interfaces.h"
#include "RC3DBaseObject.h"
class RC3DBaseDrawableObject : public RC3DBaseObject, public IDrawable
{
public:
RC3DBaseDrawableObject(void);
~RC3DBaseDrawableObject(void);
};
#pragma once
#include "interfaces.h"
#include "RC3DBaseObject.h"
class RC3DBaseDrawableObject : public RC3DBaseObject, public IDrawable
{
public:
RC3DBaseDrawableObject(void);
~RC3DBaseDrawableObject(void);
virtual void Draw(float time, ID3D11DeviceContext* context, IRC3DCamera* camera) = 0;
using RC3DBaseObject::Update;
};
#include "interfaces.h"
#include "RC3DBaseObject.h"
class RC3DBaseDrawableObject : public RC3DBaseObject, public IDrawable
{
public:
RC3DBaseDrawableObject(void);
~RC3DBaseDrawableObject(void);
virtual void Draw(float time, ID3D11DeviceContext* context, IRC3DCamera* camera) = 0;
using RC3DBaseObject::Update;
};
Before we create this game class, we will quickly create a keyboard manager class, this will help manage user input, it works just the same as in the earlier posts, but we can control it from within our game class.
Create a class called RCKeyboardStateManager with no base class. We will put in the header all the elements we need to manage the keyboard
#pragma once
#include <dinput.h>
class RCKeyboardStateManager
{
protected:
LPDIRECTINPUTDEVICE8 keyboard;
char keyboardState[256];
public:
RCKeyboardStateManager(void);
~RCKeyboardStateManager(void);
virtual LPDIRECTINPUTDEVICE8 InitializeKeyboard(HWND hwnd);
virtual char* getKeyboardState();
virtual void readKeyboard();
LPDIRECTINPUTDEVICE8 getKeyboard();
};
#include <dinput.h>
class RCKeyboardStateManager
{
protected:
LPDIRECTINPUTDEVICE8 keyboard;
char keyboardState[256];
public:
RCKeyboardStateManager(void);
~RCKeyboardStateManager(void);
virtual LPDIRECTINPUTDEVICE8 InitializeKeyboard(HWND hwnd);
virtual char* getKeyboardState();
virtual void readKeyboard();
LPDIRECTINPUTDEVICE8 getKeyboard();
};
#include "RCKeyboardStateManager.h"
RCKeyboardStateManager::RCKeyboardStateManager(void){ }
RCKeyboardStateManager::~RCKeyboardStateManager(void){ }
LPDIRECTINPUTDEVICE8 RCKeyboardStateManager::InitializeKeyboard(HWND hwnd)
{
LPDIRECTINPUT8 p_dx_KeybObject;
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&p_dx_KeybObject, NULL);
p_dx_KeybObject->CreateDevice(GUID_SysKeyboard, &keyboard, NULL);
keyboard->SetDataFormat(&c_dfDIKeyboard);
keyboard->SetCooperativeLevel(hwnd, DISCL_BACKGROUND|DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
keyboard->Acquire();
return keyboard;
}
char* RCKeyboardStateManager::getKeyboardState()
{
return keyboardState;
}
void RCKeyboardStateManager::readKeyboard()
{
keyboardState[0] = '\0';
HRESULT res = keyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState);
}
LPDIRECTINPUTDEVICE8 RCKeyboardStateManager::getKeyboard()
{
return keyboard;
}
RCKeyboardStateManager::RCKeyboardStateManager(void){ }
RCKeyboardStateManager::~RCKeyboardStateManager(void){ }
LPDIRECTINPUTDEVICE8 RCKeyboardStateManager::InitializeKeyboard(HWND hwnd)
{
LPDIRECTINPUT8 p_dx_KeybObject;
DirectInput8Create(GetModuleHandle(NULL), DIRECTINPUT_VERSION, IID_IDirectInput8, (void**)&p_dx_KeybObject, NULL);
p_dx_KeybObject->CreateDevice(GUID_SysKeyboard, &keyboard, NULL);
keyboard->SetDataFormat(&c_dfDIKeyboard);
keyboard->SetCooperativeLevel(hwnd, DISCL_BACKGROUND|DISCL_FOREGROUND|DISCL_NONEXCLUSIVE);
keyboard->Acquire();
return keyboard;
}
char* RCKeyboardStateManager::getKeyboardState()
{
return keyboardState;
}
void RCKeyboardStateManager::readKeyboard()
{
keyboardState[0] = '\0';
HRESULT res = keyboard->GetDeviceState(sizeof(keyboardState),(LPVOID)&keyboardState);
}
LPDIRECTINPUTDEVICE8 RCKeyboardStateManager::getKeyboard()
{
return keyboard;
}
#include <D3D11.h>
#include <D3DX11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include <vector>
#include "interfaces.h"
#include "RC3DGraphicsDevice.h"
#include "RC3DBaseDrawableObject.h"
#include "RC3DBaseObject.h"
#include "RCKeyboardStateManager.h"
#include <D3DX11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include <vector>
#include "interfaces.h"
#include "RC3DGraphicsDevice.h"
#include "RC3DBaseDrawableObject.h"
#include "RC3DBaseObject.h"
#include "RCKeyboardStateManager.h"
We are now going to define a number of methods that we will use in our game loop (this will still live out side of the Game class for this post), we also need a graphics device, and a keyboard manager. Our RCGame.h file should now look like this
#pragma once
#include <D3D11.h>
#include <D3DX11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include <vector>
#include "interfaces.h"
#include "RC3DGraphicsDevice.h"
#include "RC3DBaseDrawableObject.h"
#include "RC3DBaseObject.h"
#include "RCKeyboardStateManager.h"
class RC3DGame
{
public:
RC3DGame(void);
~RC3DGame(void);
// GraphicsDevice
RC3DGraphicsDevice GraphicsDevice;
// Keyboard manager
RCKeyboardStateManager KeyboardManager;
// Method to initialize the window
void Initialize(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush = COLOR_BTNFACE);
void Update(float time, std::vector<IUpdateable*>* updateambles);
// Draw call
void Draw(float time, IRC3DCamera* camera, std::vector<IDrawable*>* drawables);
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut );
};
#include <D3D11.h>
#include <D3DX11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include <vector>
#include "interfaces.h"
#include "RC3DGraphicsDevice.h"
#include "RC3DBaseDrawableObject.h"
#include "RC3DBaseObject.h"
#include "RCKeyboardStateManager.h"
class RC3DGame
{
public:
RC3DGame(void);
~RC3DGame(void);
// GraphicsDevice
RC3DGraphicsDevice GraphicsDevice;
// Keyboard manager
RCKeyboardStateManager KeyboardManager;
// Method to initialize the window
void Initialize(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush = COLOR_BTNFACE);
void Update(float time, std::vector<IUpdateable*>* updateambles);
// Draw call
void Draw(float time, IRC3DCamera* camera, std::vector<IDrawable*>* drawables);
HRESULT CompileShaderFromFile( WCHAR* szFileName, LPCSTR szEntryPoint, LPCSTR szShaderModel, ID3DBlob** ppBlobOut );
};
Game Initialize
And now to the function bodies, lets take a look at the Initialize method first
void RC3DGame::Initialize(LPCTSTR str_Title,int int_XPos, int int_YPos, int int_Width, int int_Height, WNDPROC WinProc, int colorBrush)
{
GraphicsDevice.InitializeWindow(str_Title,int_XPos, int_YPos, int_Width, int_Height, WinProc, colorBrush);
GraphicsDevice.Initialize();
KeyboardManager.InitializeKeyboard(GraphicsDevice.getWindowHandle());
}
{
GraphicsDevice.InitializeWindow(str_Title,int_XPos, int_YPos, int_Width, int_Height, WinProc, colorBrush);
GraphicsDevice.Initialize();
KeyboardManager.InitializeKeyboard(GraphicsDevice.getWindowHandle());
}
Game Update
void RC3DGame::Update(float time, std::vector<IUpdateable*>* updateambles)
{
// Componente update
for(auto c = updateambles->begin();c != updateambles->end();c++)
{
(*c)->Update(time);
}
KeyboardManager.readKeyboard();
}
{
// Componente update
for(auto c = updateambles->begin();c != updateambles->end();c++)
{
(*c)->Update(time);
}
KeyboardManager.readKeyboard();
}
Game Draw
void RC3DGame::Draw(float time,IRC3DCamera* camera, std::vector<IDrawable*>* drawables)
{
GraphicsDevice.Clear(XMFLOAT4( 0.392156862745098f, 0.5843137254901961f, 0.9294117647058824f, 1.0f),D3D11_CLEAR_DEPTH,1.0f,0);
for(auto c = drawables->begin();c != drawables->end();c++)
{
(*c)->Draw(0,GraphicsDevice.getDeviceContext(),camera);
}
GraphicsDevice.Present( 0, 0 );
}
{
GraphicsDevice.Clear(XMFLOAT4( 0.392156862745098f, 0.5843137254901961f, 0.9294117647058824f, 1.0f),D3D11_CLEAR_DEPTH,1.0f,0);
for(auto c = drawables->begin();c != drawables->end();c++)
{
(*c)->Draw(0,GraphicsDevice.getDeviceContext(),camera);
}
GraphicsDevice.Present( 0, 0 );
}
Game CompileShaderFromFile
HRESULT RC3DGame::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;
}
{
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;
}
We now have a game class we can use to update and render objects in the world, so why don’t we create an object class that can then be actually rendered.
I am going to take some more from the SDK tutorial to build this class, as we have not looked at loading mesh’s in yet, we will define our own geometry and use that to render a cube, we will now create a TestCube class that will derive from RC3DBaseDrawableObject to do this.
We also want to include the the RCGame.h and Interfaces.h in here as we will be using them. We are also going to create a number of member variables that we can then use to set up and render our cube. We will also add an Initialize method and implement the derived Draw call. Your TestCube.h file should look something like this
#pragma once
#include <D3D11.h>
#include <D3DX11.h>
#include <xnamath.h>
#include "rc3dbasedrawableobject.h"
#include "RC3DGame.h"
#include "Interfaces.h"
class TestCube : public RC3DBaseDrawableObject
{
protected:
ID3D11InputLayout* pVertexLayout;
ID3D11VertexShader* pVertexShader;
ID3D11PixelShader* pPixelShader;
ID3D11Buffer* pVertexBuffer;
ID3D11Buffer* pIndexBuffer;
ID3D11Buffer* pCBNeverChanges;
ID3D11Buffer* pCBChangeOnResize;
ID3D11Buffer* pCBChangesEveryFrame;
ID3D11ShaderResourceView* pTextureRV;
ID3D11SamplerState* pSamplerLinear;
public:
TestCube(void);
~TestCube(void);
RC3DGame* game;
XMFLOAT4 Color;
void Initialize(ID3D11Device* device );
void Draw(float time, ID3D11DeviceContext* context, IRC3DCamera* camera);
};
#include <D3D11.h>
#include <D3DX11.h>
#include <xnamath.h>
#include "rc3dbasedrawableobject.h"
#include "RC3DGame.h"
#include "Interfaces.h"
class TestCube : public RC3DBaseDrawableObject
{
protected:
ID3D11InputLayout* pVertexLayout;
ID3D11VertexShader* pVertexShader;
ID3D11PixelShader* pPixelShader;
ID3D11Buffer* pVertexBuffer;
ID3D11Buffer* pIndexBuffer;
ID3D11Buffer* pCBNeverChanges;
ID3D11Buffer* pCBChangeOnResize;
ID3D11Buffer* pCBChangesEveryFrame;
ID3D11ShaderResourceView* pTextureRV;
ID3D11SamplerState* pSamplerLinear;
public:
TestCube(void);
~TestCube(void);
RC3DGame* game;
XMFLOAT4 Color;
void Initialize(ID3D11Device* device );
void Draw(float time, ID3D11DeviceContext* context, IRC3DCamera* camera);
};
We then have references to the vertex and pixel shaders we are going to use to render this object.
We then have our vertex and index buffer, again will be defined later.
We then have a number of Buffers, these are new to me as they are part of the DirectX 11 API (remember I am coming from DirectX 9c!) and I will explain my understanding of them later.
Lastly we have a texture and a sampler reference for it.
We now have a definition, as ever, onto the function bodies, but wait, we still need some data definitions, the input layout, the vertex and index buffers, all these I have put at the top of the TestCube.cpp file, this makes them global to the class and so can be accessed across methods. Really I should have not been lazy and set them up right in the class, but I am itching to get something rendered :P
So, at the top of the TestCube.cpp file we have this lump of variables
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};
struct CBChangeOnResize
{
XMMATRIX mProjection;
};
struct CBChangesEveryFrame
{
XMMATRIX mWorld;
XMFLOAT4 vMeshColor;
XMMATRIX mView;
};
SimpleVertex vertices[] =
{
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
};
WORD indices[] =
{
3,1,0,
2,1,3,
6,4,5,
7,4,6,
11,9,8,
10,9,11,
14,12,13,
15,12,14,
19,17,16,
18,17,19,
22,20,21,
23,20,22
};
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};
struct CBChangeOnResize
{
XMMATRIX mProjection;
};
struct CBChangesEveryFrame
{
XMMATRIX mWorld;
XMFLOAT4 vMeshColor;
XMMATRIX mView;
};
SimpleVertex vertices[] =
{
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
};
WORD indices[] =
{
3,1,0,
2,1,3,
6,4,5,
7,4,6,
11,9,8,
10,9,11,
14,12,13,
15,12,14,
19,17,16,
18,17,19,
22,20,21,
23,20,22
};
SimpleVertex is the vertex structure we will use for the cube’s verts
CBChangeOnResize is a structure that is reloaded on screen resize
CBChangesEveryFrame describes what will be passed to the shader every frame
vertices and index are what will fill the vertex and index buffers to render the cube.
Our TestCube.cpp now looks like this after we have populated the member functions
#include "TestCube.h"
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};
struct CBChangeOnResize
{
XMMATRIX mProjection;
};
struct CBChangesEveryFrame
{
XMMATRIX mWorld;
XMFLOAT4 vMeshColor;
XMMATRIX mView;
};
SimpleVertex vertices[] =
{
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
};
WORD indices[] =
{
3,1,0,
2,1,3,
6,4,5,
7,4,6,
11,9,8,
10,9,11,
14,12,13,
15,12,14,
19,17,16,
18,17,19,
22,20,21,
23,20,22
};
TestCube::TestCube(void)
{
Color = XMFLOAT4(1,1,1,1);
}
TestCube::~TestCube(void){ }
void TestCube::Initialize(ID3D11Device* device)
{
// Compile the vertex shader
ID3DBlob* pVSBlob = NULL;
HRESULT hr = game->CompileShaderFromFile( L"Tutorial07.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;
}
// Create the vertex shader
hr = device->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return;
}
UINT numElements = ARRAYSIZE( layout );
// Create the input layout
hr = device->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &pVertexLayout );
pVSBlob->Release();
// Compile the pixel shader
ID3DBlob* pPSBlob = NULL;
hr = game->CompileShaderFromFile( L"Tutorial07.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;
}
// Create the pixel shader
hr = device->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return;
// Create vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 24;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = device->CreateBuffer( &bd, &InitData, &pVertexBuffer );
if( FAILED( hr ) )
return;
// Build index
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = device->CreateBuffer( &bd, &InitData, &pIndexBuffer );
if( FAILED( hr ) )
return;
// Create the constant buffers
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.ByteWidth = sizeof(CBChangeOnResize);
hr = device->CreateBuffer( &bd, NULL, &pCBChangeOnResize );
if( FAILED( hr ) )
return;
bd.ByteWidth = sizeof(CBChangesEveryFrame);
hr = device->CreateBuffer( &bd, NULL, &pCBChangesEveryFrame );
if( FAILED( hr ) )
return;
// Load the Texture
hr = D3DX11CreateShaderResourceViewFromFile( device, L"seafloor.dds", NULL, NULL, &pTextureRV, NULL );
if( FAILED( hr ) )
return;
// Create the sample state
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = device->CreateSamplerState( &sampDesc, &pSamplerLinear );
if( FAILED( hr ) )
return;
}
void TestCube::Draw(float time,ID3D11DeviceContext* context, IRC3DCamera* camera)
{
// Set the input layout
context->IASetInputLayout( pVertexLayout );
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
context->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );
// Set index buffer
context->IASetIndexBuffer( pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
// Set primitive topology
context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
// Initialize the projection matrix
CBChangeOnResize cbChangesOnResize;
cbChangesOnResize.mProjection = XMMatrixTranspose( camera->getProjection() );
context->UpdateSubresource( pCBChangeOnResize, 0, NULL, &cbChangesOnResize, 0, 0 );
//
// Update variables that change once per frame
//
CBChangesEveryFrame cb;
cb.mWorld = XMMatrixTranspose( getWorld() );
cb.vMeshColor = Color;
cb.mView = XMMatrixTranspose( camera->getView() );
context->UpdateSubresource( pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );
// Render the cube
context->VSSetShader( pVertexShader, NULL, 0 );
context->VSSetConstantBuffers( 0, 1, &pCBChangeOnResize );
context->VSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
context->PSSetShader( pPixelShader, NULL, 0 );
context->PSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
context->PSSetShaderResources( 0, 1, &pTextureRV );
context->PSSetSamplers( 0, 1, &pSamplerLinear );
context->DrawIndexed( 36, 0, 0 );
}
D3D11_INPUT_ELEMENT_DESC layout[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 12, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
struct SimpleVertex
{
XMFLOAT3 Pos;
XMFLOAT2 Tex;
};
struct CBChangeOnResize
{
XMMATRIX mProjection;
};
struct CBChangesEveryFrame
{
XMMATRIX mWorld;
XMFLOAT4 vMeshColor;
XMMATRIX mView;
};
SimpleVertex vertices[] =
{
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, -0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, -0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, -0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, -0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, -0.5f, 0.5f ), XMFLOAT2( 0.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, -0.5f, 0.5f ), XMFLOAT2( 1.0f, 0.0f ) },
{ XMFLOAT3( 0.5f, 0.5f, 0.5f ), XMFLOAT2( 1.0f, 1.0f ) },
{ XMFLOAT3( -0.5f, 0.5f, 0.5f ), XMFLOAT2( 0.0f, 1.0f ) },
};
WORD indices[] =
{
3,1,0,
2,1,3,
6,4,5,
7,4,6,
11,9,8,
10,9,11,
14,12,13,
15,12,14,
19,17,16,
18,17,19,
22,20,21,
23,20,22
};
TestCube::TestCube(void)
{
Color = XMFLOAT4(1,1,1,1);
}
TestCube::~TestCube(void){ }
void TestCube::Initialize(ID3D11Device* device)
{
// Compile the vertex shader
ID3DBlob* pVSBlob = NULL;
HRESULT hr = game->CompileShaderFromFile( L"Tutorial07.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;
}
// Create the vertex shader
hr = device->CreateVertexShader( pVSBlob->GetBufferPointer(), pVSBlob->GetBufferSize(), NULL, &pVertexShader );
if( FAILED( hr ) )
{
pVSBlob->Release();
return;
}
UINT numElements = ARRAYSIZE( layout );
// Create the input layout
hr = device->CreateInputLayout( layout, numElements, pVSBlob->GetBufferPointer(),
pVSBlob->GetBufferSize(), &pVertexLayout );
pVSBlob->Release();
// Compile the pixel shader
ID3DBlob* pPSBlob = NULL;
hr = game->CompileShaderFromFile( L"Tutorial07.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;
}
// Create the pixel shader
hr = device->CreatePixelShader( pPSBlob->GetBufferPointer(), pPSBlob->GetBufferSize(), NULL, &pPixelShader );
pPSBlob->Release();
if( FAILED( hr ) )
return;
// Create vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory( &bd, sizeof(bd) );
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( SimpleVertex ) * 24;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = 0;
D3D11_SUBRESOURCE_DATA InitData;
ZeroMemory( &InitData, sizeof(InitData) );
InitData.pSysMem = vertices;
hr = device->CreateBuffer( &bd, &InitData, &pVertexBuffer );
if( FAILED( hr ) )
return;
// Build index
bd.Usage = D3D11_USAGE_DEFAULT;
bd.ByteWidth = sizeof( WORD ) * 36;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = 0;
InitData.pSysMem = indices;
hr = device->CreateBuffer( &bd, &InitData, &pIndexBuffer );
if( FAILED( hr ) )
return;
// Create the constant buffers
bd.Usage = D3D11_USAGE_DEFAULT;
bd.BindFlags = D3D11_BIND_CONSTANT_BUFFER;
bd.ByteWidth = sizeof(CBChangeOnResize);
hr = device->CreateBuffer( &bd, NULL, &pCBChangeOnResize );
if( FAILED( hr ) )
return;
bd.ByteWidth = sizeof(CBChangesEveryFrame);
hr = device->CreateBuffer( &bd, NULL, &pCBChangesEveryFrame );
if( FAILED( hr ) )
return;
// Load the Texture
hr = D3DX11CreateShaderResourceViewFromFile( device, L"seafloor.dds", NULL, NULL, &pTextureRV, NULL );
if( FAILED( hr ) )
return;
// Create the sample state
D3D11_SAMPLER_DESC sampDesc;
ZeroMemory( &sampDesc, sizeof(sampDesc) );
sampDesc.Filter = D3D11_FILTER_MIN_MAG_MIP_LINEAR;
sampDesc.AddressU = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressV = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.AddressW = D3D11_TEXTURE_ADDRESS_WRAP;
sampDesc.ComparisonFunc = D3D11_COMPARISON_NEVER;
sampDesc.MinLOD = 0;
sampDesc.MaxLOD = D3D11_FLOAT32_MAX;
hr = device->CreateSamplerState( &sampDesc, &pSamplerLinear );
if( FAILED( hr ) )
return;
}
void TestCube::Draw(float time,ID3D11DeviceContext* context, IRC3DCamera* camera)
{
// Set the input layout
context->IASetInputLayout( pVertexLayout );
// Set vertex buffer
UINT stride = sizeof( SimpleVertex );
UINT offset = 0;
context->IASetVertexBuffers( 0, 1, &pVertexBuffer, &stride, &offset );
// Set index buffer
context->IASetIndexBuffer( pIndexBuffer, DXGI_FORMAT_R16_UINT, 0 );
// Set primitive topology
context->IASetPrimitiveTopology( D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST );
// Initialize the projection matrix
CBChangeOnResize cbChangesOnResize;
cbChangesOnResize.mProjection = XMMatrixTranspose( camera->getProjection() );
context->UpdateSubresource( pCBChangeOnResize, 0, NULL, &cbChangesOnResize, 0, 0 );
//
// Update variables that change once per frame
//
CBChangesEveryFrame cb;
cb.mWorld = XMMatrixTranspose( getWorld() );
cb.vMeshColor = Color;
cb.mView = XMMatrixTranspose( camera->getView() );
context->UpdateSubresource( pCBChangesEveryFrame, 0, NULL, &cb, 0, 0 );
// Render the cube
context->VSSetShader( pVertexShader, NULL, 0 );
context->VSSetConstantBuffers( 0, 1, &pCBChangeOnResize );
context->VSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
context->PSSetShader( pPixelShader, NULL, 0 );
context->PSSetConstantBuffers( 1, 1, &pCBChangesEveryFrame );
context->PSSetShaderResources( 0, 1, &pTextureRV );
context->PSSetSamplers( 0, 1, &pSamplerLinear );
context->DrawIndexed( 36, 0, 0 );
}
Our Draw call is again pretty straightforward, sets the device up with vertex and index buffers, sets the parameters in the buffers, then makes the draw call.
We now have something we can render, what we need now is a WinMain, a loop and some objects to render…
Just as before, create a main.cpp file in the solution
In here we will add all theeaders we need, create a WinProc call back as before and a WinMain function, we will also set up the game loop as before, but use our new game class to build the window and device.
#pragma once
#include <Windows.h>
#include "RC3DGame.h"
RC3DGame game;
int int_AppRunning = 1;
LRESULT CALLBACK winProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
MSG msg_Message;
int result = 0;
game.Initialize(L"RandomchaosDX11ProtoEngien",0,0,800,600,winProc);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
}
DestroyWindow(hWnd);
}
return result;
}
#include <Windows.h>
#include "RC3DGame.h"
RC3DGame game;
int int_AppRunning = 1;
LRESULT CALLBACK winProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
MSG msg_Message;
int result = 0;
game.Initialize(L"RandomchaosDX11ProtoEngien",0,0,800,600,winProc);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
}
DestroyWindow(hWnd);
}
return result;
}
Lets add our camera, set up a list of IDrawables and I Updateables and call the game update and draw calls. Under RC3DGame game, add the following lines (don’t forget to add the header for the camera!)
RC3DCamera* camera;
std::vector<IUpdateable*> vUpdateables;
std::vector<IDrawable*> vDrawables;
std::vector<IUpdateable*> vUpdateables;
std::vector<IDrawable*> vDrawables;
After we have initialized the graphics devic, we can initialize our camera and add it to the updateable list with in WinMain
game.Initialize(L"RandomchaosDX11ProtoEngien",0,0,800,600,winProc);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
camera = new RC3DCamera(XMFLOAT3(0,0,0),XMFLOAT3(0,1,0),XMQuaternionIdentity(), game.GraphicsDevice.getViewPort().Width,game.GraphicsDevice.getViewPort().Height);
vUpdateables.push_back(camera);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
camera = new RC3DCamera(XMFLOAT3(0,0,0),XMFLOAT3(0,1,0),XMQuaternionIdentity(), game.GraphicsDevice.getViewPort().Width,game.GraphicsDevice.getViewPort().Height);
vUpdateables.push_back(camera);
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
Include the TestCube.h file. and add the following after the IDrawable list creation
TestCube testCube;
testCube.game = &game;
testCube.setPosition(XMFLOAT3(0,0,10));
testCube.Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(&testCube);
vDrawables.push_back(&testCube);
testCube.setPosition(XMFLOAT3(0,0,10));
testCube.Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(&testCube);
vDrawables.push_back(&testCube);
and call it Shaders, then copy any dds texture you like into the project folder and call it seafloor.
In the Shaders filter/folder create anew file called Tutorial07.fx and paste the following into it
//--------------------------------------------------------------------------------------
// File: Tutorial07.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
// Modified a little for the Randomchaos: Graphics Adventures in C++ with DirectX 11 blog
// http://randomchaosdx11adventures.blogspot.co.uk/
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D txDiffuse : register( t0 );
SamplerState samLinear : register( s0 );
cbuffer cbChangeOnResize : register( b0 )
{
matrix Projection;
};
cbuffer cbChangesEveryFrame : register( b1 )
{
matrix World;
float4 vMeshColor;
matrix View;
};
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Tex = input.Tex;
return output;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}
// File: Tutorial07.fx
//
// Copyright (c) Microsoft Corporation. All rights reserved.
//--------------------------------------------------------------------------------------
// Modified a little for the Randomchaos: Graphics Adventures in C++ with DirectX 11 blog
// http://randomchaosdx11adventures.blogspot.co.uk/
//--------------------------------------------------------------------------------------
// Constant Buffer Variables
//--------------------------------------------------------------------------------------
Texture2D txDiffuse : register( t0 );
SamplerState samLinear : register( s0 );
cbuffer cbChangeOnResize : register( b0 )
{
matrix Projection;
};
cbuffer cbChangesEveryFrame : register( b1 )
{
matrix World;
float4 vMeshColor;
matrix View;
};
//--------------------------------------------------------------------------------------
struct VS_INPUT
{
float4 Pos : POSITION;
float2 Tex : TEXCOORD0;
};
struct PS_INPUT
{
float4 Pos : SV_POSITION;
float2 Tex : TEXCOORD0;
};
//--------------------------------------------------------------------------------------
// Vertex Shader
//--------------------------------------------------------------------------------------
PS_INPUT VS( VS_INPUT input )
{
PS_INPUT output = (PS_INPUT)0;
output.Pos = mul( input.Pos, World );
output.Pos = mul( output.Pos, View );
output.Pos = mul( output.Pos, Projection );
output.Tex = input.Tex;
return output;
}
//--------------------------------------------------------------------------------------
// Pixel Shader
//--------------------------------------------------------------------------------------
float4 PS( PS_INPUT input) : SV_Target
{
return txDiffuse.Sample( samLinear, input.Tex ) * vMeshColor;
}
So, we can run this now right? Nope, if you do you will get this error
We need to right click the shader file, and tell the IDE not to try and build it as we will do this at run time, change the ItemType from “HLSL Compiler” to “Does not participate in build”
If we run the project now, we will get this
AT LAST! We have rendered our cube in DirectX 11 using a basic C++ framework.
That’s all well and good, but that’s just a square of texture, how do I know it’s a cube? Well you will need to move around it, so lets wire up some keyboard controls like we have in previous posts, but the game class is already getting us the keyboard state, so we just need to react to what’s pressed.
After our WinProc callback method we can create a HandleKeyboardInput method like this
void HandleKeyboardInput()
{
float spd = .0005f;
float rotSpd = .0001f;
if (game.KeyboardManager.getKeyboardState()[DIK_ESCAPE]/128)
int_AppRunning = 0;
if (game.KeyboardManager.getKeyboardState()[DIK_LEFT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),-rotSpd);
if (game.KeyboardManager.getKeyboardState()[DIK_RIGHT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_UP]/128)
camera->Rotate(XMVectorSet(1,0,0,0),-rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_DOWN]/128)
camera->Rotate(XMVectorSet(1,0,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_SPACE]/128)
camera->setOrientation(XMQuaternionIdentity());
if(game.KeyboardManager.getKeyboardState()[DIK_W]/128)
camera->Translate(XMFLOAT3(0,0,spd));
if(game.KeyboardManager.getKeyboardState()[DIK_S]/128)
camera->Translate(XMFLOAT3(0,0,-spd));
if(game.KeyboardManager.getKeyboardState()[DIK_A]/128)
camera->Translate(XMFLOAT3(-spd,0,0));
if(game.KeyboardManager.getKeyboardState()[DIK_D]/128)
camera->Translate(XMFLOAT3(spd,0,0));
}
{
float spd = .0005f;
float rotSpd = .0001f;
if (game.KeyboardManager.getKeyboardState()[DIK_ESCAPE]/128)
int_AppRunning = 0;
if (game.KeyboardManager.getKeyboardState()[DIK_LEFT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),-rotSpd);
if (game.KeyboardManager.getKeyboardState()[DIK_RIGHT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_UP]/128)
camera->Rotate(XMVectorSet(1,0,0,0),-rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_DOWN]/128)
camera->Rotate(XMVectorSet(1,0,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_SPACE]/128)
camera->setOrientation(XMQuaternionIdentity());
if(game.KeyboardManager.getKeyboardState()[DIK_W]/128)
camera->Translate(XMFLOAT3(0,0,spd));
if(game.KeyboardManager.getKeyboardState()[DIK_S]/128)
camera->Translate(XMFLOAT3(0,0,-spd));
if(game.KeyboardManager.getKeyboardState()[DIK_A]/128)
camera->Translate(XMFLOAT3(-spd,0,0));
if(game.KeyboardManager.getKeyboardState()[DIK_D]/128)
camera->Translate(XMFLOAT3(spd,0,0));
}
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
HandleKeyboardInput();
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
HandleKeyboardInput();
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
Or, as shown in a clip a few posts ago, this :)
int cubes = 8;
for(int c = 0; c < cubes;c++)
{
TestCube* testCube = new TestCube();
testCube->game = &game;
XMFLOAT3 pos;
XMFLOAT4 col;
switch(c)
{
case 0:
pos = XMFLOAT3(-1,0,1);
col = XMFLOAT4(1,1,1,1);
break;
case 1:
pos = XMFLOAT3(1,0,1);
col = XMFLOAT4(1,0,1,1);
break;
case 2:
pos = XMFLOAT3(-1,0,3);
col = XMFLOAT4(1,1,0,1);
break;
case 3:
pos = XMFLOAT3(1,0,3);
col = XMFLOAT4(0,1,1,1);
break;
case 4:
pos = XMFLOAT3(-1,2,1);
col = XMFLOAT4(0,0,1,1);
break;
case 5:
pos = XMFLOAT3(1,2,1);
col = XMFLOAT4(1,0,0,1);
break;
case 6:
pos = XMFLOAT3(-1,2,3);
col = XMFLOAT4(0,1,0,1);
break;
case 7:
pos = XMFLOAT3(1,2,3);
col = XMFLOAT4(.5,.5,.5,1);
break;
}
testCube->setPosition(pos);
testCube->Color = col;
testCube->Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(testCube);
vDrawables.push_back(testCube);
}
for(int c = 0; c < cubes;c++)
{
TestCube* testCube = new TestCube();
testCube->game = &game;
XMFLOAT3 pos;
XMFLOAT4 col;
switch(c)
{
case 0:
pos = XMFLOAT3(-1,0,1);
col = XMFLOAT4(1,1,1,1);
break;
case 1:
pos = XMFLOAT3(1,0,1);
col = XMFLOAT4(1,0,1,1);
break;
case 2:
pos = XMFLOAT3(-1,0,3);
col = XMFLOAT4(1,1,0,1);
break;
case 3:
pos = XMFLOAT3(1,0,3);
col = XMFLOAT4(0,1,1,1);
break;
case 4:
pos = XMFLOAT3(-1,2,1);
col = XMFLOAT4(0,0,1,1);
break;
case 5:
pos = XMFLOAT3(1,2,1);
col = XMFLOAT4(1,0,0,1);
break;
case 6:
pos = XMFLOAT3(-1,2,3);
col = XMFLOAT4(0,1,0,1);
break;
case 7:
pos = XMFLOAT3(1,2,3);
col = XMFLOAT4(.5,.5,.5,1);
break;
}
testCube->setPosition(pos);
testCube->Color = col;
testCube->Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(testCube);
vDrawables.push_back(testCube);
}
So, your main.cpp would look something like this
#pragma once
#include <Windows.h>
#include "RC3DGame.h"
#include "RC3DCamera.h"
#include "TestCube.h"
RC3DGame game;
RC3DCamera* camera;
std::vector<IUpdateable*> vUpdateables;
std::vector<IDrawable*> vDrawables;
int int_AppRunning = 1;
LRESULT CALLBACK winProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
void HandleKeyboardInput()
{
float spd = .0005f;
float rotSpd = .0001f;
if (game.KeyboardManager.getKeyboardState()[DIK_ESCAPE]/128)
int_AppRunning = 0;
if (game.KeyboardManager.getKeyboardState()[DIK_LEFT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),-rotSpd);
if (game.KeyboardManager.getKeyboardState()[DIK_RIGHT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_UP]/128)
camera->Rotate(XMVectorSet(1,0,0,0),-rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_DOWN]/128)
camera->Rotate(XMVectorSet(1,0,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_SPACE]/128)
camera->setOrientation(XMQuaternionIdentity());
if(game.KeyboardManager.getKeyboardState()[DIK_W]/128)
camera->Translate(XMFLOAT3(0,0,spd));
if(game.KeyboardManager.getKeyboardState()[DIK_S]/128)
camera->Translate(XMFLOAT3(0,0,-spd));
if(game.KeyboardManager.getKeyboardState()[DIK_A]/128)
camera->Translate(XMFLOAT3(-spd,0,0));
if(game.KeyboardManager.getKeyboardState()[DIK_D]/128)
camera->Translate(XMFLOAT3(spd,0,0));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
MSG msg_Message;
int result = 0;
game.Initialize(L"RandomchaosDX11ProtoEngien",0,0,800,600,winProc);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
camera = new RC3DCamera(XMFLOAT3(0,0,0),XMFLOAT3(0,1,0),XMQuaternionIdentity(), game.GraphicsDevice.getViewPort().Width,game.GraphicsDevice.getViewPort().Height);
vUpdateables.push_back(camera);
int cubes = 8;
for(int c = 0; c < cubes;c++)
{
TestCube* testCube = new TestCube();
testCube->game = &game;
XMFLOAT3 pos;
XMFLOAT4 col;
switch(c)
{
case 0:
pos = XMFLOAT3(-1,0,1);
col = XMFLOAT4(1,1,1,1);
break;
case 1:
pos = XMFLOAT3(1,0,1);
col = XMFLOAT4(1,0,1,1);
break;
case 2:
pos = XMFLOAT3(-1,0,3);
col = XMFLOAT4(1,1,0,1);
break;
case 3:
pos = XMFLOAT3(1,0,3);
col = XMFLOAT4(0,1,1,1);
break;
case 4:
pos = XMFLOAT3(-1,2,1);
col = XMFLOAT4(0,0,1,1);
break;
case 5:
pos = XMFLOAT3(1,2,1);
col = XMFLOAT4(1,0,0,1);
break;
case 6:
pos = XMFLOAT3(-1,2,3);
col = XMFLOAT4(0,1,0,1);
break;
case 7:
pos = XMFLOAT3(1,2,3);
col = XMFLOAT4(.5,.5,.5,1);
break;
}
testCube->setPosition(pos);
testCube->Color = col;
testCube->Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(testCube);
vDrawables.push_back(testCube);
}
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
HandleKeyboardInput();
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
DestroyWindow(hWnd);
}
return result;
}
#include <Windows.h>
#include "RC3DGame.h"
#include "RC3DCamera.h"
#include "TestCube.h"
RC3DGame game;
RC3DCamera* camera;
std::vector<IUpdateable*> vUpdateables;
std::vector<IDrawable*> vDrawables;
int int_AppRunning = 1;
LRESULT CALLBACK winProc( HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam )
{
switch(message)
{
case WM_CLOSE:
{
int_AppRunning = 0;
break;
}
}
return DefWindowProc(hWnd,message,wParam,lParam);
}
void HandleKeyboardInput()
{
float spd = .0005f;
float rotSpd = .0001f;
if (game.KeyboardManager.getKeyboardState()[DIK_ESCAPE]/128)
int_AppRunning = 0;
if (game.KeyboardManager.getKeyboardState()[DIK_LEFT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),-rotSpd);
if (game.KeyboardManager.getKeyboardState()[DIK_RIGHT]/128)
camera->Rotate(XMVectorSet(0,1,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_UP]/128)
camera->Rotate(XMVectorSet(1,0,0,0),-rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_DOWN]/128)
camera->Rotate(XMVectorSet(1,0,0,0),rotSpd);
if(game.KeyboardManager.getKeyboardState()[DIK_SPACE]/128)
camera->setOrientation(XMQuaternionIdentity());
if(game.KeyboardManager.getKeyboardState()[DIK_W]/128)
camera->Translate(XMFLOAT3(0,0,spd));
if(game.KeyboardManager.getKeyboardState()[DIK_S]/128)
camera->Translate(XMFLOAT3(0,0,-spd));
if(game.KeyboardManager.getKeyboardState()[DIK_A]/128)
camera->Translate(XMFLOAT3(-spd,0,0));
if(game.KeyboardManager.getKeyboardState()[DIK_D]/128)
camera->Translate(XMFLOAT3(spd,0,0));
}
int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, PSTR pScmdline, int iCmdshow)
{
MSG msg_Message;
int result = 0;
game.Initialize(L"RandomchaosDX11ProtoEngien",0,0,800,600,winProc);
HWND hWnd = game.GraphicsDevice.getWindowHandle();
camera = new RC3DCamera(XMFLOAT3(0,0,0),XMFLOAT3(0,1,0),XMQuaternionIdentity(), game.GraphicsDevice.getViewPort().Width,game.GraphicsDevice.getViewPort().Height);
vUpdateables.push_back(camera);
int cubes = 8;
for(int c = 0; c < cubes;c++)
{
TestCube* testCube = new TestCube();
testCube->game = &game;
XMFLOAT3 pos;
XMFLOAT4 col;
switch(c)
{
case 0:
pos = XMFLOAT3(-1,0,1);
col = XMFLOAT4(1,1,1,1);
break;
case 1:
pos = XMFLOAT3(1,0,1);
col = XMFLOAT4(1,0,1,1);
break;
case 2:
pos = XMFLOAT3(-1,0,3);
col = XMFLOAT4(1,1,0,1);
break;
case 3:
pos = XMFLOAT3(1,0,3);
col = XMFLOAT4(0,1,1,1);
break;
case 4:
pos = XMFLOAT3(-1,2,1);
col = XMFLOAT4(0,0,1,1);
break;
case 5:
pos = XMFLOAT3(1,2,1);
col = XMFLOAT4(1,0,0,1);
break;
case 6:
pos = XMFLOAT3(-1,2,3);
col = XMFLOAT4(0,1,0,1);
break;
case 7:
pos = XMFLOAT3(1,2,3);
col = XMFLOAT4(.5,.5,.5,1);
break;
}
testCube->setPosition(pos);
testCube->Color = col;
testCube->Initialize(game.GraphicsDevice.getDevice());
vUpdateables.push_back(testCube);
vDrawables.push_back(testCube);
}
if(hWnd != HWND(-1))
{
while(int_AppRunning)
{
if(PeekMessage(&msg_Message,hWnd,0,0,PM_REMOVE))
DispatchMessage(&msg_Message);
HandleKeyboardInput();
game.Update(0,&vUpdateables);
game.Draw(0,camera,&vDrawables);
}
DestroyWindow(hWnd);
}
return result;
}
I hope you have found this of some use, please let me know what you think in the comments.
Source code is available here.
Oh Yea ! DirecX and C++ the XNA way.. gona love this !
ReplyDeleteZeniac
lol, I have to write it yet, don't think it's going to be that easy :P
DeleteFollowing your small tutorial series here, very educational :-)
ReplyDeleteI have some problems with adding the 8 cubes as you do in the last section, for some reason it gives me an unhandled exception.
It breaks in the testcube.cpp in the constructor.
TestCube::TestCube(void)
{
---> Color = XMFLOAT4(1,1,1,1);
}
If i change the number of cubes to 1 it runs fine.
I also tried to compile you source code and it gave me the same error.
I'm using VS2010, but would be surprised if that is the issue.
OK, that does seem odd, can't see why that line would throw an exception :S
DeleteAs the color is being set in the code after construction, remove this line from the constructor and see how it behaves...
As to the code I have supplied, if you read from the opening blog post, I state that I am using (currently) VS2012 RC, to use my source as is you will need to use VS2012, you could re build the solution in VS2010 though :)
I have been looking a bit more into my problem, and I think I now know the explanation for my issue.
ReplyDeleteIt is not recommended to use XMMATRIX or XMVECTOR in structs or as datamembers of classes, because they need to be 16byte aligned in memory which you cannot explicitly guarantee on Win32
For some reason it causes crashes on my compilation, and I would expect that you could run into similar strange problems later on in your project.
I changed all the datatypes to XMFLOAT4 and XMFLOAT4X4, and used the XMLoadFloat4 and XMStoreFloat4 type functions when I needed to work with XMVECTOR or XMMATRIX SIMD instructions.
You can read more about it here: http://msdn.microsoft.com/en-us/library/ee418725.aspx
Regards,
Stunt
Cool! Thanks for that Ill take it into account :)
DeleteReally great tutorial. I'm working on a new web site for software developers (http://www.hackishcode.com/showstory.php?id=15) and I would like to use your tutorial on the site. Can I do t. It is really great.
ReplyDeletesure if you want to, just remember to credit me and point people back to this site :)
DeleteI have a problem at the push back for the camera, I get this error:
ReplyDeleteIntelliSense: no instance of overloaded function "std::vector<_Ty, _Alloc>::push_back [with _Ty=IUpdateable *, _Alloc=std::allocator]" matches the argument list
argument types are: (G3DCamera *)
object type is: std::vector>
Been a while since I have looked at this code, looks like a configuration issue with your environment to me, push_back is part of the core code and not written by me. Make sure you have your IDE configured right I guess... Hope you sort it out :S
Deletewell, It's not a problem with my IDE.
DeleteIs it not compiling, or is it just that the IDE's intelisense is not working? What line of code is it occurring on?
Delete