#ifndef UNICODE
#define UNICODE
#endif
#include <windows.h>
#include <tchar.h>
#include <string>
// DX Header
#include <d3d11.h> // DirectX 11 헤더
#include <d3dcompiler.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 = 640;
int height = 480;
HWND hwnd = nullptr;
//DX 변수
//DX 장치
ID3D11Device* device = nullptr;
ID3D11DeviceContext* context = nullptr;
IDXGISwapChain* swapChain = nullptr;
void InitializeDevice();
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; // ::전역 변수를 쓴다는 의미
//const wchar_t CLASS_NAME[] = L"Sample Window Class";
//const wchar_t CLASS_NAME[] = TEXT("Sample Window Class"); // #include <tchar.h>
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, width, height };
RECT rect = { 0, 0, static_cast<long>(width), static_cast<long>(height) };
AdjustWindowRect(&rect, WS_OVERLAPPEDWINDOW, FALSE);
int windowWidth = rect.right - rect.left;
int windowHeight = rect.bottom - rect.top;
// 화면 중심에서 창을 그려라
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
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);
UpdateWindow(hwnd);
//창 생성
//DX 초기화
// Run the message loop.
// WM_QUIT가 아니라면 계속 수행
MSG msg = { };
while (msg.message != WM_QUIT) //GetMessage(수동적) 말고 Peek(능동적)이 있다
{
// 윈도우가 메시지 전달하면 실행
//if (GetMessage(&msg, NULL, 0, 0) > 0) // NULL은 부모 창 포인터 get은 계속 대기해야 하므로 필요한 메시지만 받는 peek을 사용한다
if(PeekMessage(&msg,nullptr,0u,0u,PM_REMOVE))
{
// 윈도우(OS)가 전달한 메시지 해석 및 전달 (WindowsProc 함수 호출)
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
// 일반적인 수행과정
// GameLoop
// Rendering
// 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
D3D_FEATURE_LEVEL levels[] =
{
D3D_FEATURE_LEVEL_11_1,
D3D_FEATURE_LEVEL_11_0,
};
//스왑체인 생성을 위한 구조체 설정
DXGI_SWAP_CHAIN_DESC swapChainDesc = {};
swapChainDesc.BufferCount = 1; //백버퍼 개수 설정 , 최소 1개 이상
swapChainDesc.BufferDesc.Width = width; // 프레임 가로크기
swapChainDesc.BufferDesc.Height = height; // 프레임 세로크기
swapChainDesc.BufferDesc.Format= DXGI_FORMAT_R8G8B8A8_UNORM; //이미지 채널별 포맷
swapChainDesc.Windowed = true; // 프레임(이미지)의 용도 (렌더링)
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;
D3D_FEATURE_LEVEL finalFeature;
//장치 초기화
//D3D11CreateDevice // 모니터 해상도 스펙 정보까지 가져옴
auto result = D3D11CreateDeviceAndSwapChain( // HRESULT 성공 여부 값을 반환 받는다
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 Creat Device.",L"Error",MB_OK);
exit(-1);
}
}
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
switch (uMsg)
{
case WM_DESTROY: // 창 삭제(종료)가 되었을 때 받는 메시지.
{
PostQuitMessage(0);
return 0; // 메인 함수에서는 워낙 일반적이라 자동으로 처리해 주는 거임.
}
case WM_KEYDOWN:
{
if (wParam == VK_ESCAPE)
{
if (MessageBox(nullptr, TEXT("ESC키를 눌렀군요. 끝낼까요?"), TEXT("테스트창"), MB_YESNO) == IDYES)
{
DestroyWindow(hwnd);
}
}
return 0;
}
case WM_MOUSEWHEEL:
{
if (MessageBox(nullptr, TEXT("마우스 휠 돌렸죠? 끝낼까요?"), TEXT("테스트창"), MB_YESNO) == IDYES)
{
DestroyWindow(hwnd);
}
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;
}
}
return DefWindowProc(hwnd, uMsg, wParam, lParam);
}
0 comments:
댓글 쓰기