◤ 2022๋…„ 7์›” 21์ผ ๋ชฉ์š”์ผ

● ์‚ผ๊ฐํ˜• ๊ทธ๋ฆฌ๊ธฐ

※ ์ง€๊ทนํžˆ ๊ฐœ์ธ์ ์ธ ์ผ์ƒ ๋ฉ”๋ชจ์™€ ๊ธฐ๋ก์„ ์œ„ํ•œ ๊ณณ์ž…๋‹ˆ๋‹ค.






#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:

๋Œ“๊ธ€ ์“ฐ๊ธฐ