Link

λ‘˜λŸ¬λ³΄κΈ°

이번 μ±•ν„°μ—μ„œλŠ” 이미 μž‘μ„±λœ μŠ€μΌˆλ ˆν†€ μ½”λ“œλ₯Ό μ‚΄νŽ΄λ³΄λ©° ν•΄λ‹Ή μ½”λ“œκ°€ μ‹€μ œλ‘œ μ–΄λ–€ 역할을 ν•˜λŠ” μ§€ ν™•μΈν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

νŒŒμΌμ€ project/src/ 폴더에 μžˆμŠ΅λ‹ˆλ‹€.

  • vk_engine.h/cpp : μ΄λŠ” μ—”μ§„μ˜ 핡심 ν΄λž˜μŠ€μž…λ‹ˆλ‹€. νŠœν† λ¦¬μ–Όμ—μ„œ λ‹€λ£° λŒ€λΆ€λΆ„μ˜ μ½”λ“œκ°€ μžˆλŠ” κ³³μž…λ‹ˆλ‹€.
  • main.cpp : μ½”λ“œμ˜ μ§„μž…μ μž…λ‹ˆλ‹€. vk_engine 호좜 μ™Έμ—λŠ” 아무 μ½”λ“œλ„ μ—†μŠ΅λ‹ˆλ‹€.
  • vk_initializers.h/cpp : Vulkan ꡬ쑰체λ₯Ό μƒμ„±ν•˜λŠ” 것을 λ•λŠ” ν•¨μˆ˜κ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • vk_images.h/cpp : 이미지와 κ΄€λ ¨λœ ν•¨μˆ˜λ“€μ„ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • vk_pipelines.h/cpp : νŒŒμ΄ν”„λΌμΈμ„ μœ„ν•œ 좔상화가 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • vk_descriptors.h/cpp : λ””μŠ€ν¬λ¦½ν„° μ…‹(descriptor set) 좔상화가 ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • vk_loader.h/cpp : GLTF νŒŒμΌμ„ 뢈러였기 μœ„ν•œ ν•¨μˆ˜κ°€ ν¬ν•¨λ˜μ–΄ μžˆμŠ΅λ‹ˆλ‹€.
  • vk_types.h : 전체 μ½”λ“œ λ² μ΄μŠ€λŠ” 이 헀더λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€. μ΄λŠ” 널리 μ‚¬μš©λ˜λŠ” κΈ°λ³Έ ꡬ쑰체와 포함 νŒŒμΌμ„ μ œκ³΅ν•©λ‹ˆλ‹€.

vk_engine은 ν”„λ‘œμ νŠΈμ˜ μ€‘μ‹¬μ΄μž μ£Όμš” μ—”μ§„ ν΄λž˜μŠ€κ°€ 될 κ²ƒμž…λ‹ˆλ‹€. vk_loaderλŠ” GLTF νŒŒμΌμ„ 뢈러올 λ•Œ vk_engineκ³Ό μƒν˜Έμž‘μš©ν•΄μ•Ό ν•˜λ―€λ‘œ, 이에 톡합될 μ˜ˆμ •μž…λ‹ˆλ‹€. κ·Έ μ™Έμ˜ λ‹€λ₯Έ νŒŒμΌλ“€μ€ νŠœν† λ¦¬μ–Ό 진행에 따라 λ§Œλ“€μ–΄μ§€λŠ” 일반적인 Vulkan 좔상화 κ³„μΈ΅μœΌλ‘œ, Vulkan μ™Έμ—λŠ” 별닀λ₯Έ μ˜μ‘΄μ„±μ΄ μ—†μŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μ΄λŸ¬ν•œ 좔상화 νŒŒμΌλ“€μ€ μ—¬λŸ¬λΆ„μ˜ λ‹€λ₯Έ ν”„λ‘œμ νŠΈμ—μ„œλ„ 자유둭게 ν™œμš©ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

μ½”λ“œ

#include <vk_engine.h>

int main(int argc, char* argv[])
{
	VulkanEngine engine;

	engine.init();	
	
	engine.run();	

	engine.cleanup();	

	return 0;
}

λ‹¨μˆœν•œ main.cpp둜 μ‹œμž‘ν•©λ‹ˆλ‹€. VulkanEngine ν•¨μˆ˜λ₯Ό ν˜ΈμΆœν•˜λŠ” κ²ƒμ™Έμ—λŠ” 아무것도 ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€.

ν–₯ν›„μ—λŠ” argc/argvμ—μ„œ μ „λ‹¬λœ λͺ…령쀄 μΈμžλ‚˜ μ„€μ •νŒŒμΌμ„ μ΄μš©ν•΄ νŒŒλΌλ―Έν„°λ₯Ό κ΅¬μ„±ν•˜λŠ” μš©λ„λ‘œ μ‚¬μš©ν•  μˆ˜λ„ μžˆμŠ΅λ‹ˆλ‹€.

vk_types.h은 λ‹€μŒμ„ ν¬ν•¨ν•©λ‹ˆλ‹€.

#pragma once

#include <memory>
#include <optional>
#include <string>
#include <vector>
#include <span>
#include <array>
#include <functional>
#include <deque>

#include <vulkan/vulkan.h>
#include <vulkan/vk_enum_string_helper.h>
#include <vk_mem_alloc.h>

#include <fmt/core.h>

#include <glm/mat4x4.hpp>
#include <glm/vec4.hpp>
#define VK_CHECK(x)                                                     \
    do {                                                                \
        VkResult err = x;                                               \
        if (err) {                                                      \
             fmt::print("Detected Vulkan error: {}", string_VkResult(err)); \
            abort();                                                    \
        }                                                               \
    } while (0)

#pragrma onceλŠ” μ»΄νŒŒμΌλŸ¬μ—κ²Œ 같은 νŒŒμΌμ„ 두 번 ν¬ν•¨ν•˜μ§€ 말라고 μ•Œλ €μ£ΌλŠ” μ „μ²˜λ¦¬κΈ° μ§€μ‹œλ¬Έμž…λ‹ˆλ‹€. μ΄λŠ” ν—€λ”κ°€λ“œμ™€ λ™μΌν•œ 역할을 ν•˜μ§€λ§Œ 더 κ°„κ²°ν•©λ‹ˆλ‹€.

<vulkan/vulkan.h>λΌλŠ” Vulkan 핡심 헀더λ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€. μ΄λŠ” μš°λ¦¬κ°€ ν•„μš”λ‘œ ν•˜λŠ” λͺ¨λ“  ꡬ쑰체와 Vulkan ν•¨μˆ˜ μ •μ˜λ₯Ό λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ½”λ“œ μ „λ°˜μ— μ‚¬μš©ν•  fmt 라이브러리의 핡심 헀더λ₯Ό ν¬ν•¨ν•˜κ³  VK_CHECK 맀크둜λ₯Ό λ§Œλ“€μ–΄ Vulkan 호좜 μ‹œ μ—λŸ¬λ₯Ό 관리할 κ²ƒμž…λ‹ˆλ‹€. νŠœν† λ¦¬μ–Όμ—μ„œλŠ” vk_enum_string_helper.hλ₯Ό μ‚¬μš©ν•  κ²ƒμž…λ‹ˆλ‹€. μ΄λŠ” Vulkan SDKκ°€ μ œκ³΅ν•˜λŠ” ν—€λ”λ‘œ, μ£Όμ–΄μ§„ Vulkan μ—΄κ±°ν˜•μ— λŒ€ν•œ λ¬Έμžμ—΄μ„ κ°€μ Έμ˜¬ 수 있게 ν•΄μ€λ‹ˆλ‹€. μ΄λŸ¬ν•œ λ°©μ‹μœΌλ‘œ 둜그λ₯Ό μž‘μ„±ν•  λ•Œ 맀우 μœ μš©ν•©λ‹ˆλ‹€.

이 νŠœν† λ¦¬μ–Όμ€ 좜λ ₯을 μœ„ν•΄ ν‘œμ€€ std::cout을 μ‚¬μš©ν•˜μ§€ μ•Šμ„ κ²ƒμž…λ‹ˆλ‹€. λŒ€μ‹  {fmt} 라이브러리λ₯Ό λŒ€μ‹  μ‚¬μš©ν•  κ²ƒμž…λ‹ˆλ‹€. μ΄λŠ” λ¬Έμžμ—΄ ν¬λ§·νŒ…κ³Ό 좜λ ₯을 μœ„ν•œ κ³ ν’ˆμ§ˆ λΌμ΄λΈŒλŸ¬λ¦¬μž…λ‹ˆλ‹€. C++20의 std::format은 이 라이브러리λ₯Ό 기반으둜 μž‘μ„±λ˜μ—ˆμ§€λ§Œ, 더 λ§Žμ€ κΈ°λŠ₯κ³Ό 지원을 μœ„ν•΄ ν•΄λ‹Ή 라이브러리λ₯Ό μ‚¬μš©ν•˜κ² μŠ΅λ‹ˆλ‹€. μ—¬κΈ°μ„œλŠ” Vulkan μ—λŸ¬κ°€ λ°œμƒν•œ 경우 fmt::println을 μ‚¬μš©ν•΄ μ½˜μ†”μ°½μ— μ—λŸ¬λ₯Ό 좜λ ₯ν•˜κ² μŠ΅λ‹ˆλ‹€.

vk_initializers.hλŠ” 사전 μž‘μ„±λœ νŒŒμΌμž…λ‹ˆλ‹€. μ΄λŠ” λŒ€λΆ€λΆ„μ˜ Vulkan info ꡬ쑰체와 λ‹€λ₯Έ μœ μ‚¬ν•œ κ²ƒλ“€μ˜ μ΄λ‹ˆμ…œλΌμ΄μ €λ₯Ό λ‹΄μŠ΅λ‹ˆλ‹€. μ΄λŠ” μ΄λŸ¬ν•œ ꡬ쑰체듀을 μ•½κ°„ μΆ”μƒν™”ν•˜μ—¬ 이λ₯Ό μ‚¬μš©ν•  λ•Œ λ§ˆλ‹€ μ½”λ“œμ™€ 좔상화에 λŒ€ν•΄ μ„€λͺ…ν•  κ²ƒμž…λ‹ˆλ‹€.

Vulkan κ·Έ 자체λ₯Ό λ‹΄λŠ” vk_types 헀더λ₯Ό ν¬ν•¨ν•˜κ³ , 이후 이곳에 μΆ”κ°€ν•  ν•¨μˆ˜λ₯Ό 담을 λ„€μž„μŠ€νŽ˜μ΄μŠ€λ₯Ό μ„ μ–Έν•©λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ 핡심 클래슀인 vk_engine.hλ₯Ό μ‚΄νŽ΄λ΄…μ‹œλ‹€.

#pragma once

#include <vk_types.h>

class VulkanEngine {
public:

	bool _isInitialized{ false };
	int _frameNumber {0};
	bool stop_rendering{ false };
	VkExtent2D _windowExtent{ 1700 , 900 };

	struct SDL_Window* _window{ nullptr };

	static VulkanEngine& Get();

	//initializes everything in the engine
	void init();

	//shuts down the engine
	void cleanup();

	//draw loop
	void draw();

	//run main loop
	void run();
};

vk_initializersκ³Ό λ§ˆμ°¬κ°€μ§€λ‘œ vk_typesλ₯Ό ν¬ν•¨ν•©λ‹ˆλ‹€. Vulkan νƒ€μž…μΈ VkExtent2Dκ°€ ν•„μš”ν•˜κΈ° λ•Œλ¬Έμž…λ‹ˆλ‹€. VulkanEngine은 μš°λ¦¬κ°€ μž‘μ—…ν•  ν•΅μ‹¬μž…λ‹ˆλ‹€. 엔진이 μˆ˜ν–‰ν•˜λŠ” λŒ€λΆ€λΆ„μ˜ μž‘μ—…μ„ 이 클래슀λ₯Ό μ€‘μ‹¬μœΌλ‘œ μž‘μ—…ν•  κ²ƒμž…λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ ν”„λ‘œμ νŠΈμ˜ μ•„ν‚€ν…μ²˜λ₯Ό λ‹¨μˆœν•˜κ²Œ λ§Œλ“€ 수 μžˆμŠ΅λ‹ˆλ‹€.

엔진이 μ΄ˆκΈ°ν™” λ˜μ—ˆλŠ”μ§€λ₯Ό ν™•μΈν•˜λŠ” ν”Œλž˜κ·Έ, ν”„λ ˆμž„μ„ λ‚˜νƒ€λ‚΄λŠ” μ •μˆ˜, 그리고 창의 크기λ₯Ό ν”½μ…€ λ‹¨μœ„λ‘œ μ €μž₯ν•˜λŠ” λ³€μˆ˜λ₯Ό κ°–μŠ΅λ‹ˆλ‹€.

μ„ μ–Έ struct SDL_Window* _window;λŠ” 특히 μ€‘μš”ν•©λ‹ˆλ‹€. structκ°€ 맨 μ•žμ— 온 점을 μœ μ˜ν•©μ‹œλ‹€. μ΄λŠ” μ „λ°© 선언이라 λΆˆλ¦¬λŠ” κ²ƒμœΌλ‘œ, VulkanEngine 헀더에 SDL을 ν¬ν•¨μ‹œν‚€μ§€ μ•Šκ³ λ„ 클래슀 λ‚΄λΆ€μ—μ„œ SDL_Window 포인터λ₯Ό μ‚¬μš© κ°€λŠ₯ν•˜κ²Œ ν•΄μ€λ‹ˆλ‹€. 이 λ³€μˆ˜λŠ” μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ—μ„œ λ§Œλ“€ 창을 λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€.

λ˜ν•œ Get() ν•¨μˆ˜λ₯Ό μ „μ—­ 싱클톀 νŒ¨ν„΄μœΌλ‘œ μΆ”κ°€ν–ˆμŠ΅λ‹ˆλ‹€.

헀더에 λŒ€ν•΄ λ‹€λ€„λ³΄μ•˜μœΌλ―€λ‘œ, cpp νŒŒμΌμ„ μ‚΄νŽ΄ λ΄…μ‹œλ‹€.

vk_engine.cpp line 1

#include "vk_engine.h"

#include <SDL.h>
#include <SDL_vulkan.h>

#include <vk_initializers.h>
#include <vk_types.h>

#include <chrono>
#include <thread>

λ‹€λ₯Έ νŒŒμΌλ“€κ³ΌλŠ” 달리, μ—¬κΈ°μ„œλŠ” 더 λ§Žμ€ 것듀을 ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. <SDL.h>와 <SDL_vulkan.h> λͺ¨λ‘λ₯Ό ν¬ν•¨ν•˜κ³  μžˆμŠ΅λ‹ˆλ‹€. SDL.hλŠ” SDL 라이브러리의 창을 μ—΄κ³  μž…λ ₯을 λ°›λŠ” 핡심 데이터λ₯Ό λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€. 반면 SDL_vulkan.hλŠ” Vulkan 특수 ν”Œλž˜κ·Έμ™€ Vulkanκ³Ό ν˜Έν™˜λ˜λŠ” 창을 μ—΄κΈ° μœ„ν•œ κΈ°λŠ₯, κ·Έ 외에도 λ‹€μ–‘ν•œ Vulkan 특수 κΈ°λŠ₯을 λ‹΄κ³  μžˆμŠ΅λ‹ˆλ‹€. λ˜ν•œ μ‚¬μš©ν•  λͺ‡λͺ‡ STL μ»¨ν…Œμ΄λ„ˆλ„ μΆ”κ°€ν•©λ‹ˆλ‹€.

vk_engine.cpp, line 10

constexpr bool bUseValidationLayers = false;

VulkanEngine* loadedEngine = nullptr;

VulkanEngine& VulkanEngine::Get() { return *loadedEngine; }
void VulkanEngine::init()
{
    // only one engine initialization is allowed with the application.
    assert(loadedEngine == nullptr);
    loadedEngine = this;

    // We initialize SDL and create a window with it.
    SDL_Init(SDL_INIT_VIDEO);

    SDL_WindowFlags window_flags = (SDL_WindowFlags)(SDL_WINDOW_VULKAN);

    _window = SDL_CreateWindow(
        "Vulkan Engine",
        SDL_WINDOWPOS_UNDEFINED,
        SDL_WINDOWPOS_UNDEFINED,
        _windowExtent.width,
        _windowExtent.height,
        window_flags);

    // everything went fine
    _isInitialized = true;
}

SDL 창을 μƒμ„±ν•˜λŠ” 첫 번재 μ½”λ“œλ₯Ό μ‚΄νŽ΄λ΄…μ‹œλ‹€. 첫 번째둜 ν•˜λŠ” 것은 SDL 라이브러리 μ΄ˆκΈ°ν™”μž…λ‹ˆλ‹€. SDL λΌμ΄λΈŒλŸ¬λ¦¬λŠ” λ‹€μ–‘ν•œ κΈ°λŠ₯을 ν¬ν•¨ν•˜κ³  있기 λ•Œλ¬Έμ— μš°λ¦¬κ°€ μ–΄λ–€ κΈ°λŠ₯을 μ‚¬μš©ν•  것인지에 λŒ€ν•œ ν”Œλž˜κ·Έλ₯Ό 전달해야 ν•©λ‹ˆλ‹€. SDL_INIT_VIDEOλŠ” SDLμ—κ²Œ κΈ°λ³Έ μ°½ κΈ°λŠ₯을 μ‚¬μš©ν•˜κ³  μ‹Άλ‹€λŠ” 것을 μ•Œλ €μ€λ‹ˆλ‹€. μ΄λŠ” λ˜ν•œ ν‚€λ³΄λ“œμ™€ 마우슀 μž…λ ₯을 λ°›λŠ” κΈ°λ³Έ μž…λ ₯ μ΄λ²€νŠΈλ„ ν¬ν•¨ν•©λ‹ˆλ‹€.

λ˜ν•œ Vulkan 엔진을 μ‹±κΈ€ν†€μœΌλ‘œ μ°Έμ‘°ν•˜κΈ° μœ„ν•œ μ „μ—­ 포인터λ₯Ό μ„€μ •ν•©λ‹ˆλ‹€. μ „ν˜•μ μΈ 싱글톀 λŒ€μ‹  이처럼 μž‘μ—…ν•˜λŠ” μ΄μœ λŠ” ν΄λž˜μŠ€κ°€ μ΄ˆκΈ°ν™”λ˜κ³  νŒŒκ΄΄λ˜λŠ” μ‹œμ μ„ λͺ…μ‹œμ μœΌλ‘œ μ œμ–΄ν•˜κΈ° μœ„ν•΄μ„œμž…λ‹ˆλ‹€. 일반적인 C++ 싱글톀 νŒ¨ν„΄μ€ μ΄λŸ¬ν•œ μ œμ–΄λ₯Ό ν•  수 μ—†μŠ΅λ‹ˆλ‹€.

SDL이 μ΄ˆκΈ°ν™”λ˜λ©΄, 이λ₯Ό μ‚¬μš©ν•΄ 창을 생성할 κ²ƒμž…λ‹ˆλ‹€. 창은 이후에 μ‚¬μš©ν•  수 μžˆλ„λ‘ _window 멀버에 λ‹΄κΉλ‹ˆλ‹€.

SDL이 C 라이브러리이기 λ•Œλ¬Έμ—, μƒμ„±μžμ™€ 파괴자λ₯Ό μ§€μ›ν•˜μ§€ μ•ŠμŠ΅λ‹ˆλ‹€. λ”°λΌμ„œ μˆ˜λ™μ μœΌλ‘œ νŒŒκ΄΄ν•΄μ£Όμ–΄μ•Ό ν•©λ‹ˆλ‹€.

창이 λ§Œλ“€μ–΄μ§€λ©΄ νŒŒκ΄΄λ„ μˆ˜ν–‰ν•΄μ•Ό ν•©λ‹ˆλ‹€.

void VulkanEngine::cleanup()
{
    if (_isInitialized) {

        SDL_DestroyWindow(_window);
    }

    // clear engine pointer
    loadedEngine = nullptr;
}

void VulkanEngine::draw()
{
    // nothing yet
}

SDL_CreateWindowμ—μ„œ ν–ˆλ˜ 것과 μœ μ‚¬ν•˜κ²Œ, SDL_DestroyWindow도 μˆ˜ν–‰ν•  ν•„μš”κ°€ μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” ν”„λ‘œκ·Έλž¨μ˜ 창을 μ œκ±°ν•©λ‹ˆλ‹€. 이제 엔진이 μ™„μ „νžˆ μ •λ¦¬λ˜μ—ˆμœΌλ―€λ‘œ, 이 μ§€μ μ—μ„œ 엔진을 κ°€λ¦¬ν‚€λŠ” 싱글톀 포인터도 μ΄ˆκΈ°ν™”ν•©λ‹ˆλ‹€.

이후에 더 λ§Žμ€ ν•¨μˆ˜λ₯Ό cleanup ν•¨μˆ˜μ— μΆ”κ°€ν•  κ²ƒμž…λ‹ˆλ‹€.

draw ν•¨μˆ˜κ°€ μ§€κΈˆμ€ λΉ„μ–΄μžˆμ§€λ§Œ, 이후에 λ Œλ”λ§ μ½”λ“œλ₯Ό μΆ”κ°€ν•  κ²ƒμž…λ‹ˆλ‹€.

void VulkanEngine::run()
{
    SDL_Event e;
    bool bQuit = false;

    // main loop
    while (!bQuit) {
        // Handle events on queue
        while (SDL_PollEvent(&e) != 0) {
            // close the window when user alt-f4s or clicks the X button
            if (e.type == SDL_QUIT)
                bQuit = true;

            if (e.type == SDL_WINDOWEVENT) {
                if (e.window.event == SDL_WINDOWEVENT_MINIMIZED) {
                    stop_rendering = true;
                }
                if (e.window.event == SDL_WINDOWEVENT_RESTORED) {
                    stop_rendering = false;
                }
            }
        }

        // do not draw if we are minimized
        if (stop_rendering) {
            // throttle the speed to avoid the endless spinning
            std::this_thread::sleep_for(std::chrono::milliseconds(100));
            continue;
        }

        draw();
    }
}

μ• ν”Œλ¦¬μΌ€μ΄μ…˜μ˜ 메인 λ£¨ν”„μž…λ‹ˆλ‹€. while()에 λ¬΄ν•œ 반볡문이 μžˆμŠ΅λ‹ˆλ‹€. μ΄λŠ” SDL이 SDL_QUITλ₯Ό λ°›μ•˜μ„ λ•Œμ—λ§Œ 멈μΆ₯λ‹ˆλ‹€.

λ§€ λ°˜λ³΅λ§ˆλ‹€ SDL_PollEventλ₯Ό μˆ˜ν–‰ν•©λ‹ˆλ‹€. μ΄λŠ” SDLμ—κ²Œ μ§€λ‚œ ν”„λ ˆμž„λ™μ•ˆ OSκ°€ μ• ν”Œλ¦¬μΌ€μ΄μ…˜μœΌλ‘œ 보낸 λͺ¨λ“  이벀트λ₯Ό μš”μ²­ν•©λ‹ˆλ‹€. μ—¬κΈ°μ„œ ν‚€λ³΄λ“œ μž…λ ₯, 마우슀 이동, μ°½ 움직이기, μ΅œμ†Œν™” 등을 확인할 수 μžˆμŠ΅λ‹ˆλ‹€. μ§€κΈˆμ€ SDL_QUITκ³Ό μ°½ μ΅œμ†Œν™”/λ³΅κ΅¬μ—λ§Œ μ‹ κ²½μ“°λ©΄ λ©λ‹ˆλ‹€. 창을 μ΅œμ†Œν™”ν•˜λŠ” 이벀트λ₯Ό λ°›μœΌλ©΄, stop_rendering 뢈 값을 true둜 μ„€μ •ν•΄ μ΅œμ†Œν™” λ˜μ—ˆμ„ λ•Œ κ·Έλ¦¬λŠ” 것을 λ°©μ§€ν•©λ‹ˆλ‹€. 창을 λ³΅κ΅¬ν•˜λ©΄ 이λ₯Ό λ‹€μ‹œ false둜 μ„€μ •ν•΄ 그리기λ₯Ό κ³„μ†ν•˜λ„λ‘ ν•©λ‹ˆλ‹€.

λ§ˆμ§€λ§‰μœΌλ‘œ, 메인 λ£¨ν”„μ˜ 각 λ°˜λ³΅λ§ˆλ‹€ draw()λ₯Ό ν˜ΈμΆœν•˜κ±°λ‚˜ 그리기가 λΉ„ν™œμ„±ν™”λœ κ²½μš°μ—λŠ” std::this_thread::sleep_forλ₯Ό ν˜ΈμΆœν•©λ‹ˆλ‹€. μ΄λ ‡κ²Œ ν•˜λ©΄ 창이 μ΅œμ†Œν™” λ˜μ—ˆμ„ λ•Œ μ‹€ν–‰λ˜λŠ” 것을 λ°©μ§€ν•¨μœΌλ‘œμ„œ μ„±λŠ₯을 μ ˆμ•½ν•  수 μžˆμŠ΅λ‹ˆλ‹€.

이제 SDL이 μ–΄λ–»κ²Œ 창을 λ§Œλ“œλŠ”μ§€λ₯Ό μ‚΄νŽ΄λ΄€μŠ΅λ‹ˆλ‹€. 사싀 κ·Έ μ™Έμ—λŠ” 큰 λ³€ν™”κ°€ μ—†μŠ΅λ‹ˆλ‹€.

이제 SDL 이벀트λ₯Ό μ‹€ν—˜ν•΄λ³΄λŠ” κ²ƒλ§Œμ΄ λ‚¨μ•˜μŠ΅λ‹ˆλ‹€.

μ—°μŠ΅μ‚Όμ•„ SDL2의 λ¬Έμ„œλ₯Ό 읽어 fmt::printλ₯Ό μ‚¬μš©ν•΄ ν‚€λ³΄λ“œ 이벀트λ₯Ό 둜그둜 좜λ ₯ν•΄λ³΄λŠ” 것도 μ’‹μŠ΅λ‹ˆλ‹€.

이제 첫 챕터λ₯Ό μ§„ν–‰ν•  수 μžˆμŠ΅λ‹ˆλ‹€. λ Œλ”λ§ 루프λ₯Ό κ΅¬ν˜„ν•΄λ³΄κ² μŠ΅λ‹ˆλ‹€.

Next: Initializing Vulkan