init tick 분리
This commit is contained in:
7
.clang-format
Normal file
7
.clang-format
Normal file
@@ -0,0 +1,7 @@
|
||||
# Google C/C++ Code Style Settings
|
||||
|
||||
Language: Cpp
|
||||
BasedOnStyle: Google
|
||||
Standard: c++20
|
||||
UseTab: Never
|
||||
ColumnLimit: 80
|
||||
14
.editorconfig
Normal file
14
.editorconfig
Normal file
@@ -0,0 +1,14 @@
|
||||
root = true
|
||||
|
||||
[*.{cpp,h,hpp,c}]
|
||||
indent_style = space
|
||||
indent_size = 2
|
||||
insert_final_newline = true
|
||||
tab_width = 2
|
||||
charset = utf-8
|
||||
trim_trailing_whitespace = true
|
||||
|
||||
[*.{vert,frag,glsl}]
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
tab_width = 4
|
||||
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@@ -0,0 +1,3 @@
|
||||
build/*
|
||||
.vs
|
||||
out
|
||||
11
CMakeLists.txt
Normal file
11
CMakeLists.txt
Normal file
@@ -0,0 +1,11 @@
|
||||
cmake_minimum_required(VERSION 3.5)
|
||||
|
||||
set(PROJECT_NAME "Asteroid")
|
||||
if(NOT CMAKE_BUILD_TYPE)
|
||||
set(CMAKE_BUILD_TYPE Release CACHE STRING "Choose the type of build." FORCE)
|
||||
endif()
|
||||
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
add_subdirectory(Client)
|
||||
# add_subdirectory(Server)
|
||||
80
Client/CMakeLists.txt
Normal file
80
Client/CMakeLists.txt
Normal file
@@ -0,0 +1,80 @@
|
||||
cmake_minimum_required(VERSION 3.22)
|
||||
set(PROJECT_NAME "Client")
|
||||
project(${PROJECT_NAME})
|
||||
|
||||
find_package(Vulkan REQUIRED)
|
||||
|
||||
include(Shaders.cmake)
|
||||
include(FetchContent)
|
||||
|
||||
FetchContent_Declare(
|
||||
glm
|
||||
GIT_REPOSITORY "https://github.com/g-truc/glm.git"
|
||||
GIT_TAG "1.0.1"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
FetchContent_MakeAvailable(glm)
|
||||
|
||||
FetchContent_Declare(
|
||||
spdlog
|
||||
GIT_REPOSITORY "https://github.com/gabime/spdlog.git"
|
||||
GIT_TAG "v1.15.2"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
FetchContent_MakeAvailable(spdlog)
|
||||
|
||||
FetchContent_Declare(
|
||||
glfw
|
||||
GIT_REPOSITORY "https://github.com/glfw/glfw.git"
|
||||
GIT_TAG "3.4"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
FetchContent_MakeAvailable(glfw)
|
||||
|
||||
FetchContent_Declare(
|
||||
GSL
|
||||
GIT_REPOSITORY "https://github.com/microsoft/GSL.git"
|
||||
GIT_TAG "v4.2.0"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
FetchContent_MakeAvailable(GSL)
|
||||
|
||||
FetchContent_Declare(
|
||||
ASSIMP
|
||||
GIT_REPOSITORY "https://github.com/assimp/assimp.git"
|
||||
GIT_TAG "v5.4.3"
|
||||
GIT_SHALLOW ON
|
||||
)
|
||||
FetchContent_MakeAvailable(ASSIMP)
|
||||
|
||||
file(GLOB_RECURSE Sources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/src/*.cpp"
|
||||
)
|
||||
|
||||
add_executable(${PROJECT_NAME} ${Sources})
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Vulkan::Vulkan)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE glm)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE glfw)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE Microsoft.GSL::GSL)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE spdlog)
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE assimp::assimp)
|
||||
|
||||
target_include_directories(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include")
|
||||
target_compile_features(${PROJECT_NAME} PRIVATE cxx_std_20)
|
||||
|
||||
target_precompile_headers(${PROJECT_NAME} PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/include/precomp.h")
|
||||
|
||||
file(GLOB_RECURSE ShaderSources CONFIGURE_DEPENDS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.vert"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/shaders/*.frag"
|
||||
)
|
||||
|
||||
add_shaders(Shaders ${ShaderSources})
|
||||
add_dependencies(${PROJECT_NAME} Shaders)
|
||||
|
||||
add_custom_command(TARGET ${PROJECT_NAME} POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_directory
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/assets"
|
||||
"${CMAKE_CURRENT_BINARY_DIR}/assets"
|
||||
COMMENT "Copying assets to build directory"
|
||||
)
|
||||
31
Client/Shaders.cmake
Normal file
31
Client/Shaders.cmake
Normal file
@@ -0,0 +1,31 @@
|
||||
function(add_shaders TARGET_NAME)
|
||||
set(SHADER_SOURCE_FILES ${ARGN})
|
||||
list(LENGTH SHADER_SOURCE_FILES FILE_COUNT)
|
||||
if(FILE_COUNT EQUAL 0)
|
||||
message(FATAL_ERROR "Cannot add shaders target without shader files!")
|
||||
endif()
|
||||
|
||||
set(SHADER_COMMANDS)
|
||||
set(SHADER_PRODUCTS)
|
||||
|
||||
foreach(SHADER_SOURCE IN LISTS SHADER_SOURCE_FILES)
|
||||
cmake_path(ABSOLUTE_PATH SHADER_SOURCE NORMALIZE)
|
||||
cmake_path(GET SHADER_SOURCE FILENAME SHADER_NAME)
|
||||
|
||||
# COMMANDS
|
||||
list(APPEND SHADER_COMMANDS COMMAND)
|
||||
list(APPEND SHADER_COMMANDS Vulkan::glslc)
|
||||
list(APPEND SHADER_COMMANDS "${SHADER_SOURCE}")
|
||||
list(APPEND SHADER_COMMANDS "-o")
|
||||
list(APPEND SHADER_COMMANDS "${CMAKE_CURRENT_BINARY_DIR}/${SHADER_NAME}.spv")
|
||||
# PRODUCTS
|
||||
list(APPEND SHADER_PRODUCTS "${CMAKE_CURRENT_BINARY_DIR}/${SHADER_NAME}.spv")
|
||||
endforeach()
|
||||
|
||||
add_custom_target(${TARGET_NAME} ALL
|
||||
${SHADER_COMMANDS}
|
||||
COMMENT "Compiling shaders..."
|
||||
SOURCES ${SHADER_SOURCE_FILES}
|
||||
BYPRODUCTS ${SHADER_PRODUCTS}
|
||||
)
|
||||
endfunction()
|
||||
BIN
Client/assets/background.fbx
Normal file
BIN
Client/assets/background.fbx
Normal file
Binary file not shown.
BIN
Client/assets/bullet.fbx
Normal file
BIN
Client/assets/bullet.fbx
Normal file
Binary file not shown.
BIN
Client/assets/player.fbx
Normal file
BIN
Client/assets/player.fbx
Normal file
Binary file not shown.
BIN
Client/assets/player_flame.fbx
Normal file
BIN
Client/assets/player_flame.fbx
Normal file
Binary file not shown.
22
Client/include/asset/loader.h
Normal file
22
Client/include/asset/loader.h
Normal file
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset/object/model.h"
|
||||
#include "assimp/Importer.hpp"
|
||||
#include "assimp/postprocess.h"
|
||||
#include "assimp/scene.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
typedef Model& inModel;
|
||||
|
||||
class Loader {
|
||||
public:
|
||||
void setPath(std::string path);
|
||||
void loadModel(inModel model);
|
||||
std::vector<std::uint8_t> readTexture();
|
||||
|
||||
private:
|
||||
Assimp::Importer importer_;
|
||||
const struct aiScene* scene_ = nullptr;
|
||||
};
|
||||
} // namespace veng
|
||||
10
Client/include/asset/object/material.h
Normal file
10
Client/include/asset/object/material.h
Normal file
@@ -0,0 +1,10 @@
|
||||
#pragma once
|
||||
|
||||
#include "vulkan/texture_handle.h"
|
||||
|
||||
namespace veng {
|
||||
struct Material {
|
||||
TextureHandle texture_handle;
|
||||
std::vector<std::uint8_t> texture_image;
|
||||
};
|
||||
} // namespace veng
|
||||
156
Client/include/asset/object/model.h
Normal file
156
Client/include/asset/object/model.h
Normal file
@@ -0,0 +1,156 @@
|
||||
#pragma once
|
||||
#include <functional>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <glm/gtc/quaternion.hpp>
|
||||
#include <vector>
|
||||
|
||||
#include "material.h"
|
||||
#include "vulkan/buffer_handle.h"
|
||||
#include "vulkan/vertex.h"
|
||||
|
||||
namespace veng {
|
||||
struct Model {
|
||||
Model() : graphics_(nullptr) {}
|
||||
Model(class Graphics* graphics) : graphics_(graphics) {}
|
||||
~Model();
|
||||
|
||||
Model(const Model& other)
|
||||
: vertices(other.vertices),
|
||||
vertex_buffer(other.vertex_buffer),
|
||||
indices(other.indices),
|
||||
index_buffer(other.index_buffer),
|
||||
transform(other.transform),
|
||||
position(other.position),
|
||||
linear_velocity(other.linear_velocity),
|
||||
linear_acceleration(other.linear_acceleration),
|
||||
rotation(other.rotation),
|
||||
angular_velocity(other.angular_velocity),
|
||||
angular_acceleration(other.angular_acceleration),
|
||||
scale(other.scale),
|
||||
material(other.material),
|
||||
original_offset(other.original_offset),
|
||||
owner(other.owner),
|
||||
radius(other.radius),
|
||||
OnColision(other.OnColision),
|
||||
visible(other.visible),
|
||||
colision(other.colision) {
|
||||
graphics_ = nullptr;
|
||||
}
|
||||
|
||||
Model(Model&& other)
|
||||
: vertices(other.vertices),
|
||||
vertex_buffer(other.vertex_buffer),
|
||||
indices(other.indices),
|
||||
index_buffer(other.index_buffer),
|
||||
transform(other.transform),
|
||||
position(other.position),
|
||||
linear_velocity(other.linear_velocity),
|
||||
linear_acceleration(other.linear_acceleration),
|
||||
rotation(other.rotation),
|
||||
angular_velocity(other.angular_velocity),
|
||||
angular_acceleration(other.angular_acceleration),
|
||||
scale(other.scale),
|
||||
material(other.material),
|
||||
original_offset(other.original_offset),
|
||||
owner(other.owner),
|
||||
radius(other.radius),
|
||||
OnColision(other.OnColision),
|
||||
visible(other.visible),
|
||||
colision(other.colision) {
|
||||
graphics_ = other.graphics_;
|
||||
other.graphics_ = nullptr;
|
||||
}
|
||||
|
||||
Model& operator=(const Model& other) {
|
||||
if (this != &other) {
|
||||
vertices = other.vertices;
|
||||
vertex_buffer = other.vertex_buffer;
|
||||
indices = other.indices;
|
||||
index_buffer = other.index_buffer;
|
||||
transform = other.transform;
|
||||
position = other.position;
|
||||
linear_velocity = other.linear_velocity;
|
||||
linear_acceleration = other.linear_acceleration;
|
||||
rotation = other.rotation;
|
||||
angular_velocity = other.angular_velocity;
|
||||
angular_acceleration = other.angular_acceleration;
|
||||
scale = other.scale;
|
||||
material = other.material;
|
||||
original_offset = other.original_offset;
|
||||
owner = other.owner;
|
||||
radius = other.radius;
|
||||
OnColision = other.OnColision;
|
||||
visible = other.visible;
|
||||
colision = other.colision;
|
||||
|
||||
graphics_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Model& operator=(Model&& other) noexcept {
|
||||
if (this != &other) {
|
||||
vertices = std::move(other.vertices);
|
||||
vertex_buffer = other.vertex_buffer;
|
||||
indices = std::move(other.indices);
|
||||
index_buffer = other.index_buffer;
|
||||
transform = other.transform;
|
||||
position = other.position;
|
||||
linear_velocity = other.linear_velocity;
|
||||
linear_acceleration = other.linear_acceleration;
|
||||
rotation = other.rotation;
|
||||
angular_velocity = other.angular_velocity;
|
||||
angular_acceleration = other.angular_acceleration;
|
||||
scale = other.scale;
|
||||
material = std::move(other.material);
|
||||
original_offset = other.original_offset;
|
||||
owner = other.owner;
|
||||
radius = other.radius;
|
||||
OnColision = other.OnColision;
|
||||
visible = other.visible;
|
||||
colision = other.colision;
|
||||
|
||||
// graphics_만 옮기고, 원본은 nullptr
|
||||
graphics_ = other.graphics_;
|
||||
other.graphics_ = nullptr;
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
std::vector<veng::Vertex> vertices;
|
||||
veng::BufferHandle vertex_buffer;
|
||||
std::vector<std::uint32_t> indices;
|
||||
veng::BufferHandle index_buffer;
|
||||
|
||||
glm::mat4 transform = glm::rotate(glm::mat4(1.0f), glm::radians(180.f),
|
||||
glm::vec3(0.f, 0.f, 1.f));
|
||||
|
||||
glm::vec3 position = glm::vec3(0.f);
|
||||
glm::vec3 linear_velocity = glm::vec3(0.f);
|
||||
glm::vec3 linear_acceleration = glm::vec3(0.f);
|
||||
|
||||
glm::quat rotation = glm::quat(1.0f, 0.0f, 0.0f, 0.0f);
|
||||
glm::vec3 angular_velocity = glm::vec3(0.f); // 축 * 각속도(rad/s)
|
||||
glm::vec3 angular_acceleration = glm::vec3(0.f);
|
||||
|
||||
glm::vec3 scale = glm::vec3(1.f);
|
||||
|
||||
Material material;
|
||||
|
||||
void Update(float dt);
|
||||
|
||||
glm::vec3 original_offset = glm::vec3(0.f);
|
||||
|
||||
Model* owner = this;
|
||||
|
||||
std::float_t radius = 0.f;
|
||||
|
||||
std::function<void(Model* self, Model* other)> OnColision = nullptr;
|
||||
|
||||
bool visible = true;
|
||||
bool colision = false;
|
||||
|
||||
private:
|
||||
class Graphics* graphics_;
|
||||
};
|
||||
} // namespace veng
|
||||
12
Client/include/glfw/glfw_initialization.h
Normal file
12
Client/include/glfw/glfw_initialization.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
namespace veng {
|
||||
struct GlfwInitialization {
|
||||
public:
|
||||
GlfwInitialization();
|
||||
~GlfwInitialization();
|
||||
|
||||
GlfwInitialization(const GlfwInitialization&) = delete;
|
||||
GlfwInitialization& operator=(const GlfwInitialization&) = delete;
|
||||
};
|
||||
} // namespace veng
|
||||
12
Client/include/glfw/glfw_monitor.h
Normal file
12
Client/include/glfw/glfw_monitor.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
struct GLFWmonitor;
|
||||
struct GLFWwindow;
|
||||
|
||||
namespace veng {
|
||||
gsl::span<GLFWmonitor *> GetMonitors();
|
||||
glm::ivec2 GetMonitorPosition(gsl::not_null<GLFWmonitor *> monitor);
|
||||
glm::ivec2 GetMonitorWorkAreaSize(gsl::not_null<GLFWmonitor *> monitor);
|
||||
void MoveWindowToMonitor(gsl::not_null<GLFWwindow *> window,
|
||||
gsl::not_null<GLFWmonitor *> monitor);
|
||||
} // namespace veng
|
||||
23
Client/include/glfw/glfw_window.h
Normal file
23
Client/include/glfw/glfw_window.h
Normal file
@@ -0,0 +1,23 @@
|
||||
#pragma once
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
namespace veng {
|
||||
class Window {
|
||||
public:
|
||||
Window(gsl::czstring name, glm::ivec2 size);
|
||||
~Window();
|
||||
|
||||
glm::ivec2 GetWindowSize() const;
|
||||
glm::ivec2 GetFramebufferSize() const;
|
||||
bool ShouldClose() const;
|
||||
GLFWwindow* GetHandle() const;
|
||||
|
||||
GLFWkeyfun SetKeyCallback(GLFWkeyfun key_callback);
|
||||
|
||||
bool TryMoveToMonitor(std::uint16_t monitor_number);
|
||||
|
||||
private:
|
||||
GLFWwindow* window_;
|
||||
};
|
||||
} // namespace veng
|
||||
16
Client/include/precomp.h
Normal file
16
Client/include/precomp.h
Normal file
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include <cmath>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <functional>
|
||||
#include <glm/glm.hpp>
|
||||
#include <gsl/gsl>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
|
||||
#include "spdlog/spdlog.h"
|
||||
#include "utilities.h"
|
||||
|
||||
#define MAX_BUFFERED_FRAMES (2)
|
||||
8422
Client/include/stb/stb_image.h
Normal file
8422
Client/include/stb/stb_image.h
Normal file
File diff suppressed because it is too large
Load Diff
8
Client/include/utilities.h
Normal file
8
Client/include/utilities.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
#include <filesystem>
|
||||
|
||||
namespace veng {
|
||||
bool streq(gsl::czstring left, gsl::czstring right);
|
||||
std::vector<std::uint8_t> ReadFile(std::filesystem::path shader_path);
|
||||
}
|
||||
12
Client/include/vulkan/buffer_handle.h
Normal file
12
Client/include/vulkan/buffer_handle.h
Normal file
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace veng {
|
||||
|
||||
struct BufferHandle {
|
||||
VkBuffer buffer = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
} // namespace veng
|
||||
39
Client/include/vulkan/coordinate.h
Normal file
39
Client/include/vulkan/coordinate.h
Normal file
@@ -0,0 +1,39 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
|
||||
#include "asset/object/model.h"
|
||||
|
||||
namespace std {
|
||||
template <>
|
||||
struct hash<glm::i64vec3> {
|
||||
std::size_t operator()(const glm::i64vec3& v) const noexcept {
|
||||
std::size_t h1 = std::hash<int64_t>()(v.x);
|
||||
std::size_t h2 = std::hash<int64_t>()(v.y);
|
||||
std::size_t h3 = std::hash<int64_t>()(v.z);
|
||||
return h1 ^ (h2 << 1) ^ (h3 << 2);
|
||||
}
|
||||
};
|
||||
} // namespace std
|
||||
|
||||
namespace veng {
|
||||
|
||||
class Coord {
|
||||
public:
|
||||
Coord() : seg(glm::i64vec3(0)), pos(glm::vec3(0.f)) {}
|
||||
Coord(glm::vec3 _pos) : seg(glm::i64vec3(0)), pos(_pos) {}
|
||||
Coord(glm::i64vec3 _seg, glm::vec3 _pos) : seg(_seg), pos(_pos) {}
|
||||
|
||||
glm::i64vec3 seg;
|
||||
glm::vec3 pos;
|
||||
|
||||
Coord operator+(const Coord& other) const;
|
||||
Coord operator-(const Coord& other) const;
|
||||
|
||||
std::unordered_map<glm::i64vec3, glm::vec3> coord_system;
|
||||
|
||||
private:
|
||||
const std::float_t border = 1000.f;
|
||||
};
|
||||
|
||||
} // namespace veng
|
||||
52
Client/include/vulkan/engine.h
Normal file
52
Client/include/vulkan/engine.h
Normal file
@@ -0,0 +1,52 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset/loader.h"
|
||||
#include "physics.h"
|
||||
#include "graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
class Engine {
|
||||
public:
|
||||
Engine(gsl::not_null<Graphics*> vulkan_graphics)
|
||||
: vulkan_graphics(vulkan_graphics) {}
|
||||
|
||||
void init();
|
||||
|
||||
void LoadModelAsset(std::string path, std::string name);
|
||||
const Model* GetStaticModel(std::string name);
|
||||
|
||||
Model* SpawnModel(std::string asset_name, std::string name);
|
||||
Model* SpawnLifedModel(std::string asset_name, std::string name,
|
||||
std::float_t lifespan);
|
||||
Model* GetSpawnedObject(std::string name);
|
||||
|
||||
void Update();
|
||||
|
||||
std::function<void(Engine&)> BeginPlay = [](Engine& engine) {};
|
||||
std::function<void(Engine&, std::float_t delta_time)> Tick =
|
||||
[](Engine& engine, std::float_t delta_time) {};
|
||||
|
||||
glm::mat4 view =
|
||||
glm::lookAt(glm::vec3(0.f, 0.f, -5.f), glm::vec3(0.f, 0.f, 0.f),
|
||||
glm::vec3(0.f, -1.f, 0.f));
|
||||
glm::mat4 projection =
|
||||
glm::perspective(glm::radians(103.f), 800.f / 600.f, 0.1f, 1000.f);
|
||||
|
||||
gsl::not_null<Graphics*> vulkan_graphics;
|
||||
private:
|
||||
Loader asset_loader_;
|
||||
|
||||
Physics physics_controller_;
|
||||
|
||||
glm::ivec2 window_size_ = {0, 0};
|
||||
std::double_t last_frame_time_ = 0.0;
|
||||
|
||||
std::unordered_map<std::string, veng::Model> model_assets_;
|
||||
|
||||
std::unordered_map<std::string, veng::Model> dynamic_immortal_models_;
|
||||
std::unordered_map<std::string, std::pair<veng::Model, std::float_t>>
|
||||
dynamic_models_;
|
||||
};
|
||||
|
||||
} // namespace veng
|
||||
193
Client/include/vulkan/graphics.h
Normal file
193
Client/include/vulkan/graphics.h
Normal file
@@ -0,0 +1,193 @@
|
||||
#pragma once
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "buffer_handle.h"
|
||||
#include "glfw/glfw_window.h"
|
||||
#include "precomp.h"
|
||||
#include "texture_handle.h"
|
||||
#include "vertex.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
struct Frame {
|
||||
VkSemaphore image_available_signal = VK_NULL_HANDLE;
|
||||
VkSemaphore render_finished_signal = VK_NULL_HANDLE;
|
||||
VkFence still_rendering_fence = VK_NULL_HANDLE;
|
||||
|
||||
VkCommandBuffer command_buffer = VK_NULL_HANDLE;
|
||||
|
||||
VkDescriptorSet uniform_set = VK_NULL_HANDLE;
|
||||
BufferHandle uniform_buffer;
|
||||
void* uniform_buffer_location;
|
||||
};
|
||||
|
||||
class Graphics final {
|
||||
public:
|
||||
Graphics(gsl::not_null<Window*> window);
|
||||
~Graphics();
|
||||
|
||||
bool BeginFrame();
|
||||
void SetModelMatrix(glm::mat4 model);
|
||||
void SetViewProjection(glm::mat4 view, glm::mat4 projection);
|
||||
void SetTexture(TextureHandle handle);
|
||||
void RenderBuffer(BufferHandle handle, std::uint32_t vertex_count);
|
||||
void RenderIndexedBuffer(BufferHandle vertex_buffer,
|
||||
BufferHandle index_buffer, std::uint32_t count);
|
||||
void RenderModel(struct Model* model);
|
||||
void EndFrame();
|
||||
|
||||
BufferHandle CreateVertexBuffer(gsl::span<Vertex> vertices);
|
||||
BufferHandle CreateIndexBuffer(gsl::span<std::uint32_t> indices);
|
||||
void DestroyBuffer(BufferHandle handle);
|
||||
TextureHandle CreateTexture(gsl::czstring path);
|
||||
TextureHandle CreateTexture(std::vector<std::uint8_t> image_file_data);
|
||||
TextureHandle CreateTexture(gsl::span<std::uint8_t> image_file_data);
|
||||
void DestroyTexture(TextureHandle handle);
|
||||
|
||||
gsl::not_null<Window*> window;
|
||||
private:
|
||||
struct QueueFamilyIndices {
|
||||
std::optional<std::uint32_t> graphics_family = std::nullopt;
|
||||
std::optional<std::uint32_t> presentation_family = std::nullopt;
|
||||
|
||||
bool IsValid() const {
|
||||
return graphics_family.has_value() && presentation_family.has_value();
|
||||
}
|
||||
};
|
||||
|
||||
struct SwapChainProperties {
|
||||
VkSurfaceCapabilitiesKHR capabilities = {};
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
|
||||
bool IsValid() const { return !formats.empty() && !present_modes.empty(); }
|
||||
};
|
||||
|
||||
// 초기화
|
||||
|
||||
void InitializeVulkan();
|
||||
void CreateInstance();
|
||||
void SetupDebugMessenger();
|
||||
void PickPhysicalDevice();
|
||||
void CreateLogicalDeviceAndQueues();
|
||||
void CreateSurface();
|
||||
void CreateSwapChain();
|
||||
void CreateImageViews();
|
||||
void CreateRenderPass();
|
||||
void CreateGraphicsPipeline();
|
||||
void CreateFramebuffers();
|
||||
void CreateCommandPool();
|
||||
void CreateCommandBuffer();
|
||||
void CreateSignals();
|
||||
void CreateDescriptorSetLayouts();
|
||||
void CreateDescriptorPools();
|
||||
void CreateDescriptorSets();
|
||||
void CreateTextureSampler();
|
||||
void CreateDepthResources();
|
||||
|
||||
void RecreateSwapChain();
|
||||
void CleanupSwapChain();
|
||||
|
||||
// 랜더링
|
||||
|
||||
void BeginCommands();
|
||||
void EndCommands();
|
||||
|
||||
std::vector<gsl::czstring> GetRequiredInstanceExtentions();
|
||||
|
||||
static gsl::span<gsl::czstring> GetSuggestedInstanceExtentions();
|
||||
static std::vector<VkExtensionProperties> GetSupprotedInstanceExtensions();
|
||||
static bool AreAllExtensionsSupported(gsl::span<gsl::czstring> extensions);
|
||||
|
||||
static std::vector<VkLayerProperties> GetSupprotedValidationLayers();
|
||||
static bool AreAllLayersSupported(gsl::span<gsl::czstring> extensions);
|
||||
|
||||
QueueFamilyIndices FindQueueFamilies(VkPhysicalDevice device);
|
||||
SwapChainProperties GetSwapChainProperties(VkPhysicalDevice device);
|
||||
bool IsDeviceSuitable(VkPhysicalDevice device);
|
||||
std::vector<VkPhysicalDevice> GetAvailableDevices();
|
||||
bool AreAllDeviceExtensionsSupported(VkPhysicalDevice device);
|
||||
std::vector<VkExtensionProperties> GetDeviceAvailableExtensions(
|
||||
VkPhysicalDevice device);
|
||||
|
||||
VkSurfaceFormatKHR ChooseSwapSurfaceFormat(
|
||||
gsl::span<VkSurfaceFormatKHR> formats);
|
||||
VkPresentModeKHR ChooseSwapPresentMode(
|
||||
gsl::span<VkPresentModeKHR> present_modes);
|
||||
VkExtent2D ChooseSwapExtent(const VkSurfaceCapabilitiesKHR& capabilities);
|
||||
std::uint32_t ChooseSwapImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& capabilities);
|
||||
|
||||
VkShaderModule CreateShaderModule(gsl::span<std::uint8_t> buffer);
|
||||
|
||||
std::uint32_t FindMemoryType(std::uint32_t type_bits_filter,
|
||||
VkMemoryPropertyFlags required_properties);
|
||||
|
||||
BufferHandle CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties);
|
||||
VkCommandBuffer BeginTransientCommandBuffer();
|
||||
void EndTransientCommandBuffer(VkCommandBuffer command_buffer);
|
||||
void CreateUniformBuffers();
|
||||
|
||||
TextureHandle CreateImage(glm::ivec2 size, VkFormat image_format,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties);
|
||||
void TransitionImageLayout(VkImage image, VkImageLayout old_layout,
|
||||
VkImageLayout new_layout);
|
||||
void CopyBufferToImage(VkBuffer buffer, VkImage image, glm::ivec2 image_size);
|
||||
VkImageView CreateImageView(VkImage image, VkFormat format,
|
||||
VkImageAspectFlags aspect_flag);
|
||||
|
||||
VkViewport GetViewport();
|
||||
VkRect2D GetScissor();
|
||||
|
||||
std::array<gsl::czstring, 1> required_device_extentions_ = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME};
|
||||
|
||||
VkInstance instance_ = VK_NULL_HANDLE;
|
||||
VkDebugUtilsMessengerEXT debug_messenger_;
|
||||
|
||||
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
|
||||
VkDevice logical_device_ = VK_NULL_HANDLE;
|
||||
VkQueue graphics_queue_ = VK_NULL_HANDLE;
|
||||
VkQueue present_queue_ = VK_NULL_HANDLE;
|
||||
|
||||
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR swap_chain_ = VK_NULL_HANDLE;
|
||||
VkSurfaceFormatKHR surface_format_;
|
||||
VkPresentModeKHR present_mode_;
|
||||
VkExtent2D extent_;
|
||||
|
||||
std::vector<VkImage> swap_chain_images_;
|
||||
std::vector<VkImageView> swap_chain_image_views_;
|
||||
std::vector<VkFramebuffer> swap_chain_framebuffers_;
|
||||
|
||||
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||
VkRenderPass render_pass_ = VK_NULL_HANDLE;
|
||||
VkPipeline pipeline_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout descriptor_set_layout_ = VK_NULL_HANDLE;
|
||||
|
||||
VkCommandPool command_pool_ = VK_NULL_HANDLE;
|
||||
|
||||
std::uint32_t current_image_index_ = 0;
|
||||
|
||||
VkDescriptorSetLayout uniform_set_layout_ = VK_NULL_HANDLE;
|
||||
VkDescriptorPool uniform_pool_ = VK_NULL_HANDLE;
|
||||
|
||||
|
||||
VkDescriptorSetLayout texture_set_layout_ = VK_NULL_HANDLE;
|
||||
VkDescriptorPool texture_pool_ = VK_NULL_HANDLE;
|
||||
VkSampler texture_sampler_ = VK_NULL_HANDLE;
|
||||
TextureHandle depth_texture_;
|
||||
|
||||
std::array<Frame, MAX_BUFFERED_FRAMES> frames_;
|
||||
std::int32_t current_frame_ = 0;
|
||||
|
||||
bool validation_enabled_ = false;
|
||||
};
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT GetCreateMessengerInfo();
|
||||
bool IsExtensionSupported(gsl::span<VkExtensionProperties> extensions,
|
||||
gsl::czstring name);
|
||||
|
||||
} // namespace veng
|
||||
20
Client/include/vulkan/physics.h
Normal file
20
Client/include/vulkan/physics.h
Normal file
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include "asset/object/model.h"
|
||||
#include "vulkan/vertex.h"
|
||||
|
||||
namespace veng {
|
||||
class Physics {
|
||||
public:
|
||||
void invokeOnColisionEvent(gsl::span<Model*> models);
|
||||
|
||||
bool RayTrace(const glm::vec3& rayOrigin, const glm::vec3& rayDir,
|
||||
const glm::vec3& v0, const glm::vec3& v1, const glm::vec3& v2,
|
||||
std::float_t& outDistance);
|
||||
|
||||
private:
|
||||
bool IsPointInsideMesh_(const glm::vec3& point,
|
||||
const std::vector<veng::Vertex>& vertices,
|
||||
const std::vector<std::uint32_t>& indices);
|
||||
};
|
||||
} // namespace veng
|
||||
14
Client/include/vulkan/texture_handle.h
Normal file
14
Client/include/vulkan/texture_handle.h
Normal file
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace veng {
|
||||
|
||||
struct TextureHandle {
|
||||
VkImage image = VK_NULL_HANDLE;
|
||||
VkImageView image_view = VK_NULL_HANDLE;
|
||||
VkDeviceMemory memory = VK_NULL_HANDLE;
|
||||
VkDescriptorSet set = VK_NULL_HANDLE;
|
||||
};
|
||||
|
||||
} // namespace veng
|
||||
8
Client/include/vulkan/uniform_transformations.h
Normal file
8
Client/include/vulkan/uniform_transformations.h
Normal file
@@ -0,0 +1,8 @@
|
||||
#pragma once
|
||||
|
||||
namespace veng {
|
||||
struct UniformTransformations {
|
||||
glm::mat4 view;
|
||||
glm::mat4 projection;
|
||||
};
|
||||
} // namespace veng
|
||||
38
Client/include/vulkan/vertex.h
Normal file
38
Client/include/vulkan/vertex.h
Normal file
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace veng {
|
||||
struct Vertex {
|
||||
Vertex() : position(glm::vec3(0.f)), uv(glm::vec2(0.f)) {}
|
||||
Vertex(glm::vec3 _position, glm::vec2 _uv) : position(_position), uv(_uv) {}
|
||||
|
||||
glm::vec3 position;
|
||||
glm::vec2 uv;
|
||||
|
||||
static VkVertexInputBindingDescription GetBindingDescription() {
|
||||
VkVertexInputBindingDescription description = {};
|
||||
description.binding = 0;
|
||||
description.stride = sizeof(Vertex);
|
||||
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
|
||||
return description;
|
||||
}
|
||||
|
||||
static std::array<VkVertexInputAttributeDescription, 2> GetAttributeDescriptions() {
|
||||
std::array<VkVertexInputAttributeDescription, 2> descriptions = {};
|
||||
|
||||
descriptions[0].binding = 0;
|
||||
descriptions[0].location = 0;
|
||||
descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
descriptions[0].offset = offsetof(Vertex, position);
|
||||
|
||||
descriptions[1].binding = 0;
|
||||
descriptions[1].location = 1;
|
||||
descriptions[1].format = VK_FORMAT_R32G32_SFLOAT;
|
||||
descriptions[1].offset = offsetof(Vertex, uv);
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
};
|
||||
} // namespace veng
|
||||
11
Client/shaders/basic.frag
Normal file
11
Client/shaders/basic.frag
Normal file
@@ -0,0 +1,11 @@
|
||||
#version 450
|
||||
#include "common.glsl"
|
||||
|
||||
layout(location = 0) in vec2 vertex_uv;
|
||||
layout(location = 0) out vec4 out_color;
|
||||
|
||||
layout(set = 1, binding = 0) uniform sampler2D texture_sampler;
|
||||
|
||||
void main() {
|
||||
out_color = texture(texture_sampler, vertex_uv);
|
||||
}
|
||||
16
Client/shaders/basic.vert
Normal file
16
Client/shaders/basic.vert
Normal file
@@ -0,0 +1,16 @@
|
||||
#version 450
|
||||
#include "common.glsl"
|
||||
|
||||
layout(location = 0) in vec3 input_position;
|
||||
layout(location = 1) in vec2 input_uv;
|
||||
|
||||
layout(location = 0) out vec2 vertex_uv;
|
||||
|
||||
layout(push_constant) uniform Model {
|
||||
mat4 transformation;
|
||||
} model;
|
||||
|
||||
void main() {
|
||||
gl_Position = camera.projection * camera.view * model.transformation * vec4(input_position, 1.0);
|
||||
vertex_uv = input_uv;
|
||||
}
|
||||
7
Client/shaders/common.glsl
Normal file
7
Client/shaders/common.glsl
Normal file
@@ -0,0 +1,7 @@
|
||||
#extension GL_KHR_vulkan_glsl : enable
|
||||
|
||||
layout(set = 0, binding = 0) uniform UniformTransformations {
|
||||
mat4 view;
|
||||
mat4 projection;
|
||||
}
|
||||
camera;
|
||||
65
Client/src/asset/loader.cpp
Normal file
65
Client/src/asset/loader.cpp
Normal file
@@ -0,0 +1,65 @@
|
||||
#include "asset/loader.h"
|
||||
|
||||
#include "stb/stb_image.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
void Loader::setPath(std::string path) {
|
||||
scene_ = importer_.ReadFile(
|
||||
path.c_str(), aiProcess_CalcTangentSpace | aiProcess_Triangulate |
|
||||
aiProcess_JoinIdenticalVertices |
|
||||
aiProcess_SortByPType | aiProcess_FlipUVs);
|
||||
if (scene_ == nullptr || !scene_->HasMeshes())
|
||||
throw std::runtime_error(importer_.GetErrorString());
|
||||
}
|
||||
void Loader::loadModel(inModel model) {
|
||||
aiMesh* mesh = scene_->mMeshes[0];
|
||||
|
||||
for (std::uint32_t i = 0; i < mesh->mNumVertices; i++) {
|
||||
glm::vec2 uv = {mesh->mTextureCoords[0][i].x, mesh->mTextureCoords[0][i].y};
|
||||
model.vertices.emplace_back(
|
||||
glm::vec3{mesh->mVertices[i].x, mesh->mVertices[i].y,
|
||||
mesh->mVertices[i].z},
|
||||
uv);
|
||||
}
|
||||
|
||||
for (Vertex& const it : model.vertices) {
|
||||
model.original_offset.x += it.position.x / model.vertices.size();
|
||||
model.original_offset.y += it.position.y / model.vertices.size();
|
||||
model.original_offset.z += it.position.z / model.vertices.size();
|
||||
}
|
||||
|
||||
for (Vertex& vertex : model.vertices) {
|
||||
vertex.position -= model.original_offset;
|
||||
model.radius = (model.radius < glm::length(vertex.position))
|
||||
? glm::length(vertex.position)
|
||||
: model.radius;
|
||||
}
|
||||
|
||||
for (std::uint32_t i = 0; i < mesh->mNumFaces; i++) {
|
||||
aiFace face = mesh->mFaces[i];
|
||||
for (unsigned int j = 0; j < face.mNumIndices; ++j) {
|
||||
model.indices.push_back(face.mIndices[j]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<std::uint8_t> Loader::readTexture() {
|
||||
aiString texture_path;
|
||||
if (scene_->mMaterials[scene_->mMeshes[0]->mMaterialIndex]->GetTexture(
|
||||
aiTextureType_DIFFUSE, 0, &texture_path) != AI_SUCCESS) {
|
||||
spdlog::warn("No texture");
|
||||
}
|
||||
|
||||
if (scene_->mNumTextures > 0 || texture_path.C_Str()[0] == '*') {
|
||||
const aiTexture* texture = scene_->GetEmbeddedTexture(texture_path.C_Str());
|
||||
|
||||
return std::vector<std::uint8_t>(
|
||||
(std::uint8_t*)texture->pcData,
|
||||
(std::uint8_t*)texture->pcData + texture->mWidth);
|
||||
}
|
||||
|
||||
return ReadFile(texture_path.C_Str());
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
30
Client/src/asset/object/model.cpp
Normal file
30
Client/src/asset/object/model.cpp
Normal file
@@ -0,0 +1,30 @@
|
||||
#include "asset/object/model.h"
|
||||
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
Model::~Model() {
|
||||
if (graphics_ == nullptr) return;
|
||||
|
||||
graphics_->DestroyTexture(material.texture_handle);
|
||||
graphics_->DestroyBuffer(vertex_buffer);
|
||||
graphics_->DestroyBuffer(index_buffer);
|
||||
}
|
||||
|
||||
void veng::Model::Update(float dt) {
|
||||
linear_velocity += linear_acceleration * dt;
|
||||
position += linear_velocity * dt;
|
||||
|
||||
angular_velocity += angular_acceleration * dt;
|
||||
if (glm::length(angular_velocity) > 1e-6f) {
|
||||
rotation =
|
||||
glm::normalize(glm::rotate(rotation, glm::length(angular_velocity * dt),
|
||||
glm::normalize(angular_velocity)));
|
||||
}
|
||||
|
||||
transform = glm::translate(glm::mat4(1.0f), position) *
|
||||
glm::mat4_cast(rotation) * glm::scale(glm::mat4(1.0f), scale);
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
21
Client/src/glfw/glfw_initialization.cpp
Normal file
21
Client/src/glfw/glfw_initialization.cpp
Normal file
@@ -0,0 +1,21 @@
|
||||
#include "glfw/glfw_initialization.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <cstdlib>
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
void glfw_error_callback(std::int32_t error_code, gsl::czstring message) {
|
||||
spdlog::error("Glfw Validation: {}", message);
|
||||
}
|
||||
|
||||
GlfwInitialization::GlfwInitialization() {
|
||||
glfwSetErrorCallback(glfw_error_callback);
|
||||
if (glfwInit() != GLFW_TRUE) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
GlfwInitialization::~GlfwInitialization() { glfwTerminate(); }
|
||||
|
||||
} // namespace veng
|
||||
34
Client/src/glfw/glfw_moniotr.cpp
Normal file
34
Client/src/glfw/glfw_moniotr.cpp
Normal file
@@ -0,0 +1,34 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "glfw/glfw_monitor.h"
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
gsl::span<GLFWmonitor *> GetMonitors() {
|
||||
std::int32_t monitor_count = 0;
|
||||
GLFWmonitor **monitor_pointers = glfwGetMonitors(&monitor_count);
|
||||
return gsl::span<GLFWmonitor *>(monitor_pointers, monitor_count);
|
||||
}
|
||||
|
||||
glm::ivec2 GetMonitorPosition(gsl::not_null<GLFWmonitor *> monitor) {
|
||||
glm::ivec2 monitor_position;
|
||||
glfwGetMonitorPos(monitor, &monitor_position.x, &monitor_position.y);
|
||||
return monitor_position;
|
||||
}
|
||||
glm::ivec2 GetMonitorWorkAreaSize(gsl::not_null<GLFWmonitor *> monitor) {
|
||||
glm::ivec2 monitor_size;
|
||||
glfwGetMonitorWorkarea(monitor, nullptr, nullptr, &monitor_size.x,
|
||||
&monitor_size.y);
|
||||
return monitor_size;
|
||||
}
|
||||
|
||||
void MoveWindowToMonitor(gsl::not_null<GLFWwindow *> window,
|
||||
gsl::not_null<GLFWmonitor *> monitor) {
|
||||
glm::ivec2 window_size;
|
||||
glfwGetWindowSize(window, &window_size.x, &window_size.y);
|
||||
const glm::ivec2 window_new_position = GetMonitorPosition(monitor) +
|
||||
(GetMonitorWorkAreaSize(monitor) / 2) -
|
||||
(window_size / 2);
|
||||
glfwSetWindowPos(window, window_new_position.x, window_new_position.y);
|
||||
}
|
||||
} // namespace veng
|
||||
50
Client/src/glfw/glfw_window.cpp
Normal file
50
Client/src/glfw/glfw_window.cpp
Normal file
@@ -0,0 +1,50 @@
|
||||
#include "glfw/glfw_window.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "glfw/glfw_monitor.h"
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
Window::Window(gsl::czstring name, glm::ivec2 size) {
|
||||
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
window_ = glfwCreateWindow(size.x, size.y, name, nullptr, nullptr);
|
||||
if (window_ == nullptr) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
Window::~Window() { glfwDestroyWindow(window_); }
|
||||
|
||||
glm::ivec2 Window::GetWindowSize() const {
|
||||
glm::ivec2 window_size;
|
||||
glfwGetWindowSize(window_, &window_size.x, &window_size.y);
|
||||
return window_size;
|
||||
}
|
||||
|
||||
glm::ivec2 Window::GetFramebufferSize() const {
|
||||
glm::ivec2 size;
|
||||
glfwGetFramebufferSize(window_, &size.x, &size.y);
|
||||
return size;
|
||||
}
|
||||
|
||||
bool Window::ShouldClose() const { return glfwWindowShouldClose(window_); }
|
||||
|
||||
GLFWwindow* Window::GetHandle() const { return window_; }
|
||||
|
||||
GLFWkeyfun Window::SetKeyCallback(GLFWkeyfun key_callback) {
|
||||
return glfwSetKeyCallback(window_, key_callback);
|
||||
}
|
||||
|
||||
bool Window::TryMoveToMonitor(std::uint16_t monitor_number) {
|
||||
gsl::span<GLFWmonitor*> monitors = veng::GetMonitors();
|
||||
|
||||
if (monitor_number < monitors.size()) {
|
||||
veng::MoveWindowToMonitor(window_, monitors[monitor_number]);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
199
Client/src/main.cpp
Normal file
199
Client/src/main.cpp
Normal file
@@ -0,0 +1,199 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include "asset/loader.h"
|
||||
#include "glfw/glfw_initialization.h"
|
||||
#include "glfw/glfw_monitor.h"
|
||||
#include "glfw/glfw_window.h"
|
||||
#include "precomp.h"
|
||||
#include "vulkan/coordinate.h"
|
||||
#include "vulkan/engine.h"
|
||||
#include "vulkan/graphics.h"
|
||||
#include "vulkan/physics.h"
|
||||
|
||||
void BeginPlay(veng::Engine& engine) {
|
||||
veng::Model* const player = engine.SpawnModel("player", "player");
|
||||
player->scale = glm::vec3(.02f);
|
||||
player->colision = true;
|
||||
veng::Model* const player_flame =
|
||||
engine.SpawnModel("player_flame", "player_flame");
|
||||
player_flame->scale = player->scale;
|
||||
player_flame->colision = false;
|
||||
|
||||
std::cout << "player addr: " << player << std::endl;
|
||||
|
||||
veng::Model* const other_player = engine.SpawnModel("player", "other_player");
|
||||
other_player->position = glm::vec3(1.f, 0.f, 0.f);
|
||||
other_player->scale = glm::vec3(.02f);
|
||||
other_player->colision = true;
|
||||
other_player->OnColision = [](veng::Model* self, veng::Model* other) {
|
||||
if (other->owner == self) return;
|
||||
std::cout << self << " and " << other << " is Nearby." << std::endl;
|
||||
|
||||
std::cout << self << "'s owner: " << self->owner << std::endl;
|
||||
std::cout << other << "'s owner: " << other->owner << std::endl;
|
||||
|
||||
std::cout << "Colided." << std::endl;
|
||||
other->colision = false;
|
||||
other->visible = false;
|
||||
};
|
||||
|
||||
std::cout << "other player addr: " << other_player << std::endl;
|
||||
|
||||
veng::Model* const camera_lag = engine.SpawnModel("", "camera_lag");
|
||||
camera_lag->colision = false;
|
||||
camera_lag->position = player->position;
|
||||
|
||||
veng::Model* const background = engine.SpawnModel("", "background");
|
||||
background->colision = false;
|
||||
background->position = {background->position.x, background->position.y, 30.f};
|
||||
background->scale *= 100;
|
||||
|
||||
veng::Model* const background0 =
|
||||
engine.SpawnModel("background", "background0");
|
||||
background0->scale = background->scale;
|
||||
veng::Model* const background1 =
|
||||
engine.SpawnModel("background", "background1");
|
||||
background1->scale = background->scale;
|
||||
veng::Model* const background2 =
|
||||
engine.SpawnModel("background", "background2");
|
||||
background2->scale = background->scale;
|
||||
veng::Model* const background3 =
|
||||
engine.SpawnModel("background", "background3");
|
||||
background3->scale = background->scale;
|
||||
}
|
||||
|
||||
void Tick(veng::Engine& engine, std::float_t delta_time) {
|
||||
static std::float_t bullet_cooldown = 0.f;
|
||||
|
||||
veng::Model* const player = engine.GetSpawnedObject("player");
|
||||
veng::Model* const player_flame = engine.GetSpawnedObject("player_flame");
|
||||
veng::Model* const camera_lag = engine.GetSpawnedObject("camera_lag");
|
||||
|
||||
veng::Model* const background = engine.GetSpawnedObject("background");
|
||||
veng::Model* const background0 = engine.GetSpawnedObject("background0");
|
||||
veng::Model* const background1 = engine.GetSpawnedObject("background1");
|
||||
veng::Model* const background2 = engine.GetSpawnedObject("background2");
|
||||
veng::Model* const background3 = engine.GetSpawnedObject("background3");
|
||||
|
||||
glm::vec3 forward = player->rotation * glm::vec3(0, 1, 0);
|
||||
glm::vec3 right = player->rotation * glm::vec3(1, 0, 0);
|
||||
|
||||
std::float_t stiffness =
|
||||
500.0f * ((glm::length(player->linear_velocity) > 1.f)
|
||||
? glm::length(player->linear_velocity)
|
||||
: 1.f); // 더 크면 빠르게 따라감
|
||||
std::float_t damping = 10.f * glm::sqrt(stiffness); // 임계 감쇠
|
||||
|
||||
// 감쇠 스프링 업데이트
|
||||
glm::vec3 displacement = camera_lag->position - player->position;
|
||||
|
||||
camera_lag->linear_velocity +=
|
||||
(-stiffness * displacement - damping * camera_lag->linear_velocity) *
|
||||
delta_time;
|
||||
|
||||
engine.view = glm::lookAt(
|
||||
glm::vec3(camera_lag->position.x, camera_lag->position.y, -5.f),
|
||||
camera_lag->position, glm::vec3(0.f, -1.f, 0.f));
|
||||
|
||||
if (glfwGetKey(engine.vulkan_graphics->window->GetHandle(), GLFW_KEY_W) ==
|
||||
GLFW_PRESS) {
|
||||
player->linear_acceleration = glm::normalize(forward) * 10.f;
|
||||
player_flame->visible = true;
|
||||
} else {
|
||||
player->linear_acceleration = forward * .0f;
|
||||
player_flame->visible = false;
|
||||
}
|
||||
|
||||
if (bullet_cooldown > std::numeric_limits<std::float_t>::epsilon()) {
|
||||
bullet_cooldown -= delta_time;
|
||||
}
|
||||
if (glfwGetKey(engine.vulkan_graphics->window->GetHandle(), GLFW_KEY_SPACE) ==
|
||||
GLFW_PRESS) {
|
||||
if (bullet_cooldown > std::numeric_limits<std::float_t>::epsilon()) {
|
||||
bullet_cooldown - delta_time;
|
||||
} else {
|
||||
bullet_cooldown = .2f;
|
||||
veng::Model* const bullet =
|
||||
engine.SpawnLifedModel("bullet", "bullet", 10.f);
|
||||
bullet->linear_velocity = player->linear_velocity + forward * 10.f;
|
||||
bullet->position = player->position + forward * player->scale.x * 10.f;
|
||||
bullet->owner = player;
|
||||
bullet->scale = player->scale;
|
||||
bullet->colision = true;
|
||||
|
||||
std::cout << "bullet address: " << bullet << std::endl;
|
||||
}
|
||||
}
|
||||
if (glfwGetKey(engine.vulkan_graphics->window->GetHandle(), GLFW_KEY_A) ==
|
||||
GLFW_PRESS) {
|
||||
right = player->rotation * glm::vec3(0, 0, 1);
|
||||
player->angular_velocity = right * 6.f;
|
||||
} else if (glfwGetKey(engine.vulkan_graphics->window->GetHandle(),
|
||||
GLFW_KEY_D) == GLFW_PRESS) {
|
||||
right = player->rotation * glm::vec3(0, 0, 1);
|
||||
player->angular_velocity = right * -6.f;
|
||||
} else {
|
||||
right = player->rotation * glm::vec3(0, 0, 1);
|
||||
player->angular_velocity = right * 0.f;
|
||||
}
|
||||
|
||||
player_flame->rotation = player->rotation;
|
||||
player_flame->position =
|
||||
player->position + player->rotation * player_flame->original_offset *
|
||||
0.5f * player_flame->scale;
|
||||
|
||||
if (player->position.x - background->position.x >= background->scale.x)
|
||||
background->position += glm::vec3(2.f, 0.f, 0.f) * background->scale;
|
||||
if (player->position.x - background->position.x < -background->scale.x)
|
||||
background->position -= glm::vec3(2.f, 0.f, 0.f) * background->scale;
|
||||
if (player->position.y - background->position.y >= background->scale.y)
|
||||
background->position += glm::vec3(0.f, 2.f, 0.f) * background->scale;
|
||||
if (player->position.y - background->position.y < -background->scale.y)
|
||||
background->position -= glm::vec3(0.f, 2.f, 0.f) * background->scale;
|
||||
|
||||
glm::vec3 sparse;
|
||||
|
||||
sparse = glm::vec3(1.f, 1.f, 0.f);
|
||||
background0->position = background->position + sparse * background->scale;
|
||||
|
||||
sparse = glm::vec3(-1.f, 1.f, 0.f);
|
||||
background1->position = background->position + sparse * background->scale;
|
||||
|
||||
sparse = glm::vec3(1.f, -1.f, 0.f);
|
||||
background2->position = background->position + sparse * background->scale;
|
||||
|
||||
sparse = glm::vec3(-1.f, -1.f, 0.f);
|
||||
background3->position = background->position + sparse * background->scale;
|
||||
}
|
||||
|
||||
std::int32_t main(std::int32_t argc, gsl::zstring* argv) {
|
||||
const veng::GlfwInitialization _glfw;
|
||||
|
||||
veng::Window window("Vulkan Engine", {800, 600});
|
||||
window.TryMoveToMonitor(0);
|
||||
|
||||
veng::Graphics graphics(&window);
|
||||
veng::Engine engine(&graphics);
|
||||
|
||||
engine.LoadModelAsset("assets/player.fbx", "player");
|
||||
engine.LoadModelAsset("assets/player_flame.fbx", "player_flame");
|
||||
engine.LoadModelAsset("assets/bullet.fbx", "bullet");
|
||||
engine.LoadModelAsset("assets/background.fbx", "background");
|
||||
|
||||
engine.BeginPlay = BeginPlay;
|
||||
engine.Tick = Tick;
|
||||
|
||||
engine.init();
|
||||
|
||||
while (!window.ShouldClose()) {
|
||||
glfwPollEvents();
|
||||
|
||||
engine.Update();
|
||||
}
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
}
|
||||
2
Client/src/stb/stb_image.cpp
Normal file
2
Client/src/stb/stb_image.cpp
Normal file
@@ -0,0 +1,2 @@
|
||||
#define STB_IMAGE_IMPLEMENTATION
|
||||
#include "stb/stb_image.h"
|
||||
28
Client/src/utilities.cpp
Normal file
28
Client/src/utilities.cpp
Normal file
@@ -0,0 +1,28 @@
|
||||
#include "utilities.h"
|
||||
|
||||
#include <fstream>
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
bool streq(gsl::czstring left, gsl::czstring right) {
|
||||
return std::strcmp(left, right) == 0;
|
||||
}
|
||||
std::vector<std::uint8_t> ReadFile(std::filesystem::path shader_path) {
|
||||
if (!std::filesystem::exists(shader_path)) return {};
|
||||
if (!std::filesystem::is_regular_file(shader_path)) return {};
|
||||
|
||||
std::ifstream file(shader_path, std::ios::binary);
|
||||
|
||||
if (!file.is_open()) return {};
|
||||
|
||||
std::uintmax_t file_size = std::filesystem::file_size(shader_path);
|
||||
if (file_size > std::numeric_limits<std::uint32_t>::max()) return {}; // 방어
|
||||
|
||||
std::uint32_t size = static_cast<std::uint32_t>(file_size);
|
||||
std::vector<std::uint8_t> buffer(size);
|
||||
file.read(reinterpret_cast<char*>(buffer.data()), size);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
} // namespace veng
|
||||
332
Client/src/vulkan/buffers.cpp
Normal file
332
Client/src/vulkan/buffers.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "asset/object/model.h"
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
#include "vulkan/uniform_transformations.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
std::uint32_t Graphics::FindMemoryType(
|
||||
std::uint32_t type_bits_filter, VkMemoryPropertyFlags required_properties) {
|
||||
VkPhysicalDeviceMemoryProperties memory_properties;
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties);
|
||||
gsl::span<VkMemoryType> memory_types(memory_properties.memoryTypes,
|
||||
memory_properties.memoryTypeCount);
|
||||
|
||||
for (std::uint32_t i = 0; i < memory_types.size(); i++) {
|
||||
bool passes_filter = type_bits_filter & (1 << i);
|
||||
bool has_property_flags =
|
||||
memory_types[i].propertyFlags & required_properties;
|
||||
|
||||
if (passes_filter && has_property_flags) return i;
|
||||
}
|
||||
|
||||
throw std::runtime_error("Cannot find memory type!");
|
||||
}
|
||||
|
||||
BufferHandle Graphics::CreateBuffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties) {
|
||||
BufferHandle handle = {};
|
||||
|
||||
VkBufferCreateInfo buffer_info = {};
|
||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_info.size = size;
|
||||
buffer_info.usage = usage;
|
||||
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
|
||||
VkResult result =
|
||||
vkCreateBuffer(logical_device_, &buffer_info, nullptr, &handle.buffer);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to create vertex buffer!");
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetBufferMemoryRequirements(logical_device_, handle.buffer,
|
||||
&memory_requirements);
|
||||
|
||||
std::uint32_t chosen_memory_type =
|
||||
FindMemoryType(memory_requirements.memoryTypeBits, properties);
|
||||
|
||||
VkMemoryAllocateInfo allocation_info = {};
|
||||
allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocation_info.allocationSize = memory_requirements.size;
|
||||
allocation_info.memoryTypeIndex = chosen_memory_type;
|
||||
|
||||
VkResult allocation_result = vkAllocateMemory(
|
||||
logical_device_, &allocation_info, nullptr, &handle.memory);
|
||||
if (allocation_result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to allocate buffer memory!");
|
||||
|
||||
vkBindBufferMemory(logical_device_, handle.buffer, handle.memory, 0);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
BufferHandle Graphics::CreateVertexBuffer(gsl::span<Vertex> vertices) {
|
||||
VkDeviceSize size = sizeof(Vertex) * vertices.size();
|
||||
BufferHandle staging_handle = CreateBuffer(
|
||||
size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
void* data;
|
||||
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
|
||||
std::memcpy(data, vertices.data(), size);
|
||||
vkUnmapMemory(logical_device_, staging_handle.memory);
|
||||
|
||||
BufferHandle gpu_handle = CreateBuffer(
|
||||
size,
|
||||
VK_BUFFER_USAGE_VERTEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
|
||||
|
||||
VkBufferCopy copy_info = {};
|
||||
copy_info.srcOffset = 0;
|
||||
copy_info.dstOffset = 0;
|
||||
copy_info.size = size;
|
||||
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
|
||||
1, ©_info);
|
||||
|
||||
EndTransientCommandBuffer(transient_commands);
|
||||
|
||||
DestroyBuffer(staging_handle);
|
||||
|
||||
return gpu_handle;
|
||||
}
|
||||
|
||||
BufferHandle Graphics::CreateIndexBuffer(gsl::span<std::uint32_t> indices) {
|
||||
VkDeviceSize size = sizeof(std::uint32_t) * indices.size();
|
||||
BufferHandle staging_handle =
|
||||
CreateBuffer(size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
void* data;
|
||||
vkMapMemory(logical_device_, staging_handle.memory, 0, size, 0, &data);
|
||||
std::memcpy(data, indices.data(), size);
|
||||
vkUnmapMemory(logical_device_, staging_handle.memory);
|
||||
|
||||
BufferHandle gpu_handle = CreateBuffer(
|
||||
size, VK_BUFFER_USAGE_INDEX_BUFFER_BIT | VK_BUFFER_USAGE_TRANSFER_DST_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VkCommandBuffer transient_commands = BeginTransientCommandBuffer();
|
||||
|
||||
VkBufferCopy copy_info = {};
|
||||
copy_info.srcOffset = 0;
|
||||
copy_info.dstOffset = 0;
|
||||
copy_info.size = size;
|
||||
vkCmdCopyBuffer(transient_commands, staging_handle.buffer, gpu_handle.buffer,
|
||||
1, ©_info);
|
||||
|
||||
EndTransientCommandBuffer(transient_commands);
|
||||
|
||||
DestroyBuffer(staging_handle);
|
||||
|
||||
return gpu_handle;
|
||||
}
|
||||
|
||||
void Graphics::DestroyBuffer(BufferHandle handle) {
|
||||
vkDeviceWaitIdle(logical_device_);
|
||||
vkDestroyBuffer(logical_device_, handle.buffer, nullptr);
|
||||
vkFreeMemory(logical_device_, handle.memory, nullptr);
|
||||
}
|
||||
|
||||
void Graphics::SetModelMatrix(glm::mat4 model) {
|
||||
// for (Frame& frame : frames_)
|
||||
vkCmdPushConstants(frames_[current_frame_].command_buffer, pipeline_layout_,
|
||||
VK_SHADER_STAGE_VERTEX_BIT, 0, sizeof(glm::mat4), &model);
|
||||
}
|
||||
|
||||
void Graphics::SetViewProjection(glm::mat4 view, glm::mat4 projection) {
|
||||
UniformTransformations transformations{view, projection};
|
||||
for (Frame& frame : frames_)
|
||||
std::memcpy(frame.uniform_buffer_location, &transformations,
|
||||
sizeof(UniformTransformations));
|
||||
}
|
||||
|
||||
void Graphics::RenderBuffer(BufferHandle handle, std::uint32_t vertex_count) {
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
|
||||
1, &frames_[current_frame_].uniform_set, 0, nullptr);
|
||||
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
|
||||
&handle.buffer, &offset);
|
||||
vkCmdDraw(frames_[current_frame_].command_buffer, vertex_count, 1, 0, 0);
|
||||
}
|
||||
|
||||
void Graphics::RenderIndexedBuffer(BufferHandle vertex_buffer,
|
||||
BufferHandle index_buffer,
|
||||
std::uint32_t count) {
|
||||
VkDeviceSize offset = 0;
|
||||
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_layout_, 0,
|
||||
1, &frames_[current_frame_].uniform_set, 0, nullptr);
|
||||
vkCmdBindVertexBuffers(frames_[current_frame_].command_buffer, 0, 1,
|
||||
&vertex_buffer.buffer, &offset);
|
||||
vkCmdBindIndexBuffer(frames_[current_frame_].command_buffer,
|
||||
index_buffer.buffer, 0, VK_INDEX_TYPE_UINT32);
|
||||
vkCmdDrawIndexed(frames_[current_frame_].command_buffer, count, 1, 0, 0, 0);
|
||||
SetModelMatrix(glm::mat4(1.f));
|
||||
}
|
||||
void Graphics::RenderModel(Model* model) {
|
||||
if (!model->visible) return;
|
||||
SetTexture(model->material.texture_handle);
|
||||
SetModelMatrix(model->transform);
|
||||
RenderIndexedBuffer(model->vertex_buffer, model->index_buffer,
|
||||
model->indices.size());
|
||||
}
|
||||
|
||||
VkCommandBuffer Graphics::BeginTransientCommandBuffer() {
|
||||
VkCommandBufferAllocateInfo allocation_info = {};
|
||||
allocation_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
allocation_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
allocation_info.commandPool = command_pool_;
|
||||
allocation_info.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer buffer;
|
||||
vkAllocateCommandBuffers(logical_device_, &allocation_info, &buffer);
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
vkBeginCommandBuffer(buffer, &begin_info);
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
void Graphics::EndTransientCommandBuffer(VkCommandBuffer command_buffer) {
|
||||
vkEndCommandBuffer(command_buffer);
|
||||
|
||||
VkSubmitInfo submit_info = {};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffer;
|
||||
|
||||
vkQueueSubmit(graphics_queue_, 1, &submit_info, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(graphics_queue_);
|
||||
vkFreeCommandBuffers(logical_device_, command_pool_, 1, &command_buffer);
|
||||
}
|
||||
|
||||
void Graphics::CreateUniformBuffers() {
|
||||
VkDeviceSize buffer_size = sizeof(UniformTransformations);
|
||||
for (Frame& frame : frames_) {
|
||||
frame.uniform_buffer =
|
||||
CreateBuffer(buffer_size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vkMapMemory(logical_device_, frame.uniform_buffer.memory, 0, buffer_size, 0,
|
||||
&frame.uniform_buffer_location);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::CreateDescriptorSetLayouts() {
|
||||
VkDescriptorSetLayoutBinding uniform_layout_binding = {};
|
||||
uniform_layout_binding.binding = 0;
|
||||
uniform_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uniform_layout_binding.descriptorCount = 1;
|
||||
uniform_layout_binding.stageFlags = VK_SHADER_STAGE_ALL_GRAPHICS;
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo uniform_layout_info = {};
|
||||
uniform_layout_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
uniform_layout_info.bindingCount = 1;
|
||||
uniform_layout_info.pBindings = &uniform_layout_binding;
|
||||
|
||||
if (vkCreateDescriptorSetLayout(logical_device_, &uniform_layout_info,
|
||||
nullptr,
|
||||
&uniform_set_layout_) != VK_SUCCESS) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
VkDescriptorSetLayoutBinding texture_layout_binding = {};
|
||||
texture_layout_binding.binding = 0;
|
||||
texture_layout_binding.descriptorType =
|
||||
VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
texture_layout_binding.descriptorCount = 1;
|
||||
texture_layout_binding.stageFlags = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo texture_layout_info = {};
|
||||
texture_layout_info.sType =
|
||||
VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
texture_layout_info.bindingCount = 1;
|
||||
texture_layout_info.pBindings = &texture_layout_binding;
|
||||
|
||||
if (vkCreateDescriptorSetLayout(logical_device_, &texture_layout_info,
|
||||
nullptr,
|
||||
&texture_set_layout_) != VK_SUCCESS) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::CreateDescriptorPools() {
|
||||
VkDescriptorPoolSize uniform_pool_size = {};
|
||||
uniform_pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
uniform_pool_size.descriptorCount = MAX_BUFFERED_FRAMES;
|
||||
|
||||
VkDescriptorPoolCreateInfo uniform_create_info = {};
|
||||
uniform_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
uniform_create_info.poolSizeCount = 1;
|
||||
uniform_create_info.pPoolSizes = &uniform_pool_size;
|
||||
uniform_create_info.maxSets = MAX_BUFFERED_FRAMES;
|
||||
|
||||
if (vkCreateDescriptorPool(logical_device_, &uniform_create_info, nullptr,
|
||||
&uniform_pool_) != VK_SUCCESS) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceProperties properties = {};
|
||||
vkGetPhysicalDeviceProperties(physical_device_, &properties);
|
||||
|
||||
VkDescriptorPoolSize texture_pool_size = {};
|
||||
texture_pool_size.type = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
texture_pool_size.descriptorCount =
|
||||
properties.limits.maxSamplerAllocationCount;
|
||||
|
||||
VkDescriptorPoolCreateInfo texture_create_info = {};
|
||||
texture_create_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
texture_create_info.poolSizeCount = 1;
|
||||
texture_create_info.pPoolSizes = &texture_pool_size;
|
||||
texture_create_info.maxSets = properties.limits.maxSamplerAllocationCount;
|
||||
texture_create_info.flags = VK_DESCRIPTOR_POOL_CREATE_FREE_DESCRIPTOR_SET_BIT;
|
||||
|
||||
if (vkCreateDescriptorPool(logical_device_, &texture_create_info, nullptr,
|
||||
&texture_pool_) != VK_SUCCESS) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::CreateDescriptorSets() {
|
||||
for (Frame& frame : frames_) {
|
||||
VkDescriptorSetAllocateInfo set_info = {};
|
||||
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
set_info.descriptorPool = uniform_pool_;
|
||||
set_info.descriptorSetCount = 1;
|
||||
set_info.pSetLayouts = &uniform_set_layout_;
|
||||
|
||||
VkResult result = vkAllocateDescriptorSets(logical_device_, &set_info,
|
||||
&frame.uniform_set);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
|
||||
VkDescriptorBufferInfo buffer_info = {};
|
||||
buffer_info.buffer = frame.uniform_buffer.buffer;
|
||||
buffer_info.offset = 0;
|
||||
buffer_info.range = sizeof(UniformTransformations);
|
||||
|
||||
VkWriteDescriptorSet descriptor_write = {};
|
||||
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_write.dstSet = frame.uniform_set;
|
||||
descriptor_write.dstBinding = 0;
|
||||
descriptor_write.dstArrayElement = 0;
|
||||
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
descriptor_write.descriptorCount = 1;
|
||||
descriptor_write.pBufferInfo = &buffer_info;
|
||||
|
||||
vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
102
Client/src/vulkan/class.cpp
Normal file
102
Client/src/vulkan/class.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
Graphics::Graphics(gsl::not_null<Window*> window) : window(window) {
|
||||
#if !defined(NDEBUG)
|
||||
validation_enabled_ = true;
|
||||
#endif
|
||||
InitializeVulkan();
|
||||
}
|
||||
|
||||
Graphics::~Graphics() {
|
||||
if (logical_device_ != VK_NULL_HANDLE) {
|
||||
vkDeviceWaitIdle(logical_device_);
|
||||
CleanupSwapChain();
|
||||
DestroyTexture(depth_texture_);
|
||||
|
||||
if (texture_pool_ != VK_NULL_HANDLE)
|
||||
vkDestroyDescriptorPool(logical_device_, texture_pool_, nullptr);
|
||||
|
||||
if (texture_set_layout_ != VK_NULL_HANDLE)
|
||||
vkDestroyDescriptorSetLayout(logical_device_, texture_set_layout_,
|
||||
nullptr);
|
||||
|
||||
if (texture_sampler_ != VK_NULL_HANDLE)
|
||||
vkDestroySampler(logical_device_, texture_sampler_, nullptr);
|
||||
|
||||
if (uniform_pool_ != VK_NULL_HANDLE)
|
||||
vkDestroyDescriptorPool(logical_device_, uniform_pool_, nullptr);
|
||||
|
||||
for (Frame& frame : frames_) {
|
||||
DestroyBuffer(frame.uniform_buffer);
|
||||
|
||||
if (frame.image_available_signal != VK_NULL_HANDLE)
|
||||
vkDestroySemaphore(logical_device_, frame.image_available_signal,
|
||||
nullptr);
|
||||
|
||||
if (frame.render_finished_signal != VK_NULL_HANDLE)
|
||||
vkDestroySemaphore(logical_device_, frame.render_finished_signal,
|
||||
nullptr);
|
||||
|
||||
if (frame.still_rendering_fence != VK_NULL_HANDLE)
|
||||
vkDestroyFence(logical_device_, frame.still_rendering_fence, nullptr);
|
||||
}
|
||||
|
||||
if (uniform_set_layout_ != VK_NULL_HANDLE)
|
||||
vkDestroyDescriptorSetLayout(logical_device_, uniform_set_layout_,
|
||||
nullptr);
|
||||
|
||||
if (command_pool_ != VK_NULL_HANDLE)
|
||||
vkDestroyCommandPool(logical_device_, command_pool_, nullptr);
|
||||
|
||||
if (logical_device_ != VK_NULL_HANDLE)
|
||||
vkDestroyPipeline(logical_device_, pipeline_, nullptr);
|
||||
|
||||
if (pipeline_layout_ != VK_NULL_HANDLE)
|
||||
vkDestroyPipelineLayout(logical_device_, pipeline_layout_, nullptr);
|
||||
|
||||
if (render_pass_ != VK_NULL_HANDLE)
|
||||
vkDestroyRenderPass(logical_device_, render_pass_, nullptr);
|
||||
|
||||
vkDestroyDevice(logical_device_, nullptr);
|
||||
}
|
||||
if (instance_ != VK_NULL_HANDLE) {
|
||||
if (surface_ != VK_NULL_HANDLE)
|
||||
vkDestroySurfaceKHR(instance_, surface_, nullptr);
|
||||
|
||||
if (debug_messenger_ != VK_NULL_HANDLE)
|
||||
vkDestroyDebugUtilsMessengerEXT(instance_, debug_messenger_, nullptr);
|
||||
|
||||
vkDestroyInstance(instance_, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::InitializeVulkan() {
|
||||
CreateInstance();
|
||||
SetupDebugMessenger();
|
||||
CreateSurface();
|
||||
PickPhysicalDevice();
|
||||
CreateLogicalDeviceAndQueues();
|
||||
CreateSwapChain();
|
||||
CreateImageViews();
|
||||
CreateRenderPass();
|
||||
CreateDescriptorSetLayouts();
|
||||
CreateGraphicsPipeline();
|
||||
CreateDepthResources();
|
||||
CreateFramebuffers();
|
||||
CreateCommandPool();
|
||||
CreateCommandBuffer();
|
||||
CreateSignals();
|
||||
CreateUniformBuffers();
|
||||
CreateDescriptorPools();
|
||||
CreateDescriptorSets();
|
||||
CreateTextureSampler();
|
||||
TransitionImageLayout(depth_texture_.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL);
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
62
Client/src/vulkan/coordinate.cpp
Normal file
62
Client/src/vulkan/coordinate.cpp
Normal file
@@ -0,0 +1,62 @@
|
||||
#include "vulkan/coordinate.h"
|
||||
|
||||
namespace veng {
|
||||
Coord Coord::operator+(const Coord& other) const {
|
||||
Coord result;
|
||||
result.seg.x = this->seg.x + other.seg.x;
|
||||
result.seg.y = this->seg.y + other.seg.y;
|
||||
result.seg.z = this->seg.z + other.seg.z;
|
||||
|
||||
if (this->pos.x + other.pos.x > border) {
|
||||
result.seg.x += 1;
|
||||
result.pos.x += glm::mod(this->pos.x, border);
|
||||
result.pos.x += glm::mod(other.pos.x, border);
|
||||
} else {
|
||||
result.pos.x = this->pos.x + other.pos.x;
|
||||
}
|
||||
if (this->pos.y + other.pos.y > border) {
|
||||
result.seg.y += 1;
|
||||
result.pos.y += glm::mod(this->pos.y, border);
|
||||
result.pos.y += glm::mod(other.pos.y, border);
|
||||
} else {
|
||||
result.pos.y = this->pos.y + other.pos.y;
|
||||
}
|
||||
if (this->pos.z + other.pos.z > border) {
|
||||
result.seg.z += 1;
|
||||
result.pos.z += glm::mod(this->pos.z, border);
|
||||
result.pos.z += glm::mod(other.pos.z, border);
|
||||
} else {
|
||||
result.pos.z = this->pos.z + other.pos.z;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
Coord Coord::operator-(const Coord& other) const {
|
||||
Coord result;
|
||||
result.seg.x = this->seg.x - other.seg.x;
|
||||
result.seg.y = this->seg.y - other.seg.y;
|
||||
result.seg.z = this->seg.z - other.seg.z;
|
||||
|
||||
if (this->pos.x - other.pos.x < -border) {
|
||||
result.seg.x -= 1;
|
||||
result.pos.x -= glm::mod(this->pos.x, border);
|
||||
result.pos.x -= glm::mod(other.pos.x, border);
|
||||
} else {
|
||||
result.pos.x = this->pos.x - other.pos.x;
|
||||
}
|
||||
if (this->pos.y - other.pos.y < -border) {
|
||||
result.seg.y -= 1;
|
||||
result.pos.y -= glm::mod(this->pos.y, border);
|
||||
result.pos.y -= glm::mod(other.pos.y, border);
|
||||
} else {
|
||||
result.pos.y = this->pos.y - other.pos.y;
|
||||
}
|
||||
if (this->pos.z - other.pos.z < -border) {
|
||||
result.seg.z -= 1;
|
||||
result.pos.z -= glm::mod(this->pos.z, border);
|
||||
result.pos.z -= glm::mod(other.pos.z, border);
|
||||
} else {
|
||||
result.pos.z = this->pos.z - other.pos.z;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
} // namespace veng
|
||||
166
Client/src/vulkan/devices_and_queues.cpp
Normal file
166
Client/src/vulkan/devices_and_queues.cpp
Normal file
@@ -0,0 +1,166 @@
|
||||
#include <set>
|
||||
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
Graphics::QueueFamilyIndices Graphics::FindQueueFamilies(
|
||||
VkPhysicalDevice device) {
|
||||
std::uint32_t queue_familiy_count = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_familiy_count,
|
||||
nullptr);
|
||||
std::vector<VkQueueFamilyProperties> families(queue_familiy_count);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(device, &queue_familiy_count,
|
||||
families.data());
|
||||
|
||||
auto graphics_family_it =
|
||||
std::find_if(families.begin(), families.end(),
|
||||
[](const VkQueueFamilyProperties& props) {
|
||||
return props.queueFlags &
|
||||
(VK_QUEUE_GRAPHICS_BIT | VK_QUEUE_TRANSFER_BIT);
|
||||
});
|
||||
|
||||
QueueFamilyIndices result;
|
||||
result.graphics_family = graphics_family_it - families.begin();
|
||||
|
||||
for (std::uint32_t i = 0; i < families.size(); i++) {
|
||||
VkBool32 has_presentation_support = false;
|
||||
vkGetPhysicalDeviceSurfaceSupportKHR(device, i, surface_,
|
||||
&has_presentation_support);
|
||||
if (has_presentation_support) {
|
||||
result.presentation_family = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
Graphics::SwapChainProperties Graphics::GetSwapChainProperties(
|
||||
VkPhysicalDevice device) {
|
||||
SwapChainProperties properties;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(device, surface_,
|
||||
&properties.capabilities);
|
||||
|
||||
std::uint32_t format_count;
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &format_count,
|
||||
nullptr);
|
||||
properties.formats.resize(format_count);
|
||||
vkGetPhysicalDeviceSurfaceFormatsKHR(device, surface_, &format_count,
|
||||
properties.formats.data());
|
||||
|
||||
std::uint32_t modes_count;
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface_, &modes_count,
|
||||
nullptr);
|
||||
properties.present_modes.resize(modes_count);
|
||||
vkGetPhysicalDeviceSurfacePresentModesKHR(device, surface_, &modes_count,
|
||||
properties.present_modes.data());
|
||||
|
||||
return properties;
|
||||
}
|
||||
|
||||
std::vector<VkExtensionProperties> Graphics::GetDeviceAvailableExtensions(
|
||||
VkPhysicalDevice device) {
|
||||
std::uint32_t available_extentions_count;
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr,
|
||||
&available_extentions_count, nullptr);
|
||||
std::vector<VkExtensionProperties> available_extentions(
|
||||
available_extentions_count);
|
||||
vkEnumerateDeviceExtensionProperties(device, nullptr,
|
||||
&available_extentions_count,
|
||||
available_extentions.data());
|
||||
return available_extentions;
|
||||
}
|
||||
|
||||
bool Graphics::AreAllDeviceExtensionsSupported(VkPhysicalDevice device) {
|
||||
std::vector<VkExtensionProperties> available_extentions =
|
||||
GetDeviceAvailableExtensions(device);
|
||||
return std::all_of(
|
||||
required_device_extentions_.begin(), required_device_extentions_.end(),
|
||||
std::bind_front(IsExtensionSupported, available_extentions));
|
||||
}
|
||||
|
||||
bool Graphics::IsDeviceSuitable(VkPhysicalDevice device) {
|
||||
QueueFamilyIndices families = FindQueueFamilies(device);
|
||||
return families.IsValid() && AreAllDeviceExtensionsSupported(device) &&
|
||||
GetSwapChainProperties(device).IsValid();
|
||||
}
|
||||
|
||||
void Graphics::PickPhysicalDevice() {
|
||||
std::vector<VkPhysicalDevice> devices = GetAvailableDevices();
|
||||
|
||||
std::erase_if(
|
||||
devices, std::not_fn(std::bind_front(&Graphics::IsDeviceSuitable, this)));
|
||||
|
||||
if (devices.empty()) {
|
||||
spdlog::error("No physical devices that match the criteria");
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
physical_device_ = devices[0];
|
||||
}
|
||||
|
||||
std::vector<VkPhysicalDevice> Graphics::GetAvailableDevices() {
|
||||
std::uint32_t device_count;
|
||||
vkEnumeratePhysicalDevices(instance_, &device_count, nullptr);
|
||||
|
||||
if (device_count == 0) return {};
|
||||
|
||||
std::vector<VkPhysicalDevice> devices(device_count);
|
||||
vkEnumeratePhysicalDevices(instance_, &device_count, devices.data());
|
||||
|
||||
return devices;
|
||||
}
|
||||
|
||||
void Graphics::CreateLogicalDeviceAndQueues() {
|
||||
QueueFamilyIndices picked_device_families =
|
||||
FindQueueFamilies(physical_device_);
|
||||
|
||||
if (!picked_device_families.IsValid()) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
std::set<std::uint32_t> unique_queue_families = {
|
||||
picked_device_families.graphics_family.value(),
|
||||
picked_device_families.presentation_family.value(),
|
||||
};
|
||||
|
||||
std::float_t queue_priority = 1.f;
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
||||
for (std::uint32_t unique_queue_family : unique_queue_families) {
|
||||
VkDeviceQueueCreateInfo queue_info = {};
|
||||
queue_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
queue_info.queueFamilyIndex = unique_queue_family;
|
||||
queue_info.queueCount = 1;
|
||||
queue_info.pQueuePriorities = &queue_priority;
|
||||
queue_create_infos.push_back(queue_info);
|
||||
}
|
||||
|
||||
VkPhysicalDeviceFeatures required_features = {};
|
||||
required_features.depthBounds = true;
|
||||
required_features.depthClamp = true;
|
||||
|
||||
VkDeviceCreateInfo device_info = {};
|
||||
device_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
device_info.queueCreateInfoCount = queue_create_infos.size();
|
||||
device_info.pQueueCreateInfos = queue_create_infos.data();
|
||||
device_info.pEnabledFeatures = &required_features;
|
||||
device_info.enabledExtensionCount = required_device_extentions_.size();
|
||||
device_info.ppEnabledExtensionNames = required_device_extentions_.data();
|
||||
|
||||
VkResult result =
|
||||
vkCreateDevice(physical_device_, &device_info, nullptr, &logical_device_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
|
||||
vkGetDeviceQueue(logical_device_,
|
||||
picked_device_families.graphics_family.value(), 0,
|
||||
&graphics_queue_);
|
||||
vkGetDeviceQueue(logical_device_,
|
||||
picked_device_families.presentation_family.value(), 0,
|
||||
&present_queue_);
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
191
Client/src/vulkan/drawing.cpp
Normal file
191
Client/src/vulkan/drawing.cpp
Normal file
@@ -0,0 +1,191 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
void Graphics::CreateFramebuffers() {
|
||||
swap_chain_framebuffers_.resize(swap_chain_image_views_.size());
|
||||
|
||||
for (std::uint32_t i = 0; i < swap_chain_image_views_.size(); i++) {
|
||||
std::array<VkImageView, 2> attachments = {swap_chain_image_views_[i],
|
||||
depth_texture_.image_view};
|
||||
|
||||
VkFramebufferCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
info.renderPass = render_pass_;
|
||||
info.attachmentCount = attachments.size();
|
||||
info.pAttachments = attachments.data();
|
||||
info.width = extent_.width;
|
||||
info.height = extent_.height;
|
||||
info.layers = 1;
|
||||
|
||||
VkResult result = vkCreateFramebuffer(logical_device_, &info, nullptr,
|
||||
&swap_chain_framebuffers_[i]);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::CreateCommandPool() {
|
||||
QueueFamilyIndices indices = FindQueueFamilies(physical_device_);
|
||||
VkCommandPoolCreateInfo pool_info = {};
|
||||
pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
pool_info.queueFamilyIndex = indices.graphics_family.value();
|
||||
|
||||
VkResult result =
|
||||
vkCreateCommandPool(logical_device_, &pool_info, nullptr, &command_pool_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Graphics::CreateCommandBuffer() {
|
||||
VkCommandBufferAllocateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
info.commandPool = command_pool_;
|
||||
info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
info.commandBufferCount = 1;
|
||||
|
||||
for (Frame& frame : frames_) {
|
||||
VkResult result =
|
||||
vkAllocateCommandBuffers(logical_device_, &info, &frame.command_buffer);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
void Graphics::BeginCommands() {
|
||||
vkResetCommandBuffer(frames_[current_frame_].command_buffer, 0);
|
||||
|
||||
VkCommandBufferBeginInfo begin_info = {};
|
||||
begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
|
||||
VkResult result = vkBeginCommandBuffer(
|
||||
frames_[current_frame_].command_buffer, &begin_info);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to begin command buffer!");
|
||||
|
||||
std::array<VkClearValue, 2> clear_values;
|
||||
clear_values[0].color = {{0.f, 0.f, 0.f, 1.f}};
|
||||
clear_values[1].depthStencil = {1.f, 0};
|
||||
|
||||
VkRenderPassBeginInfo render_pass_begin_info = {};
|
||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
render_pass_begin_info.renderPass = render_pass_;
|
||||
render_pass_begin_info.framebuffer =
|
||||
swap_chain_framebuffers_[current_image_index_];
|
||||
render_pass_begin_info.renderArea.offset = {0, 0};
|
||||
render_pass_begin_info.renderArea.extent = extent_;
|
||||
render_pass_begin_info.clearValueCount = clear_values.size();
|
||||
render_pass_begin_info.pClearValues = clear_values.data();
|
||||
|
||||
vkCmdBeginRenderPass(frames_[current_frame_].command_buffer,
|
||||
&render_pass_begin_info,
|
||||
VK_SUBPASS_CONTENTS_INLINE);
|
||||
vkCmdBindPipeline(frames_[current_frame_].command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline_);
|
||||
VkViewport viewport = GetViewport();
|
||||
VkRect2D scissor = GetScissor();
|
||||
|
||||
vkCmdSetViewport(frames_[current_frame_].command_buffer, 0, 1, &viewport);
|
||||
vkCmdSetScissor(frames_[current_frame_].command_buffer, 0, 1, &scissor);
|
||||
}
|
||||
|
||||
void Graphics::EndCommands() {
|
||||
vkCmdEndRenderPass(frames_[current_frame_].command_buffer);
|
||||
VkResult result = vkEndCommandBuffer(frames_[current_frame_].command_buffer);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to record command buffer!");
|
||||
}
|
||||
|
||||
void Graphics::CreateSignals() {
|
||||
for (Frame& frame : frames_) {
|
||||
VkSemaphoreCreateInfo semafore_info = {};
|
||||
semafore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
||||
&frame.image_available_signal) !=
|
||||
VK_SUCCESS)
|
||||
std::exit(EXIT_FAILURE);
|
||||
if (vkCreateSemaphore(logical_device_, &semafore_info, nullptr,
|
||||
&frame.render_finished_signal) !=
|
||||
VK_SUCCESS)
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
||||
VkFenceCreateInfo fence_info = {};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
if (vkCreateFence(logical_device_, &fence_info, nullptr,
|
||||
&frame.still_rendering_fence) !=
|
||||
VK_SUCCESS)
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
bool Graphics::BeginFrame() {
|
||||
vkWaitForFences(logical_device_, 1,
|
||||
&frames_[current_frame_].still_rendering_fence, VK_TRUE,
|
||||
UINT64_MAX);
|
||||
VkResult image_acquire_result = vkAcquireNextImageKHR(logical_device_, swap_chain_, UINT64_MAX,
|
||||
frames_[current_frame_].image_available_signal,
|
||||
VK_NULL_HANDLE, ¤t_image_index_);
|
||||
|
||||
if (image_acquire_result == VK_ERROR_OUT_OF_DATE_KHR) {
|
||||
RecreateSwapChain();
|
||||
return false;
|
||||
}
|
||||
|
||||
if (image_acquire_result != VK_SUCCESS &&
|
||||
image_acquire_result != VK_SUBOPTIMAL_KHR)
|
||||
throw std::runtime_error("Couldn't acquire render image!");
|
||||
|
||||
vkResetFences(logical_device_, 1,
|
||||
&frames_[current_frame_].still_rendering_fence);
|
||||
|
||||
BeginCommands();
|
||||
SetModelMatrix(glm::mat4(1.f));
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void veng::Graphics::EndFrame() {
|
||||
EndCommands();
|
||||
VkSubmitInfo submit_info = {};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
|
||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &frames_[current_frame_].image_available_signal;
|
||||
submit_info.pWaitDstStageMask = &wait_stage;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &frames_[current_frame_].command_buffer;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores =
|
||||
&frames_[current_frame_].render_finished_signal;
|
||||
|
||||
VkResult submit_result =
|
||||
vkQueueSubmit(graphics_queue_, 1, &submit_info,
|
||||
frames_[current_frame_].still_rendering_fence);
|
||||
if (submit_result != VK_SUCCESS)
|
||||
throw std::runtime_error("failed to submit draw commands!");
|
||||
|
||||
VkPresentInfoKHR present_info = {};
|
||||
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present_info.waitSemaphoreCount = 1;
|
||||
present_info.pWaitSemaphores =
|
||||
&frames_[current_frame_].render_finished_signal;
|
||||
present_info.swapchainCount = 1;
|
||||
present_info.pSwapchains = &swap_chain_;
|
||||
present_info.pImageIndices = ¤t_image_index_;
|
||||
|
||||
VkResult result = vkQueuePresentKHR(present_queue_, &present_info);
|
||||
if (result == VK_ERROR_OUT_OF_DATE_KHR || result == VK_SUBOPTIMAL_KHR)
|
||||
RecreateSwapChain();
|
||||
else if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to present swap chain image!");
|
||||
|
||||
current_frame_ = (current_frame_++) % MAX_BUFFERED_FRAMES;
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
184
Client/src/vulkan/engine.cpp
Normal file
184
Client/src/vulkan/engine.cpp
Normal file
@@ -0,0 +1,184 @@
|
||||
#include "vulkan/engine.h"
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
void Engine::init() {
|
||||
glm::ivec2 window_size_ = vulkan_graphics->window->GetFramebufferSize();
|
||||
view = glm::lookAt(glm::vec3(0.f, 0.f, -5.f), glm::vec3(0.f, 0.f, 0.f),
|
||||
glm::vec3(0.f, -1.f, 0.f));
|
||||
projection = glm::perspective(
|
||||
glm::radians(103.f),
|
||||
(std::float_t)window_size_.x / (std::float_t)window_size_.y, 0.1f,
|
||||
1000.f);
|
||||
vulkan_graphics->SetViewProjection(view, projection);
|
||||
|
||||
for (auto it = model_assets_.begin(); it != model_assets_.end();) {
|
||||
it->second.vertex_buffer =
|
||||
vulkan_graphics->CreateVertexBuffer(it->second.vertices);
|
||||
it->second.index_buffer =
|
||||
vulkan_graphics->CreateIndexBuffer(it->second.indices);
|
||||
it->second.material.texture_handle =
|
||||
vulkan_graphics->CreateTexture(it->second.material.texture_image);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
if (BeginPlay != nullptr) BeginPlay(*this);
|
||||
}
|
||||
|
||||
void Engine::LoadModelAsset(std::string path, std::string name) {
|
||||
veng::Model model(vulkan_graphics);
|
||||
asset_loader_.setPath(path);
|
||||
asset_loader_.loadModel(model);
|
||||
model.material.texture_image = asset_loader_.readTexture();
|
||||
model_assets_[name] = std::move(model);
|
||||
}
|
||||
|
||||
const Model* Engine::GetStaticModel(std::string name) {
|
||||
if (model_assets_.find(name) != model_assets_.end())
|
||||
return &model_assets_[name];
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Model* Engine::SpawnModel(std::string asset_name, std::string name) {
|
||||
if (asset_name == "") {
|
||||
Model model_to_spawn(nullptr);
|
||||
model_to_spawn.visible = false;
|
||||
dynamic_immortal_models_[name] = std::move(model_to_spawn);
|
||||
return &dynamic_immortal_models_[name];
|
||||
}
|
||||
|
||||
if (dynamic_immortal_models_.find(name) == dynamic_immortal_models_.end()) {
|
||||
Model model_to_spawn(*GetStaticModel(asset_name));
|
||||
dynamic_immortal_models_[name] = std::move(model_to_spawn);
|
||||
return &dynamic_immortal_models_[name];
|
||||
}
|
||||
|
||||
std::uint32_t i = 0;
|
||||
for (i = 0; i < std::numeric_limits<std::uint32_t>::max();) {
|
||||
if (dynamic_immortal_models_.find(name + std::to_string(i)) ==
|
||||
dynamic_immortal_models_.end()) {
|
||||
Model model_to_spawn(*GetStaticModel(asset_name));
|
||||
dynamic_immortal_models_[name + std::to_string(i)] =
|
||||
std::move(model_to_spawn);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == std::numeric_limits<std::uint32_t>::max() - 1)
|
||||
return nullptr;
|
||||
else
|
||||
return &dynamic_immortal_models_[name + std::to_string(i)];
|
||||
}
|
||||
|
||||
Model* Engine::SpawnLifedModel(std::string asset_name, std::string name,
|
||||
std::float_t lifespan) {
|
||||
if (asset_name == "") {
|
||||
Model model_to_spawn(nullptr);
|
||||
model_to_spawn.visible = false;
|
||||
dynamic_models_[name] = std::make_pair(std::move(model_to_spawn), lifespan);
|
||||
return &dynamic_models_[name].first;
|
||||
}
|
||||
if (dynamic_models_.find(name) == dynamic_models_.end()) {
|
||||
Model model_to_spawn(*GetStaticModel(asset_name));
|
||||
dynamic_models_[name] = std::make_pair(std::move(model_to_spawn), lifespan);
|
||||
return &dynamic_models_[name].first;
|
||||
}
|
||||
|
||||
std::uint32_t i = 0;
|
||||
for (i = 0; i < std::numeric_limits<std::uint32_t>::max();) {
|
||||
if (dynamic_models_.find(name + std::to_string(i)) ==
|
||||
dynamic_models_.end()) {
|
||||
Model model_to_spawn(*GetStaticModel(asset_name));
|
||||
dynamic_models_[name + std::to_string(i)] =
|
||||
std::make_pair(std::move(model_to_spawn), lifespan);
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
if (i == std::numeric_limits<std::uint32_t>::max() - 1)
|
||||
return nullptr;
|
||||
else
|
||||
return &dynamic_models_[name + std::to_string(i)].first;
|
||||
}
|
||||
|
||||
Model* Engine::GetSpawnedObject(std::string name) {
|
||||
for (auto it = dynamic_immortal_models_.begin();
|
||||
it != dynamic_immortal_models_.end();) {
|
||||
if (it->first == name) return &it->second;
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto it = dynamic_models_.begin(); it != dynamic_models_.end();) {
|
||||
if (it->first == name) return &it->second.first;
|
||||
++it;
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void Engine::Update() {
|
||||
glm::ivec2 framebuffer_size = vulkan_graphics->window->GetFramebufferSize();
|
||||
if (framebuffer_size != window_size_ && framebuffer_size.x != 0 &&
|
||||
framebuffer_size.y != 0) {
|
||||
window_size_ = framebuffer_size;
|
||||
auto grater = (framebuffer_size.x > framebuffer_size.y)
|
||||
? framebuffer_size.x
|
||||
: framebuffer_size.y;
|
||||
view = glm::lookAt(glm::vec3(0.f, 0.f, -5.f), glm::vec3(0.f, 0.f, 0.f),
|
||||
glm::vec3(0.f, -1.f, 0.f));
|
||||
projection = glm::perspective(
|
||||
glm::radians(103.f),
|
||||
(std::float_t)framebuffer_size.x / (std::float_t)framebuffer_size.y,
|
||||
0.1f, 1000.f);
|
||||
}
|
||||
vulkan_graphics->SetViewProjection(view, projection);
|
||||
|
||||
if (vulkan_graphics->BeginFrame()) {
|
||||
std::double_t current_time = glfwGetTime();
|
||||
std::float_t delta_time =
|
||||
static_cast<std::float_t>(current_time - last_frame_time_);
|
||||
last_frame_time_ = current_time;
|
||||
|
||||
if (Tick != nullptr) Tick(*this, delta_time);
|
||||
|
||||
std::vector<Model*> models;
|
||||
models.reserve(dynamic_immortal_models_.size() +
|
||||
dynamic_models_.size());
|
||||
|
||||
for (auto it = dynamic_immortal_models_.begin();
|
||||
it != dynamic_immortal_models_.end();) {
|
||||
models.push_back(&it->second);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto it = dynamic_models_.begin(); it != dynamic_models_.end();) {
|
||||
if (it->second.second < 0.f) {
|
||||
it = dynamic_models_.erase(it);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
it->second.second -= delta_time;
|
||||
}
|
||||
models.push_back(&it->second.first);
|
||||
|
||||
++it;
|
||||
}
|
||||
|
||||
for (auto it : models) {
|
||||
it->Update(delta_time);
|
||||
vulkan_graphics->RenderModel(it);
|
||||
}
|
||||
|
||||
physics_controller_.invokeOnColisionEvent({models.data(), models.size()});
|
||||
|
||||
vulkan_graphics->EndFrame();
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
11
Client/src/vulkan/graphics.cpp
Normal file
11
Client/src/vulkan/graphics.cpp
Normal file
@@ -0,0 +1,11 @@
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
} // namespace veng
|
||||
306
Client/src/vulkan/graphics_pipeline.cpp
Normal file
306
Client/src/vulkan/graphics_pipeline.cpp
Normal file
@@ -0,0 +1,306 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
VkShaderModule Graphics::CreateShaderModule(gsl::span<std::uint8_t> buffer) {
|
||||
if (buffer.empty()) return VK_NULL_HANDLE;
|
||||
|
||||
VkShaderModuleCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
info.codeSize = buffer.size();
|
||||
info.pCode = reinterpret_cast<std::uint32_t*>(buffer.data());
|
||||
|
||||
VkShaderModule shader_module;
|
||||
VkResult result =
|
||||
vkCreateShaderModule(logical_device_, &info, nullptr, &shader_module);
|
||||
if (result != VK_SUCCESS) return VK_NULL_HANDLE;
|
||||
|
||||
return shader_module;
|
||||
}
|
||||
|
||||
VkViewport Graphics::GetViewport() {
|
||||
VkViewport viewport = {};
|
||||
viewport.x = 0.f;
|
||||
viewport.y = 0.f;
|
||||
viewport.width = static_cast<std::float_t>(extent_.width);
|
||||
viewport.height = static_cast<std::float_t>(extent_.height);
|
||||
viewport.minDepth = 0.f;
|
||||
viewport.maxDepth = 1.f;
|
||||
|
||||
return viewport;
|
||||
}
|
||||
|
||||
VkRect2D Graphics::GetScissor() {
|
||||
VkRect2D scissor = {};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = extent_;
|
||||
|
||||
return scissor;
|
||||
}
|
||||
|
||||
void Graphics::CreateGraphicsPipeline() {
|
||||
std::vector<std::uint8_t> basic_vertex_data = ReadFile("./basic.vert.spv");
|
||||
VkShaderModule vertex_shader = CreateShaderModule(basic_vertex_data);
|
||||
gsl::final_action _destroy_vertex([this, vertex_shader]() {
|
||||
vkDestroyShaderModule(logical_device_, vertex_shader, nullptr);
|
||||
});
|
||||
|
||||
std::vector<std::uint8_t> basic_fragment_data = ReadFile("./basic.frag.spv");
|
||||
VkShaderModule fragment_shader = CreateShaderModule(basic_fragment_data);
|
||||
gsl::final_action _destroy_fragment([this, fragment_shader]() {
|
||||
vkDestroyShaderModule(logical_device_, fragment_shader, nullptr);
|
||||
});
|
||||
|
||||
if (vertex_shader == VK_NULL_HANDLE || fragment_shader == VK_NULL_HANDLE)
|
||||
std::exit(EXIT_FAILURE);
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertex_stage_info = {};
|
||||
vertex_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertex_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertex_stage_info.module = vertex_shader;
|
||||
vertex_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragment_stage_info = {};
|
||||
fragment_stage_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragment_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragment_stage_info.module = fragment_shader;
|
||||
fragment_stage_info.pName = "main";
|
||||
|
||||
std::array<VkPipelineShaderStageCreateInfo, 2> stage_infos = {
|
||||
vertex_stage_info, fragment_stage_info};
|
||||
|
||||
std::array<VkDynamicState, 2> dynamic_states = {VK_DYNAMIC_STATE_VIEWPORT,
|
||||
VK_DYNAMIC_STATE_SCISSOR};
|
||||
|
||||
VkPipelineDynamicStateCreateInfo dynamic_state_info = {};
|
||||
dynamic_state_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_DYNAMIC_STATE_CREATE_INFO;
|
||||
dynamic_state_info.dynamicStateCount = dynamic_states.size();
|
||||
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
||||
|
||||
VkViewport viewport = GetViewport();
|
||||
|
||||
VkRect2D scissor = GetScissor();
|
||||
|
||||
VkPipelineViewportStateCreateInfo viewport_info = {};
|
||||
viewport_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VIEWPORT_STATE_CREATE_INFO;
|
||||
viewport_info.viewportCount = 1;
|
||||
viewport_info.pViewports = &viewport;
|
||||
viewport_info.scissorCount = 1;
|
||||
viewport_info.pScissors = &scissor;
|
||||
|
||||
auto vertex_binding_description = Vertex::GetBindingDescription();
|
||||
auto vertex_attribute_descriptions = Vertex::GetAttributeDescriptions();
|
||||
|
||||
VkPipelineVertexInputStateCreateInfo vertex_input_info = {};
|
||||
vertex_input_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||
vertex_input_info.vertexBindingDescriptionCount = 1;
|
||||
vertex_input_info.pVertexBindingDescriptions = &vertex_binding_description;
|
||||
vertex_input_info.vertexAttributeDescriptionCount =
|
||||
vertex_attribute_descriptions.size();
|
||||
vertex_input_info.pVertexAttributeDescriptions =
|
||||
vertex_attribute_descriptions.data();
|
||||
|
||||
VkPipelineInputAssemblyStateCreateInfo input_assembly_info = {};
|
||||
input_assembly_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_INPUT_ASSEMBLY_STATE_CREATE_INFO;
|
||||
input_assembly_info.topology = VK_PRIMITIVE_TOPOLOGY_TRIANGLE_LIST;
|
||||
input_assembly_info.primitiveRestartEnable = VK_FALSE;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterization_state_info = {};
|
||||
rasterization_state_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterization_state_info.depthClampEnable = VK_FALSE;
|
||||
rasterization_state_info.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterization_state_info.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterization_state_info.lineWidth = 1.f;
|
||||
rasterization_state_info.cullMode = VK_CULL_MODE_NONE;
|
||||
rasterization_state_info.frontFace = VK_FRONT_FACE_CLOCKWISE;
|
||||
rasterization_state_info.depthBiasEnable = VK_FALSE;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisampling_info = {};
|
||||
multisampling_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisampling_info.sampleShadingEnable = VK_FALSE;
|
||||
multisampling_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment = {};
|
||||
color_blend_attachment.colorWriteMask =
|
||||
VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT |
|
||||
VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
color_blend_attachment.blendEnable = VK_TRUE;
|
||||
color_blend_attachment.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
color_blend_attachment.dstColorBlendFactor =
|
||||
VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
color_blend_attachment.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
color_blend_attachment.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
color_blend_attachment.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo color_blending_info = {};
|
||||
color_blending_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
color_blending_info.logicOpEnable = VK_FALSE;
|
||||
color_blending_info.attachmentCount = 1;
|
||||
color_blending_info.pAttachments = &color_blend_attachment;
|
||||
|
||||
VkPipelineDepthStencilStateCreateInfo depth_stencil_info = {};
|
||||
depth_stencil_info.sType =
|
||||
VK_STRUCTURE_TYPE_PIPELINE_DEPTH_STENCIL_STATE_CREATE_INFO;
|
||||
depth_stencil_info.depthTestEnable = VK_TRUE;
|
||||
depth_stencil_info.depthWriteEnable = VK_TRUE;
|
||||
depth_stencil_info.depthCompareOp = VK_COMPARE_OP_LESS;
|
||||
depth_stencil_info.depthBoundsTestEnable = VK_TRUE;
|
||||
depth_stencil_info.minDepthBounds = 0.f;
|
||||
depth_stencil_info.maxDepthBounds = 1.f;
|
||||
depth_stencil_info.stencilTestEnable = VK_FALSE;
|
||||
|
||||
VkPushConstantRange model_matrix_range = {};
|
||||
model_matrix_range.offset = 0;
|
||||
model_matrix_range.size = sizeof(glm::mat4);
|
||||
model_matrix_range.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
|
||||
std::array<VkDescriptorSetLayout, 2> set_layouts = {uniform_set_layout_,
|
||||
texture_set_layout_};
|
||||
|
||||
VkPipelineLayoutCreateInfo layout_info = {};
|
||||
layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
layout_info.pushConstantRangeCount = 1;
|
||||
layout_info.pPushConstantRanges = &model_matrix_range;
|
||||
layout_info.setLayoutCount = set_layouts.size();
|
||||
layout_info.pSetLayouts = set_layouts.data();
|
||||
|
||||
VkResult layout_result = vkCreatePipelineLayout(logical_device_, &layout_info,
|
||||
nullptr, &pipeline_layout_);
|
||||
if (layout_result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_info = {};
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.stageCount = stage_infos.size();
|
||||
pipeline_info.pStages = stage_infos.data();
|
||||
pipeline_info.pVertexInputState = &vertex_input_info;
|
||||
pipeline_info.pInputAssemblyState = &input_assembly_info;
|
||||
pipeline_info.pViewportState = &viewport_info;
|
||||
pipeline_info.pRasterizationState = &rasterization_state_info;
|
||||
pipeline_info.pMultisampleState = &multisampling_info;
|
||||
pipeline_info.pDepthStencilState = &depth_stencil_info;
|
||||
pipeline_info.pColorBlendState = &color_blending_info;
|
||||
pipeline_info.pDynamicState = &dynamic_state_info;
|
||||
pipeline_info.layout = pipeline_layout_;
|
||||
pipeline_info.renderPass = render_pass_;
|
||||
pipeline_info.subpass = 0;
|
||||
|
||||
VkResult pipline_result = vkCreateGraphicsPipelines(
|
||||
logical_device_, VK_NULL_HANDLE, 1, &pipeline_info, nullptr, &pipeline_);
|
||||
if (pipline_result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void Graphics::CreateRenderPass() {
|
||||
VkAttachmentDescription color_attachment = {};
|
||||
color_attachment.format = surface_format_.format;
|
||||
color_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
color_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
color_attachment.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
color_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
color_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
color_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
color_attachment.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference color_attachment_ref = {};
|
||||
color_attachment_ref.attachment = 0;
|
||||
color_attachment_ref.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentDescription depth_attachment = {};
|
||||
depth_attachment.format = VK_FORMAT_D32_SFLOAT;
|
||||
depth_attachment.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
depth_attachment.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
depth_attachment.storeOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depth_attachment.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
depth_attachment.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
depth_attachment.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
depth_attachment.finalLayout =
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkAttachmentReference depth_attachment_ref = {};
|
||||
depth_attachment_ref.attachment = 1;
|
||||
depth_attachment_ref.layout =
|
||||
VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription main_subpass = {};
|
||||
main_subpass.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
main_subpass.colorAttachmentCount = 1;
|
||||
main_subpass.pColorAttachments = &color_attachment_ref;
|
||||
main_subpass.pDepthStencilAttachment = &depth_attachment_ref;
|
||||
|
||||
VkSubpassDependency dependency = {};
|
||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependency.dstSubpass = 0;
|
||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
dependency.srcAccessMask = 0;
|
||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT |
|
||||
VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
std::array<VkAttachmentDescription, 2> attachments = {color_attachment,
|
||||
depth_attachment};
|
||||
|
||||
VkRenderPassCreateInfo render_pass_info = {};
|
||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
render_pass_info.attachmentCount = attachments.size();
|
||||
render_pass_info.pAttachments = attachments.data();
|
||||
render_pass_info.subpassCount = 1;
|
||||
render_pass_info.pSubpasses = &main_subpass;
|
||||
render_pass_info.dependencyCount = 1;
|
||||
render_pass_info.pDependencies = &dependency;
|
||||
|
||||
VkResult result = vkCreateRenderPass(logical_device_, &render_pass_info,
|
||||
nullptr, &render_pass_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
void veng::Graphics::RecreateSwapChain() {
|
||||
glm::ivec2 size = window->GetFramebufferSize();
|
||||
while (size.x == 0 || size.y == 0) {
|
||||
size = window->GetFramebufferSize();
|
||||
// glfwWaitEvents();
|
||||
return;
|
||||
}
|
||||
|
||||
vkDeviceWaitIdle(logical_device_);
|
||||
CleanupSwapChain();
|
||||
|
||||
CreateSwapChain();
|
||||
CreateImageViews();
|
||||
CreateDepthResources();
|
||||
CreateFramebuffers();
|
||||
}
|
||||
|
||||
void veng::Graphics::CleanupSwapChain() {
|
||||
if (logical_device_ == VK_NULL_HANDLE) return;
|
||||
|
||||
for (VkFramebuffer framebuffer : swap_chain_framebuffers_)
|
||||
vkDestroyFramebuffer(logical_device_, framebuffer, nullptr);
|
||||
|
||||
for (VkImageView image_view : swap_chain_image_views_)
|
||||
vkDestroyImageView(logical_device_, image_view, nullptr);
|
||||
|
||||
if (swap_chain_ != VK_NULL_HANDLE)
|
||||
vkDestroySwapchainKHR(logical_device_, swap_chain_, nullptr);
|
||||
|
||||
vkDeviceWaitIdle(logical_device_);
|
||||
vkDestroyImageView(logical_device_, depth_texture_.image_view, nullptr);
|
||||
depth_texture_.image_view = VK_NULL_HANDLE;
|
||||
vkDestroyImage(logical_device_, depth_texture_.image, nullptr);
|
||||
depth_texture_.image = VK_NULL_HANDLE;
|
||||
vkFreeMemory(logical_device_, depth_texture_.memory, nullptr);
|
||||
depth_texture_.memory = VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
102
Client/src/vulkan/instance_and_extensions.cpp
Normal file
102
Client/src/vulkan/instance_and_extensions.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
gsl::span<gsl::czstring> Graphics::GetSuggestedInstanceExtentions() {
|
||||
std::uint32_t glfw_extention_count = 0;
|
||||
gsl::czstring* glfw_extentions =
|
||||
glfwGetRequiredInstanceExtensions(&glfw_extention_count);
|
||||
return {glfw_extentions, glfw_extention_count};
|
||||
}
|
||||
|
||||
std::vector<gsl::czstring> Graphics::GetRequiredInstanceExtentions() {
|
||||
gsl::span<gsl::czstring> suggested_extentions =
|
||||
GetSuggestedInstanceExtentions();
|
||||
std::vector<gsl::czstring> required_extentions(suggested_extentions.size());
|
||||
std::copy(suggested_extentions.begin(), suggested_extentions.end(),
|
||||
required_extentions.begin());
|
||||
|
||||
if (validation_enabled_)
|
||||
required_extentions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
|
||||
if (!AreAllExtensionsSupported(suggested_extentions)) std::exit(EXIT_FAILURE);
|
||||
|
||||
return required_extentions;
|
||||
}
|
||||
|
||||
std::vector<VkExtensionProperties> Graphics::GetSupprotedInstanceExtensions() {
|
||||
std::uint32_t count;
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr);
|
||||
|
||||
if (count == 0) return {};
|
||||
|
||||
std::vector<VkExtensionProperties> properties(count);
|
||||
vkEnumerateInstanceExtensionProperties(nullptr, &count, properties.data());
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool ExtentionMatchesName(gsl::czstring name,
|
||||
const VkExtensionProperties& properties) {
|
||||
return streq(properties.extensionName, name);
|
||||
}
|
||||
|
||||
bool IsExtensionSupported(gsl::span<VkExtensionProperties> extensions,
|
||||
gsl::czstring name) {
|
||||
return std::any_of(extensions.begin(), extensions.end(),
|
||||
std::bind_front(ExtentionMatchesName, name));
|
||||
}
|
||||
|
||||
bool Graphics::AreAllExtensionsSupported(gsl::span<gsl::czstring> extensions) {
|
||||
std::vector<VkExtensionProperties> supported_extensions =
|
||||
GetSupprotedInstanceExtensions();
|
||||
|
||||
return std::all_of(
|
||||
extensions.begin(), extensions.end(),
|
||||
std::bind_front(IsExtensionSupported, supported_extensions));
|
||||
}
|
||||
|
||||
void Graphics::CreateInstance() {
|
||||
std::array<gsl::czstring, 1> validation_layers = {
|
||||
"VK_LAYER_KHRONOS_validation"};
|
||||
|
||||
if (!AreAllLayersSupported(validation_layers)) validation_enabled_ = false;
|
||||
|
||||
std::vector<gsl::czstring> required_extentions =
|
||||
GetRequiredInstanceExtentions();
|
||||
|
||||
VkApplicationInfo app_info = {};
|
||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app_info.pNext = nullptr;
|
||||
app_info.pApplicationName = "Udemy Course";
|
||||
app_info.applicationVersion = VK_MAKE_API_VERSION(0, 0, 0, 0);
|
||||
app_info.pEngineName = "VEng";
|
||||
app_info.engineVersion = VK_MAKE_API_VERSION(0, 1, 0, 0);
|
||||
app_info.apiVersion = VK_API_VERSION_1_0;
|
||||
|
||||
VkInstanceCreateInfo instance_creation_info = {};
|
||||
instance_creation_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
instance_creation_info.pNext = nullptr;
|
||||
instance_creation_info.pApplicationInfo = &app_info;
|
||||
instance_creation_info.enabledExtensionCount = required_extentions.size();
|
||||
instance_creation_info.ppEnabledExtensionNames = required_extentions.data();
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT messenger_create_info =
|
||||
GetCreateMessengerInfo();
|
||||
if (validation_enabled_) {
|
||||
instance_creation_info.pNext = &messenger_create_info;
|
||||
instance_creation_info.enabledLayerCount = validation_layers.size();
|
||||
instance_creation_info.ppEnabledLayerNames = validation_layers.data();
|
||||
} else {
|
||||
instance_creation_info.enabledLayerCount = 0;
|
||||
instance_creation_info.ppEnabledLayerNames = nullptr;
|
||||
}
|
||||
|
||||
VkResult result =
|
||||
vkCreateInstance(&instance_creation_info, nullptr, &instance_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
112
Client/src/vulkan/physics.cpp
Normal file
112
Client/src/vulkan/physics.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
#include "vulkan/physics.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <limits>
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
void Physics::invokeOnColisionEvent(gsl::span<Model*> models) {
|
||||
const std::float_t EPSILON = std::numeric_limits<std::float_t>::epsilon();
|
||||
|
||||
for (int first = 0; first < models.size(); first++) {
|
||||
if (!models[first]->colision) continue;
|
||||
for (int second = first + 1; second < models.size(); second++) {
|
||||
if (!models[second]->colision) continue;
|
||||
std::float_t distance =
|
||||
glm::distance(models[first]->position, models[second]->position);
|
||||
std::float_t model1_radius =
|
||||
models[first]->radius * models[first]->scale.x;
|
||||
std::float_t model2_radius =
|
||||
models[second]->radius * models[second]->scale.x;
|
||||
if (distance <= model1_radius + model2_radius) {
|
||||
if (models[first]->OnColision != nullptr)
|
||||
models[first]->OnColision(models[first], models[second]);
|
||||
if (models[second]->OnColision != nullptr)
|
||||
models[second]->OnColision(models[second], models[first]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool Physics::RayTrace(const glm::vec3& rayOrigin, const glm::vec3& rayDir,
|
||||
const glm::vec3& v0, const glm::vec3& v1,
|
||||
const glm::vec3& v2, std::float_t& outDistance) {
|
||||
const std::float_t EPSILON = std::numeric_limits<std::float_t>::epsilon();
|
||||
|
||||
// 삼각형 엣지와 노멀 계산
|
||||
glm::vec3 edge1 = v1 - v0;
|
||||
glm::vec3 edge2 = v2 - v0;
|
||||
glm::vec3 normal = glm::cross(edge1, edge2);
|
||||
|
||||
// 평행 여부 판단
|
||||
glm::vec3 h = glm::cross(rayDir, edge2);
|
||||
std::float_t a = glm::dot(edge1, h);
|
||||
|
||||
if (fabs(a) < EPSILON) {
|
||||
// 광선 방향과 삼각형 평면이 거의 평행 → coplanar 검사
|
||||
// 시작점이 평면 위에 있는지
|
||||
std::float_t distToPlane = glm::dot(normal, rayOrigin - v0);
|
||||
if (fabs(distToPlane) < EPSILON) {
|
||||
// 평면 위에 있다면, 점이 삼각형 내부에 있는지 검사
|
||||
auto pointInTri = [&](const glm::vec3& P) {
|
||||
// 엣지마다 P가 같은 반대 방향 노멀 쪽에 있는지
|
||||
glm::vec3 c0 = glm::cross(v1 - v0, P - v0);
|
||||
glm::vec3 c1 = glm::cross(v2 - v1, P - v1);
|
||||
glm::vec3 c2 = glm::cross(v0 - v2, P - v2);
|
||||
|
||||
std::float_t f0 = glm::dot(normal, c0);
|
||||
std::float_t f1 = glm::dot(normal, c1);
|
||||
std::float_t f2 = glm::dot(normal, c2);
|
||||
|
||||
return (f0 >= EPSILON && f1 >= EPSILON && f2 >= EPSILON);
|
||||
};
|
||||
if (pointInTri(rayOrigin)) {
|
||||
outDistance = 0.0f;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// 기존 Möller–Trumbore 알고리즘
|
||||
std::float_t f = 1.0f / a;
|
||||
glm::vec3 s = rayOrigin - v0;
|
||||
std::float_t u = f * glm::dot(s, h);
|
||||
if (u < 0.0f || u > 1.0f) return false;
|
||||
|
||||
glm::vec3 q = glm::cross(s, edge1);
|
||||
std::float_t v = f * glm::dot(rayDir, q);
|
||||
if (v < 0.0f || u + v > 1.0f) return false;
|
||||
|
||||
std::float_t t = f * glm::dot(edge2, q);
|
||||
if (t > EPSILON) {
|
||||
outDistance = t;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool Physics::IsPointInsideMesh_(const glm::vec3& point,
|
||||
const std::vector<veng::Vertex>& vertices,
|
||||
const std::vector<std::uint32_t>& indices) {
|
||||
glm::vec3 rayDir = glm::vec3(1.0f, 0.0f, 0.0f); // X+ 방향 광선
|
||||
int intersectionCount = 0;
|
||||
|
||||
for (size_t i = 0; i < indices.size(); i += 3) {
|
||||
const glm::vec3& v0 = vertices[indices[i + 0]].position;
|
||||
const glm::vec3& v1 = vertices[indices[i + 1]].position;
|
||||
const glm::vec3& v2 = vertices[indices[i + 2]].position;
|
||||
|
||||
std::float_t t;
|
||||
if (RayTrace(point, rayDir, v0, v1, v2, t)) {
|
||||
intersectionCount++;
|
||||
}
|
||||
}
|
||||
|
||||
return (intersectionCount % 2 == 1); // 홀수면 내부}
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
176
Client/src/vulkan/presentation.cpp
Normal file
176
Client/src/vulkan/presentation.cpp
Normal file
@@ -0,0 +1,176 @@
|
||||
#include "vulkan/graphics.h"
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include "precomp.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
void Graphics::CreateSurface() {
|
||||
VkResult result = glfwCreateWindowSurface(instance_, window->GetHandle(),
|
||||
nullptr, &surface_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
}
|
||||
|
||||
bool IsRgbaTypeFormat(const VkSurfaceFormatKHR& format_properties) {
|
||||
return format_properties.format == VK_FORMAT_R8G8B8A8_SRGB ||
|
||||
format_properties.format == VK_FORMAT_B8G8R8A8_SRGB;
|
||||
}
|
||||
|
||||
bool IsSrgbColorSpace(const VkSurfaceFormatKHR& format_properties) {
|
||||
return format_properties.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR;
|
||||
}
|
||||
|
||||
bool IsCorrectFormat(const VkSurfaceFormatKHR& format_properties) {
|
||||
return IsSrgbColorSpace(format_properties) &&
|
||||
IsRgbaTypeFormat(format_properties);
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR Graphics::ChooseSwapSurfaceFormat(
|
||||
gsl::span<VkSurfaceFormatKHR> formats) {
|
||||
if (formats.size() == 1 && formats[0].format == VK_FORMAT_UNDEFINED) {
|
||||
return {VkFormat::VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VkColorSpaceKHR::VK_COLORSPACE_SRGB_NONLINEAR_KHR};
|
||||
}
|
||||
|
||||
auto it = std::find_if(formats.begin(), formats.end(), IsCorrectFormat);
|
||||
if (it != formats.end()) return *it;
|
||||
|
||||
for (const VkSurfaceFormatKHR& format : formats) {
|
||||
if (format.format == VK_FORMAT_R8G8B8A8_SRGB &&
|
||||
format.colorSpace == VK_COLORSPACE_SRGB_NONLINEAR_KHR) {
|
||||
return format;
|
||||
}
|
||||
}
|
||||
|
||||
return formats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR Graphics::ChooseSwapPresentMode(
|
||||
gsl::span<VkPresentModeKHR> present_modes) {
|
||||
constexpr std::array<VkPresentModeKHR, 3> preferred_modes = {
|
||||
VK_PRESENT_MODE_MAILBOX_KHR, VK_PRESENT_MODE_IMMEDIATE_KHR,
|
||||
VK_PRESENT_MODE_FIFO_KHR};
|
||||
|
||||
for (const auto& preferred : preferred_modes)
|
||||
if (std::find(present_modes.begin(), present_modes.end(), preferred) !=
|
||||
present_modes.end())
|
||||
return preferred;
|
||||
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
VkExtent2D Graphics::ChooseSwapExtent(
|
||||
const VkSurfaceCapabilitiesKHR& capabilities) {
|
||||
constexpr std::uint32_t kInvalidSize =
|
||||
std::numeric_limits<std::uint32_t>::max();
|
||||
|
||||
if (capabilities.currentExtent.width != kInvalidSize) {
|
||||
return capabilities.currentExtent;
|
||||
} else {
|
||||
glm::ivec2 size = window->GetFramebufferSize();
|
||||
VkExtent2D actual_extent = {static_cast<std::uint32_t>(size.x),
|
||||
static_cast<std::uint32_t>(size.y)};
|
||||
|
||||
actual_extent.width =
|
||||
std::clamp(actual_extent.width, capabilities.minImageExtent.width,
|
||||
capabilities.maxImageExtent.width);
|
||||
actual_extent.height =
|
||||
std::clamp(actual_extent.height, capabilities.minImageExtent.height,
|
||||
capabilities.maxImageExtent.height);
|
||||
|
||||
return actual_extent;
|
||||
}
|
||||
}
|
||||
|
||||
std::uint32_t Graphics::ChooseSwapImageCount(
|
||||
const VkSurfaceCapabilitiesKHR& capabilities) {
|
||||
std::uint32_t image_count = capabilities.minImageCount + 1;
|
||||
if (capabilities.maxImageCount > 0 &&
|
||||
capabilities.maxImageCount < image_count)
|
||||
image_count = capabilities.maxImageCount;
|
||||
|
||||
return image_count;
|
||||
}
|
||||
|
||||
void Graphics::CreateSwapChain() {
|
||||
SwapChainProperties properties = GetSwapChainProperties(physical_device_);
|
||||
|
||||
surface_format_ = ChooseSwapSurfaceFormat(properties.formats);
|
||||
present_mode_ = ChooseSwapPresentMode(properties.present_modes);
|
||||
extent_ = ChooseSwapExtent(properties.capabilities);
|
||||
|
||||
std::uint32_t image_count = ChooseSwapImageCount(properties.capabilities);
|
||||
|
||||
VkSwapchainCreateInfoKHR info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
info.surface = surface_;
|
||||
info.minImageCount = image_count;
|
||||
info.imageFormat = surface_format_.format;
|
||||
info.imageColorSpace = surface_format_.colorSpace;
|
||||
info.imageExtent = extent_;
|
||||
info.imageArrayLayers = 1;
|
||||
info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
info.presentMode = present_mode_;
|
||||
info.preTransform = properties.capabilities.currentTransform;
|
||||
info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
info.clipped = VK_TRUE;
|
||||
info.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
QueueFamilyIndices indices = FindQueueFamilies(physical_device_);
|
||||
|
||||
if (indices.graphics_family != indices.presentation_family) {
|
||||
std::array<std::uint32_t, 2> family_indices = {
|
||||
indices.graphics_family.value(), indices.presentation_family.value()};
|
||||
info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
info.queueFamilyIndexCount = family_indices.size();
|
||||
info.pQueueFamilyIndices = family_indices.data();
|
||||
} else {
|
||||
info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
}
|
||||
|
||||
VkResult result =
|
||||
vkCreateSwapchainKHR(logical_device_, &info, nullptr, &swap_chain_);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
|
||||
std::uint32_t actual_image_count;
|
||||
vkGetSwapchainImagesKHR(logical_device_, swap_chain_, &actual_image_count,
|
||||
nullptr);
|
||||
swap_chain_images_.resize(actual_image_count);
|
||||
vkGetSwapchainImagesKHR(logical_device_, swap_chain_, &actual_image_count,
|
||||
swap_chain_images_.data());
|
||||
}
|
||||
|
||||
VkImageView Graphics::CreateImageView(VkImage image, VkFormat format, VkImageAspectFlags aspect_flag) {
|
||||
VkImageViewCreateInfo info = {};
|
||||
info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
info.image = image;
|
||||
info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
info.format = format;
|
||||
info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
info.subresourceRange.aspectMask = aspect_flag;
|
||||
info.subresourceRange.baseMipLevel = 0;
|
||||
info.subresourceRange.levelCount = 1;
|
||||
info.subresourceRange.baseArrayLayer = 0;
|
||||
info.subresourceRange.layerCount = 1;
|
||||
|
||||
VkImageView view;
|
||||
VkResult result = vkCreateImageView(logical_device_, &info, nullptr, &view);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
return view;
|
||||
}
|
||||
|
||||
void Graphics::CreateImageViews() {
|
||||
swap_chain_image_views_.resize(swap_chain_images_.size());
|
||||
|
||||
auto image_view_it = swap_chain_image_views_.begin();
|
||||
for (VkImage image : swap_chain_images_) {
|
||||
*image_view_it = CreateImageView(image, surface_format_.format, VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
|
||||
std::advance(image_view_it, 1);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
259
Client/src/vulkan/texture.cpp
Normal file
259
Client/src/vulkan/texture.cpp
Normal file
@@ -0,0 +1,259 @@
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "stb/stb_image.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
void Graphics::CreateTextureSampler() {
|
||||
VkSamplerCreateInfo sampler_info = {};
|
||||
sampler_info.sType = VK_STRUCTURE_TYPE_SAMPLER_CREATE_INFO;
|
||||
sampler_info.magFilter = VK_FILTER_LINEAR;
|
||||
sampler_info.minFilter = VK_FILTER_LINEAR;
|
||||
sampler_info.addressModeU = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler_info.addressModeV = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE;
|
||||
sampler_info.addressModeW = VK_SAMPLER_ADDRESS_MODE_REPEAT;
|
||||
sampler_info.anisotropyEnable = VK_FALSE;
|
||||
sampler_info.maxAnisotropy = 1.f;
|
||||
sampler_info.borderColor = VK_BORDER_COLOR_FLOAT_OPAQUE_BLACK;
|
||||
sampler_info.unnormalizedCoordinates = VK_FALSE;
|
||||
sampler_info.compareEnable = VK_FALSE;
|
||||
sampler_info.compareOp = VK_COMPARE_OP_ALWAYS;
|
||||
sampler_info.mipmapMode = VK_SAMPLER_MIPMAP_MODE_LINEAR;
|
||||
sampler_info.mipLodBias = 0.f;
|
||||
sampler_info.minLod = 0.f;
|
||||
sampler_info.maxLod = 0.f;
|
||||
|
||||
if (vkCreateSampler(logical_device_, &sampler_info, nullptr,
|
||||
&texture_sampler_) != VK_SUCCESS) {
|
||||
std::exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
|
||||
TextureHandle Graphics::CreateTexture(gsl::czstring path) {
|
||||
std::vector<std::uint8_t> data = ReadFile(path);
|
||||
return CreateTexture({data.data(), data.size()});
|
||||
}
|
||||
|
||||
TextureHandle Graphics::CreateTexture(
|
||||
std::vector<std::uint8_t> image_file_data) {
|
||||
return CreateTexture({image_file_data.data(), image_file_data.size()});
|
||||
}
|
||||
|
||||
TextureHandle Graphics::CreateTexture(gsl::span<std::uint8_t> image_file_data) {
|
||||
glm::ivec2 image_extents;
|
||||
std::int32_t channels;
|
||||
stbi_uc* pixel_data = stbi_load_from_memory(
|
||||
image_file_data.data(), image_file_data.size(), &image_extents.x,
|
||||
&image_extents.y, &channels, STBI_rgb_alpha);
|
||||
|
||||
VkDeviceSize buffer_size = image_extents.x * image_extents.y * 4;
|
||||
BufferHandle staging =
|
||||
CreateBuffer(buffer_size, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT |
|
||||
VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
void* data_location;
|
||||
vkMapMemory(logical_device_, staging.memory, 0, buffer_size, 0,
|
||||
&data_location);
|
||||
std::memcpy(data_location, pixel_data, buffer_size);
|
||||
vkUnmapMemory(logical_device_, staging.memory);
|
||||
|
||||
stbi_image_free(pixel_data);
|
||||
|
||||
TextureHandle handle =
|
||||
CreateImage(image_extents, VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_USAGE_TRANSFER_DST_BIT | VK_IMAGE_USAGE_SAMPLED_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_UNDEFINED,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL);
|
||||
CopyBufferToImage(staging.buffer, handle.image, image_extents);
|
||||
TransitionImageLayout(handle.image, VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL,
|
||||
VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL);
|
||||
|
||||
handle.image_view = CreateImageView(handle.image, VK_FORMAT_R8G8B8A8_SRGB,
|
||||
VK_IMAGE_ASPECT_COLOR_BIT);
|
||||
|
||||
VkDescriptorSetAllocateInfo set_info = {};
|
||||
set_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
set_info.descriptorPool = texture_pool_;
|
||||
set_info.descriptorSetCount = 1;
|
||||
set_info.pSetLayouts = &texture_set_layout_;
|
||||
|
||||
VkResult result =
|
||||
vkAllocateDescriptorSets(logical_device_, &set_info, &handle.set);
|
||||
if (result != VK_SUCCESS) std::exit(EXIT_FAILURE);
|
||||
|
||||
VkDescriptorImageInfo image_info = {};
|
||||
image_info.imageLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL;
|
||||
image_info.imageView = handle.image_view;
|
||||
image_info.sampler = texture_sampler_;
|
||||
|
||||
VkWriteDescriptorSet descriptor_write = {};
|
||||
descriptor_write.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
descriptor_write.dstSet = handle.set;
|
||||
descriptor_write.dstBinding = 0;
|
||||
descriptor_write.dstArrayElement = 0;
|
||||
descriptor_write.descriptorType = VK_DESCRIPTOR_TYPE_COMBINED_IMAGE_SAMPLER;
|
||||
descriptor_write.descriptorCount = 1;
|
||||
descriptor_write.pImageInfo = &image_info;
|
||||
|
||||
vkUpdateDescriptorSets(logical_device_, 1, &descriptor_write, 0, nullptr);
|
||||
|
||||
DestroyBuffer(staging);
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Graphics::DestroyTexture(TextureHandle handle) {
|
||||
vkDeviceWaitIdle(logical_device_);
|
||||
|
||||
if (handle.set != VK_NULL_HANDLE)
|
||||
vkFreeDescriptorSets(logical_device_, texture_pool_, 1, &handle.set);
|
||||
|
||||
if (handle.image_view != VK_NULL_HANDLE)
|
||||
vkDestroyImageView(logical_device_, handle.image_view, nullptr);
|
||||
|
||||
if (handle.image != VK_NULL_HANDLE)
|
||||
vkDestroyImage(logical_device_, handle.image, nullptr);
|
||||
|
||||
if (handle.memory != VK_NULL_HANDLE)
|
||||
vkFreeMemory(logical_device_, handle.memory, nullptr);
|
||||
}
|
||||
|
||||
void Graphics::SetTexture(TextureHandle handle) {
|
||||
vkCmdBindDescriptorSets(frames_[current_frame_].command_buffer,
|
||||
VK_PIPELINE_BIND_POINT_GRAPHICS,
|
||||
pipeline_layout_, 1, 1, &handle.set, 0, nullptr);
|
||||
}
|
||||
|
||||
void Graphics::TransitionImageLayout(VkImage image, VkImageLayout old_layout,
|
||||
VkImageLayout new_layout) {
|
||||
VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer();
|
||||
|
||||
VkImageMemoryBarrier barrier = {};
|
||||
barrier.sType = VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER;
|
||||
barrier.oldLayout = old_layout;
|
||||
barrier.newLayout = new_layout;
|
||||
barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
|
||||
barrier.image = image;
|
||||
barrier.subresourceRange.baseArrayLayer = 0;
|
||||
barrier.subresourceRange.baseMipLevel = 0;
|
||||
barrier.subresourceRange.levelCount = 1;
|
||||
barrier.subresourceRange.layerCount = 1;
|
||||
|
||||
VkPipelineStageFlags source_stage = {};
|
||||
VkPipelineStageFlags destination_stage = {};
|
||||
|
||||
if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
|
||||
new_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destination_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
} else if (old_layout == VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL &&
|
||||
new_layout == VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL) {
|
||||
barrier.srcAccessMask = VK_ACCESS_TRANSFER_WRITE_BIT;
|
||||
barrier.dstAccessMask = VK_ACCESS_SHADER_READ_BIT;
|
||||
source_stage = VK_PIPELINE_STAGE_TRANSFER_BIT;
|
||||
destination_stage = VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT;
|
||||
} else if (old_layout == VK_IMAGE_LAYOUT_UNDEFINED &&
|
||||
new_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL) {
|
||||
barrier.srcAccessMask = 0;
|
||||
barrier.dstAccessMask = VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_READ_BIT |
|
||||
VK_ACCESS_DEPTH_STENCIL_ATTACHMENT_WRITE_BIT;
|
||||
source_stage = VK_PIPELINE_STAGE_TOP_OF_PIPE_BIT;
|
||||
destination_stage = VK_PIPELINE_STAGE_EARLY_FRAGMENT_TESTS_BIT;
|
||||
}
|
||||
|
||||
if (new_layout == VK_IMAGE_LAYOUT_DEPTH_STENCIL_ATTACHMENT_OPTIMAL)
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_DEPTH_BIT;
|
||||
else
|
||||
barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
|
||||
vkCmdPipelineBarrier(local_command_buffer, source_stage, destination_stage, 0,
|
||||
0, nullptr, 0, nullptr, 1, &barrier);
|
||||
|
||||
EndTransientCommandBuffer(local_command_buffer);
|
||||
}
|
||||
|
||||
void Graphics::CopyBufferToImage(VkBuffer buffer, VkImage image,
|
||||
glm::ivec2 image_size) {
|
||||
VkCommandBuffer local_command_buffer = BeginTransientCommandBuffer();
|
||||
|
||||
VkBufferImageCopy region = {};
|
||||
region.bufferOffset = 0;
|
||||
region.bufferRowLength = 0;
|
||||
region.bufferImageHeight = 0;
|
||||
region.imageSubresource.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
region.imageSubresource.mipLevel = 0;
|
||||
region.imageSubresource.baseArrayLayer = 0;
|
||||
region.imageSubresource.layerCount = 1;
|
||||
region.imageOffset = {0, 0, 0};
|
||||
region.imageExtent = {static_cast<std::uint32_t>(image_size.x),
|
||||
static_cast<std::uint32_t>(image_size.y), 1};
|
||||
|
||||
vkCmdCopyBufferToImage(local_command_buffer, buffer, image,
|
||||
VK_IMAGE_LAYOUT_TRANSFER_DST_OPTIMAL, 1, ®ion);
|
||||
|
||||
EndTransientCommandBuffer(local_command_buffer);
|
||||
}
|
||||
|
||||
TextureHandle Graphics::CreateImage(glm::ivec2 size, VkFormat image_format,
|
||||
VkBufferUsageFlags usage,
|
||||
VkMemoryPropertyFlags properties) {
|
||||
TextureHandle handle = {};
|
||||
|
||||
VkImageCreateInfo image_info = {};
|
||||
image_info.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
|
||||
image_info.usage = usage;
|
||||
image_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
image_info.imageType = VK_IMAGE_TYPE_2D;
|
||||
image_info.extent.width = size.x;
|
||||
image_info.extent.height = size.y;
|
||||
image_info.extent.depth = 1;
|
||||
image_info.mipLevels = 1;
|
||||
image_info.arrayLayers = 1;
|
||||
image_info.format = image_format;
|
||||
image_info.tiling = VK_IMAGE_TILING_OPTIMAL;
|
||||
image_info.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
image_info.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
image_info.flags = 0;
|
||||
|
||||
VkResult result =
|
||||
vkCreateImage(logical_device_, &image_info, nullptr, &handle.image);
|
||||
if (result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to create vertex buffer!");
|
||||
|
||||
VkMemoryRequirements memory_requirements;
|
||||
vkGetImageMemoryRequirements(logical_device_, handle.image,
|
||||
&memory_requirements);
|
||||
|
||||
std::uint32_t chosen_memory_type =
|
||||
FindMemoryType(memory_requirements.memoryTypeBits, properties);
|
||||
|
||||
VkMemoryAllocateInfo allocation_info = {};
|
||||
allocation_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocation_info.allocationSize = memory_requirements.size;
|
||||
allocation_info.memoryTypeIndex = chosen_memory_type;
|
||||
|
||||
VkResult allocation_result = vkAllocateMemory(
|
||||
logical_device_, &allocation_info, nullptr, &handle.memory);
|
||||
if (allocation_result != VK_SUCCESS)
|
||||
throw std::runtime_error("Failed to allocate image memory!");
|
||||
|
||||
vkBindImageMemory(logical_device_, handle.image, handle.memory, 0);
|
||||
|
||||
return handle;
|
||||
}
|
||||
|
||||
void Graphics::CreateDepthResources() {
|
||||
VkFormat kDepthFormat = VK_FORMAT_D32_SFLOAT;
|
||||
depth_texture_ = CreateImage({extent_.width, extent_.height}, kDepthFormat,
|
||||
VK_IMAGE_USAGE_DEPTH_STENCIL_ATTACHMENT_BIT,
|
||||
VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
depth_texture_.image_view = CreateImageView(
|
||||
depth_texture_.image, kDepthFormat, VK_IMAGE_ASPECT_DEPTH_BIT);
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
73
Client/src/vulkan/validation_layers.cpp
Normal file
73
Client/src/vulkan/validation_layers.cpp
Normal file
@@ -0,0 +1,73 @@
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
namespace veng {
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL
|
||||
ValidationCallback(VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageTypes,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData) {
|
||||
if (messageSeverity & VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT) {
|
||||
spdlog::warn("Vulkan Validation: {}", pCallbackData->pMessage);
|
||||
} else {
|
||||
spdlog::error("Vulkan Validation: {}", pCallbackData->pMessage);
|
||||
}
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT GetCreateMessengerInfo() {
|
||||
VkDebugUtilsMessengerCreateInfoEXT creation_info = {};
|
||||
creation_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
creation_info.messageSeverity =
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
creation_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT |
|
||||
VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT;
|
||||
creation_info.pfnUserCallback = ValidationCallback;
|
||||
creation_info.pUserData = nullptr;
|
||||
|
||||
return creation_info;
|
||||
}
|
||||
|
||||
std::vector<VkLayerProperties> Graphics::GetSupprotedValidationLayers() {
|
||||
std::uint32_t count;
|
||||
vkEnumerateInstanceLayerProperties(&count, nullptr);
|
||||
|
||||
if (count == 0) return {};
|
||||
|
||||
std::vector<VkLayerProperties> properties(count);
|
||||
vkEnumerateInstanceLayerProperties(&count, properties.data());
|
||||
return properties;
|
||||
}
|
||||
|
||||
bool LayerMatchesName(gsl::czstring name, const VkLayerProperties& properties) {
|
||||
return streq(properties.layerName, name);
|
||||
}
|
||||
|
||||
bool IsLayerSupported(gsl::span<VkLayerProperties> layers, gsl::czstring name) {
|
||||
return std::any_of(layers.begin(), layers.end(),
|
||||
std::bind_front(LayerMatchesName, name));
|
||||
}
|
||||
|
||||
bool Graphics::AreAllLayersSupported(gsl::span<gsl::czstring> layers) {
|
||||
std::vector<VkLayerProperties> supported_layers =
|
||||
GetSupprotedValidationLayers();
|
||||
|
||||
return std::all_of(layers.begin(), layers.end(),
|
||||
std::bind_front(IsLayerSupported, supported_layers));
|
||||
}
|
||||
|
||||
void Graphics::SetupDebugMessenger() {
|
||||
if (!validation_enabled_) return;
|
||||
|
||||
VkDebugUtilsMessengerCreateInfoEXT info = GetCreateMessengerInfo();
|
||||
VkResult result = vkCreateDebugUtilsMessengerEXT(instance_, &info, nullptr,
|
||||
&debug_messenger_);
|
||||
if (result != VK_SUCCESS) {
|
||||
spdlog::error("Cannot create debug messenger");
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace veng
|
||||
25
Client/src/vulkan/vk_function_ext_impl.cpp
Normal file
25
Client/src/vulkan/vk_function_ext_impl.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
#include "precomp.h"
|
||||
#include "vulkan/graphics.h"
|
||||
|
||||
VKAPI_ATTR VkResult VKAPI_CALL vkCreateDebugUtilsMessengerEXT(
|
||||
VkInstance instance, const VkDebugUtilsMessengerCreateInfoEXT* pCreateInfo,
|
||||
const VkAllocationCallbacks* pAllocator,
|
||||
VkDebugUtilsMessengerEXT* pMessenger) {
|
||||
PFN_vkCreateDebugUtilsMessengerEXT function =
|
||||
reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(
|
||||
vkGetInstanceProcAddr(instance, "vkCreateDebugUtilsMessengerEXT"));
|
||||
if (function != nullptr) {
|
||||
return function(instance, pCreateInfo, pAllocator, pMessenger);
|
||||
} else {
|
||||
return VK_ERROR_EXTENSION_NOT_PRESENT;
|
||||
}
|
||||
}
|
||||
|
||||
VKAPI_ATTR void VKAPI_CALL vkDestroyDebugUtilsMessengerEXT(
|
||||
VkInstance instance, VkDebugUtilsMessengerEXT messenger,
|
||||
const VkAllocationCallbacks* pAllocator) {
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT function =
|
||||
reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(
|
||||
vkGetInstanceProcAddr(instance, "vkDestroyDebugUtilsMessengerEXT"));
|
||||
if (function != nullptr) function(instance, messenger, pAllocator);
|
||||
}
|
||||
Reference in New Issue
Block a user