#include "vars.h"
// the WindowProc function prototype
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
// the entry point for any Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
HWND hWnd;
WNDCLASSEX wc;
ZeroMemory(&wc, sizeof(WNDCLASSEX));
wc.cbSize = sizeof(WNDCLASSEX);
wc.style = CS_HREDRAW | CS_VREDRAW;
wc.lpfnWndProc = WindowProc;
wc.hInstance = hInstance;
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.lpszClassName = L"WindowClass";
RegisterClassEx(&wc);
RECT wr = {0, 0, SCREEN_WIDTH, SCREEN_HEIGHT};
AdjustWindowRect(&wr, WS_OVERLAPPEDWINDOW, FALSE);
hWnd = CreateWindowEx(NULL,
L"WindowClass",
L"Our First Direct3D Program",
WS_OVERLAPPEDWINDOW,
300,
300,
wr.right - wr.left,
wr.bottom - wr.top,
NULL,
NULL,
hInstance,
NULL);
ShowWindow(hWnd, nCmdShow);
// set up and initialize Direct3D
InitD3D(hWnd);
// enter the main loop:
MSG msg;
while(TRUE)
{
if(PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
if(msg.message == WM_QUIT)
break;
}
RenderFrame();
}
// clean up DirectX and COM
CleanD3D();
return msg.wParam;
}
// this is the main message handler for the program
LRESULT CALLBACK WindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
return 0;
} break;
}
return DefWindowProc (hWnd, message, wParam, lParam);
}
// this function initializes and prepares Direct3D for use
void InitD3D(HWND hWnd)
{
// create a struct to hold information about the swap chain
DXGI_SWAP_CHAIN_DESC scd;
// clear out the struct for use
ZeroMemory(&scd, sizeof(DXGI_SWAP_CHAIN_DESC));
// fill the swap chain description struct
scd.BufferCount = 1; // one back buffer
scd.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // use 32-bit color
scd.BufferDesc.Width = SCREEN_WIDTH; // set the back buffer width
scd.BufferDesc.Height = SCREEN_HEIGHT; // set the back buffer height
scd.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // how swap chain is to be used
scd.OutputWindow = hWnd; // the window to be used
scd.SampleDesc.Count = 4; // how many multisamples
scd.Windowed = TRUE; // windowed/full-screen mode
scd.Flags = DXGI_SWAP_CHAIN_FLAG_ALLOW_MODE_SWITCH; // allow full-screen switching
// create a device, device context and swap chain using the information in the scd struct
D3D11CreateDeviceAndSwapChain(NULL,
D3D_DRIVER_TYPE_HARDWARE,
NULL,
NULL,
NULL,
NULL,
D3D11_SDK_VERSION,
&scd,
&swapchain,
&dev,
NULL,
&devcon);
// create the depth buffer texture
D3D11_TEXTURE2D_DESC texd;
ZeroMemory(&texd, sizeof(texd));
texd.Width = SCREEN_WIDTH;
texd.Height = SCREEN_HEIGHT;
texd.ArraySize = 1;
texd.MipLevels = 1;
texd.SampleDesc.Count = 4;
texd.Format = DXGI_FORMAT_D32_FLOAT;
texd.BindFlags = D3D11_BIND_DEPTH_STENCIL;
ID3D11Texture2D *pDepthBuffer;
dev->CreateTexture2D(&texd, NULL, &pDepthBuffer);
// create the depth buffer
D3D11_DEPTH_STENCIL_VIEW_DESC dsvd;
ZeroMemory(&dsvd, sizeof(dsvd));
dsvd.Format = DXGI_FORMAT_D32_FLOAT;
dsvd.ViewDimension = D3D11_DSV_DIMENSION_TEXTURE2DMS;
dev->CreateDepthStencilView(pDepthBuffer, &dsvd, &zbuffer);
pDepthBuffer->Release();
// get the address of the back buffer
ID3D11Texture2D *pBackBuffer;
swapchain->GetBuffer(0, __uuidof(ID3D11Texture2D), (LPVOID*)&pBackBuffer);
// use the back buffer address to create the render target
dev->CreateRenderTargetView(pBackBuffer, NULL, &backbuffer);
pBackBuffer->Release();
// set the render target as the back buffer
devcon->OMSetRenderTargets(1, &backbuffer, zbuffer);
// Set the viewport
D3D11_VIEWPORT viewport;
ZeroMemory(&viewport, sizeof(D3D11_VIEWPORT));
viewport.TopLeftX = 0; // set the left to 0
viewport.TopLeftY = 0; // set the top to 0
viewport.Width = SCREEN_WIDTH; // set the width to the window's width
viewport.Height = SCREEN_HEIGHT; // set the height to the window's height
viewport.MinDepth = 0; // the closest an object can be on the depth buffer is 0.0
viewport.MaxDepth = 1; // the farthest an object can be on the depth buffer is 1.0
devcon->RSSetViewports(1, &viewport);
InitPipeline();
InitGraphics();
}
// this is the function used to render a single frame
void RenderFrame(void)
{
D3DXMATRIX matRotate, matView, matProjection;
D3DXMATRIX matFinal;
static float Time = 0.0f; Time += 0.0003f;
// create a world matrices
D3DXMatrixRotationY(&matRotate, Time);
// create a view matrix
D3DXMatrixLookAtLH(&matView,
&D3DXVECTOR3(0.0f, 7.0f, 5.0f), // the camera position
&D3DXVECTOR3(0.0f, 0.0f, 0.0f), // the look-at position
&D3DXVECTOR3(0.0f, 1.0f, 0.0f)); // the up direction
// create a projection matrix
D3DXMatrixPerspectiveFovLH(&matProjection,
(FLOAT)D3DXToRadian(45), // field of view
(FLOAT)SCREEN_WIDTH / (FLOAT)SCREEN_HEIGHT, // aspect ratio
1.0f, // near view-plane
1000.0f); // far view-plane
// load the matrices into the constant buffer
matFinal = matRotate * matView * matProjection;
// clear the back buffer to a deep blue
devcon->ClearRenderTargetView(backbuffer, D3DXCOLOR(0.0f, 0.0f, 0.0f, 1.0f));
// clear the depth buffer
devcon->ClearDepthStencilView(zbuffer, D3D11_CLEAR_DEPTH, 1.0f, 0);
// select which vertex buffer to display
UINT stride = sizeof(VertexType);
UINT offset = 0;
devcon->IASetVertexBuffers(0, 1, &pVBuffer, &stride, &offset);
devcon->IASetIndexBuffer(pIBuffer, DXGI_FORMAT_R32_UINT, 0);
// select which primtive type we are using
devcon->IASetPrimitiveTopology(D3D10_PRIMITIVE_TOPOLOGY_LINELIST);
//Draw
devcon->DrawIndexed(m_indexCount, 0, 0);
// switch the back buffer and the front buffer
swapchain->Present(0, 0);
}
// this is the function that cleans up Direct3D and COM
void CleanD3D(void)
{
swapchain->SetFullscreenState(FALSE, NULL); // switch to windowed mode
// close and release all existing COM objects
zbuffer->Release();
pLayout->Release();
pVS->Release();
pPS->Release();
pVBuffer->Release();
pIBuffer->Release();
swapchain->Release();
backbuffer->Release();
dev->Release();
devcon->Release();
}
// this is the function that creates the shape to render
void InitGraphics()
{
VertexType* vertices;
unsigned long* indices;
int i, j, index;
float positionX, positionZ;
// Calculate the number of vertices in the terrain mesh.
m_vertexCount = (m_terrainWidth - 1) * (m_terrainHeight - 1) * 8;
// Set the index count to the same as the vertex count.
m_indexCount = m_vertexCount;
vertices = new VertexType[m_vertexCount];
indices = new unsigned long[m_indexCount];
// Initialize the index to the vertex buffer.
index = 0;
// Load the vertex and index array with the terrain data.
for(j=0; j<(m_terrainHeight-1); j++)
{
for(i=0; i<(m_terrainWidth-1); i++)
{
// LINE 1
// Upper left.
positionX = (float)i;
positionZ = (float)(j+1);
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// Upper right.
positionX = (float)(i+1);
positionZ = (float)(j+1);
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// LINE 2
// Upper right.
positionX = (float)(i+1);
positionZ = (float)(j+1);
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// Bottom right.
positionX = (float)(i+1);
positionZ = (float)j;
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// LINE 3
// Bottom right.
positionX = (float)(i+1);
positionZ = (float)j;
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// Bottom left.
positionX = (float)i;
positionZ = (float)j;
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// LINE 4
// Bottom left.
positionX = (float)i;
positionZ = (float)j;
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
// Upper left.
positionX = (float)i;
positionZ = (float)(j+1);
vertices[index].position = D3DXVECTOR3(positionX, 0.0f, positionZ);
vertices[index].color = D3DXVECTOR4(1.0f, 1.0f, 1.0f, 1.0f);
indices[index] = index;
index++;
}
}
// create the vertex buffer
D3D11_BUFFER_DESC bd;
ZeroMemory(&bd, sizeof(bd));
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(VertexType) * m_vertexCount;
bd.BindFlags = D3D11_BIND_VERTEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
dev->CreateBuffer(&bd, NULL, &pVBuffer);
// copy the vertices into the buffer
D3D11_MAPPED_SUBRESOURCE ms;
devcon->Map(pVBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, vertices, sizeof(vertices)); // copy the data
devcon->Unmap(pVBuffer, NULL);
// create the index buffer
bd.Usage = D3D11_USAGE_DYNAMIC;
bd.ByteWidth = sizeof(unsigned long) * m_indexCount;
bd.BindFlags = D3D11_BIND_INDEX_BUFFER;
bd.CPUAccessFlags = D3D11_CPU_ACCESS_WRITE;
bd.MiscFlags = 0;
dev->CreateBuffer(&bd, NULL, &pIBuffer);
devcon->Map(pIBuffer, NULL, D3D11_MAP_WRITE_DISCARD, NULL, &ms); // map the buffer
memcpy(ms.pData, indices, sizeof(indices)); // copy the data
devcon->Unmap(pIBuffer, NULL);
/*
D3DX11CreateShaderResourceViewFromFile(dev, // the Direct3D device
L"Wood.png", // load Wood.png in the local folder
NULL, // no additional information
NULL, // no multithreading
&pTexture, // address of the shader-resource-view
NULL); // no multithreading
*/
delete [] vertices;
vertices = 0;
delete [] indices;
indices = 0;
}
// this function loads and prepares the shaders
void InitPipeline()
{
// compile the shaders
ID3D10Blob *VS, *PS;
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "VShader", "vs_5_0", 0, 0, 0, &VS, 0, 0);
D3DX11CompileFromFile(L"shaders.hlsl", 0, 0, "PShader", "ps_5_0", 0, 0, 0, &PS, 0, 0);
// create the shader objects
dev->CreateVertexShader(VS->GetBufferPointer(), VS->GetBufferSize(), NULL, &pVS);
dev->CreatePixelShader(PS->GetBufferPointer(), PS->GetBufferSize(), NULL, &pPS);
// set the shader objects
devcon->VSSetShader(pVS, 0, 0);
devcon->PSSetShader(pPS, 0, 0);
// create the input element object
D3D11_INPUT_ELEMENT_DESC ied[] =
{
{"POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0},
{"COLOR", 0, DXGI_FORMAT_R32G32B32A32_FLOAT, 0, D3D10_APPEND_ALIGNED_ELEMENT, D3D11_INPUT_PER_VERTEX_DATA, 0},
};
// use the input element descriptions to create the input layout
dev->CreateInputLayout(ied, 3, VS->GetBufferPointer(), VS->GetBufferSize(), &pLayout);
devcon->IASetInputLayout(pLayout);
}