#include <windows.h>
#include <d3d11.h>
#include <d3dx11.h>
#include <d3dcompiler.h>
#include <xnamath.h>
#include <vector>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <cstdint>
#include "resource.h"
#include "DXUT/Core/dxut.h"
#include "DXUTmisc.h"
#include "DXUTcamera.h"
#include "DXUTgui.h"
#include "DXUTsettingsDlg.h"
#include "SDKmisc.h"
#include "Effects11/Inc/d3dx11effect.h"
#include "ntx/NTX.h"
#include "debug.h"
// Convenience macros for safe effect variable retrieval
#define SAFE_GET_PASS(Technique, name, var) {assert(Technique!=NULL); var = Technique->GetPassByName( name ); assert(var->IsValid());}
#define SAFE_GET_TECHNIQUE(effect, name, var) {assert(effect!=NULL); var = effect->GetTechniqueByName( name ); assert(var->IsValid());}
#define SAFE_GET_SCALAR(effect, name, var) {assert(effect!=NULL); var = effect->GetVariableByName( name )->AsScalar(); assert(var->IsValid());}
#define SAFE_GET_VECTOR(effect, name, var) {assert(effect!=NULL); var = effect->GetVariableByName( name )->AsVector(); assert(var->IsValid());}
#define SAFE_GET_MATRIX(effect, name, var) {assert(effect!=NULL); var = effect->GetVariableByName( name )->AsMatrix(); assert(var->IsValid());}
#define SAFE_GET_SAMPLER(effect, name, var) {assert(effect!=NULL); var = effect->GetVariableByName( name )->AsSampler(); assert(var->IsValid());}
#define SAFE_GET_RESOURCE(effect, name, var) {assert(effect!=NULL); var = effect->GetVariableByName( name )->AsShaderResource(); assert(var->IsValid());}
// Help macros
#define DEG2RAD( a ) ( (a) * D3DX_PI / 180.f )
using namespace std;
//--------------------------------------------------------------------------------------
// Global variables
//--------------------------------------------------------------------------------------
// Camera
struct CAMERAPARAMS {
float m_Fovy;
float m_Aspect;
float m_NearPlane;
float m_FarPlane;
} g_CameraParams;
float g_CameraMoveScaler = 1000.f;
float g_CameraRotateScaler = 0.01f;
CFirstPersonCamera g_Camera; // A first person camera
// User Interface
CDXUTDialogResourceManager g_DialogResourceManager; // manager for shared resources of dialogs
CD3DSettingsDlg g_SettingsDlg; // Device settings dialog
CDXUTTextHelper* g_TxtHelper = NULL;
CDXUTDialog g_HUD; // dialog for standard controls
CDXUTDialog g_SampleUI; // dialog for sample specific controls
// A D3DX rendering effect
ID3DX11Effect* g_Effect = NULL; // The whole rendering effect
ID3DX11EffectTechnique* g_Technique = NULL; // One technique to render the effect
ID3DX11EffectPass* g_Pass0 = NULL; // One rendering pass of the technique
ID3DX11EffectMatrixVariable* g_WorldEV = NULL; // World matrix effect variable
ID3DX11EffectMatrixVariable* g_WorldViewProjectionEV = NULL; // WorldViewProjection matrix effect variable
ID3DX11EffectShaderResourceVariable* g_DiffuseEV = NULL; // Effect variable for the diffuse color texture
ID3DX11EffectVectorVariable* g_LightDirEV = NULL; // Light direction in object space
// Background color
D3DXVECTOR4 g_ClearColor;
// Terrain meta information
struct PtfHeader{
int16_t magicNumber; // Must be 0x00DA
int16_t version; // Must be 1
int32_t heightSize; // Height data size
int32_t colorSize; // Color data size
int32_t normalSize; // Normal data size
} g_TerrainHeader;
char g_TerrainPath[MAX_PATH] = { '\0' };
int g_TerrainResolution;
int g_TerrainNumVertices = 3;
int g_TerrainNumTriangles = 1;
float g_TerrainWidth = 1000.0f;
float g_TerrainDepth = 1000.0f;
float g_TerrainHeight = 400.0f;
bool g_TerrainSpinning = true;
float g_TerrainSpinSpeed = 0.0f;
D3DXMATRIX g_TerrainWorld; // object- to world-space transformation
// Terrain rendering resources
ID3D11InputLayout* g_TerrainVertexLayout = NULL; // Describes the structure of the vertex buffer to the input assembler stage
ID3D11Buffer* g_TerrainVB = NULL; // The terrain's vertices
ID3D11Buffer* g_TerrainIB = NULL; // The terrain's triangulation
ID3D11Texture2D* g_TerrainDiffuseTex = NULL; // The terrain's material color for diffuse lighting
ID3D11ShaderResourceView* g_TerrainDiffuseSRV = NULL; // Describes the structure of the diffuse texture to the shader stages
// Scene information
D3DXVECTOR4 g_LightDir;
// General meta data
char g_DebugTexPath[MAX_PATH] = { '\0' };
// General resources
ID3D11ShaderResourceView* g_DebugSRV = NULL;
//--------------------------------------------------------------------------------------
// UI control IDs
//--------------------------------------------------------------------------------------
#define IDC_TOGGLEFULLSCREEN 1
#define IDC_TOGGLEREF 2
#define IDC_CHANGEDEVICE 3
#define IDC_TOGGLESPIN 4
#define IDC_RELOAD_SHADERS 101
//--------------------------------------------------------------------------------------
// Forward declarations
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
void* pUserContext );
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext );
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext );
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext );
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext );
bool CALLBACK IsD3D11DeviceAcceptable( const CD3D11EnumAdapterInfo *AdapterInfo, UINT Output, const CD3D11EnumDeviceInfo *DeviceInfo,
DXGI_FORMAT BackBufferFormat, bool bWindowed, void* pUserContext );
HRESULT CALLBACK OnD3D11CreateDevice( ID3D11Device* pd3dDevice, const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc,
void* pUserContext );
HRESULT CALLBACK OnD3D11ResizedSwapChain( ID3D11Device* pd3dDevice, IDXGISwapChain* pSwapChain,
const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext );
void CALLBACK OnD3D11ReleasingSwapChain( void* pUserContext );
void CALLBACK OnD3D11DestroyDevice( void* pUserContext );
void CALLBACK OnD3D11FrameRender( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, double fTime,
float fElapsedTime, void* pUserContext );
void InitApp();
void RenderText();
void ReleaseShader();
HRESULT ReloadShader(ID3D11Device* pd3dDevice);
//--------------------------------------------------------------------------------------
// 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 )
{
// Enable run-time memory check for debug builds.
#if defined(DEBUG) | defined(_DEBUG)
_CrtSetDbgFlag( _CRTDBG_ALLOC_MEM_DF | _CRTDBG_LEAK_CHECK_DF );
#endif
// Old Direct3D Documentation:
// Start > All Programs > Microsoft DirectX SDK (June 2010) > Windows DirectX Graphics Documentation
// DXUT Documentaion:
// Start > All Programs > Microsoft DirectX SDK (June 2010) > DirectX Documentation for C++ : The DirectX Software Development Kit > Programming Guide > DXUT
// New Direct3D Documentaion (just for reference, use old documentation to find explanations):
// http://msdn.microsoft.com/en-us/library/windows/desktop/hh309466%28v=vs.85%29.aspx
// Set DXUT callbacks
DXUTSetCallbackMsgProc( MsgProc );
DXUTSetCallbackKeyboard( OnKeyboard );
DXUTSetCallbackFrameMove( OnFrameMove );
DXUTSetCallbackDeviceChanging( ModifyDeviceSettings );
DXUTSetCallbackD3D11DeviceAcceptable( IsD3D11DeviceAcceptable );
DXUTSetCallbackD3D11DeviceCreated( OnD3D11CreateDevice );
DXUTSetCallbackD3D11SwapChainResized( OnD3D11ResizedSwapChain );
DXUTSetCallbackD3D11SwapChainReleasing( OnD3D11ReleasingSwapChain );
DXUTSetCallbackD3D11DeviceDestroyed( OnD3D11DestroyDevice );
DXUTSetCallbackD3D11FrameRender( OnD3D11FrameRender );
InitApp();
DXUTInit( true, true, NULL ); // Parse the command line, show msgboxes on error, no extra command line params
DXUTSetCursorSettings( true, true );
DXUTCreateWindow( L"Terrain Viewer v0.0.1.33.7a" ); // You may change the title
DXUTCreateDevice( D3D_FEATURE_LEVEL_10_0, true, 1280, 720 );
DXUTMainLoop(); // Enter into the DXUT render loop
return DXUTGetExitCode();
}
//--------------------------------------------------------------------------------------
// Initialize the app
//--------------------------------------------------------------------------------------
void InitApp()
{
HRESULT hr;
WCHAR path[MAX_PATH];
// Parse the config file
V(DXUTFindDXSDKMediaFileCch(path, MAX_PATH, L"game.cfg"));
ifstream stream(path);
if(!stream) {
MessageBoxA (NULL, "Fatal Error: game.cfg not found.",
"Missing file", MB_ICONERROR | MB_OK);
return;
}
std::string var;
while(!stream.eof())
{
stream >> var;
if ( var.compare("DebugTexPath") ==0 ) stream >> g_DebugTexPath;
if ( var.compare("Spinning") ==0 ) stream >> g_TerrainSpinning;
if ( var.compare("SpinSpeed") ==0 ) stream >> g_TerrainSpinSpeed;
if ( var.compare("BackgroundColor")==0 ) stream >> g_ClearColor.x >> g_ClearColor.y >> g_ClearColor.z >> g_ClearColor.w;
// BEGIN: Assignment 3.2.1
// TODO: Parse the additional information in the config file into the variables:
// g_TerrainPath, g_TerrainWidth, g_TerrainDepth and g_TerrainHeight
// HINT: the operator '>>' converts the next word in 'stream' into the format of
// its right hand side and is really flexible
if ( var.compare("TerrainPath") ==0 ) stream >> g_TerrainPath;
if ( var.compare("TerrainWidth") ==0 ) stream >> g_TerrainWidth;
if ( var.compare("TerrainDepth") ==0 ) stream >> g_TerrainDepth;
if ( var.compare("TerrainHeight") ==0 ) stream >> g_TerrainHeight;
// END: Assignment 3.2.1
}
stream.close();
// Intialize the user interface
g_SettingsDlg.Init( &g_DialogResourceManager );
g_HUD.Init( &g_DialogResourceManager );
g_SampleUI.Init( &g_DialogResourceManager );
g_HUD.SetCallback( OnGUIEvent );
int iY = 30;
int iYo = 26;
g_HUD.AddButton( IDC_TOGGLEFULLSCREEN, L"Toggle full screen", 0, iY, 170, 22 );
g_HUD.AddButton( IDC_TOGGLEREF, L"Toggle REF (F3)", 0, iY += iYo, 170, 22, VK_F3 );
g_HUD.AddButton( IDC_CHANGEDEVICE, L"Change device (F2)", 0, iY += iYo, 170, 22, VK_F2 );
g_HUD.AddButton (IDC_RELOAD_SHADERS, L"Reload shaders (F5)", 0, iY += 24, 170, 22, VK_F5);
g_SampleUI.SetCallback( OnGUIEvent ); iY = 10;
iY += 24;
g_SampleUI.AddCheckBox( IDC_TOGGLESPIN, L"Toggle Spinning", 0, iY += 24, 125, 22, g_TerrainSpinning );
}
//--------------------------------------------------------------------------------------
// Render the help and statistics text. This function uses the ID3DXFont interface for
// efficient text rendering.
//--------------------------------------------------------------------------------------
void RenderText()
{
g_TxtHelper->Begin();
g_TxtHelper->SetInsertionPos( 5, 5 );
g_TxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
g_TxtHelper->DrawTextLine( DXUTGetFrameStats(true)); //DXUTIsVsyncEnabled() ) );
g_TxtHelper->DrawTextLine( DXUTGetDeviceStats() );
g_TxtHelper->End();
}
//--------------------------------------------------------------------------------------
// Reject any D3D11 devices that aren't acceptable by returning false
//--------------------------------------------------------------------------------------
bool CALLBACK IsD3D11DeviceAcceptable( const CD3D11EnumAdapterInfo *AdapterInfo, UINT Output, const CD3D11EnumDeviceInfo *DeviceInfo,
DXGI_FORMAT BackBufferFormat, bool bWindowed, void* pUserContext )
{
return true;
}
//--------------------------------------------------------------------------------------
// Specify the initial device settings
//--------------------------------------------------------------------------------------
bool CALLBACK ModifyDeviceSettings( DXUTDeviceSettings* pDeviceSettings, void* pUserContext )
{
// For the first device created if its a REF device, optionally display a warning dialog box
static bool s_bFirstTime = true;
if( s_bFirstTime )
{
s_bFirstTime = false;
if( ( DXUT_D3D9_DEVICE == pDeviceSettings->ver && pDeviceSettings->d3d9.DeviceType == D3DDEVTYPE_REF ) ||
( DXUT_D3D11_DEVICE == pDeviceSettings->ver &&
pDeviceSettings->d3d11.DriverType == D3D_DRIVER_TYPE_REFERENCE ) )
{
DXUTDisplaySwitchingToREFWarning( pDeviceSettings->ver );
}
}
//// Enable anti aliasing
//pDeviceSettings->d3d11.sd.SampleDesc.Count = 4;
//pDeviceSettings->d3d11.sd.SampleDesc.Quality = 1;
return true;
}
//--------------------------------------------------------------------------------------
// Create any D3D11 resources that aren't dependant on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11CreateDevice( ID3D11Device* pd3dDevice,
const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
HRESULT hr;
ID3D11DeviceContext* pd3dImmediateContext = DXUTGetD3D11DeviceContext(); // http://msdn.microsoft.com/en-us/library/ff476891%28v=vs.85%29
V_RETURN( g_DialogResourceManager.OnD3D11CreateDevice( pd3dDevice, pd3dImmediateContext ) );
V_RETURN( g_SettingsDlg.OnD3D11CreateDevice( pd3dDevice ) );
g_TxtHelper = new CDXUTTextHelper( pd3dDevice, pd3dImmediateContext, &g_DialogResourceManager, 15 );
V_RETURN( ReloadShader(pd3dDevice) );
errno_t error;
WCHAR path[MAX_PATH];
stringstream ss;
wstringstream wss;
// Initialize the camera
D3DXVECTOR3 Eye( 0.0f, 2 * g_TerrainHeight, -0.5f * g_TerrainDepth );
D3DXVECTOR3 At( 0.0f, 0.0f, 0.0f );
g_Camera.SetViewParams( &Eye, &At ); // http://msdn.microsoft.com/en-us/library/windows/desktop/bb206342%28v=vs.85%29.aspx
g_Camera.SetScalers( g_CameraRotateScaler, g_CameraMoveScaler );
// Load the debug texture and create a shader resource view
wss.str(L""); wss << g_DebugTexPath;
V(DXUTFindDXSDKMediaFileCch( path, MAX_PATH, wss.str().c_str()));
if (hr != S_OK) {
ss.str();
ss << "Could not find '" << g_DebugTexPath << "'";
MessageBoxA (NULL, ss.str().c_str(), "Missing file", MB_ICONERROR | MB_OK);
return hr;
}
V(D3DX11CreateShaderResourceViewFromFile(pd3dDevice, path, NULL, NULL, &g_DebugSRV, &hr));
if (hr != S_OK) {
ss.str();
ss << "Could not load texture '" << g_DebugTexPath << "'";
MessageBoxA (NULL, ss.str().c_str(), "Invalid texture", MB_ICONERROR | MB_OK);
return hr;
}
// Define the input layout
const D3D11_INPUT_ELEMENT_DESC layout[] = // http://msdn.microsoft.com/en-us/library/bb205117%28v=vs.85%29.aspx
{
{ "SV_POSITION", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "NORMAL", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, 16, D3D11_INPUT_PER_VERTEX_DATA, 0 },
{ "TEXCOORD", 0, DXGI_FORMAT_R32G32_FLOAT, 0, 32, D3D11_INPUT_PER_VERTEX_DATA, 0 },
};
UINT numElements = sizeof( layout ) / sizeof( layout[0] );
// Create the input layout
D3DX11_PASS_DESC pd;
V_RETURN(g_Pass0->GetDesc(&pd));
V_RETURN( pd3dDevice->CreateInputLayout( layout, numElements, pd.pIAInputSignature,
pd.IAInputSignatureSize, &g_TerrainVertexLayout ) );
// BEGIN: Assignment 3.2.2
// Find the terrain file
wss.str(L""); wss << g_TerrainPath;
V(DXUTFindDXSDKMediaFileCch( path, MAX_PATH, wss.str().c_str()));
if (hr != S_OK) {
ss.str();
ss << "Could not find '" << g_TerrainPath << "'";
MessageBoxA (NULL, ss.str().c_str(), "Missing file", MB_ICONERROR | MB_OK);
return hr;
}
// Open the terrain file
FILE* file;
error = _wfopen_s(&file, path, L"rb");
if (file == nullptr) {
ss.str();
ss << "Could not open '" << g_TerrainPath << "'";
MessageBoxA (NULL, ss.str().c_str(), "File error", MB_ICONERROR | MB_OK);
return E_FAIL;
}
// Read the terrain header
{
auto r = fread (&g_TerrainHeader, sizeof (g_TerrainHeader), 1, file);
if (r != 1) {
MessageBoxA (NULL, "Could not read the header.",
"Invalid terrain file", MB_ICONERROR | MB_OK);
return E_FAIL;
}
}
// Check the magic number
if (g_TerrainHeader.magicNumber != 0x00DA) {
MessageBoxA (NULL, "The magic number is incorrect.",
"Invalid terrain file header", MB_ICONERROR | MB_OK);
return E_FAIL;
}
// Check the version
if (g_TerrainHeader.version != 1) {
MessageBoxA (NULL, "The header version is incorrect.",
"Invalid terrain file header", MB_ICONERROR | MB_OK);
return E_FAIL;
}
// Calculate the terrain resoultion from the height size
g_TerrainResolution = (int)sqrt(g_TerrainHeader.heightSize / 2.0); // Assume a square terrain
g_TerrainNumVertices = g_TerrainResolution * g_TerrainResolution;
g_TerrainNumTriangles = 2 * (g_TerrainResolution - 1) * (g_TerrainResolution - 1) ;
assert((g_TerrainHeader.heightSize / 2) == g_TerrainNumVertices);
// Read the terrain heights
std::vector<unsigned short> terrainHeights;
terrainHeights.resize(g_TerrainNumVertices);
{
if (g_TerrainHeader.heightSize != (int)::fread (&terrainHeights[0], sizeof(BYTE), g_TerrainHeader.heightSize, file)) {
MessageBoxA(NULL, "Error while reading height data.",
"Invalid terrain file", MB_ICONERROR | MB_OK);
return E_FAIL;
}
}
// Read the terrain color texture for diffuse lighting
std::vector<unsigned char> terrainDiffuseNtx;
terrainDiffuseNtx.resize(g_TerrainHeader.colorSize);
{
const auto requestedSize = terrainDiffuseNtx.size();
if (requestedSize != fread (&terrainDiffuseNtx[0], sizeof(unsigned char), requestedSize, file)) {
MessageBoxA (NULL, "Error while reading color data.",
"Invalid terrain file", MB_ICONERROR | MB_OK);
return E_FAIL;
}
}
fclose(file);
// END: Assignment 3.2.2
// Create the vertex buffer for the terrain
std::vector<float> terrainVB;
terrainVB.resize(g_TerrainNumVertices * (4 + 4 + 2)); // Position / Normal / TexCoord
// BEGIN: Assignment 3.2.3
// Note:
//
// In the coordinate system of the packed terrain file (input):
// u = east, v = south, height = up height in [0,65535] (unsigned short)
//
// In the coordinate system of the vertex buffer (output):
// x = east, y = south, z = up, x,y,z in [0,1] (float)
int iVB = 0; // You can use this variable as index into the vertex buffer ( terrainVB[iVB++] = ... )
float snx = (g_TerrainHeight * (g_TerrainResolution - 1)) / (g_TerrainWidth * 2.0f);
float sny = (g_TerrainHeight * (g_TerrainResolution - 1)) / (g_TerrainDepth * 2.0f);
for(int v = 0; v < g_TerrainResolution; v++) {
for(int u = 0; u < g_TerrainResolution; u++) {
// Retrieve the height
float height = terrainHeights[u + v * g_TerrainResolution] / 65535.f; // [0, 1]
// Calculate the normal
float heightL = terrainHeights[max(0, u - 1) + v * g_TerrainResolution] / 65535.f;
float heightR = terrainHeights[min(g_TerrainResolution - 1, u + 1) + v * g_TerrainResolution] / 65535.f;
float heightU = terrainHeights[u + max(0, v - 1) * g_TerrainResolution] / 65535.f;
float heightD = terrainHeights[u + min(g_TerrainResolution - 1, v + 1) * g_TerrainResolution] / 65535.f;
D3DXVECTOR3 n(snx * (heightL - heightR), sny * (heightU - heightD), 1.f);
D3DXVec3Normalize(&n, &n);
// Write the position into the "terrainVB" vertex buffer contents (pos.x, pos.y, pos.z, 1)
// Write the normal into the "terrainVB" vertex buffer contents (nor.x, nor.y, nor.z, 0)
// Write the texture coordinates into the "terrainVB" vertex buffer contents (tex.u, tex.v)
float tu = static_cast<float>(u / (g_TerrainResolution-1));
float tv = static_cast<float>(v / (g_TerrainResolution-1));
float px = static_cast<float>(tu * g_TerrainResolution);
float py = static_cast<float>(tv * g_TerrainResolution);
float pz = static_cast<float>(g_TerrainResolution * height);
terrainVB[iVB++] = px;
terrainVB[iVB++] = py;
terrainVB[iVB++] = pz;
terrainVB[iVB++] = 1.0f;
terrainVB[iVB++] = n.x;
terrainVB[iVB++] = n.y;
terrainVB[iVB++] = n.z;
terrainVB[iVB++] = 0.0f;
terrainVB[iVB++] = tu;
terrainVB[iVB++] = tv;
}
}
// END: Assignment 3.2.3
D3D11_SUBRESOURCE_DATA id;
id.pSysMem = &terrainVB[0];
id.SysMemPitch = 10 * sizeof(float); // Stride
id.SysMemSlicePitch = 0;
D3D11_BUFFER_DESC bd;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.ByteWidth = g_TerrainNumVertices * id.SysMemPitch;
bd.CPUAccessFlags = 0;
bd.MiscFlags = 0;
bd.Usage = D3D11_USAGE_DEFAULT;
pd3dDevice->CreateBuffer(&bd, &id, &g_TerrainVB); // http://msdn.microsoft.com/en-us/library/ff476899%28v=vs.85%29.aspx
// BEGIN: Assignment 3.2.4
// TODO: Create the terrain index buffer
std::vector<unsigned int> terrainIB;
terrainIB.resize((g_TerrainResolution-1)*(g_TerrainResolution-1) * 6);
int iIB = 0;
for(int v = 0; v < g_TerrainResolution - 1; v++) {
for(int u = 0; u < g_TerrainResolution - 1; u++) {
// TODO: Write the three indices for the first triangle into the "terrainIB" index buffer contents
terrainIB[iIB++] = v + u * g_TerrainResolution;
terrainIB[iIB++] = v + (u+1) * g_TerrainResolution;
terrainIB[iIB++] = (v+1) + u * g_TerrainResolution;
// TODO: Write the three indices for the second triangle into the "terrainIB" index buffer contents
terrainIB[iIB++] = (v+1) + u * g_TerrainResolution;
terrainIB[iIB++] = v + (u+1) * g_TerrainResolution;
terrainIB[iIB++] = (v+1) + (u+1) * g_TerrainResolution;
}
}
//define initial data
D3D11_SUBRESOURCE_DATA iid;
iid.pSysMem = &terrainIB[0];
iid.SysMemPitch = 6 * sizeof(unsigned int); // Stride
iid.SysMemSlicePitch = 0;
//create the index buffer and fill desc
D3D11_BUFFER_DESC ibd;
::ZeroMemory(&ibd,sizeof(ibd));
ibd.Usage = D3D11_USAGE_DEFAULT;
ibd.ByteWidth = g_TerrainNumVertices * iid.SysMemPitch;
ibd.BindFlags = D3D10_BIND_INDEX_BUFFER;
ibd.CPUAccessFlags = 0;
ibd.MiscFlags = 0;
//define initial data
hr = pd3dDevice->CreateBuffer(&ibd,&iid,&g_TerrainIB);
if(FAILED(hr))
return hr;
// END: Assignment 3.2.4
// BEGIN: Assignment 3.2.5
// TODO: Create the terrain color texture
D3D11_TEXTURE2D_DESC tex2DDesc;
std::vector<std::vector<unsigned char>> textureData;
std::vector<D3D11_SUBRESOURCE_DATA> subresourceData;
bool sRgb;
LoadNtx(terrainDiffuseNtx,&tex2DDesc,textureData,subresourceData,sRgb);
pd3dDevice->CreateTexture2D(&tex2DDesc,&subresourceData[0],&g_TerrainDiffuseTex);
pd3dDevice->CreateShaderResourceView(g_TerrainDiffuseTex,NULL,&g_TerrainDiffuseSRV);
// END: Assignment 3.2.5
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D11CreateDevice
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11DestroyDevice( void* pUserContext )
{
g_DialogResourceManager.OnD3D11DestroyDevice();
g_SettingsDlg.OnD3D11DestroyDevice();
DXUTGetGlobalResourceCache().OnDestroyDevice();
SAFE_RELEASE( g_DebugSRV );
SAFE_RELEASE( g_TerrainVertexLayout );
SAFE_RELEASE( g_TerrainVB );
// Assignment 3.2.4
// Release the index buffer
SAFE_RELEASE( g_TerrainIB );
// Assignment 3.2.5
// Release the terrain's shader resource view and texture
SAFE_RELEASE( g_TerrainDiffuseSRV );
SAFE_RELEASE( g_TerrainDiffuseTex );
SAFE_DELETE( g_TxtHelper );
ReleaseShader();
}
//--------------------------------------------------------------------------------------
// Create any D3D11 resources that depend on the back buffer
//--------------------------------------------------------------------------------------
HRESULT CALLBACK OnD3D11ResizedSwapChain( ID3D11Device* pd3dDevice, IDXGISwapChain* pSwapChain,
const DXGI_SURFACE_DESC* pBackBufferSurfaceDesc, void* pUserContext )
{
HRESULT hr;
// Intialize the user interface
V_RETURN( g_DialogResourceManager.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );
V_RETURN( g_SettingsDlg.OnD3D11ResizedSwapChain( pd3dDevice, pBackBufferSurfaceDesc ) );
g_HUD.SetLocation( pBackBufferSurfaceDesc->Width - 170, 0 );
g_HUD.SetSize( 170, 170 );
g_SampleUI.SetLocation( pBackBufferSurfaceDesc->Width - 170, pBackBufferSurfaceDesc->Height - 300 );
g_SampleUI.SetSize( 170, 300 );
// Initialize the camera
g_CameraParams.m_Aspect = pBackBufferSurfaceDesc->Width / ( FLOAT )pBackBufferSurfaceDesc->Height;
g_CameraParams.m_Fovy = 0.785398;
g_CameraParams.m_NearPlane = 1.f;
g_CameraParams.m_FarPlane = 2000.f;
g_Camera.SetProjParams(g_CameraParams.m_Fovy, g_CameraParams.m_Aspect, g_CameraParams.m_NearPlane, g_CameraParams.m_FarPlane);
g_Camera.SetEnablePositionMovement(true);
g_Camera.SetRotateButtons(true, false, false);
g_Camera.SetScalers( g_CameraRotateScaler, g_CameraMoveScaler );
g_Camera.SetDrag( true );
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release D3D11 resources created in OnD3D11ResizedSwapChain
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11ReleasingSwapChain( void* pUserContext )
{
g_DialogResourceManager.OnD3D11ReleasingSwapChain();
}
//--------------------------------------------------------------------------------------
// Loads the effect from file
// and retrieves all dependent variables
//--------------------------------------------------------------------------------------
HRESULT ReloadShader(ID3D11Device* pd3dDevice)
{
assert(pd3dDevice != NULL);
HRESULT hr;
ReleaseShader();
WCHAR path[MAX_PATH];
stringstream ss;
wstringstream wss;
// Find and load the rendering effect
V_RETURN(DXUTFindDXSDKMediaFileCch(path, MAX_PATH, L"game.fxo"));
ifstream is(path, ios_base::binary);
is.seekg(0, ios_base::end);
streampos pos = is.tellg();
is.seekg(0, ios_base::beg);
vector<char> effectBuffer((unsigned int)pos);
is.read(&effectBuffer[0], pos);
is.close();
V_RETURN(D3DX11CreateEffectFromMemory((const void*)&effectBuffer[0], effectBuffer.size(), 0, pd3dDevice, &g_Effect));
assert(g_Effect->IsValid());
// Obtain the effect technique
SAFE_GET_TECHNIQUE(g_Effect, "Render", g_Technique);
// Obtain the effect pass
SAFE_GET_PASS(g_Technique, "P0", g_Pass0);
// Obtain the effect variables
SAFE_GET_RESOURCE(g_Effect, "g_Diffuse", g_DiffuseEV);
SAFE_GET_MATRIX(g_Effect, "g_World", g_WorldEV);
SAFE_GET_MATRIX(g_Effect, "g_WorldViewProjection", g_WorldViewProjectionEV);
SAFE_GET_VECTOR(g_Effect, "g_LightDir", g_LightDirEV);
return S_OK;
}
//--------------------------------------------------------------------------------------
// Release resources created in ReloadShader
//--------------------------------------------------------------------------------------
void ReleaseShader()
{
SAFE_RELEASE( g_Effect );
}
//--------------------------------------------------------------------------------------
// Handle messages to the application
//--------------------------------------------------------------------------------------
LRESULT CALLBACK MsgProc( HWND hWnd, UINT uMsg, WPARAM wParam, LPARAM lParam, bool* pbNoFurtherProcessing,
void* pUserContext )
{
// Pass messages to dialog resource manager calls so GUI state is updated correctly
*pbNoFurtherProcessing = g_DialogResourceManager.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
// Pass messages to settings dialog if its active
if( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.MsgProc( hWnd, uMsg, wParam, lParam );
return 0;
}
// Give the dialogs a chance to handle the message first
*pbNoFurtherProcessing = g_HUD.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
*pbNoFurtherProcessing = g_SampleUI.MsgProc( hWnd, uMsg, wParam, lParam );
if( *pbNoFurtherProcessing )
return 0;
// Use the mouse weel to control the movement speed
if(uMsg == WM_MOUSEWHEEL) {
int zDelta = GET_WHEEL_DELTA_WPARAM(wParam);
g_CameraMoveScaler *= (1 + zDelta / 500.0f);
if (g_CameraMoveScaler < 0.1f)
g_CameraMoveScaler = 0.1f;
g_Camera.SetScalers(g_CameraRotateScaler, g_CameraMoveScaler);
}
// Pass all remaining windows messages to camera so it can respond to user input
g_Camera.HandleMessages( hWnd, uMsg, wParam, lParam );
return 0;
}
//--------------------------------------------------------------------------------------
// Handle key presses
//--------------------------------------------------------------------------------------
void CALLBACK OnKeyboard( UINT nChar, bool bKeyDown, bool bAltDown, void* pUserContext )
{
}
//--------------------------------------------------------------------------------------
// Handles the GUI events
//--------------------------------------------------------------------------------------
void CALLBACK OnGUIEvent( UINT nEvent, int nControlID, CDXUTControl* pControl, void* pUserContext )
{
switch( nControlID )
{
case IDC_TOGGLEFULLSCREEN:
DXUTToggleFullScreen(); break;
case IDC_TOGGLEREF:
DXUTToggleREF(); break;
case IDC_CHANGEDEVICE:
g_SettingsDlg.SetActive( !g_SettingsDlg.IsActive() ); break;
case IDC_TOGGLESPIN:
g_TerrainSpinning = g_SampleUI.GetCheckBox( IDC_TOGGLESPIN )->GetChecked();
break;
case IDC_RELOAD_SHADERS:
ReloadShader(DXUTGetD3D11Device ());
break;
}
}
//--------------------------------------------------------------------------------------
// Handle updates to the scene. This is called regardless of which D3D API is used
//--------------------------------------------------------------------------------------
void CALLBACK OnFrameMove( double fTime, float fElapsedTime, void* pUserContext )
{
// Update the camera's position based on user input
g_Camera.FrameMove( fElapsedTime );
D3DXMATRIX mTmp;
// Initialize the terrain world matrix
// http://msdn.microsoft.com/en-us/library/windows/desktop/bb206365%28v=vs.85%29.aspx
// Set origin to (0.5, 0.5, 0)
D3DXMatrixTranslation(&g_TerrainWorld, -0.5f, -0.5f, 0.f); // Assume: x, y and z are in [0,1]
// Scale to terrain extents
D3DXMatrixScaling(&mTmp, g_TerrainWidth, g_TerrainDepth, g_TerrainHeight);
g_TerrainWorld = g_TerrainWorld * mTmp;
// Since "up" is z-axis in object space, but y-axis in world space, we rotate around the x-axis
D3DXMatrixRotationX( &mTmp, DEG2RAD( -90.0f ) );
g_TerrainWorld *= mTmp;
if( g_TerrainSpinning ) {
D3DXMatrixRotationY( &mTmp, g_TerrainSpinSpeed * DEG2RAD((float)fTime) );
g_TerrainWorld *= mTmp; // Rotate around world-space "up" axis
}
g_LightDir = D3DXVECTOR4(1, 1, 1, 0); // Direction to the directional light in world space
// Transform the light vector to terrain object space
D3DXMATRIX invWorld;
D3DXMatrixInverse(&invWorld, NULL, &g_TerrainWorld);
D3DXVec4Transform(&g_LightDir, &g_LightDir, &invWorld);
D3DXVec3Normalize((D3DXVECTOR3*)&g_LightDir, (D3DXVECTOR3*)&g_LightDir); // Normalize the light direction
}
//--------------------------------------------------------------------------------------
// Render the scene using the D3D11 device
//--------------------------------------------------------------------------------------
void CALLBACK OnD3D11FrameRender( ID3D11Device* pd3dDevice, ID3D11DeviceContext* pd3dImmediateContext, double fTime,
float fElapsedTime, void* pUserContext )
{
HRESULT hr;
// If the settings dialog is being shown, then render it instead of rendering the app's scene
if( g_SettingsDlg.IsActive() )
{
g_SettingsDlg.OnRender( fElapsedTime );
return;
}
ID3D11RenderTargetView* pRTV = DXUTGetD3D11RenderTargetView();
pd3dImmediateContext->ClearRenderTargetView( pRTV, g_ClearColor );
if(g_Effect == NULL) {
g_TxtHelper->Begin();
g_TxtHelper->SetInsertionPos( 5, 5 );
g_TxtHelper->SetForegroundColor( D3DXCOLOR( 1.0f, 1.0f, 0.0f, 1.0f ) );
g_TxtHelper->DrawTextLine( L"SHADER ERROR" );
g_TxtHelper->End();
return;
}
// Clear the depth stencil
ID3D11DepthStencilView* pDSV = DXUTGetD3D11DepthStencilView();
pd3dImmediateContext->ClearDepthStencilView( pDSV, D3D11_CLEAR_DEPTH, 1.0, 0 );
//
// Update variables that change once per frame
//
D3DXMATRIX const * view = g_Camera.GetViewMatrix(); // http://msdn.microsoft.com/en-us/library/windows/desktop/bb206342%28v=vs.85%29.aspx
D3DXMATRIX const * proj = g_Camera.GetProjMatrix(); // http://msdn.microsoft.com/en-us/library/windows/desktop/bb147302%28v=vs.85%29.aspx
D3DXMATRIX worldViewProj = g_TerrainWorld * (*view) * (*proj);
g_WorldEV->SetMatrix( ( float* )&g_TerrainWorld );
g_WorldViewProjectionEV->SetMatrix( ( float* )&worldViewProj );
g_LightDirEV->SetFloatVector( ( float* )&g_LightDir );
// Set input layout
pd3dImmediateContext->IASetInputLayout( g_TerrainVertexLayout );
// Bind the terrain vertex buffer to the input assembler stage
ID3D11Buffer* vbs[] = { g_TerrainVB, };
unsigned int strides[] = { 10 * sizeof(float), }, offsets[] = { 0, };
pd3dImmediateContext->IASetVertexBuffers(0, 1, vbs, strides, offsets);
// Tell the input assembler stage which primitive topology to use
pd3dImmediateContext->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
// Assignment 3.2.4
// Bind the terrain index buffer to the input assembler stage
pd3dImmediateContext->IASetIndexBuffer(g_TerrainIB,DXGI_FORMAT_R32_UINT,0);
// Assignment 3.2.5
// Bind the SRV of the terrain diffuse texture to the effect variable
// (instead of the SRV of the debug texture)
V(g_DiffuseEV->SetResource( g_TerrainDiffuseSRV));
// Apply the rendering pass in order to submit the necessary render state changes to the device
g_Pass0->Apply(0, pd3dImmediateContext);
// Draw
// Assignment 3.2.6
// TODO: Use DrawIndexed to draw the terrain geometry using as shared vertex list
// (instead of drawing only the vertex buffer)
pd3dImmediateContext->DrawIndexed(g_TerrainNumTriangles*3,0,0);
DXUT_BeginPerfEvent( DXUT_PERFEVENTCOLOR, L"HUD / Stats" );
g_HUD.OnRender( fElapsedTime );
g_SampleUI.OnRender( fElapsedTime );
RenderText();
DXUT_EndPerfEvent();
static DWORD dwTimefirst = GetTickCount();
if ( GetTickCount() - dwTimefirst > 5000 )
{
OutputDebugString( DXUTGetFrameStats( DXUTIsVsyncEnabled() ) );
OutputDebugString( L"\n" );
dwTimefirst = GetTickCount();
}
}