Compare commits
37 Commits
e34abea452
...
render
| Author | SHA1 | Date | |
|---|---|---|---|
| 12610f5c7f | |||
| 506776b6d6 | |||
| c95aa557c2 | |||
| 8e09b93f25 | |||
| a69dab3611 | |||
| 82ba9fd191 | |||
| ad881a97a9 | |||
| 311772cca4 | |||
| 8253b81ab1 | |||
| 5886c7acc6 | |||
| 5f3c5d4fc1 | |||
| 2a57a30e29 | |||
| 93eb08fe9f | |||
| b2dee85b26 | |||
| 3cbe642fca | |||
| 70956e2032 | |||
| 7aec01ccc8 | |||
| 280f843fb7 | |||
| 59f147fafc | |||
| cf4f8236f6 | |||
| d1692198af | |||
| 1cfbfd61be | |||
| 7d3e211a50 | |||
| a76120b73a | |||
| 52ba89f193 | |||
| a1cf661286 | |||
| e1db9fd588 | |||
| 6389e6b25f | |||
| fa3e987e93 | |||
| 582b23d0f8 | |||
| 9db3d9b0e2 | |||
| 5b6974aa8b | |||
| 12a55521bd | |||
| 734db410d1 | |||
| 1ab74b8128 | |||
| 740c80e8c7 | |||
| 1f88e0f0b9 |
+2
-1
@@ -1,3 +1,4 @@
|
||||
|
||||
[submodule "glfw"]
|
||||
path = glfw
|
||||
url = https://github.com/glfw/glfw.git
|
||||
url = https://git.burntroosters.twc1.net/Jiga228/glfw.git
|
||||
|
||||
+19
-3
@@ -14,11 +14,27 @@ if(NOT MSVC)
|
||||
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
|
||||
endif()
|
||||
|
||||
if(CMAKE_BUILD_TYPE STREQUAL "Release" OR NOT CMAKE_BUILD_TYPE)
|
||||
if(MSVC)
|
||||
add_compile_options(/GR-)
|
||||
else()
|
||||
add_compile_options(-fno-rtti)
|
||||
# Оптимизации для Microsoft Visual C++
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} /O2 /Oi /Ot /GL /Gw /arch:AVX2")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
set(CMAKE_STATIC_LINKER_FLAGS_RELEASE "${CMAKE_STATIC_LINKER_FLAGS_RELEASE} /LTCG")
|
||||
|
||||
elseif(CMAKE_CXX_COMPILER_ID MATCHES "GNU|Clang")
|
||||
# Оптимизации для GCC и Clang (у них одинаковый синтаксический синтаксис флагов)
|
||||
set(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} -O3 -march=native -flto -fomit-frame-pointer")
|
||||
set(CMAKE_EXE_LINKER_FLAGS_RELEASE "${CMAKE_EXE_LINKER_FLAGS_RELEASE} -flto")
|
||||
set(CMAKE_SHARED_LINKER_FLAGS_RELEASE "${CMAKE_SHARED_LINKER_FLAGS_RELEASE} -flto")
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#if(MSVC)
|
||||
# add_compile_options(/GR-)
|
||||
#else()
|
||||
# add_compile_options(-fno-rtti)
|
||||
#endif()
|
||||
|
||||
if(BUILD_MODE STREQUAL "Engine")
|
||||
add_subdirectory(FastRTTI)
|
||||
|
||||
+31
-6
@@ -4,13 +4,12 @@ find_package(Vulkan REQUIRED)
|
||||
|
||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||
|
||||
add_library(${CORE_NAME} STATIC ${SRC})
|
||||
target_compile_features(${CORE_NAME} PRIVATE cxx_std_17)
|
||||
target_include_directories(${CORE_NAME} PUBLIC
|
||||
add_library(Core STATIC ${SRC})
|
||||
target_compile_features(Core PRIVATE cxx_std_17)
|
||||
target_include_directories(Core PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/FastRTTI
|
||||
${PROJECT_SOURCE_DIR}/Delegate
|
||||
)
|
||||
target_include_directories(${CORE_NAME}
|
||||
target_include_directories(Core
|
||||
PRIVATE
|
||||
${CMAKE_CURRENT_SOURCE_DIR}
|
||||
${PROJECT_SOURCE_DIR}/glfw/Include
|
||||
@@ -18,9 +17,35 @@ target_include_directories(${CORE_NAME}
|
||||
${Vulkan_INCLUDE_DIRS}
|
||||
)
|
||||
|
||||
target_link_libraries(${CORE_NAME} PRIVATE
|
||||
target_link_libraries(Core PRIVATE
|
||||
${CMAKE_DL_LIBS} # For linux
|
||||
FastRTTI
|
||||
glfw
|
||||
Vulkan::Vulkan
|
||||
)
|
||||
|
||||
file(GLOB_RECURSE HEADERS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
|
||||
)
|
||||
|
||||
foreach (HEADER ${HEADERS})
|
||||
file(RELATIVE_PATH R_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||
"${HEADER}"
|
||||
)
|
||||
|
||||
get_filename_component(HEADER_DIR ${R_PATH} DIRECTORY)
|
||||
|
||||
add_custom_command(
|
||||
TARGET Core
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${HEADER_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${HEADER}"
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${R_PATH}"
|
||||
|
||||
COMMENT "Copy Core headers"
|
||||
)
|
||||
endforeach ()
|
||||
@@ -50,30 +50,12 @@ CoreInstance::CoreInstance()
|
||||
|
||||
main_config_.load(std::make_shared<SaveMap>(load_main_config));
|
||||
|
||||
// if (glfwInit() == GLFW_FALSE)
|
||||
// throw std::runtime_error("Fail init glfw");
|
||||
//
|
||||
// glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
// glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
// window_ = glfwCreateWindow(800, 600, main_config_.game_name.c_str(), nullptr, nullptr);
|
||||
// if (window_ == nullptr)
|
||||
// {
|
||||
// std::cout << "[!] Init render engine: Fail create window\n";
|
||||
// return;
|
||||
// }
|
||||
// try {
|
||||
// render_engine_ = new RenderEngine(*this, window_);
|
||||
// } catch (const std::exception& e)
|
||||
// {
|
||||
// std::cout << "[!] Init render engine: " << e.what() << '\n';
|
||||
// return;
|
||||
// }
|
||||
|
||||
try
|
||||
{
|
||||
render_engine_ = RenderEngineFactory(*this);
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
render_engine_ = nullptr;
|
||||
std::cerr << "[!] Init render engine: " << e.what() << '\n';
|
||||
return;
|
||||
}
|
||||
@@ -83,6 +65,7 @@ CoreInstance::CoreInstance()
|
||||
game_ = GameFactory(*this);
|
||||
} catch (const std::exception& e)
|
||||
{
|
||||
game_ = nullptr;
|
||||
std::cout << "[!] Init game instance: " << e.what() << '\n';
|
||||
return;
|
||||
}
|
||||
@@ -108,7 +91,7 @@ void CoreInstance::start()
|
||||
game_thread.join();
|
||||
}
|
||||
|
||||
void CoreInstance::quit()
|
||||
void CoreInstance::quit() const
|
||||
{
|
||||
// Stop the main loop
|
||||
render_engine_->stop_render();
|
||||
|
||||
@@ -10,7 +10,6 @@
|
||||
class SaveMap;
|
||||
class RenderEngineBase;
|
||||
class GameInstance;
|
||||
struct GLFWwindow;
|
||||
|
||||
/*
|
||||
* Внимательно следите, что бы у ваших объектов была "мягкая" зависимость
|
||||
@@ -37,14 +36,13 @@ class CoreInstance {
|
||||
const char* main_config_name = "main_config.conf";
|
||||
MainConfig main_config_;
|
||||
|
||||
int countCPU_;
|
||||
int countCPU_ = 0;
|
||||
// Memory in MB
|
||||
double memorySize_;
|
||||
double memorySize_ = 0;
|
||||
std::list<Module> modules_;
|
||||
|
||||
GLFWwindow* window_ = nullptr;
|
||||
RenderEngineBase* render_engine_;
|
||||
GameInstance* game_;
|
||||
RenderEngineBase* render_engine_ = nullptr;
|
||||
GameInstance* game_ = nullptr;
|
||||
|
||||
bool is_ready = false;
|
||||
public:
|
||||
@@ -52,7 +50,7 @@ public:
|
||||
~CoreInstance();
|
||||
|
||||
void start();
|
||||
void quit();
|
||||
void quit() const;
|
||||
|
||||
bool IsReady() const { return is_ready; }
|
||||
int getCountCPU() const { return countCPU_; }
|
||||
|
||||
@@ -10,23 +10,24 @@
|
||||
#include <stdexcept>
|
||||
|
||||
int System::getCountCPU() {
|
||||
DWORD len = 0;
|
||||
DWORD len = 0; // In bytes
|
||||
GetLogicalProcessorInformation(nullptr, &len);
|
||||
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
|
||||
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||
}
|
||||
DWORD count = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||
|
||||
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(len);
|
||||
std::vector<SYSTEM_LOGICAL_PROCESSOR_INFORMATION> buffer(count);
|
||||
if (!GetLogicalProcessorInformation(buffer.data(), &len)) {
|
||||
throw std::runtime_error(std::to_string(GetLastError()).c_str());
|
||||
}
|
||||
|
||||
DWORD count = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
|
||||
int physicalCoreCount = 0;
|
||||
|
||||
for (DWORD i = 0; i < count; ++i) {
|
||||
if (buffer[i].Relationship == RelationProcessorCore) {
|
||||
physicalCoreCount++;
|
||||
for (auto& i : buffer)
|
||||
{
|
||||
if (i.Relationship == RelationProcessorCore)
|
||||
{
|
||||
++physicalCoreCount;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,360 @@
|
||||
// Create by Jiga228 (https://git.burntroosters.twc1.net/Jiga228)
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
#include <stdexcept>
|
||||
|
||||
/*
|
||||
* Этоот класс по своей сути односвязный список,
|
||||
* каждый элемент которого - подписавшийся объект.
|
||||
* Реализация для случая когда Type_Parameter != void
|
||||
*/
|
||||
|
||||
template<typename Type_Parameter>
|
||||
class Delegate
|
||||
{
|
||||
class ObjectWasDelete : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {}
|
||||
};
|
||||
|
||||
/*
|
||||
* Базовая структура для записи подптсок
|
||||
*/
|
||||
struct BaseListData
|
||||
{
|
||||
std::shared_ptr<BaseListData> next;
|
||||
virtual ~BaseListData() = default;
|
||||
virtual void call(Type_Parameter data) = 0;
|
||||
};
|
||||
|
||||
template<class Type_Object>
|
||||
struct ObjectListData : public BaseListData
|
||||
{
|
||||
using Method = void(Type_Object::*)(Type_Parameter);
|
||||
std::weak_ptr<Type_Object> object;
|
||||
Method method = nullptr;
|
||||
|
||||
ObjectListData() = default;
|
||||
ObjectListData(std::weak_ptr<Type_Object> object, Method method) : object(std::move(object)), method(method) {}
|
||||
void call(Type_Parameter data)
|
||||
{
|
||||
if (auto shared_object = object.lock())
|
||||
{
|
||||
(shared_object.get()->*method)(data);
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ObjectWasDelete();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionListData : public BaseListData
|
||||
{
|
||||
void(*function)(Type_Parameter);
|
||||
FunctionListData() = default;
|
||||
FunctionListData(void(*func)(Type_Parameter)) : function(func) {}
|
||||
void call(Type_Parameter data)
|
||||
{
|
||||
function(data);
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<BaseListData> list_head = nullptr;
|
||||
std::mutex m_list;
|
||||
public:
|
||||
template<class Type_Object>
|
||||
void bind(std::weak_ptr<Type_Object> object, void (Type_Object::*method)(Type_Parameter))
|
||||
{
|
||||
if (!object.expired() && !method)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head = list_head;
|
||||
list_head = std::make_shared<ObjectListData<Type_Object>>(object, method);
|
||||
list_head->next = old_head;
|
||||
}
|
||||
|
||||
void bind(void(*function)(Type_Parameter))
|
||||
{
|
||||
if (!function)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head = list_head;
|
||||
list_head = std::make_shared<FunctionListData>(function);
|
||||
list_head->next = old_head;
|
||||
}
|
||||
|
||||
template<class Type_Object>
|
||||
void unbind(std::shared_ptr<Type_Object> object, void(Type_Object::*method)(Type_Parameter))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
|
||||
if (!list_head)
|
||||
return;
|
||||
|
||||
if (auto object_list_data = dynamic_cast<ObjectListData<Type_Object>*>(list_head.get()))
|
||||
{
|
||||
std::shared_ptr<Type_Object> shared_object_list_data = object_list_data->object.lock();
|
||||
if (!shared_object_list_data)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
}
|
||||
else if (shared_object_list_data == object && object_list_data->method == method)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseListData> old_it = list_head, iterator = list_head->next;
|
||||
while (iterator)
|
||||
{
|
||||
if (auto object_list = dynamic_cast<ObjectListData<Type_Object>*>(iterator.get()))
|
||||
{
|
||||
if (object_list->object.expired())
|
||||
old_it->next = iterator->next;
|
||||
if (object_list->object.lock() == object && object_list->method == method)
|
||||
{
|
||||
old_it->next = iterator->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
old_it = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(void(*func)(Type_Parameter))
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
|
||||
if (!list_head)
|
||||
return;
|
||||
|
||||
if (auto function_list_data = dynamic_cast<FunctionListData*>(list_head.get()))
|
||||
{
|
||||
if (function_list_data->function == func)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseListData> old_it = list_head, iterator = list_head->next;
|
||||
while (iterator)
|
||||
{
|
||||
if (auto function_list = dynamic_cast<FunctionListData*>(iterator.get()))
|
||||
{
|
||||
if (function_list->function == func)
|
||||
{
|
||||
old_it->next = iterator->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void call(Type_Parameter data)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head, iterator = list_head;
|
||||
while(iterator)
|
||||
{
|
||||
try {
|
||||
iterator->call(data);
|
||||
} catch (const ObjectWasDelete&) {
|
||||
if (iterator == list_head)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_head->next = iterator->next;
|
||||
}
|
||||
}
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
/*
|
||||
* Реализация для случая когда Type_Parameter == void
|
||||
*/
|
||||
template<>
|
||||
class Delegate<void>
|
||||
{
|
||||
class ObjectWasDelete : public std::runtime_error
|
||||
{
|
||||
public:
|
||||
ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {}
|
||||
};
|
||||
|
||||
/*
|
||||
* Базовая структура для записи подптсок
|
||||
*/
|
||||
struct BaseListData
|
||||
{
|
||||
std::shared_ptr<BaseListData> next;
|
||||
virtual ~BaseListData() = default;
|
||||
virtual void call() = 0;
|
||||
};
|
||||
|
||||
template<class Type_Object>
|
||||
struct ObjectListData : public BaseListData
|
||||
{
|
||||
using Method = void(Type_Object::*)();
|
||||
std::weak_ptr<Type_Object> object;
|
||||
Method method = nullptr;
|
||||
|
||||
ObjectListData() = default;
|
||||
ObjectListData(std::weak_ptr<Type_Object> object, Method method) : object(std::move(object)), method(method) {}
|
||||
void call()
|
||||
{
|
||||
if (auto shared_object = object.lock())
|
||||
{
|
||||
(shared_object.get()->*method)();
|
||||
}
|
||||
else
|
||||
{
|
||||
throw ObjectWasDelete();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct FunctionListData : public BaseListData
|
||||
{
|
||||
void(*function)();
|
||||
FunctionListData() = default;
|
||||
FunctionListData(void(*func)()) : function(func) {}
|
||||
void call()
|
||||
{
|
||||
function();
|
||||
}
|
||||
};
|
||||
|
||||
std::shared_ptr<BaseListData> list_head = nullptr;
|
||||
std::mutex m_list;
|
||||
public:
|
||||
template<class Type_Object>
|
||||
void bind(std::weak_ptr<Type_Object> object, void (Type_Object::*method)())
|
||||
{
|
||||
if (!object.expired() && !method)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head = list_head;
|
||||
list_head = std::make_shared<ObjectListData<Type_Object>>(object, method);
|
||||
list_head->next = old_head;
|
||||
}
|
||||
|
||||
void bind(void(*function)())
|
||||
{
|
||||
if (!function)
|
||||
return;
|
||||
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head = list_head;
|
||||
list_head = std::make_shared<FunctionListData>(function);
|
||||
list_head->next = old_head;
|
||||
}
|
||||
|
||||
template<class Type_Object>
|
||||
void unbind(std::shared_ptr<Type_Object> object, void(Type_Object::*method)())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
|
||||
if (!list_head)
|
||||
return;
|
||||
|
||||
if (auto object_list_data = dynamic_cast<ObjectListData<Type_Object>*>(list_head.get()))
|
||||
{
|
||||
std::shared_ptr<Type_Object> shared_object_list_data = object_list_data->object.lock();
|
||||
if (!shared_object_list_data)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
}
|
||||
else if (shared_object_list_data == object && object_list_data->method == method)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseListData> old_it = list_head, iterator = list_head->next;
|
||||
while (iterator)
|
||||
{
|
||||
if (auto object_list = dynamic_cast<ObjectListData<Type_Object>*>(iterator.get()))
|
||||
{
|
||||
if (object_list->object.expired())
|
||||
old_it->next = iterator->next;
|
||||
if (object_list->object.lock() == object && object_list->method == method)
|
||||
{
|
||||
old_it->next = iterator->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
old_it = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(void(*func)())
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
|
||||
if (!list_head)
|
||||
return;
|
||||
|
||||
if (auto function_list_data = dynamic_cast<FunctionListData*>(list_head.get()))
|
||||
{
|
||||
if (function_list_data->function == func)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
std::shared_ptr<BaseListData> old_it = list_head, iterator = list_head->next;
|
||||
while (iterator)
|
||||
{
|
||||
if (auto function_list = dynamic_cast<FunctionListData*>(iterator.get()))
|
||||
{
|
||||
if (function_list->function == func)
|
||||
{
|
||||
old_it->next = iterator->next;
|
||||
return;
|
||||
}
|
||||
}
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void call()
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(m_list);
|
||||
std::shared_ptr<BaseListData> old_head, iterator = list_head;
|
||||
while(iterator)
|
||||
{
|
||||
try {
|
||||
iterator->call();
|
||||
} catch (const ObjectWasDelete&) {
|
||||
if (iterator == list_head)
|
||||
{
|
||||
list_head = list_head->next;
|
||||
}
|
||||
else
|
||||
{
|
||||
old_head->next = iterator->next;
|
||||
}
|
||||
}
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
+14
-14
@@ -2,7 +2,6 @@
|
||||
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
void Actor::OnDestroy()
|
||||
{
|
||||
@@ -15,19 +14,20 @@ Actor::Actor() : loc_(new Vector3D), rot_(new Vector3D), scale_(new Vector3D)
|
||||
|
||||
std::shared_ptr<SaveMap> Actor::save()
|
||||
{
|
||||
return std::make_shared<SaveMap>("Actor")
|
||||
->SaveObject("loc", static_cast<UType::object_ptr<ISave>>(loc_))
|
||||
->SaveObject("rot", static_cast<UType::object_ptr<ISave>>(rot_))
|
||||
->SaveObject("scale", UType::object_ptr<ISave>(scale_))
|
||||
->SaveListStrings("tags", std::move(tags));
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Actor");
|
||||
save->SaveObject("loc", loc_);
|
||||
save->SaveObject("rot", rot_);
|
||||
save->SaveObject("scale", scale_);
|
||||
save->SaveListStrings("tags", std::move(tags_));
|
||||
return save;
|
||||
}
|
||||
|
||||
void Actor::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
loc_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("loc"));
|
||||
rot_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("rot"));
|
||||
scale_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("scale"));
|
||||
tags = std::move(save->GetListString("tags"));
|
||||
loc_ = std::static_pointer_cast<Vector3D>(save->GetObject("loc"));
|
||||
rot_ = std::static_pointer_cast<Vector3D>(save->GetObject("rot"));
|
||||
scale_ = std::static_pointer_cast<Vector3D>(save->GetObject("scale"));
|
||||
tags_ = std::move(save->GetListString("tags"));
|
||||
}
|
||||
|
||||
void Actor::BeginPlay()
|
||||
@@ -41,21 +41,21 @@ void Actor::Tick(double delta_time)
|
||||
void Actor::SetActorLocate(const Vector3D& loc) noexcept
|
||||
{
|
||||
*this->loc_ = loc;
|
||||
OnSetActorLocate.Call(loc);
|
||||
OnSetActorLocate.call(loc);
|
||||
}
|
||||
|
||||
void Actor::SetActorRotate(const Vector3D& rot) noexcept
|
||||
{
|
||||
*this->rot_ = rot;
|
||||
OnSetActorRotate.Call(rot);
|
||||
OnSetActorRotate.call(rot);
|
||||
}
|
||||
|
||||
void Actor::AddTag(const std::string& tag) noexcept
|
||||
{
|
||||
tags.push_back(tag);
|
||||
tags_.push_back(tag);
|
||||
}
|
||||
|
||||
void Actor::RemoveTag(const std::string& tag) noexcept
|
||||
{
|
||||
tags.remove(tag);
|
||||
tags_.remove(tag);
|
||||
}
|
||||
|
||||
@@ -7,19 +7,18 @@
|
||||
#include "Game/SaveMap/ISave.h"
|
||||
#include "Delegate/Delegate.h"
|
||||
#include "Math/Vector.hpp"
|
||||
#include "Types/object_ptr.hpp"
|
||||
|
||||
class World;
|
||||
GENERATE_META(Actor)
|
||||
|
||||
class Actor : public ISave, public IRTTI
|
||||
{
|
||||
World* world_;
|
||||
std::shared_ptr<World> world_;
|
||||
std::string name_;
|
||||
|
||||
UType::object_ptr<Vector3D> loc_, rot_, scale_;
|
||||
std::shared_ptr<Vector3D> loc_, rot_, scale_;
|
||||
|
||||
std::list<std::string> tags;
|
||||
std::list<std::string> tags_;
|
||||
|
||||
protected:
|
||||
virtual void OnDestroy();
|
||||
@@ -42,20 +41,20 @@ public:
|
||||
* Вызывает делегат OnSetActorLocate
|
||||
*/
|
||||
void SetActorLocate(const Vector3D& loc) noexcept;
|
||||
inline const UType::object_ptr<Vector3D> GetActorLocate() const { return loc_; }
|
||||
inline Vector3D GetActorLocate() const { return *loc_; }
|
||||
|
||||
/*
|
||||
* Изменяет ориентацию в пространстве
|
||||
* Вызывает делегат OnSetActorRotate
|
||||
*/
|
||||
void SetActorRotate(const Vector3D& rot) noexcept;
|
||||
inline const UType::object_ptr<Vector3D> GetActorRotate() const { return rot_; }
|
||||
inline Vector3D GetActorRotate() const { return *rot_; }
|
||||
|
||||
void AddTag(const std::string& tag) noexcept;
|
||||
void RemoveTag(const std::string& tag) noexcept;
|
||||
const std::list<std::string>& GetTags() const { return tags; }
|
||||
const std::list<std::string>& GetTags() const { return tags_; }
|
||||
|
||||
World* GetWorld() const { return world_; }
|
||||
std::shared_ptr<World> GetWorld() const { return world_; }
|
||||
const std::string& GetName() const { return name_; }
|
||||
|
||||
friend class World;
|
||||
|
||||
@@ -1,12 +1,10 @@
|
||||
#include "ObjectFactory.hpp"
|
||||
#include "Actors/Mesh/StaticMesh.hpp"
|
||||
|
||||
#include "Game/Actors/Actor.hpp"
|
||||
#include "Math/Vector.hpp"
|
||||
|
||||
std::vector<ObjectFactory> base_object_factories = {
|
||||
GENERATE_FACTORY_OBJECT(Actor)
|
||||
GENERATE_FACTORY_OBJECT(StaticMesh)
|
||||
GENERATE_FACTORY_OBJECT(Vector2D)
|
||||
GENERATE_FACTORY_OBJECT(Vector3D)
|
||||
};
|
||||
@@ -1,58 +1,49 @@
|
||||
#include "GameInstance.hpp"
|
||||
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <chrono>
|
||||
#include <thread>
|
||||
|
||||
#include "ModelManager.hpp"
|
||||
#include "Core/CoreInstance.hpp"
|
||||
#include "Game/WorldFactory.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
extern std::vector<WorldFactory> world_factories;
|
||||
|
||||
GameInstance::GameInstance(CoreInstance& core) : core(core)
|
||||
GameInstance::GameInstance(CoreInstance& core) : core_(core)
|
||||
{
|
||||
const std::string& base_world = core.getBaseWorldName();
|
||||
|
||||
// Init directories
|
||||
std::filesystem::create_directories(std::filesystem::path("./Resources"));
|
||||
|
||||
current_model_manager_ = new ModelManager();
|
||||
|
||||
for (auto& factories : world_factories)
|
||||
{
|
||||
if (factories.world_name == base_world)
|
||||
{
|
||||
world = factories.factory(*this);
|
||||
world_ = factories.factory(*this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (world == nullptr)
|
||||
if (world_ == nullptr)
|
||||
throw std::runtime_error("Can't find world");
|
||||
|
||||
}
|
||||
|
||||
GameInstance::~GameInstance()
|
||||
{
|
||||
delete world;
|
||||
delete current_model_manager_;
|
||||
}
|
||||
|
||||
void GameInstance::start()
|
||||
{
|
||||
world->BeginPlay();
|
||||
world_->BeginPlay();
|
||||
|
||||
auto first = std::chrono::steady_clock::now();
|
||||
|
||||
|
||||
while (is_running)
|
||||
while (is_running_)
|
||||
{
|
||||
auto second = std::chrono::steady_clock::now();
|
||||
std::chrono::milliseconds delta_time = std::chrono::duration_cast<std::chrono::milliseconds>(second - first);
|
||||
world->Tick(delta_time.count() / 1000.0);
|
||||
world_->Tick(delta_time.count() / 1000.0);
|
||||
first = second;
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
}
|
||||
@@ -60,11 +51,11 @@ void GameInstance::start()
|
||||
|
||||
void GameInstance::stop()
|
||||
{
|
||||
is_running = false;
|
||||
is_running_ = false;
|
||||
}
|
||||
|
||||
void GameInstance::quit()
|
||||
{
|
||||
stop();
|
||||
core.quit();
|
||||
core_.quit();
|
||||
}
|
||||
|
||||
@@ -5,18 +5,16 @@
|
||||
|
||||
class CoreInstance;
|
||||
class World;
|
||||
class ModelManager;
|
||||
|
||||
#define GENERATE_FACTORY_GAME_INSTANCE(Class) \
|
||||
GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
|
||||
|
||||
class GameInstance
|
||||
{
|
||||
CoreInstance& core;
|
||||
World* world = nullptr;
|
||||
ModelManager* current_model_manager_ = nullptr;
|
||||
CoreInstance& core_;
|
||||
std::shared_ptr<World> world_;
|
||||
|
||||
std::atomic<bool> is_running = true;
|
||||
std::atomic<bool> is_running_ = true;
|
||||
|
||||
void start();
|
||||
// Stop call from the core
|
||||
@@ -27,11 +25,10 @@ public:
|
||||
|
||||
// Init vulkan
|
||||
GameInstance(CoreInstance& core);
|
||||
virtual ~GameInstance();
|
||||
virtual ~GameInstance() = default;
|
||||
|
||||
World* GetWorld() const { return world; }
|
||||
CoreInstance& GetCore() const { return core; }
|
||||
ModelManager* GetCurrentModelManager() const { return current_model_manager_; }
|
||||
std::shared_ptr<World> GetWorld() const { return world_; }
|
||||
CoreInstance& GetCore() const { return core_; }
|
||||
|
||||
friend class CoreInstance;
|
||||
};
|
||||
|
||||
@@ -1,107 +0,0 @@
|
||||
#include "ModelManager.hpp"
|
||||
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
ModelManager::StaticModel::StaticModel(const std::vector<Voxel>& voxels, std::string name):
|
||||
name_(std::move(name)),
|
||||
voxels_(voxels)
|
||||
{
|
||||
glm::ivec3 sum_moments{0, 0, 0};
|
||||
int sum_masses = 0;
|
||||
|
||||
for (auto& i : voxels_)
|
||||
{
|
||||
sum_moments += glm::ivec3{i.loc.x * i.mass, i.loc.y * i.mass, i.loc.z * i.mass};
|
||||
sum_masses += i.mass;
|
||||
}
|
||||
|
||||
if(sum_masses != 0)
|
||||
sum_moments /= sum_masses;
|
||||
else if (!voxels_.empty())
|
||||
{
|
||||
sum_moments.x /= static_cast<int>(voxels_.size());
|
||||
sum_moments.y /= static_cast<int>(voxels_.size());
|
||||
sum_moments.z /= static_cast<int>(voxels_.size());
|
||||
}
|
||||
|
||||
mass_center_ = sum_moments;
|
||||
}
|
||||
|
||||
ModelManager::StaticModel::~StaticModel()
|
||||
{
|
||||
OnDestroy.Call(name_);
|
||||
}
|
||||
|
||||
ModelManager::owner_counter::owner_counter(const owner_counter& other) : counter(other.counter.load()), model(other.model)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int ModelManager::FNV1aHash(const char* buf)
|
||||
{
|
||||
unsigned int h_val = 0x811c9dc5;
|
||||
|
||||
while (*buf)
|
||||
{
|
||||
h_val ^= static_cast<unsigned int>(*buf++);
|
||||
h_val *= 0x01000193;
|
||||
}
|
||||
|
||||
return h_val;
|
||||
}
|
||||
|
||||
void ModelManager::OnDestroySometimeModelCaller(const std::string& name)
|
||||
{
|
||||
Loging::Log("Free model: " + name);
|
||||
OnDestroySometimeModel.Call(name);
|
||||
}
|
||||
|
||||
ModelManager::~ModelManager()
|
||||
{
|
||||
for (const auto& [it, counter] : models)
|
||||
{
|
||||
counter.model->OnDestroy.unbind(this, &ModelManager::OnDestroySometimeModelCaller);
|
||||
}
|
||||
models.clear();
|
||||
}
|
||||
|
||||
ModelManager::StaticModel* ModelManager::LoadModel(const std::string& name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
unsigned int hash = FNV1aHash(name.c_str());
|
||||
auto counter = models.find(hash);
|
||||
if (counter != models.cend())
|
||||
{
|
||||
++counter->second.counter;
|
||||
return counter->second.model;
|
||||
}
|
||||
|
||||
Loging::Log("Load new model: " + name);
|
||||
|
||||
std::vector<Voxel> model_data;
|
||||
// Load model_data
|
||||
owner_counter new_counter;
|
||||
new_counter.counter.store(1);
|
||||
new_counter.model = new StaticModel(model_data, name);
|
||||
new_counter.model->OnDestroy.bind(this, &ModelManager::OnDestroySometimeModelCaller);
|
||||
models.try_emplace(hash, new_counter);
|
||||
OnLoadSometimeModel.Call(new_counter.model);
|
||||
return new_counter.model;
|
||||
}
|
||||
|
||||
void ModelManager::FreeModel(const std::string& name)
|
||||
{
|
||||
if (name.empty())
|
||||
return;
|
||||
|
||||
unsigned int hash = FNV1aHash(name.c_str());
|
||||
auto counter = models.find(hash);
|
||||
--counter->second.counter;
|
||||
|
||||
StaticModel* model = counter->second.model;
|
||||
if (counter->second.counter.load() == 0)
|
||||
{
|
||||
models.erase(hash);
|
||||
delete model;
|
||||
}
|
||||
}
|
||||
@@ -1,58 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <Delegate/Delegate.h>
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
class ModelManager
|
||||
{
|
||||
public:
|
||||
struct Voxel
|
||||
{
|
||||
glm::vec3 loc, color;
|
||||
int mass;
|
||||
};
|
||||
class StaticModel
|
||||
{
|
||||
std::string name_;
|
||||
std::vector<Voxel> voxels_;
|
||||
glm::vec3 mass_center_;
|
||||
public:
|
||||
Delegate<const std::string&> OnDestroy;
|
||||
|
||||
StaticModel(const std::vector<Voxel>& voxels, std::string name);
|
||||
~StaticModel();
|
||||
|
||||
const std::vector<Voxel>& GetVoxels() const { return voxels_; }
|
||||
glm::vec3 GetMassCenter() const { return mass_center_; }
|
||||
const std::string& GetName() const { return name_; }
|
||||
};
|
||||
|
||||
struct owner_counter
|
||||
{
|
||||
std::atomic_ullong counter;
|
||||
StaticModel* model;
|
||||
|
||||
owner_counter() = default;
|
||||
owner_counter(const owner_counter& other);
|
||||
};
|
||||
|
||||
private:
|
||||
|
||||
std::unordered_map<unsigned int, owner_counter> models;
|
||||
|
||||
static unsigned int FNV1aHash (const char *buf);
|
||||
|
||||
void OnDestroySometimeModelCaller(const std::string& name);
|
||||
|
||||
public:
|
||||
Delegate<std::string> OnDestroySometimeModel;
|
||||
Delegate<StaticModel*> OnLoadSometimeModel;
|
||||
|
||||
~ModelManager();
|
||||
|
||||
StaticModel* LoadModel(const std::string& name);
|
||||
void FreeModel(const std::string& name);
|
||||
};
|
||||
@@ -4,7 +4,7 @@
|
||||
|
||||
class SaveMap;
|
||||
|
||||
class ISave
|
||||
class ISave : public std::enable_shared_from_this<ISave>
|
||||
{
|
||||
public:
|
||||
virtual ~ISave() = default;
|
||||
|
||||
@@ -21,7 +21,7 @@ ISave* SaveMap::MakeObjectByName(const std::string& name)
|
||||
return factory.factory();
|
||||
}
|
||||
}
|
||||
throw std::runtime_error("Object not found");
|
||||
throw std::runtime_error("Object not found (" + name + ")");
|
||||
}
|
||||
|
||||
SaveMap::SaveMap(const char* class_name) : class_name(class_name)
|
||||
@@ -56,14 +56,14 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
size_t end = i = json_data_blank.find_first_of(",}", i);
|
||||
i++;
|
||||
std::string value = json_data_blank.substr(begin, end - begin);
|
||||
save_long[name.c_str() + 1] = std::stoll(value);
|
||||
save_long[name.c_str() + 1] = std::stoll(value); // (name.c_str() + 1) - отсекаем метаданные
|
||||
} else if (name[0] == 'd')
|
||||
{
|
||||
size_t begin = json_data_blank.find(':', i) + 1;
|
||||
size_t end = i = json_data_blank.find_first_of(",}", i);
|
||||
i++;
|
||||
std::string value = json_data_blank.substr(begin, end - begin);
|
||||
save_double[name.c_str() + 1] = std::stod(value);
|
||||
save_double[name.c_str() + 1] = std::stod(value); // (name.c_str() + 1) - отсекаем метаданные
|
||||
} else if (name[0] == 's')
|
||||
{
|
||||
size_t begin = json_data_blank.find(':', i) + 2;
|
||||
@@ -74,7 +74,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
value = json_data_blank.substr(begin, end - begin);
|
||||
else
|
||||
value = "";
|
||||
save_string[name.c_str() + 1] = value;
|
||||
save_string[name.c_str() + 1] = value; // (name.c_str() + 1) - отсекаем метаданные
|
||||
} else if (name[0] == 'o')
|
||||
{
|
||||
size_t begin = i = json_data_blank.find('{', i);
|
||||
@@ -97,13 +97,13 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
end = object_json.find('\"', begin);
|
||||
|
||||
std::string object_name = object_json.substr(begin, end - begin);
|
||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
|
||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||
save_objects[name.c_str() + 1] = object_ptr;
|
||||
save_objects[name.c_str() + 1] = object_ptr; // (name.c_str() + 1) - отсекаем метаданные
|
||||
} else if (name[0] == 'v')
|
||||
{
|
||||
std::string key = name.substr(2, name.length() - 2);
|
||||
std::string key = name.substr(2, name.length() - 2); // (off = 2) - отсечение метаданных; (name.length() - 2) - отсечение кавычки и перевод в индексы
|
||||
|
||||
size_t begin_arr = i = json_data_blank.find('[', i);
|
||||
int open = 1, close = 0;
|
||||
@@ -171,10 +171,10 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
}
|
||||
} else if (name[1] == 'o')
|
||||
{
|
||||
save_vector_objects[key] = std::vector<UType::object_ptr<ISave>>();
|
||||
save_vector_objects[key] = std::vector<std::shared_ptr<ISave>>();
|
||||
if (arr_data.length() == 2)
|
||||
continue;
|
||||
std::vector<UType::object_ptr<ISave>>& vector_object = save_vector_objects[key];
|
||||
std::vector<std::shared_ptr<ISave>>& vector_object = save_vector_objects[key];
|
||||
|
||||
size_t j = 1;
|
||||
while (j < arr_data.length())
|
||||
@@ -198,7 +198,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
size_t end_name = object_json.find('\"', begin_name);
|
||||
|
||||
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
|
||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||
vector_object.push_back(object_ptr);
|
||||
@@ -272,10 +272,10 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
}
|
||||
} else if (name[1] == 'o')
|
||||
{
|
||||
save_list_objects[key] = std::list<UType::object_ptr<ISave>>();
|
||||
save_list_objects[key] = std::list<std::shared_ptr<ISave>>();
|
||||
if (arr_data.length() == 2)
|
||||
continue;
|
||||
std::list<UType::object_ptr<ISave>>& list_object = save_list_objects[key];
|
||||
std::list<std::shared_ptr<ISave>>& list_object = save_list_objects[key];
|
||||
|
||||
size_t j = 1;
|
||||
while (j < arr_data.length())
|
||||
@@ -299,7 +299,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
||||
size_t end_name = object_json.find('\"', begin_name);
|
||||
|
||||
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||
|
||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||
list_object.push_back(object_ptr);
|
||||
@@ -371,76 +371,64 @@ save_list_objects(std::move(save_map.save_list_objects))
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveInteger(const char* name, int value) noexcept
|
||||
void SaveMap::SaveInteger(const char* name, int value) noexcept
|
||||
{
|
||||
save_long[name] = value;
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveDouble(const char* name, double value) noexcept
|
||||
void SaveMap::SaveDouble(const char* name, double value) noexcept
|
||||
{
|
||||
save_double[name] = value;
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveString(const char* name, const std::string& value) noexcept
|
||||
void SaveMap::SaveString(const char* name, const std::string& value) noexcept
|
||||
{
|
||||
save_string[name] = value;
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept
|
||||
void SaveMap::SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept
|
||||
{
|
||||
save_objects[name] = object;
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept
|
||||
void SaveMap::SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept
|
||||
{
|
||||
save_vector_integer[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept
|
||||
void SaveMap::SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept
|
||||
{
|
||||
save_vector_double[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept
|
||||
void SaveMap::SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept
|
||||
{
|
||||
save_vector_strings[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept
|
||||
void SaveMap::SaveVectorObject(const char* name, std::vector<std::shared_ptr<ISave>>&& value) noexcept
|
||||
{
|
||||
save_vector_objects[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveListInteger(const char* name, std::list<long long>&& value) noexcept
|
||||
void SaveMap::SaveListInteger(const char* name, std::list<long long>&& value) noexcept
|
||||
{
|
||||
save_list_integer[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveListDouble(const char* name, std::list<double>&& value) noexcept
|
||||
void SaveMap::SaveListDouble(const char* name, std::list<double>&& value) noexcept
|
||||
{
|
||||
save_list_double[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveListStrings(const char* name, std::list<std::string>&& value) noexcept
|
||||
void SaveMap::SaveListStrings(const char* name, std::list<std::string>&& value) noexcept
|
||||
{
|
||||
save_list_strings[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& value) noexcept
|
||||
void SaveMap::SaveListObject(const char* name, std::list<std::shared_ptr<ISave>>&& value) noexcept
|
||||
{
|
||||
save_list_objects[name] = std::move(value);
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
long long SaveMap::GetInteger(const char* name)
|
||||
@@ -458,7 +446,7 @@ std::string SaveMap::GetString(const char* name)
|
||||
return save_string[name];
|
||||
}
|
||||
|
||||
UType::object_ptr<ISave> SaveMap::GetObject(const char* name)
|
||||
std::shared_ptr<ISave> SaveMap::GetObject(const char* name)
|
||||
{
|
||||
return save_objects[name];
|
||||
}
|
||||
@@ -478,7 +466,7 @@ std::vector<std::string> SaveMap::GetVectorString(const char* name)
|
||||
return save_vector_strings[name];
|
||||
}
|
||||
|
||||
std::vector<UType::object_ptr<ISave>>& SaveMap::GetVectorObject(const char* name)
|
||||
std::vector<std::shared_ptr<ISave>>& SaveMap::GetVectorObject(const char* name)
|
||||
{
|
||||
return save_vector_objects[name];
|
||||
}
|
||||
@@ -498,7 +486,7 @@ std::list<std::string>& SaveMap::GetListString(const char* name)
|
||||
return save_list_strings[name];
|
||||
}
|
||||
|
||||
std::list<UType::object_ptr<ISave>>& SaveMap::GetListObject(const char* name)
|
||||
std::list<std::shared_ptr<ISave>>& SaveMap::GetListObject(const char* name)
|
||||
{
|
||||
return save_list_objects[name];
|
||||
}
|
||||
@@ -517,7 +505,7 @@ std::string SaveMap::serialize() noexcept
|
||||
buffer += ",\"s" + key + "\":\"" + value + '\"';
|
||||
|
||||
for (auto& [key, value] : save_objects)
|
||||
buffer += ",\"o" + key + "\":\"" + value->save()->serialize();
|
||||
buffer += ",\"o" + key + "\":" + value->save()->serialize();
|
||||
|
||||
for (auto& [key, value] : save_vector_integer)
|
||||
{
|
||||
@@ -631,13 +619,12 @@ std::string SaveMap::serialize() noexcept
|
||||
return buffer;
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> SaveMap::connect_to(const std::shared_ptr<SaveMap>& parent)
|
||||
void SaveMap::connect_to(const std::shared_ptr<SaveMap>& parent)
|
||||
{
|
||||
if (this->parent_ != nullptr)
|
||||
throw std::runtime_error("Can't connect to second parent");
|
||||
|
||||
this->parent_ = parent;
|
||||
return std::shared_ptr<SaveMap>(this);
|
||||
}
|
||||
|
||||
std::string SaveMap::CleaningJSON(const std::string& json_data)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
#pragma once
|
||||
|
||||
#include "ISave.h"
|
||||
#include "Types/object_ptr.hpp"
|
||||
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
@@ -18,18 +17,18 @@ class SaveMap final
|
||||
std::unordered_map<std::string, long long> save_long;
|
||||
std::unordered_map<std::string, double> save_double;
|
||||
std::unordered_map<std::string, std::string> save_string;
|
||||
std::unordered_map<std::string, UType::object_ptr<ISave>> save_objects;
|
||||
std::unordered_map<std::string, std::shared_ptr<ISave>> save_objects;
|
||||
|
||||
// Массивы
|
||||
std::unordered_map<std::string, std::vector<long long>> save_vector_integer;
|
||||
std::unordered_map<std::string, std::vector<double>> save_vector_double;
|
||||
std::unordered_map<std::string, std::vector<UType::object_ptr<ISave>>> save_vector_objects;
|
||||
std::unordered_map<std::string, std::vector<std::shared_ptr<ISave>>> save_vector_objects;
|
||||
std::unordered_map<std::string, std::vector<std::string>> save_vector_strings;
|
||||
|
||||
// Связаные списки
|
||||
std::unordered_map<std::string, std::list<long long>> save_list_integer;
|
||||
std::unordered_map<std::string, std::list<double>> save_list_double;
|
||||
std::unordered_map<std::string, std::list<UType::object_ptr<ISave>>> save_list_objects;
|
||||
std::unordered_map<std::string, std::list<std::shared_ptr<ISave>>> save_list_objects;
|
||||
std::unordered_map<std::string, std::list<std::string>> save_list_strings;
|
||||
|
||||
static ISave* MakeObjectByName(const std::string& name);
|
||||
@@ -45,32 +44,32 @@ public:
|
||||
SaveMap(SaveMap&& save_map) noexcept;
|
||||
|
||||
// Методы созранения значений
|
||||
std::shared_ptr<SaveMap> SaveInteger(const char* name, int value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveDouble(const char* name, double value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveString(const char* name, const std::string& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveListInteger(const char* name, std::list<long long>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveListDouble(const char* name, std::list<double>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
|
||||
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& value) noexcept;
|
||||
void SaveInteger(const char* name, int value) noexcept;
|
||||
void SaveDouble(const char* name, double value) noexcept;
|
||||
void SaveString(const char* name, const std::string& value) noexcept;
|
||||
void SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept;
|
||||
void SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
|
||||
void SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
|
||||
void SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
|
||||
void SaveVectorObject(const char* name, std::vector<std::shared_ptr<ISave>>&& value) noexcept;
|
||||
void SaveListInteger(const char* name, std::list<long long>&& value) noexcept;
|
||||
void SaveListDouble(const char* name, std::list<double>&& value) noexcept;
|
||||
void SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
|
||||
void SaveListObject(const char* name, std::list<std::shared_ptr<ISave>>&& value) noexcept;
|
||||
|
||||
// Методы получения значенй
|
||||
long long GetInteger(const char* name);
|
||||
double GetDouble(const char* name);
|
||||
std::string GetString(const char* name);
|
||||
UType::object_ptr<ISave> GetObject(const char* name);
|
||||
std::shared_ptr<ISave> GetObject(const char* name);
|
||||
std::vector<long long>& GetVectorInteger(const char* name);
|
||||
std::vector<double>& GetVectorDouble(const char* name);
|
||||
std::vector<std::string> GetVectorString(const char* name);
|
||||
std::vector<UType::object_ptr<ISave>>& GetVectorObject(const char* name);
|
||||
std::vector<std::shared_ptr<ISave>>& GetVectorObject(const char* name);
|
||||
std::list<long long>& GetListInteger(const char* name);
|
||||
std::list<double>& GetListDouble(const char* name);
|
||||
std::list<std::string>& GetListString(const char* name);
|
||||
std::list<UType::object_ptr<ISave>>& GetListObject(const char* name);
|
||||
std::list<std::shared_ptr<ISave>>& GetListObject(const char* name);
|
||||
|
||||
std::shared_ptr<SaveMap> getParent() const { return parent_; }
|
||||
const std::string& getClassName() const { return class_name; }
|
||||
@@ -78,7 +77,7 @@ public:
|
||||
// Собирает все токены в JSON объект
|
||||
std::string serialize() noexcept;
|
||||
|
||||
std::shared_ptr<SaveMap> connect_to(const std::shared_ptr<SaveMap>& parent);
|
||||
void connect_to(const std::shared_ptr<SaveMap>& parent);
|
||||
|
||||
static std::string CleaningJSON(const std::string& json_data);
|
||||
};
|
||||
|
||||
+29
-14
@@ -2,57 +2,72 @@
|
||||
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
|
||||
World::World(GameInstance& game_instance) : game_instance(game_instance)
|
||||
World::World(GameInstance& game_instance) : game_instance_(game_instance)
|
||||
{
|
||||
}
|
||||
|
||||
World::~World()
|
||||
{
|
||||
for (auto& i : actors_map)
|
||||
for (auto& i : actors_map_)
|
||||
i.second->OnDestroy();
|
||||
actors_map.clear();
|
||||
actors_map_.clear();
|
||||
}
|
||||
|
||||
void World::BeginPlay()
|
||||
{
|
||||
for (auto& i : actors_map)
|
||||
for (auto& i : actors_map_)
|
||||
i.second->BeginPlay();
|
||||
}
|
||||
|
||||
void World::Tick(double delta_time)
|
||||
{
|
||||
for (auto& i : actors_map)
|
||||
for (auto& i : actors_map_)
|
||||
i.second->Tick(delta_time);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> World::save()
|
||||
{
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("World");
|
||||
|
||||
std::vector<std::string> ActorsIDs;
|
||||
ActorsIDs.reserve(actors_map_.size());
|
||||
std::list<std::shared_ptr<ISave>> actors;
|
||||
for (auto[it, flag] : actors_map_)
|
||||
{
|
||||
ActorsIDs.push_back(it);
|
||||
actors.push_back(flag);
|
||||
}
|
||||
save->SaveVectorStrings("ActorsIDs", std::move(ActorsIDs));
|
||||
save->SaveListObject("Actors", std::move(actors));
|
||||
|
||||
return save;
|
||||
}
|
||||
|
||||
void World::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
std::vector<std::string> actors_IDs = save->GetVectorString("ActorsIDs");
|
||||
std::list<UType::object_ptr<Actor>> act = std::move(reinterpret_cast<std::list<UType::object_ptr<Actor>>&>(save->GetListObject("Actors")));
|
||||
std::list<std::shared_ptr<ISave>> act = save->GetListObject("Actors");
|
||||
|
||||
size_t i_id = 0;
|
||||
for (auto& i : act)
|
||||
{
|
||||
auto[it, flag] = actors_map.try_emplace(actors_IDs[i_id], i);
|
||||
it->second->world_ = this;
|
||||
auto[it, flag] = actors_map_.try_emplace(actors_IDs[i_id], std::static_pointer_cast<Actor>(i));
|
||||
it->second->world_ = std::static_pointer_cast<World>(shared_from_this());
|
||||
it->second->name_ = it->first;
|
||||
i_id++;
|
||||
}
|
||||
}
|
||||
|
||||
void World::DestroyActor(UType::object_ptr<Actor> ptr)
|
||||
void World::DestroyActor(std::weak_ptr<Actor> ptr)
|
||||
{
|
||||
if (ptr.get() == nullptr)
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
std::shared_ptr<Actor> actor = ptr.lock();
|
||||
if (actor == nullptr)
|
||||
return;
|
||||
|
||||
std::string name = ptr->GetName();
|
||||
actors_map.erase(name);
|
||||
ptr->OnDestroy();
|
||||
ptr.destroy();
|
||||
std::string name = actor->GetName();
|
||||
actor->OnDestroy();
|
||||
actors_map_.erase(name);
|
||||
}
|
||||
|
||||
+35
-23
@@ -4,20 +4,20 @@
|
||||
#include <unordered_map>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <mutex>
|
||||
|
||||
#include "RTTI.h"
|
||||
#include "Game/Actors/Actor.hpp"
|
||||
#include "Game/Actors/Mesh/Mesh.hpp"
|
||||
#include "Types/object_ptr.hpp"
|
||||
|
||||
class GameInstance;
|
||||
|
||||
GENERATE_META(World);
|
||||
class World : public ISave
|
||||
{
|
||||
GameInstance& game_instance;
|
||||
GameInstance& game_instance_;
|
||||
|
||||
std::unordered_map<std::string, UType::object_ptr<Actor>> actors_map;
|
||||
std::unordered_map<std::string, std::shared_ptr<Actor>> actors_map_;
|
||||
std::mutex m_actors_map_;
|
||||
|
||||
public:
|
||||
World(GameInstance& game_instance);
|
||||
@@ -26,50 +26,57 @@ public:
|
||||
virtual void BeginPlay();
|
||||
virtual void Tick(double delta_time);
|
||||
|
||||
GameInstance& GetGameInstance() const { return game_instance; }
|
||||
GameInstance& GetGameInstance() const { return game_instance_; }
|
||||
|
||||
#pragma region ISave
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
#pragma endregion
|
||||
|
||||
template<class T>
|
||||
std::vector<UType::object_ptr<T>> GetActorsByClass()
|
||||
template<class T, template<class...> class Container = std::vector>
|
||||
Container<std::weak_ptr<T>> GetActorsByClass()
|
||||
{
|
||||
std::vector<UType::object_ptr<T>> list;
|
||||
for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i)
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
Container<std::weak_ptr<T>> list;
|
||||
for (auto i = actors_map_.cbegin(); i != actors_map_.cend(); ++i)
|
||||
{
|
||||
if (T* cast_object = RTTI::dyn_cast<T, Actor>(i->second.get()))
|
||||
list.push_back(UType::object_ptr<T>(cast_object));
|
||||
if (RTTI::dyn_cast<T, Actor>(i->second.get()))
|
||||
list.push_back(std::static_pointer_cast<T>(i->second));
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UType::object_ptr<T> SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 })
|
||||
std::weak_ptr<T> SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 })
|
||||
{
|
||||
UType::object_ptr<T> object(new T());
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
std::shared_ptr<T> object = std::make_shared<T>();
|
||||
object->SetActorLocate(loc);
|
||||
object->SetActorRotate(rot);
|
||||
static_cast<Actor*>(object)->world_ = this;
|
||||
actors_map.try_emplace(name, object);
|
||||
std::static_pointer_cast<Actor>(object)->world_ = std::static_pointer_cast<World>(shared_from_this());
|
||||
std::static_pointer_cast<Actor>(object)->name_ = name;
|
||||
actors_map_.try_emplace(name, object);
|
||||
return object;
|
||||
}
|
||||
|
||||
void DestroyActor(UType::object_ptr<Actor> ptr);
|
||||
void DestroyActor(std::weak_ptr<Actor> ptr);
|
||||
|
||||
template<class T, class Container = std::vector<T*>>
|
||||
Container GetActorsByTag(std::string tag)
|
||||
template<class T, template<class...> class Container = std::vector>
|
||||
Container<std::weak_ptr<T>> GetActorsByTag(std::string tag)
|
||||
{
|
||||
Container container;
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
Container<std::weak_ptr<T>> container;
|
||||
|
||||
for (auto& i : actors_map)
|
||||
for (auto& i : actors_map_)
|
||||
{
|
||||
if (RTTI::dyn_cast<T, Actor>(i.second.get()))
|
||||
{
|
||||
const std::list<std::string>& tags = i.second->GetTags();
|
||||
for (auto& j : tags)
|
||||
{
|
||||
if (j == tag)
|
||||
container.push_back(i);
|
||||
container.push_back(i.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -77,9 +84,14 @@ public:
|
||||
}
|
||||
|
||||
template<class T>
|
||||
UType::object_ptr<T> GetActorByID(const std::string& id)
|
||||
std::weak_ptr<T> GetActorByName(const std::string& name)
|
||||
{
|
||||
return actors_map[id];
|
||||
std::scoped_lock lock(m_actors_map_);
|
||||
auto it = actors_map_.find(name);
|
||||
if (it == actors_map_.end() || it->second == nullptr)
|
||||
return {};
|
||||
|
||||
return std::static_pointer_cast<T>(it->second);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -11,7 +11,7 @@ class World;
|
||||
struct WorldFactory
|
||||
{
|
||||
const char* world_name;
|
||||
World*(*factory)(GameInstance&);
|
||||
std::shared_ptr<World>(*factory)(GameInstance&);
|
||||
};
|
||||
|
||||
// Создаёт ассоцеативный список
|
||||
@@ -20,8 +20,8 @@ struct WorldFactory
|
||||
|
||||
// Генерирует элемент списка
|
||||
#define GENERATE_WORLD_FACTORY(Class, WorldName) WorldFactory{#WorldName,\
|
||||
[](GameInstance& game_insance)->World* {\
|
||||
Class* world = new Class(game_insance);\
|
||||
[](GameInstance& game_insance)->std::shared_ptr<World> {\
|
||||
std::shared_ptr<Class> world = std::make_shared<Class>(game_insance);\
|
||||
std::ifstream config_file("./Worlds/" #WorldName ".world");\
|
||||
if (config_file.fail())\
|
||||
throw std::runtime_error("Can't open world file");\
|
||||
@@ -32,7 +32,7 @@ struct WorldFactory
|
||||
data.resize(file_size);\
|
||||
config_file.read(data.data(), file_size);\
|
||||
world->load(std::make_shared<SaveMap>(data));\
|
||||
return world;\
|
||||
return std::static_pointer_cast<World>(world);\
|
||||
}},
|
||||
|
||||
/*
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
|
||||
Vector2D::Vector2D(const double x, const double y) : x(x), y(y)
|
||||
Vector2D::Vector2D(double x, double y) : x(x), y(y)
|
||||
{}
|
||||
|
||||
Vector2D::Vector2D(const Vector3D& vec3D) : x(vec3D.x), y(vec3D.y)
|
||||
@@ -20,8 +20,9 @@ Vector2D Vector2D::operator-(const Vector2D& v) const
|
||||
|
||||
std::shared_ptr<SaveMap> Vector2D::save()
|
||||
{
|
||||
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector2D");
|
||||
save->SaveDouble("x", x)->SaveDouble("y", y);
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Vector2D");
|
||||
save->SaveDouble("x", x);
|
||||
save->SaveDouble("y", y);
|
||||
return save;
|
||||
}
|
||||
|
||||
@@ -31,7 +32,7 @@ void Vector2D::load(std::shared_ptr<SaveMap> save)
|
||||
y = save->GetDouble("y");
|
||||
}
|
||||
|
||||
Vector3D::Vector3D(const double x, const double y, const double z) : x(x), y(y), z(z)
|
||||
Vector3D::Vector3D(double x, double y, double z) : x(x), y(y), z(z)
|
||||
{}
|
||||
|
||||
Vector3D::Vector3D(const Vector2D& vec2D) : x(vec2D.x), y(vec2D.y)
|
||||
@@ -50,7 +51,9 @@ Vector3D Vector3D::operator-(const Vector3D& v) const
|
||||
std::shared_ptr<SaveMap> Vector3D::save()
|
||||
{
|
||||
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector3D");
|
||||
save->SaveDouble("x", x)->SaveDouble("y", y)->SaveDouble("z", z);
|
||||
save->SaveDouble("x", x);
|
||||
save->SaveDouble("y", y);
|
||||
save->SaveDouble("z", z);
|
||||
return save;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
#include "object_ptr.hpp"
|
||||
|
||||
std::unordered_map<void*, UType::counter::counter_owners> UType::counter::owners_map;
|
||||
@@ -1,185 +0,0 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
#include <unordered_map>
|
||||
#include <list>
|
||||
|
||||
namespace UType
|
||||
{
|
||||
template<typename Ty>
|
||||
class object_ptr;
|
||||
|
||||
class counter
|
||||
{
|
||||
struct counter_owners
|
||||
{
|
||||
std::atomic_bool is_destroyed;
|
||||
std::mutex mutex;
|
||||
std::list<void*> owners;
|
||||
|
||||
counter_owners()
|
||||
: is_destroyed(false)
|
||||
{
|
||||
}
|
||||
|
||||
counter_owners(const counter_owners&) = delete;
|
||||
counter_owners& operator=(const counter_owners&) = delete;
|
||||
|
||||
counter_owners(counter_owners&& other) noexcept
|
||||
: is_destroyed(other.is_destroyed.load())
|
||||
, owners(std::move(other.owners))
|
||||
{
|
||||
}
|
||||
|
||||
counter_owners& operator=(counter_owners&& other) noexcept
|
||||
{
|
||||
if (this != &other)
|
||||
{
|
||||
is_destroyed.store(other.is_destroyed.load());
|
||||
owners = std::move(other.owners);
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
static std::unordered_map<void*, counter_owners> owners_map;
|
||||
|
||||
public:
|
||||
template<typename Ty>
|
||||
static void add_owner(object_ptr<Ty>& ptr)
|
||||
{
|
||||
auto counter = owners_map.find(ptr.ptr_.load());
|
||||
if (counter == owners_map.end())
|
||||
{
|
||||
counter_owners owners;
|
||||
owners.owners.push_back(&ptr);
|
||||
auto [it, inserted] = owners_map.try_emplace(ptr.ptr_.load(), std::move(owners));
|
||||
if (!inserted)
|
||||
{
|
||||
ptr.ptr_.store(nullptr);
|
||||
}
|
||||
}
|
||||
else if (!counter->second.is_destroyed)
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(counter->second.mutex);
|
||||
counter->second.owners.push_back(&ptr);
|
||||
}
|
||||
else
|
||||
ptr.ptr_.store(nullptr);
|
||||
}
|
||||
|
||||
template<typename Ty>
|
||||
static void remove_owner(object_ptr<Ty>& ptr)
|
||||
{
|
||||
auto counter = owners_map.find(ptr.ptr_);
|
||||
if (counter != owners_map.end())
|
||||
{
|
||||
counter->second.owners.remove(&ptr);
|
||||
|
||||
if (counter->second.is_destroyed)
|
||||
{
|
||||
ptr.ptr_.store(nullptr);
|
||||
}
|
||||
else if (counter->second.owners.empty())
|
||||
{
|
||||
counter->second.is_destroyed.store(true);
|
||||
for (auto& owner : counter->second.owners)
|
||||
static_cast<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
|
||||
delete static_cast<Ty*>(counter->first);
|
||||
owners_map.erase(counter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Ty>
|
||||
static void remove_object(Ty* ptr)
|
||||
{
|
||||
auto counter = owners_map.find(ptr);
|
||||
if (counter != owners_map.end())
|
||||
{
|
||||
counter->second.is_destroyed.store(true);
|
||||
for (auto& owner : counter->second.owners)
|
||||
static_cast<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
|
||||
delete ptr;
|
||||
owners_map.erase(counter);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<typename Ty>
|
||||
class object_ptr
|
||||
{
|
||||
std::atomic<Ty*> ptr_;
|
||||
public:
|
||||
explicit object_ptr(Ty* ptr = nullptr)
|
||||
{
|
||||
ptr_.store(ptr);
|
||||
if (ptr) counter::add_owner<Ty>(*this);
|
||||
}
|
||||
|
||||
object_ptr(const object_ptr& ptr)
|
||||
{
|
||||
ptr_.store(ptr.ptr_);
|
||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
||||
}
|
||||
|
||||
object_ptr(object_ptr&& ptr) noexcept
|
||||
{
|
||||
ptr_.store(ptr.ptr_);
|
||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
||||
ptr.ptr_.store(nullptr);
|
||||
}
|
||||
|
||||
~object_ptr()
|
||||
{
|
||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
||||
}
|
||||
|
||||
void reset(Ty* new_ptr = nullptr)
|
||||
{
|
||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
||||
ptr_.store(new_ptr);
|
||||
if (new_ptr) counter::add_owner<Ty>(*this);
|
||||
}
|
||||
|
||||
void reset(const object_ptr& ptr)
|
||||
{
|
||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
||||
ptr_.store(ptr.ptr_);
|
||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
||||
}
|
||||
|
||||
void destroy()
|
||||
{
|
||||
if (ptr_) counter::remove_object<Ty>(ptr_);
|
||||
}
|
||||
|
||||
Ty* get() const { return ptr_.load(); }
|
||||
Ty& operator*() const
|
||||
{
|
||||
if (!ptr_.load())
|
||||
throw std::runtime_error("Null pointer");
|
||||
return *ptr_;
|
||||
}
|
||||
Ty* operator->() const
|
||||
{
|
||||
if (!ptr_.load())
|
||||
throw std::runtime_error("Null pointer");
|
||||
return ptr_.load();
|
||||
}
|
||||
operator bool() const noexcept { return ptr_.load() != nullptr; }
|
||||
object_ptr<Ty>& operator=(const object_ptr<Ty>& ptr)
|
||||
{
|
||||
reset(ptr);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template<typename target_Ty>
|
||||
explicit operator object_ptr<target_Ty>() const noexcept
|
||||
{
|
||||
return object_ptr<target_Ty>(reinterpret_cast<target_Ty*>(ptr_.load()));
|
||||
}
|
||||
|
||||
friend class counter;
|
||||
};
|
||||
}
|
||||
@@ -1,333 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <mutex>
|
||||
|
||||
template<typename TypeParameter>
|
||||
class Delegate
|
||||
{
|
||||
struct DelegateDataBase
|
||||
{
|
||||
virtual ~DelegateDataBase() = default;
|
||||
DelegateDataBase* next = nullptr;
|
||||
long long Hash = 0;
|
||||
virtual void Call(TypeParameter) = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct DelegateDataForClass : DelegateDataBase
|
||||
{
|
||||
T* object = nullptr;
|
||||
|
||||
typedef void(T::*Method)(TypeParameter);
|
||||
Method method = nullptr;
|
||||
|
||||
void Call(TypeParameter data) override
|
||||
{
|
||||
(object->*method)(data);
|
||||
}
|
||||
};
|
||||
|
||||
struct DelegateDataForFunction : DelegateDataBase
|
||||
{
|
||||
typedef void(*Func)(TypeParameter);
|
||||
Func func = nullptr;
|
||||
|
||||
void Call(TypeParameter data) override
|
||||
{
|
||||
func(data);
|
||||
}
|
||||
};
|
||||
|
||||
DelegateDataBase* firstElement = nullptr;
|
||||
|
||||
std::mutex mDelegateList;
|
||||
|
||||
static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) {
|
||||
return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U);
|
||||
}
|
||||
public:
|
||||
template<typename T>
|
||||
void bind(T* object, void(T::*method)(TypeParameter))
|
||||
{
|
||||
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))];
|
||||
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||
for (long unsigned int i = 0; i < sizeof(T*); ++i)
|
||||
str[i] = ptrToObjectRef[i];
|
||||
|
||||
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||
for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i)
|
||||
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||
|
||||
DelegateDataForClass<T>* data = new DelegateDataForClass<T>;
|
||||
data->next = firstElement;
|
||||
data->object = object;
|
||||
data->method = method;
|
||||
data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter)));
|
||||
|
||||
delete[] str;
|
||||
|
||||
mDelegateList.lock();
|
||||
firstElement = data;
|
||||
mDelegateList.unlock();
|
||||
}
|
||||
|
||||
void bind(void(*func)(TypeParameter))
|
||||
{
|
||||
char* str = new char[sizeof(void(*)(TypeParameter))];
|
||||
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||
for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i)
|
||||
str[i] = ptrToFuncRef[i];
|
||||
|
||||
DelegateDataForFunction* data = new DelegateDataForFunction;
|
||||
data->next = firstElement;
|
||||
data->func = func;
|
||||
data->Hash = FNV1a(str, sizeof(func));
|
||||
delete[] str;
|
||||
|
||||
mDelegateList.lock();
|
||||
firstElement = data;
|
||||
mDelegateList.unlock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unbind(T* object, void(T::*method)(TypeParameter))
|
||||
{
|
||||
if (firstElement == nullptr)
|
||||
return;
|
||||
|
||||
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))];
|
||||
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||
for (long unsigned int i = 0; i < 8; ++i)
|
||||
str[i] = ptrToObjectRef[i];
|
||||
|
||||
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||
for (long unsigned int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)(TypeParameter)); ++i)
|
||||
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||
|
||||
unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)(TypeParameter)));
|
||||
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
DelegateDataBase* temp = nullptr;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
if (iterator->Hash == Hash)
|
||||
{
|
||||
if (temp != nullptr)
|
||||
temp->next = iterator->next;
|
||||
else
|
||||
firstElement = iterator->next;
|
||||
|
||||
delete static_cast<DelegateDataForClass<T>*>(iterator);
|
||||
break;
|
||||
}
|
||||
|
||||
temp = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(void(*func)(TypeParameter))
|
||||
{
|
||||
char* str = new char[sizeof(void(*)(TypeParameter))];
|
||||
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||
for (int i = 0; i < sizeof(void(*)(TypeParameter)); ++i)
|
||||
str[i] = ptrToFuncRef[i];
|
||||
|
||||
unsigned int Hash = FNV1a(str, sizeof(void(*)(TypeParameter)));
|
||||
delete[] str;
|
||||
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
DelegateDataBase* temp = nullptr;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
if (iterator->Hash == Hash)
|
||||
{
|
||||
if (temp != nullptr)
|
||||
temp->next = iterator->next;
|
||||
else
|
||||
firstElement = iterator->next;
|
||||
|
||||
delete static_cast<DelegateDataForFunction*>(iterator);
|
||||
break;
|
||||
}
|
||||
|
||||
temp = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void Call(TypeParameter data) const
|
||||
{
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
iterator->Call(data);
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
template<>
|
||||
class Delegate<void>
|
||||
{
|
||||
struct DelegateDataBase
|
||||
{
|
||||
virtual ~DelegateDataBase() = default;
|
||||
DelegateDataBase* next = nullptr;
|
||||
long long Hash = 0;
|
||||
virtual void call() = 0;
|
||||
};
|
||||
|
||||
template<class T>
|
||||
struct DelegateDataForClass : DelegateDataBase
|
||||
{
|
||||
T* object = nullptr;
|
||||
|
||||
typedef void(T::*Method)();
|
||||
Method method = nullptr;
|
||||
|
||||
void call() override
|
||||
{
|
||||
(object->*method)();
|
||||
}
|
||||
};
|
||||
|
||||
struct DelegateDataForFunction : DelegateDataBase
|
||||
{
|
||||
typedef void(*Func)();
|
||||
Func func = nullptr;
|
||||
|
||||
void call() override
|
||||
{
|
||||
func();
|
||||
}
|
||||
};
|
||||
|
||||
DelegateDataBase* firstElement = nullptr;
|
||||
|
||||
std::mutex mDelegateList;
|
||||
|
||||
static constexpr unsigned int FNV1a(const char* str, unsigned int n, unsigned int hash = 2166136261U) {
|
||||
return n == 0 ? hash : FNV1a(str + 1, n - 1, (hash ^ str[0]) * 19777619U);
|
||||
}
|
||||
public:
|
||||
template<typename T>
|
||||
void bind(T* object, void(T::*method)())
|
||||
{
|
||||
char* str = new char[sizeof(T*) + sizeof(void(T::*)())];
|
||||
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||
for (int i = 0; i < sizeof(T*); ++i)
|
||||
str[i] = ptrToObjectRef[i];
|
||||
|
||||
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||
for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i)
|
||||
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||
|
||||
DelegateDataForClass<T>* data = new DelegateDataForClass<T>;
|
||||
data->next = firstElement;
|
||||
data->object = object;
|
||||
data->method = method;
|
||||
data->Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)()));
|
||||
|
||||
delete[] str;
|
||||
|
||||
mDelegateList.lock();
|
||||
firstElement = data;
|
||||
mDelegateList.unlock();
|
||||
}
|
||||
|
||||
void bind(void(*func)())
|
||||
{
|
||||
char* str = new char[sizeof(func)];
|
||||
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||
for (int i = 0; i < sizeof(void(*)()); ++i)
|
||||
str[i] = ptrToFuncRef[i];
|
||||
|
||||
DelegateDataForFunction* data = new DelegateDataForFunction;
|
||||
data->next = firstElement;
|
||||
data->func = func;
|
||||
data->Hash = FNV1a(str, 8);
|
||||
delete[] str;
|
||||
|
||||
mDelegateList.lock();
|
||||
firstElement = data;
|
||||
mDelegateList.unlock();
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void unbind(T* object, void(T::*method)())
|
||||
{
|
||||
if (firstElement == nullptr)
|
||||
return;
|
||||
|
||||
char* str = new char[sizeof(T*) + sizeof(void(T::*)())];
|
||||
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object);
|
||||
for (int i = 0; i < sizeof(T*); ++i)
|
||||
str[i] = ptrToObjectRef[i];
|
||||
|
||||
const char* ptrToMethodRef = reinterpret_cast<const char*>(&method);
|
||||
for (int i = sizeof(T*); i < sizeof(T*) + sizeof(void(T::*)()); ++i)
|
||||
str[i] = ptrToMethodRef[i - sizeof(T*)];
|
||||
|
||||
unsigned int Hash = FNV1a(str, sizeof(T*) + sizeof(void(T::*)()));
|
||||
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
DelegateDataBase* temp = nullptr;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
if (iterator->Hash == Hash)
|
||||
{
|
||||
if (temp != nullptr)
|
||||
temp->next = iterator->next;
|
||||
else
|
||||
firstElement = iterator->next;
|
||||
|
||||
delete static_cast<DelegateDataForClass<T>*>(iterator);
|
||||
break;
|
||||
}
|
||||
|
||||
temp = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void unbind(void(*func)())
|
||||
{
|
||||
char* str = new char[sizeof(void(*)())];
|
||||
const char* ptrToFuncRef = reinterpret_cast<const char*>(&func);
|
||||
for (int i = 0; i < sizeof(void(*)()); ++i)
|
||||
str[i] = ptrToFuncRef[i];
|
||||
|
||||
unsigned int Hash = FNV1a(str, sizeof(void(*)()));
|
||||
delete[] str;
|
||||
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
DelegateDataBase* temp = nullptr;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
if (iterator->Hash == Hash)
|
||||
{
|
||||
if (temp != nullptr)
|
||||
temp->next = iterator->next;
|
||||
else
|
||||
firstElement = iterator->next;
|
||||
|
||||
delete static_cast<DelegateDataForFunction*>(iterator);
|
||||
break;
|
||||
}
|
||||
|
||||
temp = iterator;
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
|
||||
void Call() const
|
||||
{
|
||||
DelegateDataBase* iterator = firstElement;
|
||||
while (iterator != nullptr)
|
||||
{
|
||||
iterator->call();
|
||||
iterator = iterator->next;
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -13,5 +13,5 @@ template<class T> struct Meta;
|
||||
// Enum type classes
|
||||
enum class Classes
|
||||
{
|
||||
IRTTI, IResource, Actor, TestActor, Mesh, StaticMesh, World, TestWorld
|
||||
IRTTI, IResource, Actor, World, Mesh, StaticMesh, Camera, TestWorld, TestActor
|
||||
};
|
||||
|
||||
@@ -3,3 +3,18 @@ set(CMAKE_CXX_STANDARD 20)
|
||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||
|
||||
add_executable(ProjectGenerator ${SRC})
|
||||
|
||||
if(MSVC)
|
||||
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>)
|
||||
else()
|
||||
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||
endif()
|
||||
|
||||
add_custom_command(
|
||||
TARGET ProjectGenerator
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/ProjectFile.txt
|
||||
${OUTPUT_PATH}/ProjectFile.txt
|
||||
COMMENT "Copying project files"
|
||||
)
|
||||
@@ -4,6 +4,8 @@ file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.hpp" "*.h")
|
||||
|
||||
add_library(RenderEngineSDK ${SRC})
|
||||
|
||||
target_compile_features(RenderEngineSDK PRIVATE cxx_std_17)
|
||||
|
||||
target_include_directories(RenderEngineSDK PUBLIC
|
||||
${PROJECT_SOURCE_DIR}/glfw/Include
|
||||
${PROJECT_SOURCE_DIR}/Delegate
|
||||
|
||||
@@ -0,0 +1,129 @@
|
||||
#include "DeviceFunctions.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
#include <optional>
|
||||
|
||||
VkExtent2D DeviceFunctions::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
|
||||
{
|
||||
// The acceptable rendering sparsity is calculated here
|
||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||
return capabilities.currentExtent;
|
||||
else
|
||||
{
|
||||
int width, height;
|
||||
glfwGetFramebufferSize(window, &width, &height);
|
||||
VkExtent2D actualExtent = {
|
||||
static_cast<uint32_t>(width),
|
||||
static_cast<uint32_t>(height)
|
||||
};
|
||||
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||
return actualExtent;
|
||||
}
|
||||
}
|
||||
|
||||
uint32_t DeviceFunctions::find_memory_type(VkPhysicalDevice physical_device, uint32_t typeFilter,
|
||||
VkMemoryPropertyFlags properties)
|
||||
{
|
||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||
vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
|
||||
|
||||
std::optional<uint32_t> mem_type = 0;
|
||||
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i)
|
||||
{
|
||||
if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||
mem_type = i;
|
||||
}
|
||||
|
||||
if (mem_type.has_value() == false)
|
||||
throw std::runtime_error("failed to find suitable memory type!");
|
||||
return mem_type.value();
|
||||
}
|
||||
|
||||
void DeviceFunctions::device_memcpy(VkDevice device, uint32_t transfer_queue_family, VkBuffer src, VkBuffer dst, size_t size)
|
||||
{
|
||||
VkCommandPool copy_pool;
|
||||
VkCommandPoolCreateInfo copy_pool_info{};
|
||||
copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
copy_pool_info.queueFamilyIndex = transfer_queue_family;
|
||||
copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
VK_CHECK(vkCreateCommandPool(device, ©_pool_info, nullptr, ©_pool))
|
||||
|
||||
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
command_buffer_allocate_info.commandPool = copy_pool;
|
||||
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
command_buffer_allocate_info.commandBufferCount = 1;
|
||||
|
||||
VkCommandBuffer copy_buffer;
|
||||
VK_CHECK(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, ©_buffer))
|
||||
|
||||
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
||||
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||
|
||||
VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info))
|
||||
|
||||
VkBufferCopy buffer_copy;
|
||||
buffer_copy.srcOffset = 0;
|
||||
buffer_copy.dstOffset = 0;
|
||||
buffer_copy.size = size;
|
||||
vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy);
|
||||
|
||||
vkEndCommandBuffer(copy_buffer);
|
||||
|
||||
VkSubmitInfo submit_info{};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = ©_buffer;
|
||||
|
||||
VkQueue transfer_queue;
|
||||
vkGetDeviceQueue(device, transfer_queue_family, 0, &transfer_queue);
|
||||
|
||||
vkQueueSubmit(transfer_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||
vkQueueWaitIdle(transfer_queue);
|
||||
|
||||
vkFreeCommandBuffers(device, copy_pool, 1, ©_buffer);
|
||||
vkDestroyCommandPool(device, copy_pool, nullptr);
|
||||
}
|
||||
|
||||
VkBuffer DeviceFunctions::create_buffer(VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
const std::vector<uint32_t>& queue_families)
|
||||
{
|
||||
VkBufferCreateInfo buffer_info{};
|
||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||
buffer_info.size = size;
|
||||
buffer_info.usage = usage;
|
||||
|
||||
if (queue_families.size() > 1)
|
||||
{
|
||||
buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
buffer_info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
|
||||
buffer_info.pQueueFamilyIndices = queue_families.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
buffer_info.queueFamilyIndexCount = 0;
|
||||
buffer_info.pQueueFamilyIndices = nullptr;
|
||||
}
|
||||
|
||||
VkBuffer buffer;
|
||||
VK_CHECK(vkCreateBuffer(device, &buffer_info, nullptr, &buffer))
|
||||
return buffer;
|
||||
}
|
||||
|
||||
VkDeviceMemory DeviceFunctions::allocate_device_memory(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkMemoryPropertyFlags property)
|
||||
{
|
||||
VkMemoryRequirements requirements{};
|
||||
vkGetBufferMemoryRequirements(device, buffer, &requirements);
|
||||
|
||||
VkMemoryAllocateInfo allocate_info{};
|
||||
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||
allocate_info.allocationSize = requirements.size;
|
||||
allocate_info.memoryTypeIndex = find_memory_type(physical_device, requirements.memoryTypeBits, property);
|
||||
|
||||
VkDeviceMemory device_memory;
|
||||
VK_CHECK(vkAllocateMemory(device, &allocate_info, nullptr, &device_memory))
|
||||
return device_memory;
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include <GLFW/glfw3.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <assert.h>
|
||||
#define VK_CHECK(res) assert(res == VK_SUCCESS);
|
||||
#else
|
||||
#define VK_CHECK(val) {int res = (val); if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(static_cast<int>(res)));}
|
||||
#endif
|
||||
|
||||
namespace DeviceFunctions
|
||||
{
|
||||
VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window);
|
||||
uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||
void device_memcpy(VkDevice device, uint32_t transfer_queue_family, VkBuffer src, VkBuffer dst, size_t size);
|
||||
VkBuffer create_buffer(VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, const std::vector<uint32_t>& queue_families);
|
||||
VkDeviceMemory allocate_device_memory(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkMemoryPropertyFlags property);
|
||||
}
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
RenderEngineBase::RenderEngineBase()
|
||||
#include "Core/CoreInstance.hpp"
|
||||
|
||||
RenderEngineBase::RenderEngineBase(CoreInstance& core)
|
||||
{
|
||||
if (!glfwInit())
|
||||
throw std::runtime_error("Fail init glfw");
|
||||
@@ -10,7 +12,7 @@ RenderEngineBase::RenderEngineBase()
|
||||
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
|
||||
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API);
|
||||
|
||||
window_ = glfwCreateWindow(800, 600, "UwU Engine", nullptr, nullptr);
|
||||
window_ = glfwCreateWindow(800, 600, core.getGameName().c_str(), nullptr, nullptr);
|
||||
if (window_ == nullptr)
|
||||
throw std::runtime_error("Fail create window");
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class RenderEngineBase
|
||||
GLFWwindow* window_ = nullptr;
|
||||
|
||||
public:
|
||||
explicit RenderEngineBase();
|
||||
explicit RenderEngineBase(CoreInstance& core);
|
||||
virtual ~RenderEngineBase();
|
||||
|
||||
virtual void start() = 0;
|
||||
|
||||
@@ -8,6 +8,7 @@ add_executable(${GAME_NAME} ${SRC})
|
||||
target_link_libraries(${GAME_NAME} PRIVATE Core UwURenderEngine)
|
||||
target_include_directories(${GAME_NAME} PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/Core
|
||||
${PROJECT_SOURCE_DIR}/UwURenderEngine
|
||||
)
|
||||
|
||||
if(MSVC)
|
||||
|
||||
@@ -1,9 +1,14 @@
|
||||
{
|
||||
"Class name": "TestWorld",
|
||||
"dtime": 5.000000,
|
||||
"dtime": 5,
|
||||
"Parent parameters": {
|
||||
"Class name": "World",
|
||||
"vsActorsIDs": ["TestMesh1","TestMesh2"],
|
||||
"vsActorsIDs": [
|
||||
"TestMesh1",
|
||||
"MainCamera",
|
||||
"TestMesh2",
|
||||
"TestActor1"
|
||||
],
|
||||
"loActors": [
|
||||
{
|
||||
"Class name": "StaticMesh",
|
||||
@@ -14,26 +19,51 @@
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx":1.0,
|
||||
"dy":-1.0,
|
||||
"dz":1.0
|
||||
"dx": 1,
|
||||
"dy": -1,
|
||||
"dz": 1
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx":0.0,
|
||||
"dy":0.0,
|
||||
"dz":0.0
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1.0,
|
||||
"dy": 1.0,
|
||||
"dz": 1.0
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"tags":[]
|
||||
"lstags": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Class name": "Camera",
|
||||
"Parent parameters": {
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 2,
|
||||
"dy": 2,
|
||||
"dz": 2
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": -2.335,
|
||||
"dy": -0.785,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"lstags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"Class name": "StaticMesh",
|
||||
"Parent parameters": {
|
||||
@@ -43,25 +73,50 @@
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx":0.0,
|
||||
"dy":-1.0,
|
||||
"dz":1.0
|
||||
"dx": 0,
|
||||
"dy": -1,
|
||||
"dz": 1
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx":0.0,
|
||||
"dy":0.0,
|
||||
"dz":0.0
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1.0,
|
||||
"dy": 1.0,
|
||||
"dz": 1.0
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"tags":[]
|
||||
"lstags": []
|
||||
}
|
||||
}
|
||||
},
|
||||
{
|
||||
"Class name": "TestActor",
|
||||
"Parent parameters": {
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"lstags": []
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
@@ -1,9 +1,36 @@
|
||||
#include "TestActor.h"
|
||||
|
||||
#include "Game/Actors/Camera.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
void TestActor::print_when_main_camera_rotate(const Vector3D& rot)
|
||||
{
|
||||
std::string msg = + "(" + name_ + ") camera move to x: " + std::to_string(rot.x) +
|
||||
" y: " + std::to_string(rot.y) +
|
||||
" z: " + std::to_string(rot.z);
|
||||
Loging::Log(msg);
|
||||
}
|
||||
|
||||
void TestActor::BeginPlay()
|
||||
{
|
||||
Actor::BeginPlay();
|
||||
Loging::Log("TestActor::BeginPlay");
|
||||
GetWorld()->GetActorsByClass<Camera>()[0].lock()->OnSetActorRotate.bind<TestActor>(
|
||||
std::static_pointer_cast<TestActor>(shared_from_this()),
|
||||
&TestActor::print_when_main_camera_rotate
|
||||
);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> TestActor::save()
|
||||
{
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("TestActor");
|
||||
save->connect_to(Actor::save());
|
||||
return save;
|
||||
}
|
||||
|
||||
void TestActor::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
Actor::load(save->getParent());
|
||||
}
|
||||
@@ -5,6 +5,11 @@
|
||||
GENERATE_META(TestActor)
|
||||
class TestActor final : public Actor
|
||||
{
|
||||
const std::string name_ = "First test actor";
|
||||
void print_when_main_camera_rotate(const Vector3D& rot);
|
||||
public:
|
||||
void BeginPlay() override;
|
||||
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
};
|
||||
@@ -1,7 +1,11 @@
|
||||
#include "Game/ObjectFactory.hpp"
|
||||
|
||||
#include "../Actors/TestActor.h"
|
||||
#include "Game/Actors/Camera.hpp"
|
||||
#include "Game/Actors/Mesh/StaticMesh.hpp"
|
||||
|
||||
FACTORIES_LIST{
|
||||
GENERATE_FACTORY_OBJECT(StaticMesh)
|
||||
GENERATE_FACTORY_OBJECT(TestActor)
|
||||
GENERATE_FACTORY_OBJECT(Camera)
|
||||
};
|
||||
|
||||
@@ -1,9 +1,7 @@
|
||||
#include "TestGameInstance.h"
|
||||
|
||||
#include "Game/Resource/Resource.hpp"
|
||||
#include <iostream>
|
||||
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance)
|
||||
|
||||
|
||||
@@ -1,8 +1,21 @@
|
||||
#include "TestWorld.h"
|
||||
|
||||
#include <glm/ext/scalar_constants.hpp>
|
||||
|
||||
#include "../Actors/TestActor.h"
|
||||
#include "Game/GameInstance.hpp"
|
||||
#include "Game/Actors/Camera.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
#include "Game/Actors/Mesh/Mesh.hpp"
|
||||
|
||||
void TestWorld::print_when_camera_move(const Vector3D& loc_)
|
||||
{
|
||||
std::string msg = + "(" + name_ + ") camera move to x: " + std::to_string(loc_.x) +
|
||||
" y: " + std::to_string(loc_.y) +
|
||||
" z: " + std::to_string(loc_.z);
|
||||
Loging::Log(msg);
|
||||
}
|
||||
|
||||
TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
||||
{}
|
||||
@@ -10,23 +23,47 @@ TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
||||
void TestWorld::BeginPlay()
|
||||
{
|
||||
World::BeginPlay();
|
||||
std::vector<UType::object_ptr<Actor>> meshes = GetActorsByClass<Actor>();
|
||||
std::vector<std::weak_ptr<Actor>> meshes = GetActorsByClass<Actor>();
|
||||
for (const auto& i : meshes)
|
||||
Loging::Log("Load actor: " + i->GetName());
|
||||
{
|
||||
Loging::Message("Load actor: " + i.lock()->GetName());
|
||||
}
|
||||
|
||||
main_camera_ = GetActorsByClass<Camera>()[0];
|
||||
std::shared_ptr<Camera> lock_main_camera = main_camera_.lock();
|
||||
lock_main_camera->SetActive();
|
||||
lock_main_camera->OnSetActorLocate.bind<TestWorld>(
|
||||
std::static_pointer_cast<TestWorld>(shared_from_this()),
|
||||
&TestWorld::print_when_camera_move
|
||||
);
|
||||
std::shared_ptr<SaveMap> save_world = save();
|
||||
Loging::Message(save_world->serialize());
|
||||
}
|
||||
|
||||
void TestWorld::Tick(double delta_time)
|
||||
{
|
||||
World::Tick(delta_time);
|
||||
|
||||
static double time1 = 0.0;
|
||||
time1 += delta_time;
|
||||
double delta1 = sin(time1);
|
||||
double delta2 = sin(3*time1);
|
||||
std::shared_ptr<Camera> lock_main_camera = main_camera_.lock();
|
||||
if (lock_main_camera != nullptr)
|
||||
{
|
||||
lock_main_camera->SetActorLocate(Vector3D{2 + delta2, 2 + delta2, 2 + delta2});
|
||||
lock_main_camera->SetActorRotate(Vector3D{-3*glm::pi<double>()/4 + glm::pi<double>()/4 * delta1, glm::pi<double>() / -4, 0});
|
||||
}
|
||||
|
||||
time += delta_time;
|
||||
if (time >= 10.0)
|
||||
{
|
||||
std::vector<UType::object_ptr<Mesh>> meshes = GetActorsByClass<Mesh>();
|
||||
std::vector<std::weak_ptr<Mesh>> meshes = GetActorsByClass<Mesh>();
|
||||
if (!meshes.empty())
|
||||
{
|
||||
Loging::Message("TestWorld destroy: " + meshes[0]->GetName());
|
||||
DestroyActor(static_cast<UType::object_ptr<Actor>>(meshes[0]));
|
||||
std::shared_ptr<Mesh> mesh = meshes[0].lock();
|
||||
Loging::Message("TestWorld destroy: " + mesh->GetName());
|
||||
DestroyActor(meshes[0]);
|
||||
time = 7.0;
|
||||
return;
|
||||
}
|
||||
@@ -39,7 +76,8 @@ std::shared_ptr<SaveMap> TestWorld::save()
|
||||
{
|
||||
std::shared_ptr<SaveMap> save = World::save();
|
||||
std::shared_ptr<SaveMap> my_save = std::make_shared<SaveMap>("TestWorld");
|
||||
my_save->SaveDouble("time", time)->connect_to(save);
|
||||
my_save->SaveDouble("time", time);
|
||||
my_save->connect_to(save);
|
||||
return my_save;
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,16 @@
|
||||
|
||||
#include "Game/World/World.hpp"
|
||||
|
||||
class Camera;
|
||||
GENERATE_META(TestWorld)
|
||||
|
||||
class TestWorld final : public World
|
||||
{
|
||||
double time = 0;
|
||||
std::weak_ptr<Camera> main_camera_;
|
||||
const std::string name_ = "First test world";
|
||||
|
||||
void print_when_camera_move(const Vector3D& loc_);
|
||||
public:
|
||||
TestWorld(GameInstance& game_instance);
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
set(CMAKE_CXX_STANDARD 17)
|
||||
set(CMAKE_CXX_STANDARD 20)
|
||||
include(FetchContent)
|
||||
FetchContent_Declare(
|
||||
googletest
|
||||
@@ -11,19 +11,16 @@ FetchContent_MakeAvailable(googletest)
|
||||
enable_testing()
|
||||
|
||||
file(GLOB SRC
|
||||
"SaveMapTest.cpp"
|
||||
"ObjectPtrTest.cpp"
|
||||
|
||||
"${PROJECT_SOURCE_DIR}/Core/Game/SaveMap/SaveMap.cpp"
|
||||
"${PROJECT_SOURCE_DIR}/Core/Types/object_ptr.cpp"
|
||||
"ObjectFactory.cpp" "WorldFactory.cpp" "TestRenderEngine.cpp" "TestRenderEngine.h" "TestGameInstance.cpp" "TestGameInstance.h"
|
||||
"SaveMap/SaveMapTest.cpp" "SaveMap/CustomObject.h"
|
||||
"World/WorldTest.cpp" "World/TestWorld.h" "World/TestActor.cpp" "World/TestActor.h"
|
||||
)
|
||||
|
||||
add_executable(Tests ${SRC})
|
||||
target_link_libraries(Tests PRIVATE
|
||||
GTest::gtest_main
|
||||
)
|
||||
target_link_libraries(Tests PRIVATE GTest::gtest_main Core RenderEngineSDK)
|
||||
target_include_directories(Tests PRIVATE
|
||||
${PROJECT_SOURCE_DIR}/Core
|
||||
${PROJECT_SOURCE_DIR}/RenderEngineSDK
|
||||
)
|
||||
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "Game/ObjectFactory.hpp"
|
||||
|
||||
#include "SaveMap/CustomObject.h"
|
||||
#include "World/TestActor.h"
|
||||
|
||||
|
||||
FACTORIES_LIST{
|
||||
GENERATE_FACTORY_OBJECT(CustomObject)
|
||||
GENERATE_FACTORY_OBJECT(TestActor)
|
||||
};
|
||||
@@ -1,59 +0,0 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include "Types/object_ptr.hpp"
|
||||
|
||||
class TestClass
|
||||
{
|
||||
int* test_ptr_;
|
||||
public:
|
||||
TestClass(int* test_ptr) : test_ptr_(test_ptr)
|
||||
{
|
||||
*test_ptr_ = 1;
|
||||
}
|
||||
|
||||
~TestClass()
|
||||
{
|
||||
*test_ptr_ = 2;
|
||||
}
|
||||
};
|
||||
|
||||
TEST(object_ptr_test, base_test)
|
||||
{
|
||||
int* test = new int(123);
|
||||
UType::object_ptr<int> ptr(test);
|
||||
EXPECT_EQ(*ptr.get(), 123);
|
||||
|
||||
UType::object_ptr<int> ptr2(ptr);
|
||||
EXPECT_EQ(*ptr2.get(), 123);
|
||||
EXPECT_EQ(ptr2.get(), ptr.get());
|
||||
|
||||
ptr.destroy();
|
||||
EXPECT_EQ(ptr.get(), nullptr);
|
||||
EXPECT_EQ(ptr2.get(), nullptr);
|
||||
}
|
||||
|
||||
TEST(object_ptr_test, check_destry)
|
||||
{
|
||||
UType::object_ptr<int> ptr(new int(123)), ptr2(ptr);
|
||||
|
||||
ptr.destroy();
|
||||
EXPECT_EQ(ptr.get(), nullptr);
|
||||
EXPECT_EQ(ptr2.get(), nullptr);
|
||||
}
|
||||
|
||||
TEST(object_ptr_test, check_destroy)
|
||||
{
|
||||
int* test = new int(0);
|
||||
{
|
||||
UType::object_ptr<TestClass> ptr(new TestClass(test));
|
||||
EXPECT_EQ(*test, 1);
|
||||
}
|
||||
EXPECT_EQ(*test, 2);
|
||||
|
||||
*test = 0;
|
||||
{
|
||||
UType::object_ptr<TestClass> ptr(new TestClass(test));
|
||||
UType::object_ptr<TestClass> ptr2(ptr);
|
||||
EXPECT_EQ(*test, 1);
|
||||
}
|
||||
EXPECT_EQ(*test, 2);
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/SaveMap/ISave.h"
|
||||
|
||||
#include <string>
|
||||
#include <memory>
|
||||
|
||||
class CustomObject : public ISave
|
||||
{
|
||||
public:
|
||||
int num;
|
||||
std::string str;
|
||||
double dbl;
|
||||
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
bool operator==(const CustomObject& obj) const;
|
||||
};
|
||||
@@ -1,38 +1,29 @@
|
||||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "Game/ObjectFactory.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "CustomObject.h"
|
||||
|
||||
class CustomObject : public ISave
|
||||
std::shared_ptr<SaveMap> CustomObject::save()
|
||||
{
|
||||
public:
|
||||
int num;
|
||||
std::string str;
|
||||
double dbl;
|
||||
|
||||
std::shared_ptr<SaveMap> save() override
|
||||
{
|
||||
return std::make_shared<SaveMap>("CustomObject")->SaveInteger("num", num)->SaveString("str", str)->SaveDouble("dbl", dbl);
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("CustomObject");
|
||||
save->SaveInteger("num", num);
|
||||
save->SaveString("str", str);
|
||||
save->SaveDouble("dbl", dbl);
|
||||
return save;
|
||||
}
|
||||
void load(std::shared_ptr<SaveMap> save) override
|
||||
|
||||
void CustomObject::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
num = static_cast<int>(save->GetInteger("num"));
|
||||
str = save->GetString("str");
|
||||
dbl = save->GetDouble("dbl");
|
||||
}
|
||||
|
||||
bool operator==(const CustomObject& obj) const
|
||||
bool CustomObject::operator==(const CustomObject& obj) const
|
||||
{
|
||||
return num == obj.num && str == obj.str && dbl == obj.dbl;
|
||||
}
|
||||
};
|
||||
|
||||
FACTORIES_LIST {
|
||||
GENERATE_FACTORY_OBJECT(CustomObject)
|
||||
};
|
||||
// A compatibility plug
|
||||
std::vector<ObjectFactory> base_object_factories = {};
|
||||
|
||||
TEST(SaveMapTest, check_clean)
|
||||
{
|
||||
@@ -158,14 +149,15 @@ TEST(SaveMapTest, check_load_with_custom_type)
|
||||
EXPECT_EQ(test_vector_string[i], save_map.GetVectorString("TestVectorString")[i]);
|
||||
}
|
||||
|
||||
UType::object_ptr<CustomObject> obj = static_cast<UType::object_ptr<CustomObject>>(save_map.GetObject("CustomObject"));
|
||||
std::shared_ptr obj = std::static_pointer_cast<CustomObject>(save_map.GetObject("CustomObject"));
|
||||
|
||||
CustomObject test_obj;
|
||||
test_obj.num = 123;
|
||||
test_obj.str = "str123";
|
||||
test_obj.dbl = 123.45;
|
||||
EXPECT_EQ(*obj.get(), test_obj);
|
||||
|
||||
std::vector<UType::object_ptr<CustomObject>> vec_obj = reinterpret_cast<std::vector<UType::object_ptr<CustomObject>>&>(save_map.GetVectorObject("CustomObjects"));
|
||||
std::vector<std::shared_ptr<CustomObject>> vec_obj = reinterpret_cast<std::vector<std::shared_ptr<CustomObject>>&>(save_map.GetVectorObject("CustomObjects"));
|
||||
std::vector<CustomObject*> vec_obj_test = {
|
||||
new CustomObject,
|
||||
new CustomObject,
|
||||
@@ -179,7 +171,6 @@ TEST(SaveMapTest, check_load_with_custom_type)
|
||||
for (auto i = 0; i < 2; i++)
|
||||
{
|
||||
EXPECT_EQ(*vec_obj[i].get(), *vec_obj_test[i]);
|
||||
vec_obj[i].destroy();
|
||||
delete vec_obj_test[i];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
#include "TestGameInstance.h"
|
||||
|
||||
#include <iostream>
|
||||
|
||||
#include "Game/World/World.hpp"
|
||||
GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance)
|
||||
|
||||
TestGameInstance::TestGameInstance(CoreInstance& core) : GameInstance(core)
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/GameInstance.hpp"
|
||||
|
||||
class TestGameInstance : public GameInstance
|
||||
{
|
||||
public:
|
||||
TestGameInstance(CoreInstance& core);
|
||||
};
|
||||
@@ -0,0 +1,15 @@
|
||||
#include "TestRenderEngine.h"
|
||||
|
||||
RENDER_ENGINE_FACTORY_GENERATE(TestRenderEngine)
|
||||
|
||||
TestRenderEngine::TestRenderEngine(CoreInstance& core):RenderEngineBase(core)
|
||||
{
|
||||
}
|
||||
|
||||
void TestRenderEngine::start()
|
||||
{
|
||||
}
|
||||
|
||||
void TestRenderEngine::stop_render() const
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderEngineBase.hpp"
|
||||
|
||||
class TestRenderEngine final : public RenderEngineBase
|
||||
{
|
||||
public:
|
||||
TestRenderEngine(CoreInstance& core);
|
||||
|
||||
void start() override;
|
||||
void stop_render() const override;
|
||||
};
|
||||
@@ -0,0 +1,19 @@
|
||||
#include "TestActor.h"
|
||||
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
|
||||
TestActor::TestActor()
|
||||
{
|
||||
SetType(Classes::TestActor);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> TestActor::save()
|
||||
{
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("TestActor");
|
||||
save->connect_to(Actor::save());
|
||||
return save;
|
||||
}
|
||||
void TestActor::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
Actor::load(save->getParent());
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
#pragma once
|
||||
|
||||
#include "RTTI_Meta.h"
|
||||
#include "Game/Actors/Actor.hpp"
|
||||
|
||||
GENERATE_META(TestActor)
|
||||
class TestActor : public Actor
|
||||
{
|
||||
public:
|
||||
TestActor();
|
||||
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
};
|
||||
@@ -0,0 +1,12 @@
|
||||
#pragma once
|
||||
|
||||
#include "Game/World/World.hpp"
|
||||
|
||||
class TestWorld : public World
|
||||
{
|
||||
public:
|
||||
explicit TestWorld(GameInstance& game_instance);
|
||||
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
};
|
||||
@@ -0,0 +1,265 @@
|
||||
#include <filesystem>
|
||||
#include <fstream>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
#include "TestActor.h"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "TestWorld.h"
|
||||
#include "Core/CoreInstance.hpp"
|
||||
#include "Game/GameInstance.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
|
||||
TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
||||
{
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> TestWorld::save()
|
||||
{
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("TestWorld");
|
||||
save->connect_to(World::save());
|
||||
return save;
|
||||
}
|
||||
void TestWorld::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
World::load(save->getParent());
|
||||
}
|
||||
|
||||
TEST(World, check_load)
|
||||
{
|
||||
const std::string main_config =
|
||||
R"({
|
||||
"Class name":"MainConfig",
|
||||
"dmin_memory_size":4096.0,
|
||||
"imin_CPU_count":1,
|
||||
"sgame_name":"tests",
|
||||
"sbase_world":"tests"
|
||||
})";
|
||||
std::ofstream main_config_file("main_config.conf");
|
||||
main_config_file << main_config;
|
||||
main_config_file.close();
|
||||
|
||||
const std::string world_config =
|
||||
R"(
|
||||
{
|
||||
"Class name": "TestWorld",
|
||||
"Parent parameters": {
|
||||
"Class name": "World",
|
||||
"vsActorsIDs": [
|
||||
"TempActor"
|
||||
],
|
||||
"loActors": [
|
||||
{
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": -1,
|
||||
"dz": 1
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"lstags": []
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)";
|
||||
|
||||
std::filesystem::create_directories("Worlds");
|
||||
std::ofstream world_file("Worlds/tests.world");
|
||||
world_file << world_config;
|
||||
world_file.close();
|
||||
|
||||
CoreInstance tmp_core;
|
||||
tmp_core.GetGameInstance()->GetWorld()->SpawnActorFormClass<TestActor>("Test");
|
||||
|
||||
std::vector<std::weak_ptr<Actor>> actors = tmp_core.GetGameInstance()->GetWorld()->GetActorsByClass<Actor>();
|
||||
ASSERT_EQ(actors.size(), 2);
|
||||
|
||||
try {
|
||||
std::filesystem::remove("main_config.conf");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds/tests.world");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds");
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
TEST(World, check_finders)
|
||||
{
|
||||
const std::string main_config =
|
||||
R"({
|
||||
"Class name":"MainConfig",
|
||||
"dmin_memory_size":4096.0,
|
||||
"imin_CPU_count":1,
|
||||
"sgame_name":"tests",
|
||||
"sbase_world":"tests"
|
||||
})";
|
||||
std::ofstream main_config_file("main_config.conf");
|
||||
main_config_file << main_config;
|
||||
main_config_file.close();
|
||||
|
||||
const std::string world_config =
|
||||
R"(
|
||||
{
|
||||
"Class name": "TestWorld",
|
||||
"Parent parameters": {
|
||||
"Class name": "World",
|
||||
"vsActorsIDs": [
|
||||
"TempActor1",
|
||||
"TempActor2"
|
||||
],
|
||||
"loActors": [
|
||||
{
|
||||
"Class name": "TestActor",
|
||||
"Parent parameters":{
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": -1,
|
||||
"dz": 1
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"lstags": []
|
||||
}
|
||||
},
|
||||
{
|
||||
"Class name": "Actor",
|
||||
"oloc": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": -1,
|
||||
"dz": 1
|
||||
},
|
||||
"orot": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 0,
|
||||
"dy": 0,
|
||||
"dz": 0
|
||||
},
|
||||
"oscale": {
|
||||
"Class name": "Vector3D",
|
||||
"dx": 1,
|
||||
"dy": 1,
|
||||
"dz": 1
|
||||
},
|
||||
"lstags": ["Simple"]
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
)";
|
||||
std::filesystem::create_directories("Worlds");
|
||||
std::ofstream world_file("Worlds/tests.world");
|
||||
world_file << world_config;
|
||||
world_file.close();
|
||||
|
||||
CoreInstance tmp_core;
|
||||
|
||||
// Test find by class
|
||||
std::list<std::weak_ptr<TestActor>> test_actors = tmp_core.GetGameInstance()->GetWorld()->GetActorsByClass<TestActor, std::list>();
|
||||
ASSERT_EQ(test_actors.size(), 1);
|
||||
|
||||
// Test find by tag
|
||||
std::vector<std::weak_ptr<Actor>> actors = tmp_core.GetGameInstance()->GetWorld()->GetActorsByTag<Actor>("Simple");
|
||||
ASSERT_EQ(actors.size(), 1);
|
||||
|
||||
// Test find by name
|
||||
std::weak_ptr<Actor> actor_by_name = tmp_core.GetGameInstance()->GetWorld()->GetActorByName<Actor>("TempActor2");
|
||||
ASSERT_EQ(actor_by_name.expired(), false);
|
||||
ASSERT_EQ(*actor_by_name.lock()->GetTags().begin(), "Simple");
|
||||
|
||||
try {
|
||||
std::filesystem::remove("main_config.conf");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds/tests.world");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds");
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
|
||||
TEST(World, check_spawn_actor_from_class)
|
||||
{
|
||||
const std::string main_config =
|
||||
R"({
|
||||
"Class name":"MainConfig",
|
||||
"dmin_memory_size":4096.0,
|
||||
"imin_CPU_count":1,
|
||||
"sgame_name":"tests",
|
||||
"sbase_world":"tests"
|
||||
})";
|
||||
std::ofstream main_config_file("main_config.conf");
|
||||
main_config_file << main_config;
|
||||
main_config_file.close();
|
||||
|
||||
const std::string world_config =
|
||||
R"(
|
||||
{
|
||||
"Class name": "TestWorld",
|
||||
"Parent parameters": {
|
||||
"Class name": "World",
|
||||
"vsActorsIDs": [
|
||||
],
|
||||
"loActors": [
|
||||
]
|
||||
}
|
||||
}
|
||||
)";
|
||||
std::filesystem::create_directories("Worlds");
|
||||
std::ofstream world_file("Worlds/tests.world");
|
||||
world_file << world_config;
|
||||
world_file.close();
|
||||
|
||||
CoreInstance tmp_core;
|
||||
std::vector<std::weak_ptr<TestActor>> test_actors = tmp_core.GetGameInstance()->GetWorld()->GetActorsByClass<TestActor>();
|
||||
ASSERT_EQ(test_actors.size(), 0);
|
||||
|
||||
tmp_core.GetGameInstance()->GetWorld()->SpawnActorFormClass<TestActor>("Test");
|
||||
test_actors = tmp_core.GetGameInstance()->GetWorld()->GetActorsByClass<TestActor>();
|
||||
ASSERT_EQ(test_actors.size(), 1);
|
||||
|
||||
try {
|
||||
std::filesystem::remove("main_config.conf");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds/tests.world");
|
||||
}
|
||||
catch (...) {}
|
||||
try {
|
||||
std::filesystem::remove("Worlds");
|
||||
}
|
||||
catch (...) {}
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
#include <Game/WorldFactory.hpp>
|
||||
|
||||
#include "World/TestWorld.h"
|
||||
|
||||
WORLDS_LIST
|
||||
{
|
||||
GENERATE_WORLD_FACTORY(TestWorld, tests)
|
||||
};
|
||||
@@ -1,7 +1,33 @@
|
||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.hpp" "*.h")
|
||||
|
||||
add_library(UwURenderEngine ${SRC})
|
||||
target_include_directories(UwURenderEngine PRIVATE ${PROJECT_SOURCE_DIR}/RenderEngineSDK)
|
||||
target_link_libraries(UwURenderEngine PRIVATE RenderEngineSDK)
|
||||
target_include_directories(UwURenderEngine PUBLIC ${PROJECT_SOURCE_DIR}/RenderEngineSDK)
|
||||
target_link_libraries(UwURenderEngine PUBLIC RenderEngineSDK)
|
||||
|
||||
target_compile_features(UwURenderEngine PRIVATE cxx_std_17)
|
||||
|
||||
file(GLOB_RECURSE HEADERS
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
|
||||
)
|
||||
|
||||
foreach (HEADER ${HEADERS})
|
||||
file(RELATIVE_PATH R_PATH
|
||||
"${CMAKE_CURRENT_SOURCE_DIR}/"
|
||||
"${HEADER}"
|
||||
)
|
||||
|
||||
get_filename_component(HEADER_DIR "${R_PATH}" DIRECTORY)
|
||||
|
||||
add_custom_command(
|
||||
TARGET UwURenderEngine
|
||||
POST_BUILD
|
||||
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${HEADER_DIR}"
|
||||
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||
"${HEADER}"
|
||||
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${R_PATH}"
|
||||
|
||||
COMMENT "Copy UwURenderEngine headers"
|
||||
)
|
||||
endforeach ()
|
||||
@@ -0,0 +1,29 @@
|
||||
#include "Camera.hpp"
|
||||
|
||||
#include "../../RenderEngine/UwURenderEngine.hpp"
|
||||
#include "Core/CoreInstance.hpp"
|
||||
#include "Game/GameInstance.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
|
||||
Camera::Camera()
|
||||
{
|
||||
SetType(Classes::Camera);
|
||||
}
|
||||
|
||||
std::shared_ptr<SaveMap> Camera::save()
|
||||
{
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Camera");
|
||||
save->connect_to(Actor::save());
|
||||
return save;
|
||||
}
|
||||
|
||||
void Camera::load(std::shared_ptr<SaveMap> save)
|
||||
{
|
||||
Actor::load(save->getParent());
|
||||
}
|
||||
|
||||
void Camera::SetActive() const noexcept
|
||||
{
|
||||
GET_RENDER_ENGINE->SetActiveCamera(GetWorld()->GetActorByName<Camera>(GetName()));
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
#pragma once
|
||||
#include "RTTI_Meta.h"
|
||||
#include "Game/Actors/Actor.hpp"
|
||||
|
||||
GENERATE_META(Camera)
|
||||
|
||||
class Camera : public Actor
|
||||
{
|
||||
public:
|
||||
Camera();
|
||||
|
||||
std::shared_ptr<SaveMap> save() override;
|
||||
void load(std::shared_ptr<SaveMap> save) override;
|
||||
|
||||
void SetActive() const noexcept;
|
||||
};
|
||||
@@ -9,9 +9,10 @@ Mesh::Mesh()
|
||||
|
||||
std::shared_ptr<SaveMap> Mesh::save()
|
||||
{
|
||||
return std::make_shared<SaveMap>("Mesh")
|
||||
->SaveString("model_name_", model_name_)
|
||||
->connect_to(Actor::save());
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Mesh");
|
||||
save->SaveString("model_name_", model_name_);
|
||||
save->connect_to(Actor::save());
|
||||
return save;
|
||||
}
|
||||
|
||||
void Mesh::load(std::shared_ptr<SaveMap> save)
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
#include <string>
|
||||
|
||||
#include "../Actor.hpp"
|
||||
#include "Game/Actors/Actor.hpp"
|
||||
|
||||
GENERATE_META(Mesh)
|
||||
class Mesh : public Actor
|
||||
+7
-3
@@ -4,6 +4,7 @@
|
||||
#include "Game/GameInstance.hpp"
|
||||
#include "Game/SaveMap/SaveMap.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "../../../RenderEngine/UwURenderEngine.hpp"
|
||||
|
||||
StaticMesh::StaticMesh()
|
||||
{
|
||||
@@ -12,7 +13,9 @@ StaticMesh::StaticMesh()
|
||||
|
||||
std::shared_ptr<SaveMap> StaticMesh::save()
|
||||
{
|
||||
return std::make_shared<SaveMap>("StaticMesh")->connect_to(Mesh::save());
|
||||
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("StaticMesh");
|
||||
save->connect_to(Mesh::save());
|
||||
return save;
|
||||
}
|
||||
|
||||
void StaticMesh::load(std::shared_ptr<SaveMap> save)
|
||||
@@ -23,12 +26,13 @@ void StaticMesh::load(std::shared_ptr<SaveMap> save)
|
||||
void StaticMesh::load_model(const std::string& model_name)
|
||||
{
|
||||
model_name_ = model_name;
|
||||
model_ = GET_RENDER_ENGINE->GetModelManager()->LoadModel(model_name);
|
||||
SetModelName(model_name);
|
||||
model_ = GetWorld()->GetGameInstance().GetCurrentModelManager()->LoadModel(model_name);
|
||||
}
|
||||
|
||||
void StaticMesh::OnDestroy()
|
||||
{
|
||||
Mesh::OnDestroy();
|
||||
GetWorld()->GetGameInstance().GetCurrentModelManager()->FreeModel(model_name_);
|
||||
|
||||
GET_RENDER_ENGINE->GetModelManager()->FreeModel(model_name_);
|
||||
}
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#pragma once
|
||||
|
||||
#include "Mesh.hpp"
|
||||
#include "Game/ModelManager.hpp"
|
||||
#include "../../../RenderEngine/ModelManager.hpp"
|
||||
|
||||
GENERATE_META(StaticMesh)
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
#include "GPU_GarbageCollector.h"
|
||||
|
||||
|
||||
GPU_GarbageCollector::GPU_GarbageCollector(VkDevice device) : device_(device)
|
||||
{}
|
||||
|
||||
void GPU_GarbageCollector::AddGarbage(Garbage garbage)
|
||||
{
|
||||
std::scoped_lock lock(m_heap_);
|
||||
heap_.push_back(garbage);
|
||||
}
|
||||
|
||||
void GPU_GarbageCollector::FreeHeap()
|
||||
{
|
||||
std::scoped_lock lock(m_heap_);
|
||||
for (auto& i : heap_)
|
||||
{
|
||||
vkFreeMemory(device_, i.device_memory, nullptr);
|
||||
vkDestroyBuffer(device_, i.buffer, nullptr);
|
||||
}
|
||||
heap_.clear();
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
#pragma once
|
||||
|
||||
#include <list>
|
||||
#include <mutex>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class GPU_GarbageCollector
|
||||
{
|
||||
public:
|
||||
struct Garbage
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory device_memory;
|
||||
};
|
||||
private:
|
||||
VkDevice device_ = VK_NULL_HANDLE;
|
||||
|
||||
std::list<Garbage> heap_;
|
||||
std::mutex m_heap_;
|
||||
public:
|
||||
GPU_GarbageCollector() = default;
|
||||
|
||||
explicit GPU_GarbageCollector(VkDevice device);
|
||||
|
||||
void AddGarbage(Garbage garbage);
|
||||
void FreeHeap();
|
||||
};
|
||||
@@ -0,0 +1,113 @@
|
||||
#include "ModelManager.hpp"
|
||||
|
||||
#include <array>
|
||||
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
ModelManager::StaticModel::StaticModel(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices,
|
||||
VkPhysicalDevice physical_device, VkDevice device):
|
||||
physical_device_(physical_device),
|
||||
device_(device)
|
||||
{
|
||||
}
|
||||
|
||||
ModelManager::StaticModel::~StaticModel()
|
||||
{
|
||||
}
|
||||
|
||||
VkVertexInputBindingDescription ModelManager::Vertex::get_binding_description()
|
||||
{
|
||||
VkVertexInputBindingDescription description;
|
||||
description.binding = 0;
|
||||
description.stride = sizeof(Vertex);
|
||||
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||
return description;
|
||||
}
|
||||
|
||||
std::array<VkVertexInputAttributeDescription, 2> ModelManager::Vertex::get_vertex_attribute_descriptions()
|
||||
{
|
||||
std::array<VkVertexInputAttributeDescription, 2> descriptions;
|
||||
// Bind vertex loc
|
||||
descriptions[0].binding = 0;
|
||||
descriptions[0].location = 0;
|
||||
descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
descriptions[0].offset = offsetof(Vertex, pos);
|
||||
|
||||
// Bind color
|
||||
descriptions[1].binding = 0;
|
||||
descriptions[1].location = 1;
|
||||
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||
descriptions[1].offset = offsetof(Vertex, color);
|
||||
|
||||
return descriptions;
|
||||
}
|
||||
|
||||
ModelManager::owner_counter::owner_counter(const owner_counter& other) : counter(other.counter.load()), model(other.model)
|
||||
{
|
||||
}
|
||||
|
||||
unsigned int ModelManager::FNV1aHash(const char* buf)
|
||||
{
|
||||
unsigned int h_val = 0x811c9dc5;
|
||||
|
||||
while (*buf)
|
||||
{
|
||||
h_val ^= static_cast<unsigned int>(*buf++);
|
||||
h_val *= 0x01000193;
|
||||
}
|
||||
|
||||
return h_val;
|
||||
}
|
||||
|
||||
ModelManager::ModelManager(VkPhysicalDevice physical_device, VkDevice device):
|
||||
physical_device_(physical_device),
|
||||
device_(device)
|
||||
{}
|
||||
|
||||
ModelManager::~ModelManager()
|
||||
{
|
||||
models.clear();
|
||||
}
|
||||
|
||||
ModelManager::StaticModel* ModelManager::LoadModel(const std::string& name)
|
||||
{
|
||||
if (name.empty())
|
||||
return nullptr;
|
||||
unsigned int hash = FNV1aHash(name.c_str());
|
||||
auto counter = models.find(hash);
|
||||
if (counter != models.cend())
|
||||
{
|
||||
++counter->second.counter;
|
||||
return counter->second.model;
|
||||
}
|
||||
|
||||
Loging::Log("Load new model: " + name);
|
||||
|
||||
std::vector<Vertex> vertices;
|
||||
std::vector<uint32_t> indices;
|
||||
// Load model_data
|
||||
|
||||
owner_counter new_counter;
|
||||
new_counter.counter.store(1);
|
||||
new_counter.model = new StaticModel(vertices, indices, physical_device_, device_);
|
||||
models.try_emplace(hash, new_counter);
|
||||
return new_counter.model;
|
||||
}
|
||||
|
||||
void ModelManager::FreeModel(const std::string& name)
|
||||
{
|
||||
if (name.empty())
|
||||
return;
|
||||
|
||||
unsigned int hash = FNV1aHash(name.c_str());
|
||||
auto counter = models.find(hash);
|
||||
--counter->second.counter;
|
||||
|
||||
StaticModel* model = counter->second.model;
|
||||
if (counter->second.counter.load() == 0)
|
||||
{
|
||||
Loging::Log("Free model: " + name);
|
||||
models.erase(hash);
|
||||
delete model;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,57 @@
|
||||
#pragma once
|
||||
|
||||
#include <unordered_map>
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <glm/vec3.hpp>
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
class ModelManager
|
||||
{
|
||||
public:
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 pos, color;
|
||||
static VkVertexInputBindingDescription get_binding_description();
|
||||
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
||||
|
||||
};
|
||||
class StaticModel
|
||||
{
|
||||
VkPhysicalDevice physical_device_;
|
||||
VkDevice device_;
|
||||
VkBuffer vertex_buffer_;
|
||||
VkBuffer index_buffer_;
|
||||
|
||||
|
||||
public:
|
||||
StaticModel(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices,
|
||||
VkPhysicalDevice physical_device, VkDevice device);
|
||||
~StaticModel();
|
||||
|
||||
};
|
||||
|
||||
struct owner_counter
|
||||
{
|
||||
std::atomic_ullong counter;
|
||||
StaticModel* model;
|
||||
|
||||
owner_counter() = default;
|
||||
owner_counter(const owner_counter& other);
|
||||
};
|
||||
|
||||
private:
|
||||
VkPhysicalDevice physical_device_;
|
||||
VkDevice device_;
|
||||
std::unordered_map<unsigned int, owner_counter> models;
|
||||
|
||||
static unsigned int FNV1aHash (const char *buf);
|
||||
|
||||
public:
|
||||
ModelManager(VkPhysicalDevice physical_device, VkDevice device);
|
||||
~ModelManager();
|
||||
|
||||
StaticModel* LoadModel(const std::string& name);
|
||||
void FreeModel(const std::string& name);
|
||||
};
|
||||
@@ -0,0 +1,134 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <stdexcept>
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include "GPU_GarbageCollector.h"
|
||||
#include "Delegate/Delegate.h"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
#include "VkObjects/Device.hpp"
|
||||
#include "VkObjects/PhysicalDevice.hpp"
|
||||
|
||||
|
||||
template <typename T>
|
||||
class UniformBuffer
|
||||
{
|
||||
const VkObjects::Device& device_;
|
||||
const VkObjects::PhysicalDevice& physical_device_;
|
||||
size_t count_;
|
||||
std::shared_ptr<GPU_GarbageCollector> gc_;
|
||||
|
||||
VkBuffer buffer_ = nullptr;
|
||||
VkDeviceMemory device_memory_ = nullptr;
|
||||
void* map_ = nullptr;
|
||||
|
||||
VkBuffer create_buffer(VkDeviceSize size) const
|
||||
{
|
||||
return DeviceFunctions::create_buffer(
|
||||
device_.get_native(),
|
||||
size,
|
||||
VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT,
|
||||
physical_device_.get_unique_family_indices()
|
||||
);
|
||||
}
|
||||
VkDeviceMemory allocate_device_memory(VkBuffer buffer) const
|
||||
{
|
||||
return DeviceFunctions::allocate_device_memory(
|
||||
physical_device_.get_native(),
|
||||
device_.get_native(),
|
||||
buffer,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT
|
||||
);
|
||||
}
|
||||
public:
|
||||
struct BufferDataDelegate
|
||||
{
|
||||
VkBuffer buffer;
|
||||
VkDeviceMemory device_memory;
|
||||
VkDeviceSize size;
|
||||
};
|
||||
// Параметр - дескрипторы нового буфера
|
||||
Delegate<const BufferDataDelegate&> OnResize;
|
||||
|
||||
explicit UniformBuffer( const VkObjects::Device& device,
|
||||
const VkObjects::PhysicalDevice& physical_device,
|
||||
const std::shared_ptr<GPU_GarbageCollector>& gc,
|
||||
size_t count = 1):
|
||||
device_(device), physical_device_(physical_device), count_(count), gc_(gc)
|
||||
{
|
||||
if (count == 0)
|
||||
throw std::runtime_error("Count of 0 is not allowed to be 0");
|
||||
|
||||
const VkDeviceSize size = sizeof(T) * count;
|
||||
buffer_ = create_buffer(size);
|
||||
device_memory_ = allocate_device_memory(buffer_);
|
||||
vkBindBufferMemory(device.get_native(), buffer_, device_memory_, 0);
|
||||
|
||||
vkMapMemory(device.get_native(), device_memory_, 0, size, 0, &map_);
|
||||
}
|
||||
|
||||
virtual ~UniformBuffer()
|
||||
{
|
||||
if (device_memory_ != nullptr && map_ != nullptr)
|
||||
{
|
||||
vkUnmapMemory(device_.get_native(), device_memory_);
|
||||
map_ = nullptr;
|
||||
}
|
||||
|
||||
gc_->AddGarbage({buffer_, device_memory_});
|
||||
}
|
||||
|
||||
operator T*() const
|
||||
{
|
||||
return map_;
|
||||
}
|
||||
|
||||
operator void*() const
|
||||
{
|
||||
return map_;
|
||||
}
|
||||
|
||||
operator VkBuffer() const
|
||||
{
|
||||
return buffer_;
|
||||
}
|
||||
|
||||
T& operator[](size_t index)
|
||||
{
|
||||
if (index < count_)
|
||||
return map_[index];
|
||||
throw std::runtime_error("Index out of range!");
|
||||
}
|
||||
|
||||
void resize(size_t new_count)
|
||||
{
|
||||
if (new_count == count_)
|
||||
return;
|
||||
|
||||
if (new_count == 0)
|
||||
throw std::runtime_error("Count of 0 is not allowed to be 0");
|
||||
|
||||
const VkDeviceSize new_size = sizeof(T) * new_count;
|
||||
void* new_map = nullptr;
|
||||
|
||||
VkBuffer new_buffer = create_buffer(new_size);
|
||||
VkDeviceMemory new_memory = allocate_device_memory(new_buffer);
|
||||
vkBindBufferMemory(device_.get_native(), new_buffer, new_memory, 0);
|
||||
vkMapMemory(device_.get_native(), new_memory, 0, new_size, 0, &new_map);
|
||||
|
||||
memcpy_s(new_map, new_size, map_, sizeof(T) * count_);
|
||||
|
||||
vkUnmapMemory(device_.get_native(), device_memory_);
|
||||
gc_->AddGarbage({ buffer_, device_memory_ });
|
||||
BufferDataDelegate data{ new_buffer, new_memory, new_size };
|
||||
OnResize.call(data);
|
||||
|
||||
buffer_ = new_buffer;
|
||||
device_memory_ = new_memory;
|
||||
map_ = new_map;
|
||||
count_ = new_count;
|
||||
}
|
||||
};
|
||||
@@ -0,0 +1,418 @@
|
||||
#include "UwURenderEngine.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <chrono>
|
||||
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#include "GPU_GarbageCollector.h"
|
||||
#include "../Game/Actors/Camera.hpp"
|
||||
#include "Core/CoreInstance.hpp"
|
||||
|
||||
#include "Game/GameInstance.hpp"
|
||||
#include "Game/World/World.hpp"
|
||||
#include "../Game/Actors/Mesh/Mesh.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
|
||||
RENDER_ENGINE_FACTORY_GENERATE(UwURenderEngine)
|
||||
|
||||
void UwURenderEngine::create_uniform_buffers()
|
||||
{
|
||||
uniform_buffers_.resize(swapchain_.get_images().size());
|
||||
|
||||
for (auto & i : uniform_buffers_)
|
||||
{
|
||||
i.reset(new UniformBuffer<UniformBufferObject>(device_, physical_device_, garbage_collector_, 1));
|
||||
}
|
||||
}
|
||||
|
||||
void UwURenderEngine::create_descriptor_pool()
|
||||
{
|
||||
VkDescriptorPoolSize pool_size;
|
||||
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
pool_size.descriptorCount = static_cast<uint32_t>(swapchain_.get_images().size());
|
||||
|
||||
VkDescriptorPoolCreateInfo descriptor_pool_info{};
|
||||
descriptor_pool_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_POOL_CREATE_INFO;
|
||||
descriptor_pool_info.poolSizeCount = 1;
|
||||
descriptor_pool_info.pPoolSizes = &pool_size;
|
||||
descriptor_pool_info.maxSets = static_cast<uint32_t>(swapchain_.get_images().size());
|
||||
|
||||
VK_CHECK(vkCreateDescriptorPool(device_.get_native(), &descriptor_pool_info, nullptr, &descriptor_pool_))
|
||||
}
|
||||
|
||||
void UwURenderEngine::update_descriptor_sets()
|
||||
{
|
||||
std::vector<VkDescriptorSetLayout> layouts(swapchain_.get_images().size(), layout_binding_.get_native());
|
||||
VkDescriptorSetAllocateInfo descriptor_set_allocate_info{};
|
||||
descriptor_set_allocate_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_ALLOCATE_INFO;
|
||||
descriptor_set_allocate_info.descriptorPool = descriptor_pool_;
|
||||
descriptor_set_allocate_info.descriptorSetCount = static_cast<uint32_t>(swapchain_.get_images().size());
|
||||
descriptor_set_allocate_info.pSetLayouts = layouts.data();
|
||||
|
||||
descriptor_sets_.resize(swapchain_.get_images().size());
|
||||
VK_CHECK(vkAllocateDescriptorSets(device_.get_native(), &descriptor_set_allocate_info, descriptor_sets_.data()))
|
||||
|
||||
for (size_t i = 0; i < swapchain_.get_images().size(); ++i)
|
||||
{
|
||||
VkDescriptorBufferInfo buffer_info{};
|
||||
buffer_info.buffer = *uniform_buffers_[i];
|
||||
buffer_info.offset = 0;
|
||||
buffer_info.range = sizeof(UniformBufferObject);
|
||||
|
||||
VkWriteDescriptorSet write_descriptor_set{};
|
||||
write_descriptor_set.sType = VK_STRUCTURE_TYPE_WRITE_DESCRIPTOR_SET;
|
||||
write_descriptor_set.dstSet = descriptor_sets_[i];
|
||||
write_descriptor_set.dstBinding = 0;
|
||||
write_descriptor_set.dstArrayElement = 0;
|
||||
write_descriptor_set.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
write_descriptor_set.descriptorCount = 1;
|
||||
write_descriptor_set.pBufferInfo = &buffer_info;
|
||||
write_descriptor_set.pImageInfo = nullptr;
|
||||
write_descriptor_set.pTexelBufferView = nullptr;
|
||||
|
||||
vkUpdateDescriptorSets(device_.get_native(), 1, &write_descriptor_set, 0, nullptr);
|
||||
}
|
||||
}
|
||||
|
||||
void UwURenderEngine::create_framebuffers()
|
||||
{
|
||||
framebuffers_.resize(swapchain_.get_images().size());
|
||||
|
||||
VkFramebufferCreateInfo framebuffer_info{};
|
||||
framebuffer_info.sType = VK_STRUCTURE_TYPE_FRAMEBUFFER_CREATE_INFO;
|
||||
framebuffer_info.renderPass = render_pass_.get_native();
|
||||
framebuffer_info.attachmentCount = 1;
|
||||
framebuffer_info.width = swapchain_.get_extent().width;
|
||||
framebuffer_info.height = swapchain_.get_extent().height;
|
||||
framebuffer_info.layers = 1;
|
||||
|
||||
for (size_t i = 0; i < framebuffers_.size(); ++i)
|
||||
{
|
||||
framebuffer_info.pAttachments = &swapchain_.get_image_views()[i];
|
||||
VK_CHECK(vkCreateFramebuffer(device_.get_native(), &framebuffer_info, nullptr, &framebuffers_[i]))
|
||||
}
|
||||
}
|
||||
|
||||
void UwURenderEngine::create_command_pool()
|
||||
{
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices queue_family_indices = physical_device_.get_queue_family_indices();
|
||||
|
||||
VkCommandPoolCreateInfo command_pool_info{};
|
||||
command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||
command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family;
|
||||
command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||
|
||||
VK_CHECK(vkCreateCommandPool(device_.get_native(), &command_pool_info, nullptr, &command_pool_))
|
||||
}
|
||||
|
||||
void UwURenderEngine::allocate_vertex_buffer()
|
||||
{
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices indices = physical_device_.get_queue_family_indices();
|
||||
|
||||
|
||||
std::vector<uint32_t> arr_indices = physical_device_.get_unique_family_indices();
|
||||
std::vector<uint32_t> transfer_index = {indices.transfer_family};
|
||||
|
||||
VkDeviceSize size_buffer = sizeof(vertices_[0]) * vertices_.size();
|
||||
VkBuffer staging_buffer = DeviceFunctions::create_buffer(device_.get_native(), size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
transfer_index);
|
||||
VkDeviceMemory staging_buffer_memory = DeviceFunctions::allocate_device_memory(
|
||||
physical_device_.get_native(), device_.get_native(), staging_buffer,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
|
||||
vertex_buffer_ = DeviceFunctions::create_buffer(device_.get_native(), size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, arr_indices);
|
||||
vertex_buffer_memory_ = DeviceFunctions::allocate_device_memory(physical_device_.get_native(), device_.get_native(), vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
|
||||
VK_CHECK(vkBindBufferMemory(device_.get_native(), staging_buffer, staging_buffer_memory, 0))
|
||||
VK_CHECK(vkBindBufferMemory(device_.get_native(), vertex_buffer_, vertex_buffer_memory_, 0))
|
||||
|
||||
void* data;
|
||||
VK_CHECK(vkMapMemory(device_.get_native(), staging_buffer_memory, 0, size_buffer, 0, &data))
|
||||
memcpy(data, vertices_.data(), size_buffer);
|
||||
vkUnmapMemory(device_.get_native(), staging_buffer_memory);
|
||||
|
||||
DeviceFunctions::device_memcpy(device_.get_native(), indices.transfer_family, staging_buffer, vertex_buffer_, size_buffer);
|
||||
|
||||
vkFreeMemory(device_.get_native(), staging_buffer_memory, nullptr);
|
||||
vkDestroyBuffer(device_.get_native(), staging_buffer, nullptr);
|
||||
}
|
||||
|
||||
void UwURenderEngine::allocate_index_buffer()
|
||||
{
|
||||
std::vector<uint32_t> arr_indices = physical_device_.get_unique_family_indices();
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices indices = physical_device_.get_queue_family_indices();
|
||||
std::vector<uint32_t> transfer_index = {indices.transfer_family};
|
||||
|
||||
VkDeviceSize size_buffer = sizeof(indices_[0]) * indices_.size();
|
||||
VkBuffer staging_buffer = DeviceFunctions::create_buffer(device_.get_native(), size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||
transfer_index);
|
||||
VkDeviceMemory staging_buffer_memory = DeviceFunctions::allocate_device_memory(
|
||||
physical_device_.get_native(), device_.get_native(), staging_buffer,
|
||||
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||
vkBindBufferMemory(device_.get_native(), staging_buffer, staging_buffer_memory, 0);
|
||||
|
||||
void* data;
|
||||
vkMapMemory(device_.get_native(), staging_buffer_memory, 0, size_buffer, 0, &data);
|
||||
memcpy(data, indices_.data(), size_buffer);
|
||||
vkUnmapMemory(device_.get_native(), staging_buffer_memory);
|
||||
|
||||
index_buffer_ = DeviceFunctions::create_buffer(device_.get_native(), size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, arr_indices);
|
||||
index_buffer_memory_ = DeviceFunctions::allocate_device_memory(physical_device_.get_native(), device_.get_native(), index_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||
vkBindBufferMemory(device_.get_native(), index_buffer_, index_buffer_memory_, 0);
|
||||
|
||||
DeviceFunctions::device_memcpy(device_.get_native(), indices.transfer_family,staging_buffer, index_buffer_, size_buffer);
|
||||
|
||||
vkDestroyBuffer(device_.get_native(), staging_buffer, nullptr);
|
||||
vkFreeMemory(device_.get_native(), staging_buffer_memory, nullptr);
|
||||
}
|
||||
|
||||
void UwURenderEngine::allocate_command_buffers()
|
||||
{
|
||||
command_buffers_.resize(swapchain_.get_images().size());
|
||||
|
||||
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||
command_buffer_allocate_info.commandPool = command_pool_;
|
||||
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||
command_buffer_allocate_info.commandBufferCount = static_cast<uint32_t>(command_buffers_.size());
|
||||
|
||||
VK_CHECK(vkAllocateCommandBuffers(device_.get_native(), &command_buffer_allocate_info, command_buffers_.data()))
|
||||
}
|
||||
|
||||
void UwURenderEngine::create_sync_objects()
|
||||
{
|
||||
image_available_semaphores_.resize(swapchain_.get_images().size());
|
||||
render_finished_semaphores_.resize(swapchain_.get_images().size());
|
||||
in_flight_fences_.resize(swapchain_.get_images().size());
|
||||
|
||||
VkSemaphoreCreateInfo semaphore_info{};
|
||||
semaphore_info.sType = VK_STRUCTURE_TYPE_SEMAPHORE_CREATE_INFO;
|
||||
|
||||
VkFenceCreateInfo fence_info{};
|
||||
fence_info.sType = VK_STRUCTURE_TYPE_FENCE_CREATE_INFO;
|
||||
fence_info.flags = VK_FENCE_CREATE_SIGNALED_BIT;
|
||||
|
||||
for (size_t i = 0; i < swapchain_.get_images().size(); ++i)
|
||||
{
|
||||
VK_CHECK(vkCreateSemaphore(device_.get_native(), &semaphore_info, nullptr, &image_available_semaphores_[i]))
|
||||
VK_CHECK(vkCreateSemaphore(device_.get_native(), &semaphore_info, nullptr, &render_finished_semaphores_[i]))
|
||||
VK_CHECK(vkCreateFence(device_.get_native(), &fence_info, nullptr, &in_flight_fences_[i]))
|
||||
}
|
||||
}
|
||||
|
||||
void UwURenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const
|
||||
{
|
||||
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
||||
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||
VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info))
|
||||
|
||||
constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||
VkRenderPassBeginInfo render_pass_begin_info{};
|
||||
render_pass_begin_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
|
||||
render_pass_begin_info.renderPass = render_pass_.get_native();
|
||||
render_pass_begin_info.framebuffer = framebuffers_[image_index];
|
||||
render_pass_begin_info.renderArea.offset = {0, 0};
|
||||
render_pass_begin_info.renderArea.extent = swapchain_.get_extent();
|
||||
render_pass_begin_info.clearValueCount = 1;
|
||||
render_pass_begin_info.pClearValues = &clear_color;
|
||||
vkCmdBeginRenderPass(command_buffer, &render_pass_begin_info, VK_SUBPASS_CONTENTS_INLINE);
|
||||
|
||||
vkCmdBindPipeline(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_.get_native());
|
||||
|
||||
VkBuffer vertex_buffers[] = {vertex_buffer_};
|
||||
VkDeviceSize offset[] = {0};
|
||||
vkCmdBindVertexBuffers(command_buffer, 0, 1, vertex_buffers, offset);
|
||||
|
||||
vkCmdBindDescriptorSets(command_buffer, VK_PIPELINE_BIND_POINT_GRAPHICS, pipeline_.get_layout(), 0, 1, &descriptor_sets_[current_frame_], 0, nullptr);
|
||||
|
||||
vkCmdBindIndexBuffer(command_buffer, index_buffer_, 0, VK_INDEX_TYPE_UINT16);
|
||||
|
||||
VkViewport viewport;
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(swapchain_.get_extent().width);
|
||||
viewport.height = static_cast<float>(swapchain_.get_extent().height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
vkCmdSetViewport(command_buffer, 0, 1, &viewport);
|
||||
|
||||
VkRect2D scissor;
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = swapchain_.get_extent();
|
||||
vkCmdSetScissor(command_buffer, 0, 1, &scissor);
|
||||
|
||||
vkCmdDrawIndexed(command_buffer, static_cast<uint32_t>(indices_.size()), 1, 0, 0, 0);
|
||||
|
||||
vkCmdEndRenderPass(command_buffer);
|
||||
VK_CHECK(vkEndCommandBuffer(command_buffer))
|
||||
}
|
||||
|
||||
void UwURenderEngine::update_uniform_buffer(uint32_t current_frame) const
|
||||
{
|
||||
glm::vec3 eye{0, 0, 0};
|
||||
glm::vec3 center{0, 0, 0};
|
||||
glm::vec3 up{0, 1, 0};
|
||||
if (active_camera_.expired() == false)
|
||||
{
|
||||
std::shared_ptr<Camera> camera = active_camera_.lock();
|
||||
Vector3D loc = camera->GetActorLocate();
|
||||
eye = {loc.x, loc.y, loc.z};
|
||||
|
||||
Vector3D rot = camera->GetActorRotate();
|
||||
glm::vec3 direction{glm::cos(rot.x)*glm::cos(rot.y), glm::sin(rot.x)*glm::cos(rot.y), glm::sin(rot.y)};
|
||||
center = eye + direction;
|
||||
|
||||
up = {0, glm::sin(rot.z), glm::cos(rot.z)};
|
||||
}
|
||||
|
||||
// static auto start_time = std::chrono::high_resolution_clock::now();
|
||||
// auto current_time = std::chrono::high_resolution_clock::now();
|
||||
// float time = std::chrono::duration_cast<std::chrono::duration<float>>(current_time - start_time).count();
|
||||
UniformBufferObject ubo;
|
||||
ubo.model = glm::rotate(glm::mat4(1.0f), /*time * glm::radians(45.0f)*/0.f, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||
ubo.view = glm::lookAt(eye, center, up);
|
||||
ubo.proj = glm::perspective(glm::radians(45.0f), static_cast<float>(swapchain_.get_extent().width) / static_cast<float>(swapchain_.get_extent().height), 0.1f, 256.0f);
|
||||
ubo.proj[1][1] *= -1;
|
||||
memcpy(*uniform_buffers_[current_frame], &ubo, sizeof(ubo));
|
||||
}
|
||||
|
||||
void UwURenderEngine::draw_frame()
|
||||
{
|
||||
vkWaitForFences(device_.get_native(), 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX);
|
||||
vkResetFences(device_.get_native(), 1, &in_flight_fences_[current_frame_]);
|
||||
|
||||
// Free video memory
|
||||
garbage_collector_->FreeHeap();
|
||||
|
||||
uint32_t image_index;
|
||||
vkAcquireNextImageKHR(device_.get_native(), swapchain_.get_native(), UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index);
|
||||
|
||||
vkResetCommandBuffer(command_buffers_[current_frame_], 0);
|
||||
|
||||
update_uniform_buffer(current_frame_);
|
||||
record_command_buffer(command_buffers_[current_frame_], image_index);
|
||||
|
||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
VkSubmitInfo submit_info{};
|
||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||
submit_info.commandBufferCount = 1;
|
||||
submit_info.pCommandBuffers = &command_buffers_[current_frame_];
|
||||
submit_info.waitSemaphoreCount = 1;
|
||||
submit_info.pWaitSemaphores = &image_available_semaphores_[current_frame_];
|
||||
submit_info.pWaitDstStageMask = &wait_stage;
|
||||
submit_info.signalSemaphoreCount = 1;
|
||||
submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_];
|
||||
|
||||
VK_CHECK(vkQueueSubmit(device_.get_graphics_queue(), 1, &submit_info, in_flight_fences_[current_frame_]))
|
||||
|
||||
VkSwapchainKHR swapchain = swapchain_.get_native();
|
||||
VkPresentInfoKHR present_info{};
|
||||
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||
present_info.waitSemaphoreCount = 1;
|
||||
present_info.pWaitSemaphores = &render_finished_semaphores_[current_frame_];
|
||||
present_info.swapchainCount = 1;
|
||||
present_info.pSwapchains = &swapchain;
|
||||
present_info.pImageIndices = &image_index;
|
||||
present_info.pResults = nullptr;
|
||||
|
||||
vkQueuePresentKHR(device_.get_present_queue(), &present_info);
|
||||
|
||||
current_frame_ = (current_frame_ + 1) % static_cast<unsigned int>(swapchain_.get_images().size());
|
||||
}
|
||||
|
||||
UwURenderEngine::UwURenderEngine(CoreInstance& core):
|
||||
RenderEngineBase(core),
|
||||
core_(core),
|
||||
instance_(core),
|
||||
surface_(instance_, get_window()),
|
||||
physical_device_(instance_, surface_, deviceExtensions),
|
||||
device_(physical_device_, deviceExtensions),
|
||||
swapchain_(surface_, physical_device_, device_, get_window()),
|
||||
render_pass_(device_, swapchain_),
|
||||
layout_binding_(device_),
|
||||
pipeline_(device_, swapchain_, render_pass_, layout_binding_)
|
||||
{
|
||||
garbage_collector_.reset(new GPU_GarbageCollector(device_.get_native()));
|
||||
model_manager_.reset(new ModelManager(physical_device_.get_native(), device_.get_native()));
|
||||
|
||||
create_uniform_buffers();
|
||||
create_descriptor_pool();
|
||||
update_descriptor_sets();
|
||||
create_framebuffers();
|
||||
create_command_pool();
|
||||
allocate_vertex_buffer();
|
||||
allocate_command_buffers();
|
||||
allocate_index_buffer();
|
||||
create_sync_objects();
|
||||
}
|
||||
|
||||
UwURenderEngine::~UwURenderEngine()
|
||||
{
|
||||
vkDeviceWaitIdle(device_.get_native());
|
||||
|
||||
if (index_buffer_memory_ != VK_NULL_HANDLE)
|
||||
vkFreeMemory(device_.get_native(), index_buffer_memory_, nullptr);
|
||||
|
||||
if (index_buffer_ != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(device_.get_native(), index_buffer_, nullptr);
|
||||
|
||||
if (vertex_buffer_memory_ != VK_NULL_HANDLE)
|
||||
vkFreeMemory(device_.get_native(), vertex_buffer_memory_, nullptr);
|
||||
|
||||
if (vertex_buffer_ != VK_NULL_HANDLE)
|
||||
vkDestroyBuffer(device_.get_native(), vertex_buffer_, nullptr);
|
||||
|
||||
for (auto& i : image_available_semaphores_)
|
||||
vkDestroySemaphore(device_.get_native(), i, nullptr);
|
||||
|
||||
for (auto& i : render_finished_semaphores_)
|
||||
vkDestroySemaphore(device_.get_native(), i, nullptr);
|
||||
|
||||
for (auto& i : in_flight_fences_)
|
||||
vkDestroyFence(device_.get_native(), i, nullptr);
|
||||
|
||||
if (command_buffers_.empty() == false)
|
||||
vkFreeCommandBuffers(device_.get_native(), command_pool_, static_cast<uint32_t>(command_buffers_.size()), command_buffers_.data());
|
||||
|
||||
if (command_pool_ != VK_NULL_HANDLE)
|
||||
vkDestroyCommandPool(device_.get_native(), command_pool_, nullptr);
|
||||
|
||||
for (auto& i : framebuffers_)
|
||||
vkDestroyFramebuffer(device_.get_native(), i, nullptr);
|
||||
|
||||
uniform_buffers_.clear();
|
||||
|
||||
vkDestroyDescriptorPool(device_.get_native(), descriptor_pool_, nullptr);
|
||||
|
||||
garbage_collector_->FreeHeap();
|
||||
}
|
||||
|
||||
void UwURenderEngine::start()
|
||||
{
|
||||
std::shared_ptr<World> world = core_.GetGameInstance()->GetWorld();
|
||||
std::vector<std::weak_ptr<Mesh>> meshes = world->GetActorsByClass<Mesh>();
|
||||
for (auto& i : meshes)
|
||||
{
|
||||
std::shared_ptr<Mesh> mesh = i.lock();
|
||||
mesh->load_model(mesh->GetModelName());
|
||||
}
|
||||
|
||||
while (!glfwWindowShouldClose(get_window()))
|
||||
{
|
||||
glfwPollEvents();
|
||||
draw_frame();
|
||||
}
|
||||
}
|
||||
|
||||
void UwURenderEngine::stop_render() const
|
||||
{
|
||||
if (!glfwWindowShouldClose(get_window()))
|
||||
glfwSetWindowShouldClose(get_window(), true);
|
||||
}
|
||||
|
||||
void UwURenderEngine::SetActiveCamera(const std::weak_ptr<Camera>& camera)
|
||||
{
|
||||
std::scoped_lock lock(m_active_camera_);
|
||||
active_camera_ = camera;
|
||||
}
|
||||
@@ -0,0 +1,115 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderEngineBase.hpp"
|
||||
#include "ModelManager.hpp"
|
||||
|
||||
#include <vector>
|
||||
#include <memory>
|
||||
#include <mutex>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/glm.hpp>
|
||||
|
||||
#include "UniformBuffer.hpp"
|
||||
#include "VkObjects/DescriptorSetLayout.hpp"
|
||||
#include "VkObjects/Device.hpp"
|
||||
#include "VkObjects/Instance.hpp"
|
||||
#include "VkObjects/PhysicalDevice.hpp"
|
||||
#include "VkObjects/Pipeline.hpp"
|
||||
#include "VkObjects/RenderPass.hpp"
|
||||
#include "VkObjects/Surface.hpp"
|
||||
#include "VkObjects/Swapchain.hpp"
|
||||
|
||||
class Camera;
|
||||
class GPU_GarbageCollector;
|
||||
|
||||
#define GET_RENDER_ENGINE static_cast<UwURenderEngine*>(GetWorld()->GetGameInstance().GetCore().GetRenderEngine())
|
||||
|
||||
class UwURenderEngine final : public RenderEngineBase
|
||||
{
|
||||
struct UniformBufferObject {
|
||||
glm::mat4 model;
|
||||
glm::mat4 view;
|
||||
glm::mat4 proj;
|
||||
};
|
||||
|
||||
const std::vector<ModelManager::Vertex> vertices_ = {
|
||||
{{-0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}
|
||||
};
|
||||
const std::vector<uint16_t> indices_ = {
|
||||
0, 1, 2, 2, 3, 0,
|
||||
2, 1, 5, 5, 6, 2,
|
||||
0, 3, 7, 7, 4, 0,
|
||||
3, 2, 6, 6, 7, 3,
|
||||
7, 6, 5, 5, 4, 7,
|
||||
4, 5, 1, 1, 0, 4
|
||||
};
|
||||
|
||||
const std::vector<const char*> deviceExtensions = {
|
||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||
};
|
||||
|
||||
// Counting frame from the beginning
|
||||
unsigned int current_frame_ = 0;
|
||||
|
||||
CoreInstance& core_;
|
||||
std::shared_ptr<ModelManager> model_manager_;
|
||||
std::shared_ptr<GPU_GarbageCollector> garbage_collector_;
|
||||
std::weak_ptr<Camera> active_camera_;
|
||||
std::mutex m_active_camera_;
|
||||
|
||||
VkObjects::Instance instance_;
|
||||
VkObjects::Surface surface_;
|
||||
VkObjects::PhysicalDevice physical_device_;
|
||||
VkObjects::Device device_;
|
||||
VkObjects::Swapchain swapchain_;
|
||||
VkObjects::RenderPass render_pass_;
|
||||
VkObjects::DescriptorSetLayout layout_binding_;
|
||||
VkDescriptorPool descriptor_pool_ = VK_NULL_HANDLE;
|
||||
std::vector<VkDescriptorSet> descriptor_sets_;
|
||||
VkObjects::Pipeline pipeline_;
|
||||
std::vector<VkFramebuffer> framebuffers_;
|
||||
VkCommandPool command_pool_ = VK_NULL_HANDLE;
|
||||
std::vector<VkCommandBuffer> command_buffers_;
|
||||
VkBuffer vertex_buffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE;
|
||||
VkBuffer index_buffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceMemory index_buffer_memory_ = VK_NULL_HANDLE;
|
||||
std::vector<std::unique_ptr<UniformBuffer<UniformBufferObject>>> uniform_buffers_;
|
||||
|
||||
// Sync objects
|
||||
std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_;
|
||||
std::vector<VkFence> in_flight_fences_;
|
||||
|
||||
void create_uniform_buffers();
|
||||
void create_descriptor_pool();
|
||||
void update_descriptor_sets();
|
||||
void create_framebuffers();
|
||||
void create_command_pool();
|
||||
void allocate_command_buffers();
|
||||
void create_sync_objects();
|
||||
void allocate_vertex_buffer();
|
||||
void allocate_index_buffer();
|
||||
|
||||
void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const;
|
||||
void update_uniform_buffer(uint32_t current_frame) const;
|
||||
void draw_frame();
|
||||
public:
|
||||
// Can throw the exception
|
||||
explicit UwURenderEngine(CoreInstance& core);
|
||||
~UwURenderEngine() override;
|
||||
|
||||
void start() override;
|
||||
void stop_render() const override;
|
||||
|
||||
std::shared_ptr<ModelManager> GetModelManager() const { return model_manager_; }
|
||||
|
||||
void SetActiveCamera(const std::weak_ptr<Camera>& camera);
|
||||
};
|
||||
@@ -0,0 +1,30 @@
|
||||
#include "DescriptorSetLayout.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "Device.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
|
||||
VkObjects::DescriptorSetLayout::DescriptorSetLayout(const Device& device):device_(device)
|
||||
{
|
||||
VkDescriptorSetLayoutBinding ubo_layout_binding;
|
||||
ubo_layout_binding.binding = 0;
|
||||
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||
ubo_layout_binding.descriptorCount = 1;
|
||||
ubo_layout_binding.stageFlags = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
ubo_layout_binding.pImmutableSamplers = nullptr;
|
||||
|
||||
VkDescriptorSetLayoutCreateInfo ubo_layout_info{};
|
||||
ubo_layout_info.sType = VK_STRUCTURE_TYPE_DESCRIPTOR_SET_LAYOUT_CREATE_INFO;
|
||||
ubo_layout_info.bindingCount = 1;
|
||||
ubo_layout_info.pBindings = &ubo_layout_binding;
|
||||
|
||||
VK_CHECK(vkCreateDescriptorSetLayout(device_.get_native(), &ubo_layout_info, nullptr, &layout_binding_))
|
||||
}
|
||||
|
||||
VkObjects::DescriptorSetLayout::~DescriptorSetLayout()
|
||||
{
|
||||
if (layout_binding_ != nullptr)
|
||||
vkDestroyDescriptorSetLayout(device_.get_native(), layout_binding_, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Device;
|
||||
|
||||
class DescriptorSetLayout
|
||||
{
|
||||
VkDescriptorSetLayout layout_binding_ = nullptr;
|
||||
const Device& device_;
|
||||
public:
|
||||
DescriptorSetLayout(const Device& device);
|
||||
~DescriptorSetLayout();
|
||||
|
||||
inline VkDescriptorSetLayout get_native() const { return layout_binding_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
#include "Device.hpp"
|
||||
|
||||
#include "PhysicalDevice.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
|
||||
VkObjects::Device::Device(const PhysicalDevice& physical_device, const std::vector<const char*>& device_extensions)
|
||||
{
|
||||
PhysicalDevice::QueueFamilyIndices indices = physical_device.get_queue_family_indices();
|
||||
|
||||
VkPhysicalDeviceFeatures device_features{};
|
||||
|
||||
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
||||
std::set<uint32_t> unique_queue_families = {indices.graphics_family,
|
||||
indices.present_family,
|
||||
indices.transfer_family};
|
||||
|
||||
float queue_priority = 1.0f;
|
||||
VkDeviceQueueCreateInfo device_queue_create_info{};
|
||||
device_queue_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
||||
device_queue_create_info.pQueuePriorities = &queue_priority;
|
||||
for (auto queue_family : unique_queue_families)
|
||||
{
|
||||
device_queue_create_info.queueFamilyIndex = queue_family;
|
||||
device_queue_create_info.queueCount = 1;
|
||||
queue_create_infos.push_back(device_queue_create_info);
|
||||
}
|
||||
|
||||
VkDeviceCreateInfo device_create_info{};
|
||||
device_create_info.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO;
|
||||
device_create_info.queueCreateInfoCount = static_cast<uint32_t>(unique_queue_families.size());
|
||||
device_create_info.pQueueCreateInfos = queue_create_infos.data();
|
||||
device_create_info.pEnabledFeatures = &device_features;
|
||||
device_create_info.enabledExtensionCount = static_cast<uint32_t>(device_extensions.size());
|
||||
device_create_info.ppEnabledExtensionNames = device_extensions.data();
|
||||
|
||||
#ifdef _DEBUG
|
||||
const std::vector<const char*> layers_validation = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
device_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
||||
device_create_info.ppEnabledLayerNames = layers_validation.data();
|
||||
#else
|
||||
device_create_info.enabledLayerCount = 0;
|
||||
device_create_info.ppEnabledLayerNames = nullptr;
|
||||
|
||||
#endif
|
||||
VK_CHECK(vkCreateDevice(physical_device.get_native(), &device_create_info, nullptr, &device_))
|
||||
vkGetDeviceQueue(device_, indices.graphics_family, 0, &graphics_queue_);
|
||||
vkGetDeviceQueue(device_, indices.present_family, 0, &present_queue_);
|
||||
vkGetDeviceQueue(device_, indices.transfer_family, 0, &transfer_queue_);
|
||||
}
|
||||
|
||||
VkObjects::Device::~Device()
|
||||
{
|
||||
if (device_ != nullptr)
|
||||
vkDestroyDevice(device_, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class PhysicalDevice;
|
||||
|
||||
class Device final
|
||||
{
|
||||
VkDevice device_ = nullptr;
|
||||
VkQueue graphics_queue_ = nullptr;
|
||||
VkQueue present_queue_ = nullptr;
|
||||
VkQueue transfer_queue_ = nullptr;
|
||||
public:
|
||||
explicit Device(const PhysicalDevice& physical_device, const std::vector<const char*>& device_extensions);
|
||||
~Device();
|
||||
|
||||
inline VkDevice get_native() const { return device_; }
|
||||
inline VkQueue get_graphics_queue() const { return graphics_queue_; }
|
||||
inline VkQueue get_present_queue() const { return present_queue_; }
|
||||
inline VkQueue get_transfer_queue() const { return transfer_queue_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,92 @@
|
||||
#include "Instance.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
|
||||
#include "Core/CoreInstance.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
VkBool32 Instance::debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData) {
|
||||
|
||||
std::string msg = "validation layer: ";
|
||||
msg += pCallbackData->pMessage;
|
||||
Loging::Log(msg);
|
||||
|
||||
return VK_FALSE;
|
||||
}
|
||||
|
||||
VkResult Instance::enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info)
|
||||
{
|
||||
PFN_vkCreateDebugUtilsMessengerEXT debug_creator = reinterpret_cast<PFN_vkCreateDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkCreateDebugUtilsMessengerEXT"));
|
||||
return debug_creator(instance_, create_info, nullptr, &debug_messenger_);
|
||||
}
|
||||
#endif
|
||||
|
||||
std::vector<const char*> Instance::get_required_extensions()
|
||||
{
|
||||
uint32_t extensions_count = 0;
|
||||
const char** glfw_extension = glfwGetRequiredInstanceExtensions(&extensions_count);
|
||||
std::vector<const char*> extensions(glfw_extension, glfw_extension + extensions_count);
|
||||
|
||||
#ifdef _DEBUG
|
||||
extensions.push_back(VK_EXT_DEBUG_UTILS_EXTENSION_NAME);
|
||||
#endif
|
||||
return extensions;
|
||||
}
|
||||
|
||||
Instance::Instance(CoreInstance& core)
|
||||
{
|
||||
std::vector<const char*> extensions = get_required_extensions();
|
||||
|
||||
VkApplicationInfo app_info{};
|
||||
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
|
||||
app_info.apiVersion = VK_API_VERSION_1_0;
|
||||
app_info.applicationVersion = VK_MAKE_VERSION(0, 0, 0);
|
||||
app_info.pApplicationName = core.getGameName().c_str();
|
||||
app_info.pEngineName = "UwU Engine";
|
||||
app_info.engineVersion = VK_MAKE_VERSION(0, 0, 0);
|
||||
|
||||
|
||||
VkInstanceCreateInfo instance_create_info{};
|
||||
instance_create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
||||
instance_create_info.pApplicationInfo = &app_info;
|
||||
instance_create_info.enabledExtensionCount = static_cast<uint32_t>(extensions.size());
|
||||
instance_create_info.ppEnabledExtensionNames = extensions.data();
|
||||
#ifdef _DEBUG
|
||||
const std::vector<const char*> layers_validation = {
|
||||
"VK_LAYER_KHRONOS_validation"
|
||||
};
|
||||
instance_create_info.enabledLayerCount = static_cast<uint32_t>(layers_validation.size());
|
||||
instance_create_info.ppEnabledLayerNames = layers_validation.data();
|
||||
VkDebugUtilsMessengerCreateInfoEXT debug_messenger_create_info{};
|
||||
debug_messenger_create_info.sType = VK_STRUCTURE_TYPE_DEBUG_UTILS_MESSENGER_CREATE_INFO_EXT;
|
||||
debug_messenger_create_info.messageSeverity = VK_DEBUG_UTILS_MESSAGE_SEVERITY_VERBOSE_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_WARNING_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_SEVERITY_ERROR_BIT_EXT;
|
||||
debug_messenger_create_info.messageType = VK_DEBUG_UTILS_MESSAGE_TYPE_GENERAL_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_VALIDATION_BIT_EXT | VK_DEBUG_UTILS_MESSAGE_TYPE_PERFORMANCE_BIT_EXT;
|
||||
debug_messenger_create_info.pfnUserCallback = &Instance::debugCallback;
|
||||
instance_create_info.pNext = &debug_messenger_create_info;
|
||||
#endif
|
||||
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_))
|
||||
#ifdef _DEBUG
|
||||
VK_CHECK(enable_layer_validation(&debug_messenger_create_info))
|
||||
#endif
|
||||
}
|
||||
|
||||
Instance::~Instance()
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
if (debug_messenger_ != nullptr && instance_ != nullptr) {
|
||||
PFN_vkDestroyDebugUtilsMessengerEXT destroyer_messenger = reinterpret_cast<PFN_vkDestroyDebugUtilsMessengerEXT>(vkGetInstanceProcAddr(instance_, "vkDestroyDebugUtilsMessengerEXT"));
|
||||
destroyer_messenger(instance_, debug_messenger_, nullptr);
|
||||
}
|
||||
#endif
|
||||
if(instance_ != nullptr)
|
||||
vkDestroyInstance(instance_, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <vector>
|
||||
|
||||
class CoreInstance;
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Instance final
|
||||
{
|
||||
VkInstance instance_ = nullptr;
|
||||
|
||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||
VkDebugUtilsMessageTypeFlagsEXT messageType,
|
||||
const VkDebugUtilsMessengerCallbackDataEXT* pCallbackData,
|
||||
void* pUserData
|
||||
);
|
||||
|
||||
#ifdef _DEBUG
|
||||
VkResult enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info);
|
||||
VkDebugUtilsMessengerEXT debug_messenger_;
|
||||
#endif
|
||||
|
||||
std::vector<const char*> Instance::get_required_extensions();
|
||||
public:
|
||||
explicit Instance(CoreInstance& core);
|
||||
~Instance();
|
||||
|
||||
inline VkInstance get_native() const { return instance_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,166 @@
|
||||
#include "PhysicalDevice.hpp"
|
||||
|
||||
#include <set>
|
||||
|
||||
#include "Surface.hpp"
|
||||
#include "Instance.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
#include "Log/Log.hpp"
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices VkObjects::PhysicalDevice::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface, const std::vector<const char*>& device_extensions)
|
||||
{
|
||||
VkPhysicalDeviceProperties device_properties;
|
||||
VkPhysicalDeviceFeatures device_features;
|
||||
vkGetPhysicalDeviceProperties(device, &device_properties);
|
||||
vkGetPhysicalDeviceFeatures(device, &device_features);
|
||||
|
||||
if(check_device_extensions_support(device, device_extensions) == false)
|
||||
throw std::runtime_error("Device not supported");
|
||||
|
||||
return find_queue_family_indices(device, surface);
|
||||
}
|
||||
|
||||
bool VkObjects::PhysicalDevice::check_device_extensions_support(VkPhysicalDevice device, const std::vector<const char*>& device_extensions)
|
||||
{
|
||||
uint32_t extension_count;
|
||||
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr))
|
||||
std::vector<VkExtensionProperties> available_extensions(extension_count);
|
||||
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data()))
|
||||
|
||||
for (const auto& extension : device_extensions)
|
||||
{
|
||||
bool isFind = false;
|
||||
for (const auto& i : available_extensions)
|
||||
{
|
||||
if (std::strcmp(i.extensionName, extension) == 0)
|
||||
{
|
||||
isFind = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!isFind)
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices VkObjects::PhysicalDevice::find_queue_family_indices(
|
||||
VkPhysicalDevice physical_device, VkSurfaceKHR surface)
|
||||
{
|
||||
QueueFamilyIndices queue_family_indices;
|
||||
|
||||
uint32_t queueFamilyCount = 0;
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, nullptr);
|
||||
std::vector<VkQueueFamilyProperties> family_properties(queueFamilyCount);
|
||||
vkGetPhysicalDeviceQueueFamilyProperties(physical_device, &queueFamilyCount, family_properties.data());
|
||||
|
||||
// Find graphics
|
||||
bool is_find_graphics_family = false;
|
||||
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||
{
|
||||
if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||
{
|
||||
queue_family_indices.graphics_family = i;
|
||||
is_find_graphics_family = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_find_graphics_family == false)
|
||||
throw std::runtime_error("Failed to find a graphics queue family");
|
||||
|
||||
// Find present
|
||||
VkBool32 present_support = false;
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family, surface, &present_support))
|
||||
// Если графическая очередь поддерживет презентацию кадров, то используем её
|
||||
bool is_find_present_family = false;
|
||||
if (present_support == VK_TRUE)
|
||||
{
|
||||
queue_family_indices.present_family = queue_family_indices.graphics_family;
|
||||
is_find_present_family = true;
|
||||
}
|
||||
// иначе ищем другую подходящую очередь
|
||||
else
|
||||
{
|
||||
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||
{
|
||||
present_support = false;
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support))
|
||||
if (present_support == VK_TRUE)
|
||||
{
|
||||
queue_family_indices.present_family = i;
|
||||
is_find_present_family = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (is_find_present_family == false)
|
||||
throw std::runtime_error("Failed to find a present queue family");
|
||||
|
||||
// С начала пытаемся найти очередь специалезированную
|
||||
// для копирования отличную от графической
|
||||
bool is_find_transfer_family = false;
|
||||
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||
{
|
||||
if (i == queue_family_indices.graphics_family)
|
||||
continue;
|
||||
if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
||||
{
|
||||
queue_family_indices.transfer_family = i;
|
||||
is_find_transfer_family = true;
|
||||
}
|
||||
}
|
||||
// Если не находим, то используем графическую
|
||||
if (is_find_transfer_family == false)
|
||||
{
|
||||
queue_family_indices.transfer_family = queue_family_indices.graphics_family;
|
||||
}
|
||||
return queue_family_indices;
|
||||
}
|
||||
|
||||
VkObjects::PhysicalDevice::PhysicalDevice(const Instance& instance,
|
||||
const Surface& surface,
|
||||
const std::vector<const char*>& device_extensions)
|
||||
{
|
||||
uint32_t device_count = 0;
|
||||
std::vector<VkPhysicalDevice> devices;
|
||||
VK_CHECK(vkEnumeratePhysicalDevices(instance.get_native(), &device_count, nullptr))
|
||||
devices.resize(device_count);
|
||||
VK_CHECK(vkEnumeratePhysicalDevices(instance.get_native(), &device_count, devices.data()))
|
||||
|
||||
for (const auto& device : devices)
|
||||
{
|
||||
try
|
||||
{
|
||||
queue_family_indices_ = is_device_suitable(device, surface.get_native(), device_extensions);
|
||||
physical_device_ = device;
|
||||
VkPhysicalDeviceProperties device_properties;
|
||||
vkGetPhysicalDeviceProperties(physical_device_, &device_properties);
|
||||
Loging::Log("Using device: " + std::string(device_properties.deviceName));
|
||||
break;
|
||||
}
|
||||
catch(...)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
if (VK_NULL_HANDLE == physical_device_)
|
||||
throw std::runtime_error("No suitable device found");
|
||||
}
|
||||
|
||||
std::vector<uint32_t> VkObjects::PhysicalDevice::get_unique_family_indices() const
|
||||
{
|
||||
std::set<uint32_t> set_indices = {queue_family_indices_.graphics_family,
|
||||
queue_family_indices_.present_family,
|
||||
queue_family_indices_.transfer_family};
|
||||
|
||||
std::vector<uint32_t> arr_indices;
|
||||
arr_indices.reserve(set_indices.size());
|
||||
for (auto& i : set_indices)
|
||||
arr_indices.push_back(i);
|
||||
return arr_indices;
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan_core.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Surface;
|
||||
class Instance;
|
||||
|
||||
class PhysicalDevice final
|
||||
{
|
||||
public:
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
uint32_t graphics_family = 0;
|
||||
uint32_t present_family = 0;
|
||||
uint32_t transfer_family = 0;
|
||||
};
|
||||
|
||||
QueueFamilyIndices queue_family_indices_{};
|
||||
private:
|
||||
VkPhysicalDevice physical_device_ = nullptr;
|
||||
|
||||
// Выбрасывает исключение если не подходит
|
||||
static QueueFamilyIndices is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface, const std::vector<const char*>& device_extensions);
|
||||
static bool check_device_extensions_support(VkPhysicalDevice device, const std::vector<const char*>& device_extensions);
|
||||
static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device,
|
||||
VkSurfaceKHR surface);
|
||||
public:
|
||||
explicit PhysicalDevice(const Instance& instance, const Surface& surface, const std::vector<const char*>& device_extensions);
|
||||
|
||||
inline VkPhysicalDevice get_native() const { return physical_device_; }
|
||||
inline QueueFamilyIndices get_queue_family_indices() const { return queue_family_indices_; }
|
||||
std::vector<uint32_t> get_unique_family_indices() const;
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,177 @@
|
||||
#include "Pipeline.hpp"
|
||||
|
||||
#include <array>
|
||||
#include <stdexcept>
|
||||
#include <fstream>
|
||||
|
||||
#include "DescriptorSetLayout.hpp"
|
||||
#include "Device.hpp"
|
||||
#include "RenderPass.hpp"
|
||||
#include "Swapchain.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
#include "../ModelManager.hpp"
|
||||
|
||||
VkShaderModule VkObjects::Pipeline::create_shader_module(const Device& device, const std::string& code) const
|
||||
{
|
||||
VkShaderModuleCreateInfo shader_module_info{};
|
||||
shader_module_info.sType = VK_STRUCTURE_TYPE_SHADER_MODULE_CREATE_INFO;
|
||||
shader_module_info.codeSize = code.size();
|
||||
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(code.c_str());
|
||||
|
||||
VkShaderModule shader_module;
|
||||
VK_CHECK(vkCreateShaderModule(device.get_native(), &shader_module_info, nullptr, &shader_module))
|
||||
return shader_module;
|
||||
}
|
||||
|
||||
VkObjects::Pipeline::Pipeline(const Device& device, const Swapchain& swapchain,
|
||||
const RenderPass& render_pass, const DescriptorSetLayout& layout_binding):device_(device)
|
||||
{
|
||||
std::ifstream vertex_shader_file("Shaders/vertex.spv", std::ios::binary);
|
||||
if (!vertex_shader_file.is_open())
|
||||
throw std::runtime_error("Vertex shader not found");
|
||||
std::ifstream fragment_shader_file("Shaders/fragment.spv", std::ios::binary);
|
||||
if (!fragment_shader_file.is_open()) {
|
||||
vertex_shader_file.close();
|
||||
throw std::runtime_error("Fragment shader not found");
|
||||
}
|
||||
|
||||
std::string vertex_shader_code((std::istreambuf_iterator<char>(vertex_shader_file)), std::istreambuf_iterator<char>());
|
||||
std::string fragment_shader_code((std::istreambuf_iterator<char>(fragment_shader_file)), std::istreambuf_iterator<char>());
|
||||
vertex_shader_file.close();
|
||||
fragment_shader_file.close();
|
||||
|
||||
VkShaderModule vertex_shader = create_shader_module(device_, vertex_shader_code);
|
||||
VkShaderModule fragment_shader = create_shader_module(device_, fragment_shader_code);
|
||||
|
||||
VkPipelineShaderStageCreateInfo vertex_shader_stage_info{};
|
||||
vertex_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
vertex_shader_stage_info.stage = VK_SHADER_STAGE_VERTEX_BIT;
|
||||
vertex_shader_stage_info.module = vertex_shader;
|
||||
vertex_shader_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo fragment_shader_stage_info{};
|
||||
fragment_shader_stage_info.sType = VK_STRUCTURE_TYPE_PIPELINE_SHADER_STAGE_CREATE_INFO;
|
||||
fragment_shader_stage_info.stage = VK_SHADER_STAGE_FRAGMENT_BIT;
|
||||
fragment_shader_stage_info.module = fragment_shader;
|
||||
fragment_shader_stage_info.pName = "main";
|
||||
|
||||
VkPipelineShaderStageCreateInfo shader_stages[] = {vertex_shader_stage_info, fragment_shader_stage_info};
|
||||
const std::vector<VkDynamicState> 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 = static_cast<uint32_t>(dynamic_states.size());
|
||||
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
||||
|
||||
VkVertexInputBindingDescription binding_description = ModelManager::Vertex::get_binding_description();
|
||||
std::array<VkVertexInputAttributeDescription, 2> attribute_descriptions = ModelManager::Vertex::get_vertex_attribute_descriptions();
|
||||
|
||||
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 = &binding_description;
|
||||
vertex_input_info.vertexAttributeDescriptionCount = static_cast<uint32_t>(attribute_descriptions.size());
|
||||
vertex_input_info.pVertexAttributeDescriptions = 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;
|
||||
|
||||
VkViewport viewport{};
|
||||
viewport.x = 0.0f;
|
||||
viewport.y = 0.0f;
|
||||
viewport.width = static_cast<float>(swapchain.get_extent().width);
|
||||
viewport.height = static_cast<float>(swapchain.get_extent().height);
|
||||
viewport.minDepth = 0.0f;
|
||||
viewport.maxDepth = 1.0f;
|
||||
|
||||
VkRect2D scissor{};
|
||||
scissor.offset = {0, 0};
|
||||
scissor.extent = swapchain.get_extent();
|
||||
|
||||
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;
|
||||
|
||||
VkPipelineRasterizationStateCreateInfo rasterization_info{};
|
||||
rasterization_info.sType = VK_STRUCTURE_TYPE_PIPELINE_RASTERIZATION_STATE_CREATE_INFO;
|
||||
rasterization_info.depthClampEnable = VK_FALSE;
|
||||
rasterization_info.rasterizerDiscardEnable = VK_FALSE;
|
||||
rasterization_info.polygonMode = VK_POLYGON_MODE_FILL;
|
||||
rasterization_info.lineWidth = 1.0f;
|
||||
rasterization_info.cullMode = VK_CULL_MODE_BACK_BIT;
|
||||
rasterization_info.frontFace = VK_FRONT_FACE_COUNTER_CLOCKWISE;
|
||||
rasterization_info.depthBiasEnable = VK_FALSE;
|
||||
|
||||
VkPipelineMultisampleStateCreateInfo multisample_info{};
|
||||
multisample_info.sType = VK_STRUCTURE_TYPE_PIPELINE_MULTISAMPLE_STATE_CREATE_INFO;
|
||||
multisample_info.sampleShadingEnable = VK_FALSE;
|
||||
multisample_info.rasterizationSamples = VK_SAMPLE_COUNT_1_BIT;
|
||||
|
||||
VkPipelineColorBlendAttachmentState color_blend_attachment_state{};
|
||||
color_blend_attachment_state.colorWriteMask = VK_COLOR_COMPONENT_R_BIT | VK_COLOR_COMPONENT_G_BIT | VK_COLOR_COMPONENT_B_BIT | VK_COLOR_COMPONENT_A_BIT;
|
||||
color_blend_attachment_state.blendEnable = VK_TRUE;
|
||||
color_blend_attachment_state.srcColorBlendFactor = VK_BLEND_FACTOR_SRC_ALPHA;
|
||||
color_blend_attachment_state.dstColorBlendFactor = VK_BLEND_FACTOR_ONE_MINUS_SRC_ALPHA;
|
||||
color_blend_attachment_state.colorBlendOp = VK_BLEND_OP_ADD;
|
||||
color_blend_attachment_state.srcAlphaBlendFactor = VK_BLEND_FACTOR_ONE;
|
||||
color_blend_attachment_state.dstAlphaBlendFactor = VK_BLEND_FACTOR_ZERO;
|
||||
color_blend_attachment_state.alphaBlendOp = VK_BLEND_OP_ADD;
|
||||
|
||||
VkPipelineColorBlendStateCreateInfo color_blend_info{};
|
||||
color_blend_info.sType = VK_STRUCTURE_TYPE_PIPELINE_COLOR_BLEND_STATE_CREATE_INFO;
|
||||
color_blend_info.logicOpEnable = VK_FALSE;
|
||||
color_blend_info.attachmentCount = 1;
|
||||
color_blend_info.pAttachments = &color_blend_attachment_state;
|
||||
color_blend_info.blendConstants[0] = 0.0f;
|
||||
color_blend_info.blendConstants[1] = 0.0f;
|
||||
color_blend_info.blendConstants[2] = 0.0f;
|
||||
color_blend_info.blendConstants[3] = 0.0f;
|
||||
|
||||
VkDescriptorSetLayout layout = layout_binding.get_native();
|
||||
VkPipelineLayoutCreateInfo pipeline_layout_info{};
|
||||
pipeline_layout_info.sType = VK_STRUCTURE_TYPE_PIPELINE_LAYOUT_CREATE_INFO;
|
||||
pipeline_layout_info.setLayoutCount = 1;
|
||||
pipeline_layout_info.pSetLayouts = &layout;
|
||||
|
||||
VK_CHECK(vkCreatePipelineLayout(device_.get_native(), &pipeline_layout_info, nullptr, &pipeline_layout_))
|
||||
|
||||
VkGraphicsPipelineCreateInfo pipeline_info{};
|
||||
pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||
pipeline_info.stageCount = 2;
|
||||
pipeline_info.pStages = shader_stages;
|
||||
pipeline_info.layout = pipeline_layout_;
|
||||
pipeline_info.pColorBlendState = &color_blend_info;
|
||||
pipeline_info.pDynamicState = &dynamic_state_info;
|
||||
pipeline_info.pInputAssemblyState = &input_assembly_info;
|
||||
pipeline_info.pMultisampleState = &multisample_info;
|
||||
pipeline_info.pRasterizationState = &rasterization_info;
|
||||
pipeline_info.pViewportState = &viewport_info;
|
||||
pipeline_info.pVertexInputState = &vertex_input_info;
|
||||
pipeline_info.pDepthStencilState = nullptr;
|
||||
pipeline_info.renderPass = render_pass.get_native();
|
||||
pipeline_info.subpass = 0;
|
||||
pipeline_info.basePipelineHandle = nullptr;
|
||||
pipeline_info.basePipelineIndex = -1;
|
||||
|
||||
VK_CHECK(vkCreateGraphicsPipelines(device_.get_native(), nullptr, 1, &pipeline_info, nullptr, &pipeline_))
|
||||
|
||||
vkDestroyShaderModule(device_.get_native(), vertex_shader, nullptr);
|
||||
vkDestroyShaderModule(device_.get_native(), fragment_shader, nullptr);
|
||||
}
|
||||
|
||||
VkObjects::Pipeline::~Pipeline()
|
||||
{
|
||||
if (pipeline_ != nullptr)
|
||||
vkDestroyPipeline(device_.get_native(), pipeline_, nullptr);
|
||||
|
||||
if (pipeline_layout_ != nullptr)
|
||||
vkDestroyPipelineLayout(device_.get_native(), pipeline_layout_, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
#include <string>
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class DescriptorSetLayout;
|
||||
class RenderPass;
|
||||
class Swapchain;
|
||||
class Device;
|
||||
|
||||
class Pipeline
|
||||
{
|
||||
VkPipeline pipeline_ = nullptr;
|
||||
VkPipelineLayout pipeline_layout_ = nullptr;
|
||||
const Device& device_;
|
||||
|
||||
VkShaderModule create_shader_module(const Device& device, const std::string& code) const;
|
||||
public:
|
||||
Pipeline(const Device& device, const Swapchain& swapchain,
|
||||
const RenderPass& render_pass, const DescriptorSetLayout& layout_binding);
|
||||
~Pipeline();
|
||||
|
||||
inline VkPipeline get_native() const { return pipeline_; }
|
||||
inline VkPipelineLayout get_layout() const { return pipeline_layout_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,55 @@
|
||||
#include "RenderPass.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
#include "Swapchain.hpp"
|
||||
#include "Device.hpp"
|
||||
|
||||
VkObjects::RenderPass::RenderPass(const Device& device, const Swapchain& swapchain):device_(device)
|
||||
{
|
||||
VkAttachmentDescription attachment_description{};
|
||||
attachment_description.format = swapchain.get_image_format();
|
||||
attachment_description.samples = VK_SAMPLE_COUNT_1_BIT;
|
||||
attachment_description.loadOp = VK_ATTACHMENT_LOAD_OP_CLEAR;
|
||||
attachment_description.storeOp = VK_ATTACHMENT_STORE_OP_STORE;
|
||||
attachment_description.stencilLoadOp = VK_ATTACHMENT_LOAD_OP_DONT_CARE;
|
||||
attachment_description.stencilStoreOp = VK_ATTACHMENT_STORE_OP_DONT_CARE;
|
||||
attachment_description.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
|
||||
attachment_description.finalLayout = VK_IMAGE_LAYOUT_PRESENT_SRC_KHR;
|
||||
|
||||
VkAttachmentReference attachment_reference;
|
||||
attachment_reference.attachment = 0;
|
||||
attachment_reference.layout = VK_IMAGE_LAYOUT_COLOR_ATTACHMENT_OPTIMAL;
|
||||
|
||||
VkSubpassDescription subpass_description{};
|
||||
subpass_description.pipelineBindPoint = VK_PIPELINE_BIND_POINT_GRAPHICS;
|
||||
subpass_description.colorAttachmentCount = 1;
|
||||
subpass_description.pColorAttachments = &attachment_reference;
|
||||
|
||||
VkSubpassDependency dependency{};
|
||||
dependency.srcSubpass = VK_SUBPASS_EXTERNAL;
|
||||
dependency.dstSubpass = 0;
|
||||
dependency.srcStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.srcAccessMask = 0;
|
||||
dependency.dstStageMask = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||
dependency.dstAccessMask = VK_ACCESS_COLOR_ATTACHMENT_WRITE_BIT;
|
||||
|
||||
VkRenderPassCreateInfo render_pass_info{};
|
||||
render_pass_info.sType = VK_STRUCTURE_TYPE_RENDER_PASS_CREATE_INFO;
|
||||
render_pass_info.attachmentCount = 1;
|
||||
render_pass_info.pAttachments = &attachment_description;
|
||||
render_pass_info.subpassCount = 1;
|
||||
render_pass_info.pSubpasses = &subpass_description;
|
||||
render_pass_info.dependencyCount = 1;
|
||||
render_pass_info.pDependencies = &dependency;
|
||||
|
||||
VK_CHECK(vkCreateRenderPass(device_.get_native(), &render_pass_info, nullptr, &render_pass_))
|
||||
}
|
||||
|
||||
VkObjects::RenderPass::~RenderPass()
|
||||
{
|
||||
if (render_pass_ != nullptr)
|
||||
vkDestroyRenderPass(device_.get_native(), render_pass_, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
#pragma once
|
||||
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Swapchain;
|
||||
class Device;
|
||||
|
||||
class RenderPass final
|
||||
{
|
||||
const Device& device_;
|
||||
VkRenderPass render_pass_;
|
||||
public:
|
||||
explicit RenderPass(const Device& device, const Swapchain& swapchain);
|
||||
~RenderPass();
|
||||
|
||||
inline VkRenderPass get_native() const { return render_pass_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#include "Surface.hpp"
|
||||
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "Instance.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
Surface::Surface(const Instance& instance, GLFWwindow* window):instance_(instance)
|
||||
{
|
||||
VK_CHECK(glfwCreateWindowSurface(instance_.get_native(), window, nullptr, &surface_))
|
||||
}
|
||||
|
||||
Surface::~Surface()
|
||||
{
|
||||
if(surface_ != nullptr)
|
||||
vkDestroySurfaceKHR(instance_.get_native(), surface_, nullptr);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
#pragma once
|
||||
|
||||
#define GLFW_INCLUDE_VULKAN
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Instance;
|
||||
|
||||
class Surface final
|
||||
{
|
||||
VkSurfaceKHR surface_ = nullptr;
|
||||
const Instance& instance_;
|
||||
public:
|
||||
explicit Surface(const Instance& instance, GLFWwindow* window);
|
||||
~Surface();
|
||||
|
||||
inline VkSurfaceKHR get_native() const { return surface_; }
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,150 @@
|
||||
#include "Swapchain.hpp"
|
||||
|
||||
#include <set>
|
||||
#include <stdexcept>
|
||||
#include <string>
|
||||
|
||||
#include "Device.hpp"
|
||||
#include "PhysicalDevice.hpp"
|
||||
#include "Surface.hpp"
|
||||
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||
|
||||
VkObjects::Swapchain::SwapchainSupportDetails VkObjects::Swapchain::query_swapchain_details(const Surface& surface, const PhysicalDevice& physical_device)
|
||||
{
|
||||
SwapchainSupportDetails details;
|
||||
|
||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device.get_native(), surface.get_native(), &details.capabilities);
|
||||
|
||||
uint32_t surface_format_cnt = 0;
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device.get_native(), surface.get_native(), &surface_format_cnt, nullptr))
|
||||
details.formats.resize(surface_format_cnt);
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device.get_native(), surface.get_native(), &surface_format_cnt, details.formats.data()))
|
||||
|
||||
uint32_t present_modes_cnt = 0;
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device.get_native(), surface.get_native(), &present_modes_cnt, nullptr))
|
||||
details.present_modes.resize(surface_format_cnt);
|
||||
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device.get_native(), surface.get_native(), &present_modes_cnt, details.present_modes.data()))
|
||||
|
||||
return details;
|
||||
}
|
||||
|
||||
VkSurfaceFormatKHR VkObjects::Swapchain::choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats)
|
||||
{
|
||||
for (const auto& i : surface_formats)
|
||||
{
|
||||
if (i.format == VK_FORMAT_B8G8R8A8_SRGB && i.colorSpace == VK_COLOR_SPACE_SRGB_NONLINEAR_KHR)
|
||||
return i;
|
||||
}
|
||||
return surface_formats[0];
|
||||
}
|
||||
|
||||
VkPresentModeKHR VkObjects::Swapchain::choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes,
|
||||
VkPresentModeKHR desired_present_mode)
|
||||
{
|
||||
for (const auto& i : present_modes)
|
||||
{
|
||||
if (i == desired_present_mode)
|
||||
return i;
|
||||
}
|
||||
return VK_PRESENT_MODE_FIFO_KHR;
|
||||
}
|
||||
|
||||
void VkObjects::Swapchain::create_swapchain(const Surface& surface, const PhysicalDevice& physical_device, GLFWwindow* window)
|
||||
{
|
||||
SwapchainSupportDetails swapchain_support = query_swapchain_details(surface, physical_device);
|
||||
VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats);
|
||||
VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, VK_PRESENT_MODE_MAILBOX_KHR);
|
||||
VkExtent2D extent = DeviceFunctions::choose_extent(swapchain_support.capabilities, window);
|
||||
|
||||
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
||||
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount)
|
||||
image_count = swapchain_support.capabilities.maxImageCount;
|
||||
|
||||
VkSwapchainCreateInfoKHR swapchain_create_info{};
|
||||
swapchain_create_info.sType = VK_STRUCTURE_TYPE_SWAPCHAIN_CREATE_INFO_KHR;
|
||||
swapchain_create_info.surface = surface.get_native();
|
||||
swapchain_create_info.minImageCount = image_count;
|
||||
swapchain_create_info.imageFormat = surface_format.format;
|
||||
swapchain_create_info.imageColorSpace = surface_format.colorSpace;
|
||||
swapchain_create_info.imageExtent = extent;
|
||||
swapchain_create_info.imageArrayLayers = 1;
|
||||
swapchain_create_info.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
|
||||
swapchain_create_info.preTransform = swapchain_support.capabilities.currentTransform;
|
||||
swapchain_create_info.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR;
|
||||
swapchain_create_info.presentMode = present_mode;
|
||||
swapchain_create_info.clipped = VK_TRUE;
|
||||
swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||
|
||||
VkObjects::PhysicalDevice::QueueFamilyIndices family_indices = physical_device.get_queue_family_indices();
|
||||
const std::set<uint32_t> queue_family_indices = { family_indices.graphics_family,
|
||||
family_indices.present_family,
|
||||
family_indices.transfer_family };
|
||||
std::vector<uint32_t> arr_families;
|
||||
if (queue_family_indices.size() > 1)
|
||||
{
|
||||
arr_families.reserve(queue_family_indices.size());
|
||||
for(auto& i : queue_family_indices)
|
||||
arr_families.push_back(i);
|
||||
|
||||
|
||||
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||
swapchain_create_info.queueFamilyIndexCount = static_cast<uint32_t>(arr_families.size());
|
||||
swapchain_create_info.pQueueFamilyIndices = arr_families.data();
|
||||
}
|
||||
else
|
||||
{
|
||||
swapchain_create_info.imageSharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||
swapchain_create_info.queueFamilyIndexCount = 0;
|
||||
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
||||
}
|
||||
|
||||
VK_CHECK(vkCreateSwapchainKHR(device_.get_native(), &swapchain_create_info, nullptr, &swapchain_))
|
||||
|
||||
vkGetSwapchainImagesKHR(device_.get_native(), swapchain_, &image_count, nullptr);
|
||||
swapchain_images_.resize(image_count);
|
||||
vkGetSwapchainImagesKHR(device_.get_native(), swapchain_, &image_count, swapchain_images_.data());
|
||||
|
||||
swapchain_image_format_ = surface_format.format;
|
||||
swapchain_extent_ = extent;
|
||||
}
|
||||
|
||||
void VkObjects::Swapchain::create_image_views()
|
||||
{
|
||||
VkImageViewCreateInfo image_view_info{};
|
||||
image_view_info.sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO;
|
||||
image_view_info.viewType = VK_IMAGE_VIEW_TYPE_2D;
|
||||
image_view_info.format = swapchain_image_format_;
|
||||
image_view_info.components.r = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
image_view_info.components.g = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
image_view_info.components.b = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
image_view_info.components.a = VK_COMPONENT_SWIZZLE_IDENTITY;
|
||||
image_view_info.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
|
||||
image_view_info.subresourceRange.baseMipLevel = 0;
|
||||
image_view_info.subresourceRange.levelCount = 1;
|
||||
image_view_info.subresourceRange.baseArrayLayer = 0;
|
||||
image_view_info.subresourceRange.layerCount = 1;
|
||||
|
||||
swapchain_image_views_.resize(swapchain_images_.size());
|
||||
for (uint32_t i = 0; i < swapchain_images_.size(); ++i)
|
||||
{
|
||||
image_view_info.image = swapchain_images_[i];
|
||||
VK_CHECK(vkCreateImageView(device_.get_native(), &image_view_info, nullptr, &swapchain_image_views_[i]))
|
||||
}
|
||||
}
|
||||
|
||||
VkObjects::Swapchain::Swapchain(const Surface& surface, const PhysicalDevice& physical_device, const Device& device, GLFWwindow* window):
|
||||
device_(device)
|
||||
{
|
||||
create_swapchain(surface, physical_device, window);
|
||||
create_image_views();
|
||||
}
|
||||
|
||||
VkObjects::Swapchain::~Swapchain()
|
||||
{
|
||||
for (auto image_view : swapchain_image_views_)
|
||||
vkDestroyImageView(device_.get_native(), image_view, nullptr);
|
||||
swapchain_image_views_.clear();
|
||||
|
||||
if (swapchain_ != nullptr)
|
||||
vkDestroySwapchainKHR(device_.get_native(), swapchain_, nullptr);
|
||||
}
|
||||
@@ -0,0 +1,46 @@
|
||||
#pragma once
|
||||
|
||||
#include <vector>
|
||||
#include <vulkan/vulkan.h>
|
||||
|
||||
#include "GLFW/glfw3.h"
|
||||
|
||||
namespace VkObjects
|
||||
{
|
||||
class Device;
|
||||
class PhysicalDevice;
|
||||
class Surface;
|
||||
|
||||
class Swapchain final
|
||||
{
|
||||
struct SwapchainSupportDetails
|
||||
{
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
};
|
||||
|
||||
const Device& device_;
|
||||
VkSwapchainKHR swapchain_ = nullptr;
|
||||
std::vector<VkImage> swapchain_images_;
|
||||
std::vector<VkImageView> swapchain_image_views_;
|
||||
VkFormat swapchain_image_format_;
|
||||
VkExtent2D swapchain_extent_;
|
||||
|
||||
static SwapchainSupportDetails query_swapchain_details(const Surface& surface, const PhysicalDevice& physical_device);
|
||||
static VkSurfaceFormatKHR choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats);
|
||||
static VkPresentModeKHR choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode);
|
||||
|
||||
void create_swapchain(const Surface& surface, const PhysicalDevice& physical_device, GLFWwindow* window);
|
||||
void create_image_views();
|
||||
public:
|
||||
Swapchain(const Surface& surface, const PhysicalDevice& physical_device, const Device& device, GLFWwindow* window);
|
||||
~Swapchain();
|
||||
|
||||
inline VkSwapchainKHR get_native() const { return swapchain_; }
|
||||
inline const std::vector<VkImage>& get_images() const { return swapchain_images_; }
|
||||
inline const std::vector<VkImageView>& get_image_views() const { return swapchain_image_views_; }
|
||||
inline VkExtent2D get_extent() const { return swapchain_extent_; }
|
||||
inline VkFormat get_image_format() const { return swapchain_image_format_; }
|
||||
};
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,158 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include "RenderEngineBase.hpp"
|
||||
|
||||
#include <optional>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
|
||||
#define GLM_FORCE_RADIANS
|
||||
#include <glm/glm.hpp>
|
||||
#include <glm/gtc/matrix_transform.hpp>
|
||||
|
||||
#ifdef _DEBUG
|
||||
#include <assert.h>
|
||||
#define VK_CHECK(res) assert(res == VK_SUCCESS)
|
||||
#else
|
||||
#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res))
|
||||
#endif
|
||||
|
||||
class UwURenderEngine : public RenderEngineBase
|
||||
{
|
||||
struct QueueFamilyIndices
|
||||
{
|
||||
std::optional<uint32_t> graphics_family;
|
||||
std::optional<uint32_t> present_family;
|
||||
std::optional<uint32_t> transfer_family;
|
||||
};
|
||||
struct SwapchainSupportDetails
|
||||
{
|
||||
VkSurfaceCapabilitiesKHR capabilities;
|
||||
std::vector<VkSurfaceFormatKHR> formats;
|
||||
std::vector<VkPresentModeKHR> present_modes;
|
||||
};
|
||||
struct Vertex
|
||||
{
|
||||
glm::vec3 pos;
|
||||
glm::vec3 color;
|
||||
static VkVertexInputBindingDescription get_binding_description();
|
||||
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
||||
};
|
||||
struct UniformBufferObject {
|
||||
glm::mat4 model;
|
||||
glm::mat4 view;
|
||||
glm::mat4 proj;
|
||||
};
|
||||
|
||||
const std::vector<Vertex> vertices_ = {
|
||||
{{-0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, 0.5f}, {1.0f, 1.0f, 1.0f}},
|
||||
{{-0.5f, -0.5f, -0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||
{{0.5f, -0.5f, -0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||
{{0.5f, 0.5f, -0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||
{{-0.5f, 0.5f, -0.5f}, {1.0f, 1.0f, 1.0f}}
|
||||
};
|
||||
const std::vector<uint16_t> indices_ = {
|
||||
0, 1, 2, 2, 3, 0,
|
||||
2, 1, 5, 5, 6, 2,
|
||||
0, 3, 7, 7, 4, 0,
|
||||
3, 2, 6, 6, 7, 3,
|
||||
7, 6, 5, 5, 4, 7,
|
||||
4, 5, 1, 1, 0, 4
|
||||
};
|
||||
|
||||
static const std::vector<const char*> deviceExtensions;
|
||||
|
||||
int current_frame_ = 0;
|
||||
|
||||
CoreInstance& core_;
|
||||
|
||||
VkInstance instance_ = VK_NULL_HANDLE;
|
||||
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
||||
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE;
|
||||
VkDevice device_ = VK_NULL_HANDLE;
|
||||
VkQueue graphics_queue_ = VK_NULL_HANDLE;
|
||||
VkQueue present_queue_ = VK_NULL_HANDLE;
|
||||
VkQueue transfer_queue_ = VK_NULL_HANDLE;
|
||||
VkSwapchainKHR swapchain_ = VK_NULL_HANDLE;
|
||||
std::vector<VkImage> swapchain_images_;
|
||||
VkFormat swapchain_image_format_;
|
||||
VkExtent2D swapchain_extent_;
|
||||
std::vector<VkImageView> swapchain_image_views_;
|
||||
VkRenderPass render_pass_ = VK_NULL_HANDLE;
|
||||
VkDescriptorSetLayout ubo_layout_binding_ = VK_NULL_HANDLE;
|
||||
VkDescriptorPool descriptor_pool_ = VK_NULL_HANDLE;
|
||||
std::vector<VkDescriptorSet> descriptor_sets_;
|
||||
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE;
|
||||
VkPipeline graphics_pipeline_ = VK_NULL_HANDLE;
|
||||
std::vector<VkFramebuffer> framebuffers_;
|
||||
VkCommandPool command_pool_ = VK_NULL_HANDLE;
|
||||
std::vector<VkCommandBuffer> command_buffers_;
|
||||
VkBuffer vertex_buffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE;
|
||||
VkBuffer index_buffer_ = VK_NULL_HANDLE;
|
||||
VkDeviceMemory index_buffer_memory_ = VK_NULL_HANDLE;
|
||||
std::vector<VkBuffer> uniform_buffers_;
|
||||
std::vector<VkDeviceMemory> uniform_buffers_memory_;
|
||||
std::vector<void*> uniform_buffers_mapped_;
|
||||
|
||||
// Sync objects
|
||||
std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_;
|
||||
std::vector<VkFence> in_flight_fences_;
|
||||
|
||||
#ifdef _DEBUG
|
||||
VkResult enable_layer_validation(const VkDebugUtilsMessengerCreateInfoEXT* create_info);
|
||||
VkDebugUtilsMessengerEXT debug_messenger_;
|
||||
#endif
|
||||
SwapchainSupportDetails query_swapchain_details() const;
|
||||
|
||||
static std::vector<const char*> get_required_extensions();
|
||||
static bool is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface);
|
||||
static bool check_device_extensions_support(VkPhysicalDevice device);
|
||||
static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface);
|
||||
static VkSurfaceFormatKHR choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats);
|
||||
static VkPresentModeKHR choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode);
|
||||
static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window);
|
||||
VkShaderModule create_shader_module(const std::string& code) const;
|
||||
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
||||
VkBuffer* buffer, const std::vector<uint32_t>& queue_families);
|
||||
void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory);
|
||||
uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;
|
||||
std::vector<uint32_t> get_unique_family_indices(const QueueFamilyIndices& indices);
|
||||
|
||||
void create_instance();
|
||||
void create_surface();
|
||||
void pick_physical_device();
|
||||
void create_logical_device();
|
||||
void create_swapchain();
|
||||
void create_image_views();
|
||||
void create_render_pass();
|
||||
void create_description_set_layout();
|
||||
void create_uniform_buffers();
|
||||
void create_descriptor_pool();
|
||||
void create_descriptor_sets();
|
||||
void create_graphics_pipeline();
|
||||
void create_framebuffers();
|
||||
void create_command_pool();
|
||||
void allocate_command_buffers();
|
||||
void create_sync_objects();
|
||||
void allocate_vertex_buffer();
|
||||
void allocate_index_buffer();
|
||||
|
||||
void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size);
|
||||
void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const;
|
||||
void update_uniform_buffer(uint32_t current_frame);
|
||||
void draw_frame();
|
||||
public:
|
||||
// Can throw the exception
|
||||
UwURenderEngine(CoreInstance& core);
|
||||
~UwURenderEngine() override;
|
||||
|
||||
void start() override;
|
||||
void stop_render() const override;
|
||||
|
||||
};
|
||||
|
||||
RENDER_ENGINE_FACTORY_GENERATE(UwURenderEngine)
|
||||
@@ -1,4 +1,5 @@
|
||||
@echo off
|
||||
cd build
|
||||
cmake -DBUILD_MODE=All ..
|
||||
cmake --build . --config Release
|
||||
pause
|
||||
+32
-5
@@ -1,11 +1,38 @@
|
||||
@echo off
|
||||
|
||||
if "%VULKAN_SDK%"=="" (
|
||||
echo Vulkan SDK not found.
|
||||
|
||||
:: Запрашиваем подтверждение установки. Значение по умолчанию — Y
|
||||
set "ANSWER=y"
|
||||
set /p "ANSWER=Would you like to install it? [y/n, default: y]: "
|
||||
|
||||
:: Проверяем ответ с использованием отложенного расширения (! вместо %)
|
||||
if /i not "!ANSWER!"=="y" (
|
||||
echo Installation cancelled by user.
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo Downloading Vulkan SDK...
|
||||
curl -L -o ".\vulkan_sdk.exe" "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe"
|
||||
|
||||
if exist ".\vulkan_sdk.exe" (
|
||||
echo Downloading finished successfully.
|
||||
echo Starting installation...
|
||||
|
||||
:: Запуск установщика в тихом режиме (параметр /S)
|
||||
start "" /wait ".\vulkan_sdk.exe" /S
|
||||
del .\vulkan_sdk.exe
|
||||
echo Installation completed.
|
||||
) else (
|
||||
echo Error: Failed to download Vulkan SDK.
|
||||
)
|
||||
) else (
|
||||
echo Vulkan SDK is already installed at: %VULKAN_SDK%
|
||||
)
|
||||
|
||||
mkdir .\build
|
||||
cd build
|
||||
cmake -DBUILD_MODE=Engine ..
|
||||
cmake --build . --config Release
|
||||
cd ..
|
||||
mkdir ".\build\bin\include"
|
||||
robocopy ".\Core" ".\build\bin\include\Core" *.h *.hpp /S
|
||||
robocopy ".\Delegate" ".\build\bin\include\Delegate" *.h *.hpp /S
|
||||
robocopy ".\FastRTTI" ".\build\bin\include\FastRTTI" *.h *.hpp /S
|
||||
pause
|
||||
@@ -1,4 +1,36 @@
|
||||
@echo off
|
||||
|
||||
if "%VULKAN_SDK%"=="" (
|
||||
echo Vulkan SDK not found.
|
||||
|
||||
:: Запрашиваем подтверждение установки. Значение по умолчанию — Y
|
||||
set "ANSWER=y"
|
||||
set /p "ANSWER=Would you like to install it? [y/n, default: y]: "
|
||||
|
||||
:: Проверяем ответ с использованием отложенного расширения (! вместо %)
|
||||
if /i not "!ANSWER!"=="y" (
|
||||
echo Installation cancelled by user.
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo Downloading Vulkan SDK...
|
||||
curl -L -o ".\vulkan_sdk.exe" "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe"
|
||||
|
||||
if exist ".\vulkan_sdk.exe" (
|
||||
echo Downloading finished successfully.
|
||||
echo Starting installation...
|
||||
|
||||
:: Запуск установщика в тихом режиме (параметр /S)
|
||||
start "" /wait ".\vulkan_sdk.exe" /S
|
||||
del .\vulkan_sdk.exe
|
||||
echo Installation completed.
|
||||
) else (
|
||||
echo Error: Failed to download Vulkan SDK.
|
||||
)
|
||||
) else (
|
||||
echo Vulkan SDK is already installed at: %VULKAN_SDK%
|
||||
)
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_MODE=All .. -A Win32
|
||||
|
||||
@@ -1,4 +1,36 @@
|
||||
@echo off
|
||||
|
||||
if "%VULKAN_SDK%"=="" (
|
||||
echo Vulkan SDK not found.
|
||||
|
||||
:: Запрашиваем подтверждение установки. Значение по умолчанию — Y
|
||||
set "ANSWER=y"
|
||||
set /p "ANSWER=Would you like to install it? [y/n, default: y]: "
|
||||
|
||||
:: Проверяем ответ с использованием отложенного расширения (! вместо %)
|
||||
if /i not "!ANSWER!"=="y" (
|
||||
echo Installation cancelled by user.
|
||||
exit /b
|
||||
)
|
||||
|
||||
echo Downloading Vulkan SDK...
|
||||
curl -L -o ".\vulkan_sdk.exe" "https://sdk.lunarg.com/sdk/download/latest/windows/vulkan-sdk.exe"
|
||||
|
||||
if exist ".\vulkan_sdk.exe" (
|
||||
echo Downloading finished successfully.
|
||||
echo Starting installation...
|
||||
|
||||
:: Запуск установщика в тихом режиме (параметр /S)
|
||||
start "" /wait ".\vulkan_sdk.exe" /S
|
||||
del .\vulkan_sdk.exe
|
||||
echo Installation completed.
|
||||
) else (
|
||||
echo Error: Failed to download Vulkan SDK.
|
||||
)
|
||||
) else (
|
||||
echo Vulkan SDK is already installed at: %VULKAN_SDK%
|
||||
)
|
||||
|
||||
mkdir build
|
||||
cd build
|
||||
cmake -DBUILD_MODE=All .. -A x64
|
||||
|
||||
+1
-1
Submodule glfw updated: 8e15281d34...b00e6a8a88
Reference in New Issue
Block a user