홍정모 강사님의 그래픽스 강의를 듣다가 갑자기 프로젝트를 하나 만들고 싶었다.
해당 강의는 아무래도 다이렉트 X 자체보다는 그래픽스에 더 집중하는 부분이 있었다. 물론 이 부분은 교육에 정말 도움이 되고 긍정적으로 생각하고 있다. 어느 그래픽스 라이브러리를 사용하더라도, 쉽게 적응할 수 있도록 이론적인 부분에 더 초점을 두신 것 같다.
그렇게, 큰 틀은 대부분 직접 구현하신 상태로 그래픽스에 관한 부분만 비워서 직접 작성해보며 테스트 할 수 있게 예제 프로젝트를 제공해주시는데, 갑자기 왠지 모를 욕심이 생겨서 나만의 프로젝트를 만들어서 초기화하며 교육 내용을 직접 적용해보고 싶다는 생각이 들었다.
그런 이유로, DirectX를 이용한 그래픽스 프로젝트를 시작하기로 했다...
프로젝트라고 하지만 거창한 무언가를 할 계획은 아니고, 강의를 들으며 배운 내용을 나의 프로젝트에 적용해보며 구현해볼 생각이다.
먼저 Windows API기반으로 프로젝트를 생성한 뒤, DirectXTK를 프로젝트에 추가해주었다.
(홍정모 강사님의 강의에서 SimpleMath를 사용하셔서, 추가하게 되었다.)
그리고, Main함수에 있는 윈도우 초기화 함수들을 정리해주었다.
#include "framework.h"
#include "GraphicsProject.h"
#include "EngineBase.h"
#include <iostream>
#include <d3d11.h>
#pragma comment (lib, "d3d11.lib")
#pragma comment(linker, "/entry:wWinMainCRTStartup /subsystem:console")
int APIENTRY wWinMain(_In_ HINSTANCE hInstance,
_In_opt_ HINSTANCE hPrevInstance,
_In_ LPWSTR lpCmdLine,
_In_ int nCmdShow)
{
EngineBase NewEngineBase;
if (!NewEngineBase.Init(hInstance))
{
std::cout << "Init Failed!" << std::endl;
return -1;
}
NewEngineBase.Loop();
WPARAM EndParam = NewEngineBase.End();
return (int)EndParam;
}
먼저, EngineBase라는 클래스를 하나 정의하였고, 해당 함수에 Init, Loop, End 함수를 만들었다.
Init에선 여러 초기화를 실행하도록 정리하였고, Loop에선 메세지 루프가 실행되도록 하였다.
End는 프로그램이 종료될 때 처리해야 할 것들을 구현하기 위해서 정의하였다.
EngineBase에는 기존에 작성되어 있던 윈도우 초기화 함수들을 정리해서 넣어주었다.
#pragma once
#include "Windows.h"
class EngineBase
{
public:
EngineBase();
~EngineBase();
EngineBase(const EngineBase& _Other) = delete;
EngineBase(EngineBase&& _Other) noexcept = delete;
EngineBase& operator=(const EngineBase& _Other) = delete;
EngineBase& operator=(EngineBase&& _Other) noexcept = delete;
ATOM MyRegisterClass(HINSTANCE hInstance);
static LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam);
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow);
BOOL Init(HINSTANCE _hInstance);
void Loop();
WPARAM End();
protected:
private:
HINSTANCE hInstance;
WNDCLASSEXW wcex;
MSG msg;
};
먼저, HINSTANCE나 MSG같은 중요한 변수들은 멤버변수에 저장해주었다.
멤버함수들의 구현부를 보면 아래와 같다.
BOOL EngineBase::Init(HINSTANCE _hInstance)
{
hInstance = _hInstance;
MyRegisterClass(hInstance);
if (!InitInstance(hInstance, SW_SHOW))
{
return FALSE;
}
return TRUE;
}
Init함수에선 MyRegisterClass함수를 먼저 실행해주었다.
해당 함수는 윈도우를 생성하기 전에, 어떻게 생성할지에 관한 여러 정보를 세팅하는 함수이다.
InitInstance함수는 윈도우를 생성하는 함수이다. 만약 윈도우 생성이 실패했다면, init함수는 FALSE를 반환하도록 하였다.
main함수에서 Init이 FALSE를 반환할 경우, 콘솔창에 메세지를 출력하도록 함으로써 디버깅을 좀 더 수월하게 하였다.
ATOM EngineBase::MyRegisterClass(HINSTANCE _hInstance)
{
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = &EngineBase::WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = _hInstance;
wcex.hIcon = nullptr; //LoadIcon(_hInstance, MAKEINTRESOURCE(IDI_GRAPHICSPROJECT));
wcex.hCursor = nullptr; //LoadCursor(nullptr, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcex.lpszMenuName = nullptr; //MAKEINTRESOURCEW(IDC_GRAPHICSPROJECT);
wcex.lpszClassName = L"WindowDefault";
wcex.hIconSm = nullptr; //LoadIcon(wcex._hInstance, MAKEINTRESOURCE(IDI_SMALL));
return RegisterClassExW(&wcex);
}
myRegisterClass함수 내부이다.
윈도우의 모양이나 색상, 이름 등을 정의할 수 있는데, 지금 당장 필요하다고 생각하는 것들이 딱히 없어서 대부분 nullptr로 설정해주었다.
wcex.lpfnwndproc를 보면, 메세지 함수를 콜백 형식으로 저장할 수 있는데 본인은 멤버함수를 사용하기 위해, WndProc함수를 static으로 선언해주었다.
BOOL EngineBase::InitInstance(HINSTANCE _hInstance, int nCmdShow)
{
hInstance = _hInstance;
HWND hWnd = CreateWindowW(L"WindowDefault", L"GraphicsProject", WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
if (!hWnd)
{
return FALSE;
}
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
return TRUE;
}
InitInstance함수 내부도 심플하다. 윈도우를 생성해주었고, 실패시 FALSE를 반환하도록 하였다.
다음은 Loop함수를 보자.
void EngineBase::Loop()
{
while(WM_QUIT != msg.message)
{
if ((PeekMessage(&msg, nullptr, 0, 0, PM_REMOVE)))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
기본적인 메세지 루프만 담고있다.
While문이나 if문의 조건문을 조금 수정해주었다.
WM_QUIT 메세지가 전달되기 전까지 반복문을 계속 돌도록 하였으며, 메세지를 전달받으면 해당 메세지를 처리하도록 해주었다.
다음은 End이다.
WPARAM EngineBase::End()
{
return msg.wParam;
}
아직은 뭐 추가한 기능이 하나도 없어서, End에서 처리할 것이 따로 없다.
기존에 메인함수에서 msg.wparam을 return하도록 되어있길래, 동일하게 이 것을 리턴해주며 main함수에서는 반환된 값을 저장하여 return하도록 해주었다.
WindowAPI의 기초적인 함수만 정리하는데도 생각보다 시간이 좀 소요되었다.
쓸모없는 기능은 쳐내고, 필요한 기능은 남겨두면서 정리를 하려고 했는데, 뭐가 쓸모없는 기능인지 찾는 것도 쉽지 않았다.
일단, 간단한 틀은 완성되었고 이 틀에 계속 살을 붙혀서 원하고자 하는 것을 렌더링 할 수 있을 때까지 가보도록 하겠다.
'프로젝트 > Direct X 그래픽스' 카테고리의 다른 글
프로젝트 : DirectX를 활용한 그래픽스 (6 - 버텍스 쉐이더, 인풋 레이아웃, 픽셀 쉐이더) (1) | 2024.05.01 |
---|---|
프로젝트 : DirectX를 활용한 그래픽스 (5 - 상수 버퍼) (0) | 2024.05.01 |
프로젝트 : DirectX를 활용한 그래픽스(4 - 릭 제거) (0) | 2024.05.01 |
프로젝트 : DirectX를 활용한 그래픽스 (3 - 버텍스 버퍼, 인덱스 버퍼) (0) | 2024.05.01 |
프로젝트 : DirectX를 활용한 그래픽스 (2 - 다이렉트X 초기화) (1) | 2024.04.30 |