#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <string>
//#include <time.h>
//#include <cmath>
// DX Header
#include <d3d11.h> // DirectX11 ํค๋
#include <d3dcompiler.h> // ์์ด๋ ์ปดํ์ผ๋ฌ ๊ธฐ๋ฅ ์ ๊ณต
#include <comdef.h>
// lib ๋งํน
#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "d3dcompiler.lib")
// ๋ณ์
// ์ ์ญ ๋ณ์ <-> ํจ์ ๋ด์ ์๋ ๋ณ์๋ ์ง์ญ ๋ณ์
std::wstring className = TEXT("Sample Window Class");
std::wstring title = TEXT("STL Render Engine");
HINSTANCE hInstance = nullptr;
int width = 1600;
int height = 900;
HWND hwnd = nullptr;
// DX ๋ณ์
// DX ์ฅ์น
ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr;
IDXGISwapChain* swapChain = nullptr;
ID3D11RenderTargetView* renderTargetView = nullptr;
// ์ ์ ๋ฒํผ ๊ด๋ จ ๋ณ์
unsigned int vertexByteWidth = 0u;
unsigned int vertexCount = 0u;
ID3D11Buffer* vertexBuffer = nullptr;
ID3D11VertexShader* vertexShader = nullptr;
ID3D11PixelShader* pixelShader = nullptr;
ID3D11InputLayout* inputlayout = nullptr;
// DX ์ฅ์น ์ด๊ธฐํ
void InitializeDevice();
// ์ฅ๋ฉด ์ด๊ธฐํ
void InitializeScene();
void Draw();
// ์ค๋ฅ ๋ฉ์์ง ์ป์ด์ค๋ ํจ์
std::wstring GetErrorMessage(HRESULT hr)
{
_com_error error(hr);
return error.ErrorMessage();
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
int WINAPI wWinMain(
_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nShowCmd)
{
// Register the window class.
::hInstance = hInstance; // ::์ ์ญ ๋ณ์๋ฅผ ๊ฐ๋ฆฌํด
WNDCLASS wc = { };
//memset(&wc, 0, sizeof(wc));
// Invoke
wc.lpfnWndProc = WindowProc; // ์ฝ๋ฐฑ(Callback) / ์์(Delegate)
wc.hInstance = hInstance;
wc.lpszClassName = className.c_str();
// ์ฐฝ ํด๋์ค ์ด๋ฆ ๋ฑ๋ก
RegisterClass(&wc);
// Create the window.
// ์ฐฝ ํฌ๊ธฐ ์กฐ์ .
// RECT๋ ์ง์ฌ๊ฐํ ๊ตฌ์กฐ์ฒด, (left, top, right, bottom)
RECT rect = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
// ์กฐ์ ๋ ์ง์ฌ๊ฐํ ํฌ๊ธฐ๋ก ์ฐฝ ๊ฐ๋ก/์ธ๋ก ํฌ๊ธฐ ๊ตฌํ๊ธฐ(Window๋ ์ข์ธก ์๋จ์ด ๊ธฐ์ค์ )
int windowWidth = rect.right - rect.left;
int windowHeight = rect.bottom - rect.top;
// ํ๋ฉด ์ค์ฌ์์ ์ฐฝ์ ๊ทธ๋ฆฌ๊ธฐ ์ํ ์์ฑ์ขํ ๊ตฌํ๊ธฐ
// GetSystemMetrics(SM_CXSCREEN) -> ๋ชจ๋ํฐ ๊ฐ๋ก ํฌ๊ธฐ ๊ตฌํ๋ ํจ์
// GetSystemMetrics(SM_CYSCREEN) -> ๋ชจ๋ํฐ ์ธ๋ก ํฌ๊ธฐ ๊ตฌํ๋ ํจ์
int xPosition = (GetSystemMetrics(SM_CXSCREEN) - windowWidth) / 2;
int yPosition = (GetSystemMetrics(SM_CYSCREEN) - windowHeight) / 2;
hwnd = CreateWindowEx(
0, // Optional window styles.
className.c_str(), // Window class
title.c_str(), // Window text
WS_OVERLAPPEDWINDOW, // Window style
// Size and position (์คํ ์ ์์น์ ํฌ๊ธฐ)
//CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,
xPosition, yPosition, windowWidth, windowHeight,
nullptr, // Parent window
nullptr, // Menu
hInstance, // Instance handle
nullptr // Additional application data
);
if (hwnd == nullptr)
{
return 0;
}
ShowWindow(hwnd, SW_SHOW); // window ์ฐฝ ์ผ๋ฐ์ ์ธ ์ํ๋ก ๋ณด์ด๊ธฐ
UpdateWindow(hwnd); // ์ฐฝ ์
๋ฐ์ดํธ
// ------ ์ฐฝ ์์ฑ ------ //
// DX ์ด๊ธฐํ
InitializeDevice();
// ์ฅ๋ฉด ์ด๊ธฐํ
InitializeScene();
// Run the message loop.
MSG msg = { }; // MSG ๊ตฌ์กฐ์ฒด์ ๋ง์ฐ์ค ํด๋ฆญ ๋ฐ์ ๋ฑ์ด ๋ค์ด์์
// WM_QUIT ๋ฉ์์ง๊ฐ ์๋๋ฉด ๊ณ์ ๋ฃจํ ์คํ
while (msg.message != WM_QUIT)
{
// ์๋์ฐ๊ฐ ๋ฉ์์ง ์ ๋ฌํ๋ฉด ์คํ
//if (GetMessage(&msg, NULL, 0, 0) > 0)
if (PeekMessage(&msg, nullptr, 0u, 0u, PM_REMOVE))
{
// ์๋์ฐ(OS)๊ฐ ์ ๋ฌํ ๋ฉ์์ง ํด์ ๋ฐ ์ ๋ฌ(WindowProc ํจ์ ํธ์ถ)
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
Draw();
// GameLoop
// Rendering (DX ์์
์ ์ฌ๊ธฐ์ ์คํ)
// ProcessInput
// Update
// Render
// PostRender
}
}
// ์ฐฝ ๋ฑ๋ก ํด์
UnregisterClass(className.c_str(), hInstance);
return 0;
}
void InitializeDevice()
{
// ์ฅ์น ์์ฑํ ๋ ์ ๋ฌํ ์ต์
๊ฐ
unsigned int createFlag = 0;
#if _DEBUG
// Debug ๋ชจ๋์ธ ๊ฒฝ์ฐ,
// ์ฅ์น ์์ฑ ๊ณผ์ ์์ ์ค๋ฅ๊ฐ ๋ฐฉ์ํ์ ๋ ๋๋ฒ๊น
์ ๋ณด๋ฅผ ๋ ๋ง์ด ์ ๋ฌํด๋ฌ๋ผ๋ ์ต์
์ถ๊ฐ
createFlag |= D3D11_CREATE_DEVICE_DEBUG;
#endif
// DX11 ๋ฒ์ ์ง์
// ์์ ๋ฒ์ ์ ์์ ๋ฃ์ผ๋ฉด ๋จผ์ ์๋ํด๋ณด๊ณ , ์ง์ํ์ง ์์ผ๋ฉด ๋ค์ ๋ฒ์ ์ผ๋ก ๋์ด๊ฐ
D3D_FEATURE_LEVEL levels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0
};
// ์ค์์ฒด์ธ ์์ฑ์ ์ํ ๊ตฌ์กฐ์ฒด ์ค์
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 1; // ๋ฐฑ๋ฒํผ ๊ฐ์ ์ค์
swapChainDesc.BufferDesc.Width = width; // ํ๋ ์(์ด๋ฏธ์ง) ๊ฐ๋ก ํฌ๊ธฐ
swapChainDesc.BufferDesc.Height = height; // ํ๋ ์(์ด๋ฏธ์ง) ์ธ๋ก ํฌ๊ธฐ
swapChainDesc.BufferDesc.Format = DXGI_FORMAT_R8G8B8A8_UNORM; // ์ด๋ฏธ์ง ์ฑ๋๋ณ ํฌ๋ฉง
swapChainDesc.Windowed = true; // ์ฐฝ(Window) ๋ชจ๋ ์ฌ๋ถ ์ค์
swapChainDesc.BufferUsage = DXGI_USAGE_RENDER_TARGET_OUTPUT; // ํ๋ ์(์ด๋ฏธ์ง)์ ์ฉ๋ (๋ ๋๋ง)
swapChainDesc.SwapEffect = DXGI_SWAP_EFFECT_DISCARD; // Front <-> Back ๋ฒํผ ๋ณ๊ฒฝํ ๋ ํจ๊ณผ ๋ฃ์์ง ์ค์
swapChainDesc.SampleDesc.Count = 1; // ๋ฉํฐ ์ํ๋ง ํ ์ง ์ฌ๋ถ ์ค์ -> ์ํจ
swapChainDesc.SampleDesc.Quality = 0; // ๋ฉํฐ ์ํ๋ง ํ์ง ์ค์ -> ๊ธฐ๋ณธ ๊ฐ (Count - 1)
swapChainDesc.OutputWindow = hwnd; // DX๊ฐ ๊ทธ๋ฆด ์ฐฝ ํธ๋ค
D3D_FEATURE_LEVEL finalFeature;
// ์ฅ์น ์ด๊ธฐํ
auto result = D3D11CreateDeviceAndSwapChain(
nullptr,
D3D_DRIVER_TYPE_HARDWARE,
nullptr,
createFlag,
levels,
//ARRAYSIZE(levels),
_countof(levels),
D3D11_SDK_VERSION,
&swapChainDesc,
&swapChain,
&device,
&finalFeature,
&context
);
// ์คํจ ์ฌ๋ถ ํ์ธ
if (FAILED(result))
{
//MessageBox(nullptr, L"Failed to create device.", L"Error", MB_OK);
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ๋๋(Render, ๊ทธ๋ฆฐ๋ค, Draw) ํ๊ฒ (๋ฐฑ๋ฒํผ) -> ์ฐ๋ฆฌ๊ฐ ์ด๋ฏธ์ง๋ฅผ ๊ทธ๋ฆด ๋ฒํผ(๋ฉ๋ชจ๋ฆฌ)
ID3D11Texture2D* backbuffer = nullptr;
// ๊ทธ๋ํฝ์นด๋๊ฐ ๊ฐ์ง๊ณ ์๋ ๋ฐฑ๋ฒํผ ์ ๋ณด๋ฅผ ์ป์ด์จ๋ค.
result = swapChain->GetBuffer(
0,
__uuidof(ID3D11Texture2D),
reinterpret_cast<void**>(&backbuffer)
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ๋ ๋ ํ๊ฒ ๋ทฐ(RenderTargetView) ์์ฑ
renderTargetView = nullptr;
result = device->CreateRenderTargetView(
backbuffer,
nullptr,
&renderTargetView
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ๋ฐฑ๋ฒํผ ํด์
// COM
backbuffer->Release();
// ๋ ๋ ํ์ผ ๋ทฐ ์ค์
context->OMSetRenderTargets(1, &renderTargetView, nullptr);
// ํ๋ฉด(Viewport) ์ค์
D3D11_VIEWPORT viewport = {};
viewport.TopLeftX = 0.0f;
viewport.TopLeftY = 0.0f;
viewport.Width = static_cast<float>(width); // width๊ฐ int ์ด๋ฏ๋ก float ๋ก ํ๋ณํ
viewport.Height = static_cast<float>(height); // height๊ฐ int ์ด๋ฏ๋ก float ๋ก ํ๋ณํ
viewport.MinDepth = 0.0f;
viewport.MaxDepth = 1.0f;
// ๋ทฐํฌํธ ์ค์
context->RSSetViewports(1, &viewport);
}
void InitializeScene()
{
// 1. ์ ์ (Virtex) ๋ฐ์ดํฐ ์์ฑ
struct Vertex
{
float x;
float y;
float z;
};
// ์ ๋ฐ์ดํฐ
// NDC-(Viewport)
Vertex vertices[] =
{
{ 0.0f, 0.5f, 0.5f }, /*{x, y, z?}*/
{ 0.5f, -0.5f, 0.5f },
{ -0.5f, -0.5f, 0.5f }
};
//
vertexByteWidth = sizeof(Vertex);
vertexCount = _countof(vertices);
// ์ ์ ๋ฒํผ๋ฅผ ์ค๋ช
ํ๋ ๊ตฌ์กฐ์ฒด
D3D11_BUFFER_DESC vertexBufferDesc = {};
vertexBufferDesc.ByteWidth = sizeof(Vertex) * _countof(vertices);
vertexBufferDesc.BindFlags = D3D11_BIND_VERTEX_BUFFER;
// ์ ์ ๋ฐฐ์ด(๋ฐ์ดํฐ)์ ๋ด์ ๊ตฌ์กฐ์ฒด
D3D11_SUBRESOURCE_DATA vertexData = {};
vertexData.pSysMem = vertices;
// ์ ์ ๋ฒํผ
//ID3D11Buffer* vertexBuffer = nullptr;
// ์ ์ ๋ฒํผ ์์ฑ
auto result = device->CreateBuffer(
&vertexBufferDesc,
&vertexData,
&vertexBuffer
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ์
ฐ์ด๋(Shader-๊ทธ๋ํฝ ์นด๋์์ ์ฌ์ฉํ๋ ํ๋ก๊ทธ๋จ) ์์ฑ (์ ์ ์
ฐ์ด๋ / ํฝ์
์
ฐ์ด๋)
// ์ ์ ์
ฐ์ด๋ ์์ฑ
// 1. ์ปดํ์ผ
// 2. ์ปดํ์ผ๋ ์ด์ง ํ์ผ ๋ก๋
// 3. ์
ฐ์ด๋ ์์ฑ
ID3DBlob* vertexShaderBuffer = nullptr;
result = D3DCompileFromFile(
L"VertexShader.hlsl",
nullptr,
nullptr,
"main",
"vs_5_0",
0u,
0u,
&vertexShaderBuffer,
nullptr
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ์ ์ ์
ฐ์ด๋ ์์ฑ
//ID3D11VertexShader* vertexShader = nullptr;
result = device->CreateVertexShader(
vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(),
nullptr,
&vertexShader
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ํฝ์
์
ฐ์ด๋
ID3DBlob* pixelShaderBuffer = nullptr;
result = D3DCompileFromFile(
L"pixelShader.hlsl",
nullptr,
nullptr,
"main",
"ps_5_0",
0u,
0u,
&pixelShaderBuffer,
nullptr
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ํฝ์
์
ฐ์ด๋ ์์ฑ
//ID3D11VertexShader* vertexShader = nullptr;
result = device->CreatePixelShader(
pixelShaderBuffer->GetBufferPointer(),
pixelShaderBuffer->GetBufferSize(),
nullptr,
&pixelShader
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
// ์
๋ ฅ ๋ ์ด์์ ์์ฑ (์
๋ ฅ=์ ์ , ์ ์ ์ ์๊น์)
//ID3D11InputLayout* inputlayout = nullptr;
//LPCSTR SemanticName;
//UINT SemanticIndex;
//DXGI_FORMAT Format;
//UINT InputSlot;
//UINT AlignedByteOffset;
//D3D11_INPUT_CLASSIFICATION InputSlotClass;
//UINT InstanceDataStepRate;
D3D11_INPUT_ELEMENT_DESC inputElementDesc[] =
{
{ "POSITION", 0, DXGI_FORMAT_R32G32B32_FLOAT, 0, 0, D3D11_INPUT_PER_VERTEX_DATA, 0 }
};
result = device->CreateInputLayout(
inputElementDesc,
_countof(inputElementDesc),
vertexShaderBuffer->GetBufferPointer(),
vertexShaderBuffer->GetBufferSize(),
&inputlayout
);
// ์ค๋ฅ ํ์ธ
if (FAILED(result))
{
MessageBox(nullptr, GetErrorMessage(result).c_str(), L"Error", MB_OK);
exit(-1);
}
}
void Draw()
{
// ๋ฐฐ๊ฒฝ ์ง์ฐ๊ธฐ
float color[] = { 0.2f, 0.4f, 0.6f, 1.0f }; // red, green, blue ์์
context->ClearRenderTargetView(renderTargetView, color);
// ๊ทธ๋ฆฌ๊ธฐ
// ๋ฐ์ดํฐ/์
ฐ์ด๋ ์ค์
// ์์ ์๊ด ์์
// ์ ์ ์ฐ๊ฒฐํด์ ๋ฉด์ ๋ง๋ค ๋ ๊ธฐ์ค์ด๋๋ ๋ฐฉ์์ ์ง์ ํจ
context->IASetPrimitiveTopology(D3D11_PRIMITIVE_TOPOLOGY_TRIANGLELIST);
static unsigned int stride = vertexByteWidth; // static์ ์ฌ์ฉํ๋ฉด ๋๋ก์ฐ ์ฝ ํ ๋ ๋ณ์๋ฅผ ํ ๋ฒ๋ง ์์ฑํด์ ๊ณต์ ํ๋ค.
static unsigned int offset = 0u;
// ์ ์ ๋ฒํผ ์ค์
context->IASetVertexBuffers(0, 1, &vertexBuffer, &stride, &offset);
context->IASetInputLayout(inputlayout);
// ์
ฐ์ด๋ ์ค์
context->VSSetShader(vertexShader, nullptr, 0);
context->PSSetShader(pixelShader, nullptr, 0);
// ๋๋ก์ฐ ์ฝ
context->Draw(vertexCount, 0);
swapChain->Present(1u, 0u); // 1์ ๋ฃ์ผ๋ฉด ๋ชจ๋ํฐ์ ํ๋ ์ ๋๊ธฐํ, 0์ ๋ฃ์ผ๋ฉด ๋ชจ๋ํฐ์ ํ๋ ์ ๋๊ธฐํ๋ฅผ ํ์ง ์์.
// BeginRender -> ๋ฐฐ๊ฒฝ ์ง์ฐ๊ธฐ
// Render -> ์ ๋ฉด ๊ทธ๋ฆฌ๊ธฐ
// EndRender -> ์ค์์ฒด์ธ ๊ตํ
}
// ์ฐฝ ๊ตฌํ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY: // ์ฐฝ์ด ๋ซํ๋ ๊ฒฝ์ฐ ํ๋ก๊ทธ๋จ ์ข
๋ฃ
PostQuitMessage(0);
return 0;
case WM_PAINT: // ๊ทธ๋ฆฌ๋ ๊ธฐ๋ฅ์ ์ฌ์ฉ
{
PAINTSTRUCT ps;
HDC hdc = BeginPaint(hwnd, &ps);
// All painting occurs here, between BeginPaint and EndPaint.
FillRect(hdc, &ps.rcPaint, (HBRUSH)(COLOR_WINDOW + 1));
EndPaint(hwnd, &ps);
}
return 0;
case WM_KEYDOWN:
{
// ESC ํค๊ฐ ๋๋ฆฌ๋ฉด
if (wParam == VK_ESCAPE)
{
// ๋ฉ์์ง ์์ ๋์ฐ๊ธฐ
// ์/์๋์ ๋ฒํผ์ ์ ๊ณตํ๋ ๋ฉ์์ง ์์๋ฅผ ๋์ฐ๊ณ , "์"๋ฅผ ์ ํํ๋ฉด ์ฐฝ ์ญ์
if (MessageBox(nullptr, TEXT("Quit?"), TEXT("Quit Engine"), MB_YESNO/*๋์์ธ*/) == IDYES/*YES๋ฅผ ๋๋ฅด๋ฉด ์คํ*/)
{
// ์ฐฝ ํธ๋ค ์ญ์ -> ์ฐฝ ์ญ์
DestroyWindow(hwnd);
}
}
}
return 0;
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
0 comments:
๋๊ธ ์ฐ๊ธฐ