[DirectX 11] 5. Engine 구성하기

psj98·2022년 11월 5일
0
post-thumbnail

개요

이전 단계인 "4. DirectX 창 만들기" 에서는 RenderWindow에서 창을 만들고 메시지를 처리했습니다.

이번 단계에서는 Engine 클래스가 WindowContainer 클래스를 상속받아 창을 초기화하고 메시지를 처리하려고 합니다.


WindowContainer

  • RenderWindow와 관련 있는 작업 포함
  • RenderWindow 타입을 가진 render_window 변수를 선언합니다.
  • 아래 Engine 클래스에서 render_window 변수를 통해 창을 초기화하고 메시지를 전달합니다.

WindowContainer.h

#pragma once
#include "RenderWindow.h"

class WindowContainer
{
public:
	LRESULT WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam);
protected:
	RenderWindow render_window;

private:

};

WindowContainer.cpp

#include "WindowContainer.h"

LRESULT WindowContainer::WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	/* 처리되지 않은 모든 메시지의 디폴트 처리를 수행 */
	return DefWindowProc(hwnd, uMsg, wParam, lParam);
}

Engine

  • WindowContainer를 상속받습니다.
  • WindowContainer에서 선언한 render_window로 창을 초기화하고 메시지를 처리합니다.

Engine.h

#pragma once
#include "WindowContainer.h"

/* WindowContainer 클래스 상속 */
class Engine : WindowContainer
{
public:
	bool Initialize(HINSTANCE hInstance, string window_title, string window_class, int width, int height); // 창 초기화
	bool ProcessMessages(); // 메시지 처리
};

Engine.cpp

#include "Engine.h"

/* RenderWindow 초기화 */
bool Engine::Initialize(HINSTANCE hInstance, string window_title, string window_class, int width, int height)
{
	return this->render_window.Initialize(this, hInstance, window_title, window_class, width, height);
}

/* 메시지 처리 */
bool Engine::ProcessMessages()
{
	return this->render_window.ProcessMessages();
}

RenderWindow

  • 각 창을 띄우기 위해 WindowContainer를 인자에 추가합니다.
  • HandleMsgRedirect와 HandleMessageSetup을 통해 창이 생생되었는지 체크하고 WindowContainer로 메시지를 전달합니다.

변경점

  • 헤더 파일 변경
  • 함수 인자 변경 : bool RenderWindow::Initialize(WindowContainer* pWindowContainer, HINSTANCE hInstance, string window_title, string window_class, int width, int height)
  • 함수 추가 : HandleMsgRedirect와 HandleMessageSetup

RenderWindow.h

#pragma once
#include "ErrorLogger.h"

class WindowContainer; // 추가

class RenderWindow
{
public:
	/* 함수 인자 변경 */
	bool Initialize(WindowContainer* pWindowContainer, HINSTANCE hInstance, string window_title, string window_class, int width, int height);

/* 동일 부분 제외 */
};

RenderWindow.cpp

#include "WindowContainer.h" // WindowContainer에서 선언한 RenderWindow가 있기 때문

/* 초기화 -> handle의 마지막 파라미터를 pWindowContainer로 변경 */ 
bool RenderWindow::Initialize(WindowContainer* pWindowContainer, HINSTANCE hInstance, string window_title, string window_class, int width, int height)
{
	/* 동일 부분 제외 */
    
	this->handle = CreateWindowEx(
    	/* 동일 부분 제외 */
		pWindowContainer); // 창을 생성하기 위해
}

/* 동일 함수 제외 */

LRESULT CALLBACK HandleMsgRedirect(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
    // 창 종료 시
	case WM_CLOSE:
		DestroyWindow(hwnd);
		return 0;

	default:
	{
		// WindowContainer 클래스로 포인터 검색
		WindowContainer* const pWindow = reinterpret_cast<WindowContainer*>(GetWindowLongPtr(hwnd, GWLP_USERDATA));
        
		// WindowContainer로 메시지 전달
		return pWindow->WindowProc(hwnd, uMsg, wParam, lParam);
	}
	}
}

LRESULT CALLBACK HandleMessageSetup(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	switch (uMsg)
	{
	case WM_NCCREATE: // 창이 생성될 때 메시지를 전달해줌
	{
		const CREATESTRUCTW* const pCreate = reinterpret_cast<CREATESTRUCTW*>(lParam);
		WindowContainer* pWindow = reinterpret_cast<WindowContainer*>(pCreate->lpCreateParams);

		/* WindowContainer가 생성되었는지 체크 */
		if (pWindow == nullptr) 
		{
			ErrorLogger::Log("Critical Error: Pointer to window container is null during WM_NCCREATE.");
			exit(-1);
		}
		
        // GWLP_USERDATA 유저 데이터를 win32 내에 저장할 수 있는데 이 핸들값을 저장해둠
		SetWindowLongPtr(hwnd, GWLP_USERDATA, reinterpret_cast<LONG_PTR>(pWindow));
        
        // 메시지 처리를 HandleMsgRedirect에 넘김
		SetWindowLongPtr(hwnd, GWLP_WNDPROC, reinterpret_cast<LONG_PTR>(HandleMsgRedirect));

		return pWindow->WindowProc(hwnd, uMsg, wParam, lParam);
	}
	default:
		return DefWindowProc(hwnd, uMsg, wParam, lParam);
	}
}

/* 렌더링 할 윈도우 특징 설정 */
void RenderWindow::RegisterWindowClass()
{
	WNDCLASSEX wc; // 윈도우 클래스

	/* 이 창에서 메시지를 처리하기 위한 WindowProc 함수 포인터 */
	wc.lpfnWndProc = HandleMessageSetup;
	
    /* 동일 부분 제외 */
}

main

변경점

  • 헤더 파일 변경
  • WindowContainer 클래스를 상속받은 Engine 클래스의 Initialize로 초기화

main.cpp

#include "Engine.h" // 변경점

#pragma comment(lib, "d3d11.lib")
#pragma comment(lib, "DirectXTK.lib")

int APIENTRY wWinMain(_In_ HINSTANCE hInstance, // 인스턴스에 대한 핸들
	_In_opt_ HINSTANCE hPrevInstance, // 사용 X
	_In_ LPWSTR lpCmdLine, // 커맨드 라인을 유니코드 문자열로 포함
	_In_ int cCmdShow) // 기본 응용 프로그램 창이 최소화, 최대화 또는 정상적으로 표시되는지 여부를 나타내는 플래그
{
	/* 변경점 */
	Engine engine;
	engine.Initialize(hInstance, "Title", "MyWindowClass", 800, 600);

	while (engine.ProcessMessages() == true) {

	}

	return 0;
}
profile
SSAFY 9기

0개의 댓글