Compare commits

21 Commits

Author SHA1 Message Date
Jiga228 12610f5c7f Добавил resize в UniformBuffer 2026-07-11 19:06:48 +07:00
Jiga228 506776b6d6 Добавил UniformBuffer. Это умный указатель на память в GPU, но он так же берёт на себя задачу выделения памяти 2026-07-11 17:59:50 +07:00
Jiga228 c95aa557c2 Сделал World потокобезопасным 2026-06-28 20:29:19 +07:00
Jiga228 8e09b93f25 Добавил фильтрацию по типу в GetActorsByTag 2026-06-28 20:20:05 +07:00
Jiga228 a69dab3611 Добавил возможность выбирать контейнер для GetActorsByClass 2026-06-28 19:59:54 +07:00
Jiga228 82ba9fd191 Навёл порядок в тестах. Добавил тесты для мира. Исправил ошибку в SpawnActorFromClass 2026-06-28 19:27:01 +07:00
Jiga228 ad881a97a9 Добавил shared_from_this как основной способ создать умный указатель на "себя". Добавил пример работы с ним 2026-06-28 15:44:58 +07:00
Jiga228 311772cca4 Исправил тесты 2026-06-28 14:23:39 +07:00
Jiga228 8253b81ab1 Убрал паттерн Builder из SaveMap из-за неправильной работы 2026-06-28 14:16:58 +07:00
Jiga228 5886c7acc6 Исправил неопределённое поведение и добавил агрессивные оптимизации для Release конфигурации 2026-06-25 20:32:27 +07:00
Jiga228 5f3c5d4fc1 Вынес управление VkDescriptorSetLayout и VkPipeline в отдельные классы 2026-06-25 20:08:11 +07:00
Jiga228 2a57a30e29 Вынес управление VkRenderPass в отдельный класс 2026-06-24 12:10:47 +07:00
Jiga228 93eb08fe9f Перенёс управление VkSwapchainKHR и ImageViews в отдельный класс 2026-06-23 21:59:34 +07:00
Jiga228 b2dee85b26 Вынес управление VkDevice в отдельный класс 2026-06-23 20:51:12 +07:00
Jiga228 3cbe642fca Вынес работу с VpPhysicalDevice в отдельный класс 2026-06-23 18:35:48 +07:00
Jiga228 70956e2032 Добавил namespace VkObjectsдля обёрток. Вынес управление VkSurface в отдельный класс 2026-06-23 18:02:42 +07:00
Jiga228 7aec01ccc8 Вынес управление VkInstance в отдельный класс 2026-06-23 17:46:21 +07:00
Jiga228 280f843fb7 Чутка доделал делегаты 2026-06-22 14:47:53 +07:00
Jiga228 59f147fafc Обновил библиотеку Delegate.h до последней версии 2026-06-05 21:07:58 +07:00
Jiga228 cf4f8236f6 Merge pull request 'Добавил автоматическую установку Vulkan SDK (пока только для Windows)' (#3) from main into render
Reviewed-on: #3
2026-06-03 12:51:16 +00:00
Jiga228 7d3e211a50 Merge pull request 'Merge pull request 'Merge pull request #5 from Jiga228/main' (#1) from render into main' (#2) from main into render
Reviewed-on: #2
2026-06-01 09:37:37 +00:00
61 changed files with 2354 additions and 1429 deletions
+20 -4
View File
@@ -14,12 +14,28 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g") set(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} -g")
endif() endif()
if(MSVC) if(CMAKE_BUILD_TYPE STREQUAL "Release" OR NOT CMAKE_BUILD_TYPE)
add_compile_options(/GR-) if(MSVC)
else() # Оптимизации для Microsoft Visual C++
add_compile_options(-fno-rtti) 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() endif()
#if(MSVC)
# add_compile_options(/GR-)
#else()
# add_compile_options(-fno-rtti)
#endif()
if(BUILD_MODE STREQUAL "Engine") if(BUILD_MODE STREQUAL "Engine")
add_subdirectory(FastRTTI) add_subdirectory(FastRTTI)
add_subdirectory(glfw) add_subdirectory(glfw)
+1 -20
View File
@@ -50,25 +50,6 @@ CoreInstance::CoreInstance()
main_config_.load(std::make_shared<SaveMap>(load_main_config)); 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 try
{ {
render_engine_ = RenderEngineFactory(*this); render_engine_ = RenderEngineFactory(*this);
@@ -110,7 +91,7 @@ void CoreInstance::start()
game_thread.join(); game_thread.join();
} }
void CoreInstance::quit() void CoreInstance::quit() const
{ {
// Stop the main loop // Stop the main loop
render_engine_->stop_render(); render_engine_->stop_render();
+5 -7
View File
@@ -10,7 +10,6 @@
class SaveMap; class SaveMap;
class RenderEngineBase; class RenderEngineBase;
class GameInstance; class GameInstance;
struct GLFWwindow;
/* /*
* Внимательно следите, что бы у ваших объектов была "мягкая" зависимость * Внимательно следите, что бы у ваших объектов была "мягкая" зависимость
@@ -37,14 +36,13 @@ class CoreInstance {
const char* main_config_name = "main_config.conf"; const char* main_config_name = "main_config.conf";
MainConfig main_config_; MainConfig main_config_;
int countCPU_; int countCPU_ = 0;
// Memory in MB // Memory in MB
double memorySize_; double memorySize_ = 0;
std::list<Module> modules_; std::list<Module> modules_;
GLFWwindow* window_ = nullptr; RenderEngineBase* render_engine_ = nullptr;
RenderEngineBase* render_engine_; GameInstance* game_ = nullptr;
GameInstance* game_;
bool is_ready = false; bool is_ready = false;
public: public:
@@ -52,7 +50,7 @@ public:
~CoreInstance(); ~CoreInstance();
void start(); void start();
void quit(); void quit() const;
bool IsReady() const { return is_ready; } bool IsReady() const { return is_ready; }
int getCountCPU() const { return countCPU_; } int getCountCPU() const { return countCPU_; }
+8 -7
View File
@@ -10,23 +10,24 @@
#include <stdexcept> #include <stdexcept>
int System::getCountCPU() { int System::getCountCPU() {
DWORD len = 0; DWORD len = 0; // In bytes
GetLogicalProcessorInformation(nullptr, &len); GetLogicalProcessorInformation(nullptr, &len);
if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) { if (GetLastError() != ERROR_INSUFFICIENT_BUFFER) {
throw std::runtime_error(std::to_string(GetLastError()).c_str()); 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)) { if (!GetLogicalProcessorInformation(buffer.data(), &len)) {
throw std::runtime_error(std::to_string(GetLastError()).c_str()); throw std::runtime_error(std::to_string(GetLastError()).c_str());
} }
DWORD count = len / sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
int physicalCoreCount = 0; int physicalCoreCount = 0;
for (auto& i : buffer)
for (DWORD i = 0; i < count; ++i) { {
if (buffer[i].Relationship == RelationProcessorCore) { if (i.Relationship == RelationProcessorCore)
physicalCoreCount++; {
++physicalCoreCount;
} }
} }
+263 -236
View File
@@ -1,332 +1,359 @@
#pragma once // Create by Jiga228 (https://git.burntroosters.twc1.net/Jiga228)
#pragma once
#include <memory>
#include <mutex> #include <mutex>
#include <stdexcept>
template<typename TypeParameter> /*
* Этоот класс по своей сути односвязный список,
* каждый элемент которого - подписавшийся объект.
* Реализация для случая когда Type_Parameter != void
*/
template<typename Type_Parameter>
class Delegate class Delegate
{ {
struct DelegateDataBase class ObjectWasDelete : public std::runtime_error
{ {
virtual ~DelegateDataBase() = default; public:
DelegateDataBase* next = nullptr; ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {}
long long Hash = 0;
virtual void Call(TypeParameter) = 0;
}; };
template<class T> /*
struct DelegateDataForClass : DelegateDataBase * Базовая структура для записи подптсок
*/
struct BaseListData
{ {
T* object = nullptr; std::shared_ptr<BaseListData> next;
virtual ~BaseListData() = default;
virtual void call(Type_Parameter data) = 0;
};
typedef void(T::*Method)(TypeParameter); template<class Type_Object>
struct ObjectListData : public BaseListData
{
using Method = void(Type_Object::*)(Type_Parameter);
std::weak_ptr<Type_Object> object;
Method method = nullptr; Method method = nullptr;
void Call(TypeParameter data) override ObjectListData() = default;
ObjectListData(std::weak_ptr<Type_Object> object, Method method) : object(std::move(object)), method(method) {}
void call(Type_Parameter data)
{ {
(object->*method)(data); if (auto shared_object = object.lock())
{
(shared_object.get()->*method)(data);
}
else
{
throw ObjectWasDelete();
}
} }
}; };
struct DelegateDataForFunction : DelegateDataBase struct FunctionListData : public BaseListData
{ {
typedef void(*Func)(TypeParameter); void(*function)(Type_Parameter);
Func func = nullptr; FunctionListData() = default;
FunctionListData(void(*func)(Type_Parameter)) : function(func) {}
void Call(TypeParameter data) override void call(Type_Parameter data)
{ {
func(data); function(data);
} }
}; };
DelegateDataBase* firstElement = nullptr; std::shared_ptr<BaseListData> list_head = nullptr;
std::mutex m_list;
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: public:
template<typename T> template<class Type_Object>
void bind(T* object, void(T::*method)(TypeParameter)) void bind(std::weak_ptr<Type_Object> object, void (Type_Object::*method)(Type_Parameter))
{ {
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))]; if (!object.expired() && !method)
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; return;
char* str = new char[sizeof(T*) + sizeof(void(T::*)(TypeParameter))]; std::lock_guard<std::mutex> lock(m_list);
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object); std::shared_ptr<BaseListData> old_head = list_head;
for (long unsigned int i = 0; i < 8; ++i) list_head = std::make_shared<ObjectListData<Type_Object>>(object, method);
str[i] = ptrToObjectRef[i]; list_head->next = old_head;
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; 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; iterator = iterator->next;
} }
} }
void unbind(void(*func)(TypeParameter)) void unbind(void(*func)(Type_Parameter))
{ {
char* str = new char[sizeof(void(*)(TypeParameter))]; std::lock_guard<std::mutex> lock(m_list);
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))); if (!list_head)
delete[] str; return;
DelegateDataBase* iterator = firstElement; if (auto function_list_data = dynamic_cast<FunctionListData*>(list_head.get()))
DelegateDataBase* temp = nullptr;
while (iterator != nullptr)
{ {
if (iterator->Hash == Hash) if (function_list_data->function == func)
{ {
if (temp != nullptr) list_head = list_head->next;
temp->next = iterator->next; return;
else }
firstElement = iterator->next;
delete static_cast<DelegateDataForFunction*>(iterator);
break;
} }
temp = iterator; 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; iterator = iterator->next;
} }
} }
void Call(TypeParameter data) const void call(Type_Parameter data)
{ {
DelegateDataBase* iterator = firstElement; std::lock_guard<std::mutex> lock(m_list);
while (iterator != nullptr) std::shared_ptr<BaseListData> old_head, iterator = list_head;
while(iterator)
{ {
iterator->Call(data); 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; iterator = iterator->next;
} }
} }
}; };
/*
* Реализация для случая когда Type_Parameter == void
*/
template<> template<>
class Delegate<void> class Delegate<void>
{ {
struct DelegateDataBase class ObjectWasDelete : public std::runtime_error
{ {
virtual ~DelegateDataBase() = default; public:
DelegateDataBase* next = nullptr; ObjectWasDelete() : std::runtime_error("Delegate (call): Object was delete") {}
long long Hash = 0; };
/*
* Базовая структура для записи подптсок
*/
struct BaseListData
{
std::shared_ptr<BaseListData> next;
virtual ~BaseListData() = default;
virtual void call() = 0; virtual void call() = 0;
}; };
template<class T> template<class Type_Object>
struct DelegateDataForClass : DelegateDataBase struct ObjectListData : public BaseListData
{ {
T* object = nullptr; using Method = void(Type_Object::*)();
std::weak_ptr<Type_Object> object;
typedef void(T::*Method)();
Method method = nullptr; Method method = nullptr;
void call() override ObjectListData() = default;
ObjectListData(std::weak_ptr<Type_Object> object, Method method) : object(std::move(object)), method(method) {}
void call()
{ {
(object->*method)(); if (auto shared_object = object.lock())
{
(shared_object.get()->*method)();
}
else
{
throw ObjectWasDelete();
}
} }
}; };
struct DelegateDataForFunction : DelegateDataBase struct FunctionListData : public BaseListData
{ {
typedef void(*Func)(); void(*function)();
Func func = nullptr; FunctionListData() = default;
FunctionListData(void(*func)()) : function(func) {}
void call() override void call()
{ {
func(); function();
} }
}; };
DelegateDataBase* firstElement = nullptr; std::shared_ptr<BaseListData> list_head = nullptr;
std::mutex m_list;
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: public:
template<typename T> template<class Type_Object>
void bind(T* object, void(T::*method)()) void bind(std::weak_ptr<Type_Object> object, void (Type_Object::*method)())
{ {
char* str = new char[sizeof(T*) + sizeof(void(T::*)())]; if (!object.expired() && !method)
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; return;
char* str = new char[sizeof(T*) + sizeof(void(T::*)())]; std::lock_guard<std::mutex> lock(m_list);
const char* ptrToObjectRef = reinterpret_cast<const char*>(&object); std::shared_ptr<BaseListData> old_head = list_head;
for (int i = 0; i < sizeof(T*); ++i) list_head = std::make_shared<ObjectListData<Type_Object>>(object, method);
str[i] = ptrToObjectRef[i]; list_head->next = old_head;
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; 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; iterator = iterator->next;
} }
} }
void unbind(void(*func)()) void unbind(void(*func)())
{ {
char* str = new char[sizeof(void(*)())]; std::lock_guard<std::mutex> lock(m_list);
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(*)())); if (!list_head)
delete[] str; return;
DelegateDataBase* iterator = firstElement; if (auto function_list_data = dynamic_cast<FunctionListData*>(list_head.get()))
DelegateDataBase* temp = nullptr;
while (iterator != nullptr)
{ {
if (iterator->Hash == Hash) if (function_list_data->function == func)
{ {
if (temp != nullptr) list_head = list_head->next;
temp->next = iterator->next; return;
else }
firstElement = iterator->next;
delete static_cast<DelegateDataForFunction*>(iterator);
break;
} }
temp = iterator; 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; iterator = iterator->next;
} }
} }
void Call() const void call()
{ {
DelegateDataBase* iterator = firstElement; std::lock_guard<std::mutex> lock(m_list);
while (iterator != nullptr) std::shared_ptr<BaseListData> old_head, iterator = list_head;
while(iterator)
{ {
try {
iterator->call(); iterator->call();
} catch (const ObjectWasDelete&) {
if (iterator == list_head)
{
list_head = list_head->next;
}
else
{
old_head->next = iterator->next;
}
}
iterator = iterator->next; iterator = iterator->next;
} }
} }
+11 -10
View File
@@ -14,11 +14,12 @@ Actor::Actor() : loc_(new Vector3D), rot_(new Vector3D), scale_(new Vector3D)
std::shared_ptr<SaveMap> Actor::save() std::shared_ptr<SaveMap> Actor::save()
{ {
return std::make_shared<SaveMap>("Actor") std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Actor");
->SaveObject("loc", loc_) save->SaveObject("loc", loc_);
->SaveObject("rot", rot_) save->SaveObject("rot", rot_);
->SaveObject("scale", scale_) save->SaveObject("scale", scale_);
->SaveListStrings("tags", std::move(tags)); save->SaveListStrings("tags", std::move(tags_));
return save;
} }
void Actor::load(std::shared_ptr<SaveMap> save) void Actor::load(std::shared_ptr<SaveMap> save)
@@ -26,7 +27,7 @@ void Actor::load(std::shared_ptr<SaveMap> save)
loc_ = std::static_pointer_cast<Vector3D>(save->GetObject("loc")); loc_ = std::static_pointer_cast<Vector3D>(save->GetObject("loc"));
rot_ = std::static_pointer_cast<Vector3D>(save->GetObject("rot")); rot_ = std::static_pointer_cast<Vector3D>(save->GetObject("rot"));
scale_ = std::static_pointer_cast<Vector3D>(save->GetObject("scale")); scale_ = std::static_pointer_cast<Vector3D>(save->GetObject("scale"));
tags = std::move(save->GetListString("tags")); tags_ = std::move(save->GetListString("tags"));
} }
void Actor::BeginPlay() void Actor::BeginPlay()
@@ -40,21 +41,21 @@ void Actor::Tick(double delta_time)
void Actor::SetActorLocate(const Vector3D& loc) noexcept void Actor::SetActorLocate(const Vector3D& loc) noexcept
{ {
*this->loc_ = loc; *this->loc_ = loc;
OnSetActorLocate.Call(loc); OnSetActorLocate.call(loc);
} }
void Actor::SetActorRotate(const Vector3D& rot) noexcept void Actor::SetActorRotate(const Vector3D& rot) noexcept
{ {
*this->rot_ = rot; *this->rot_ = rot;
OnSetActorRotate.Call(rot); OnSetActorRotate.call(rot);
} }
void Actor::AddTag(const std::string& tag) noexcept void Actor::AddTag(const std::string& tag) noexcept
{ {
tags.push_back(tag); tags_.push_back(tag);
} }
void Actor::RemoveTag(const std::string& tag) noexcept void Actor::RemoveTag(const std::string& tag) noexcept
{ {
tags.remove(tag); tags_.remove(tag);
} }
+4 -4
View File
@@ -13,12 +13,12 @@ GENERATE_META(Actor)
class Actor : public ISave, public IRTTI class Actor : public ISave, public IRTTI
{ {
World* world_; std::shared_ptr<World> world_;
std::string name_; std::string name_;
std::shared_ptr<Vector3D> loc_, rot_, scale_; std::shared_ptr<Vector3D> loc_, rot_, scale_;
std::list<std::string> tags; std::list<std::string> tags_;
protected: protected:
virtual void OnDestroy(); virtual void OnDestroy();
@@ -52,9 +52,9 @@ public:
void AddTag(const std::string& tag) noexcept; void AddTag(const std::string& tag) noexcept;
void RemoveTag(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_; } const std::string& GetName() const { return name_; }
friend class World; friend class World;
+9 -13
View File
@@ -7,10 +7,11 @@
#include "Core/CoreInstance.hpp" #include "Core/CoreInstance.hpp"
#include "Game/WorldFactory.hpp" #include "Game/WorldFactory.hpp"
#include "Game/World/World.hpp" #include "Game/World/World.hpp"
#include "Log/Log.hpp"
extern std::vector<WorldFactory> world_factories; 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(); const std::string& base_world = core.getBaseWorldName();
@@ -21,33 +22,28 @@ GameInstance::GameInstance(CoreInstance& core) : core(core)
{ {
if (factories.world_name == base_world) if (factories.world_name == base_world)
{ {
world = factories.factory(*this); world_ = factories.factory(*this);
break; break;
} }
} }
if (world == nullptr) if (world_ == nullptr)
throw std::runtime_error("Can't find world"); throw std::runtime_error("Can't find world");
} }
GameInstance::~GameInstance()
{
delete world;
}
void GameInstance::start() void GameInstance::start()
{ {
world->BeginPlay(); world_->BeginPlay();
auto first = std::chrono::steady_clock::now(); auto first = std::chrono::steady_clock::now();
while (is_running) while (is_running_)
{ {
auto second = std::chrono::steady_clock::now(); auto second = std::chrono::steady_clock::now();
std::chrono::milliseconds delta_time = std::chrono::duration_cast<std::chrono::milliseconds>(second - first); 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; first = second;
std::this_thread::sleep_for(std::chrono::milliseconds(10)); std::this_thread::sleep_for(std::chrono::milliseconds(10));
} }
@@ -55,11 +51,11 @@ void GameInstance::start()
void GameInstance::stop() void GameInstance::stop()
{ {
is_running = false; is_running_ = false;
} }
void GameInstance::quit() void GameInstance::quit()
{ {
stop(); stop();
core.quit(); core_.quit();
} }
+6 -6
View File
@@ -11,10 +11,10 @@ GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
class GameInstance class GameInstance
{ {
CoreInstance& core; CoreInstance& core_;
World* world = nullptr; std::shared_ptr<World> world_;
std::atomic<bool> is_running = true; std::atomic<bool> is_running_ = true;
void start(); void start();
// Stop call from the core // Stop call from the core
@@ -25,10 +25,10 @@ public:
// Init vulkan // Init vulkan
GameInstance(CoreInstance& core); GameInstance(CoreInstance& core);
virtual ~GameInstance(); virtual ~GameInstance() = default;
World* GetWorld() const { return world; } std::shared_ptr<World> GetWorld() const { return world_; }
CoreInstance& GetCore() const { return core; } CoreInstance& GetCore() const { return core_; }
friend class CoreInstance; friend class CoreInstance;
}; };
+1 -1
View File
@@ -4,7 +4,7 @@
class SaveMap; class SaveMap;
class ISave class ISave : public std::enable_shared_from_this<ISave>
{ {
public: public:
virtual ~ISave() = default; virtual ~ISave() = default;
+20 -33
View File
@@ -21,7 +21,7 @@ ISave* SaveMap::MakeObjectByName(const std::string& name)
return factory.factory(); 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) 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); size_t end = i = json_data_blank.find_first_of(",}", i);
i++; i++;
std::string value = json_data_blank.substr(begin, end - begin); 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') } else if (name[0] == 'd')
{ {
size_t begin = json_data_blank.find(':', i) + 1; size_t begin = json_data_blank.find(':', i) + 1;
size_t end = i = json_data_blank.find_first_of(",}", i); size_t end = i = json_data_blank.find_first_of(",}", i);
i++; i++;
std::string value = json_data_blank.substr(begin, end - begin); 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') } else if (name[0] == 's')
{ {
size_t begin = json_data_blank.find(':', i) + 2; 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); value = json_data_blank.substr(begin, end - begin);
else else
value = ""; value = "";
save_string[name.c_str() + 1] = value; save_string[name.c_str() + 1] = value; // (name.c_str() + 1) - отсекаем метаданные
} else if (name[0] == 'o') } else if (name[0] == 'o')
{ {
size_t begin = i = json_data_blank.find('{', i); size_t begin = i = json_data_blank.find('{', i);
@@ -100,10 +100,10 @@ SaveMap::SaveMap(const std::string& json_data)
std::shared_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)); 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') } 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); size_t begin_arr = i = json_data_blank.find('[', i);
int open = 1, close = 0; int open = 1, close = 0;
@@ -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; 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; 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; save_string[name] = value;
return std::shared_ptr<SaveMap>(this);
} }
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept void SaveMap::SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept
{ {
save_objects[name] = object; 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); 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); 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); save_vector_strings[name] = std::move(value);
return std::shared_ptr<SaveMap>(this);
} }
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<std::shared_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); 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); 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); 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); save_list_strings[name] = std::move(value);
return std::shared_ptr<SaveMap>(this);
} }
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<std::shared_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); save_list_objects[name] = std::move(value);
return std::shared_ptr<SaveMap>(this);
} }
long long SaveMap::GetInteger(const char* name) long long SaveMap::GetInteger(const char* name)
@@ -517,7 +505,7 @@ std::string SaveMap::serialize() noexcept
buffer += ",\"s" + key + "\":\"" + value + '\"'; buffer += ",\"s" + key + "\":\"" + value + '\"';
for (auto& [key, value] : save_objects) 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) for (auto& [key, value] : save_vector_integer)
{ {
@@ -631,13 +619,12 @@ std::string SaveMap::serialize() noexcept
return buffer; 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) if (this->parent_ != nullptr)
throw std::runtime_error("Can't connect to second parent"); throw std::runtime_error("Can't connect to second parent");
this->parent_ = parent; this->parent_ = parent;
return std::shared_ptr<SaveMap>(this);
} }
std::string SaveMap::CleaningJSON(const std::string& json_data) std::string SaveMap::CleaningJSON(const std::string& json_data)
+13 -13
View File
@@ -44,18 +44,18 @@ public:
SaveMap(SaveMap&& save_map) noexcept; SaveMap(SaveMap&& save_map) noexcept;
// Методы созранения значений // Методы созранения значений
std::shared_ptr<SaveMap> SaveInteger(const char* name, int value) noexcept; void SaveInteger(const char* name, int value) noexcept;
std::shared_ptr<SaveMap> SaveDouble(const char* name, double value) noexcept; void SaveDouble(const char* name, double value) noexcept;
std::shared_ptr<SaveMap> SaveString(const char* name, const std::string& value) noexcept; void SaveString(const char* name, const std::string& value) noexcept;
std::shared_ptr<SaveMap> SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept; void SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept;
std::shared_ptr<SaveMap> SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept; void SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept; void SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept; void SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
std::shared_ptr<SaveMap> SaveVectorObject(const char* name, std::vector<std::shared_ptr<ISave>>&& value) noexcept; void SaveVectorObject(const char* name, std::vector<std::shared_ptr<ISave>>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListInteger(const char* name, std::list<long long>&& value) noexcept; void SaveListInteger(const char* name, std::list<long long>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListDouble(const char* name, std::list<double>&& value) noexcept; void SaveListDouble(const char* name, std::list<double>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListStrings(const char* name, std::list<std::string>&& value) noexcept; void SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<std::shared_ptr<ISave>>&& value) noexcept; void SaveListObject(const char* name, std::list<std::shared_ptr<ISave>>&& value) noexcept;
// Методы получения значенй // Методы получения значенй
long long GetInteger(const char* name); long long GetInteger(const char* name);
@@ -77,7 +77,7 @@ public:
// Собирает все токены в JSON объект // Собирает все токены в JSON объект
std::string serialize() noexcept; 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); static std::string CleaningJSON(const std::string& json_data);
}; };
+24 -9
View File
@@ -8,39 +8,53 @@ World::World(GameInstance& game_instance) : game_instance_(game_instance)
World::~World() World::~World()
{ {
for (auto& i : actors_map) for (auto& i : actors_map_)
i.second->OnDestroy(); i.second->OnDestroy();
actors_map.clear(); actors_map_.clear();
} }
void World::BeginPlay() void World::BeginPlay()
{ {
for (auto& i : actors_map) for (auto& i : actors_map_)
i.second->BeginPlay(); i.second->BeginPlay();
} }
void World::Tick(double delta_time) void World::Tick(double delta_time)
{ {
for (auto& i : actors_map) for (auto& i : actors_map_)
i.second->Tick(delta_time); i.second->Tick(delta_time);
} }
std::shared_ptr<SaveMap> World::save() std::shared_ptr<SaveMap> World::save()
{ {
std::scoped_lock lock(m_actors_map_);
std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("World"); 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; return save;
} }
void World::load(std::shared_ptr<SaveMap> 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::vector<std::string> actors_IDs = save->GetVectorString("ActorsIDs");
std::list<std::shared_ptr<Actor>> act = std::move(reinterpret_cast<std::list<std::shared_ptr<Actor>>&>(save->GetListObject("Actors"))); std::list<std::shared_ptr<ISave>> act = save->GetListObject("Actors");
size_t i_id = 0; size_t i_id = 0;
for (auto& i : act) for (auto& i : act)
{ {
auto[it, flag] = actors_map.try_emplace(actors_IDs[i_id], i); auto[it, flag] = actors_map_.try_emplace(actors_IDs[i_id], std::static_pointer_cast<Actor>(i));
it->second->world_ = this; it->second->world_ = std::static_pointer_cast<World>(shared_from_this());
it->second->name_ = it->first; it->second->name_ = it->first;
i_id++; i_id++;
} }
@@ -48,11 +62,12 @@ void World::load(std::shared_ptr<SaveMap> save)
void World::DestroyActor(std::weak_ptr<Actor> ptr) void World::DestroyActor(std::weak_ptr<Actor> ptr)
{ {
std::scoped_lock lock(m_actors_map_);
std::shared_ptr<Actor> actor = ptr.lock(); std::shared_ptr<Actor> actor = ptr.lock();
if (actor.get() == nullptr) if (actor == nullptr)
return; return;
std::string name = actor->GetName(); std::string name = actor->GetName();
actor->OnDestroy(); actor->OnDestroy();
actors_map.erase(name); actors_map_.erase(name);
} }
+25 -16
View File
@@ -4,6 +4,7 @@
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
#include <string> #include <string>
#include <mutex>
#include "RTTI.h" #include "RTTI.h"
#include "Game/Actors/Actor.hpp" #include "Game/Actors/Actor.hpp"
@@ -15,7 +16,8 @@ class World : public ISave
{ {
GameInstance& game_instance_; GameInstance& game_instance_;
std::unordered_map<std::string, std::shared_ptr<Actor>> actors_map; std::unordered_map<std::string, std::shared_ptr<Actor>> actors_map_;
std::mutex m_actors_map_;
public: public:
World(GameInstance& game_instance); World(GameInstance& game_instance);
@@ -31,11 +33,12 @@ public:
void load(std::shared_ptr<SaveMap> save) override; void load(std::shared_ptr<SaveMap> save) override;
#pragma endregion #pragma endregion
template<class T> template<class T, template<class...> class Container = std::vector>
std::vector<std::weak_ptr<T>> GetActorsByClass() Container<std::weak_ptr<T>> GetActorsByClass()
{ {
std::vector<std::weak_ptr<T>> list; std::scoped_lock lock(m_actors_map_);
for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i) Container<std::weak_ptr<T>> list;
for (auto i = actors_map_.cbegin(); i != actors_map_.cend(); ++i)
{ {
if (RTTI::dyn_cast<T, Actor>(i->second.get())) if (RTTI::dyn_cast<T, Actor>(i->second.get()))
list.push_back(std::static_pointer_cast<T>(i->second)); list.push_back(std::static_pointer_cast<T>(i->second));
@@ -46,29 +49,34 @@ public:
template<class T> template<class T>
std::weak_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 })
{ {
std::scoped_lock lock(m_actors_map_);
std::shared_ptr<T> object = std::make_shared<T>(); std::shared_ptr<T> object = std::make_shared<T>();
object->SetActorLocate(loc); object->SetActorLocate(loc);
object->SetActorRotate(rot); object->SetActorRotate(rot);
static_cast<Actor*>(object)->world_ = this; std::static_pointer_cast<Actor>(object)->world_ = std::static_pointer_cast<World>(shared_from_this());
static_cast<Actor*>(object)->name_ = name; std::static_pointer_cast<Actor>(object)->name_ = name;
actors_map.try_emplace(name, object); actors_map_.try_emplace(name, object);
return object; return object;
} }
void DestroyActor(std::weak_ptr<Actor> ptr); void DestroyActor(std::weak_ptr<Actor> ptr);
template<class T, class Container = std::vector<T*>> template<class T, template<class...> class Container = std::vector>
Container GetActorsByTag(std::string tag) 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(); const std::list<std::string>& tags = i.second->GetTags();
for (auto& j : tags) for (auto& j : tags)
{ {
if (j == tag) if (j == tag)
container.push_back(i); container.push_back(i.second);
}
} }
} }
@@ -76,10 +84,11 @@ public:
} }
template<class T> template<class T>
std::weak_ptr<T> GetActorByID(const std::string& id) std::weak_ptr<T> GetActorByName(const std::string& name)
{ {
auto it = actors_map.find(id); std::scoped_lock lock(m_actors_map_);
if (it == actors_map.end() || it->second == nullptr) auto it = actors_map_.find(name);
if (it == actors_map_.end() || it->second == nullptr)
return {}; return {};
return std::static_pointer_cast<T>(it->second); return std::static_pointer_cast<T>(it->second);
+4 -4
View File
@@ -11,7 +11,7 @@ class World;
struct WorldFactory struct WorldFactory
{ {
const char* world_name; 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,\ #define GENERATE_WORLD_FACTORY(Class, WorldName) WorldFactory{#WorldName,\
[](GameInstance& game_insance)->World* {\ [](GameInstance& game_insance)->std::shared_ptr<World> {\
Class* world = new Class(game_insance);\ std::shared_ptr<Class> world = std::make_shared<Class>(game_insance);\
std::ifstream config_file("./Worlds/" #WorldName ".world");\ std::ifstream config_file("./Worlds/" #WorldName ".world");\
if (config_file.fail())\ if (config_file.fail())\
throw std::runtime_error("Can't open world file");\ throw std::runtime_error("Can't open world file");\
@@ -32,7 +32,7 @@ struct WorldFactory
data.resize(file_size);\ data.resize(file_size);\
config_file.read(data.data(), file_size);\ config_file.read(data.data(), file_size);\
world->load(std::make_shared<SaveMap>(data));\ world->load(std::make_shared<SaveMap>(data));\
return world;\ return std::static_pointer_cast<World>(world);\
}}, }},
/* /*
+6 -3
View File
@@ -20,8 +20,9 @@ Vector2D Vector2D::operator-(const Vector2D& v) const
std::shared_ptr<SaveMap> Vector2D::save() std::shared_ptr<SaveMap> Vector2D::save()
{ {
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector2D"); std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Vector2D");
save->SaveDouble("x", x)->SaveDouble("y", y); save->SaveDouble("x", x);
save->SaveDouble("y", y);
return save; return save;
} }
@@ -50,7 +51,9 @@ Vector3D Vector3D::operator-(const Vector3D& v) const
std::shared_ptr<SaveMap> Vector3D::save() std::shared_ptr<SaveMap> Vector3D::save()
{ {
std::unique_ptr<SaveMap> save = std::make_unique<SaveMap>("Vector3D"); 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; return save;
} }
+2
View File
@@ -4,6 +4,8 @@ file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.hpp" "*.h")
add_library(RenderEngineSDK ${SRC}) add_library(RenderEngineSDK ${SRC})
target_compile_features(RenderEngineSDK PRIVATE cxx_std_17)
target_include_directories(RenderEngineSDK PUBLIC target_include_directories(RenderEngineSDK PUBLIC
${PROJECT_SOURCE_DIR}/glfw/Include ${PROJECT_SOURCE_DIR}/glfw/Include
${PROJECT_SOURCE_DIR}/Delegate ${PROJECT_SOURCE_DIR}/Delegate
@@ -2,6 +2,7 @@
#include <stdexcept> #include <stdexcept>
#include <string> #include <string>
#include <optional>
VkExtent2D DeviceFunctions::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window) VkExtent2D DeviceFunctions::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
{ {
@@ -27,13 +28,16 @@ uint32_t DeviceFunctions::find_memory_type(VkPhysicalDevice physical_device, uin
VkPhysicalDeviceMemoryProperties memory_properties{}; VkPhysicalDeviceMemoryProperties memory_properties{};
vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties); vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
std::optional<uint32_t> mem_type = 0;
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i) for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i)
{ {
if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties) if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties)
return i; mem_type = i;
} }
if (mem_type.has_value() == false)
throw std::runtime_error("failed to find suitable memory type!"); 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) void DeviceFunctions::device_memcpy(VkDevice device, uint32_t transfer_queue_family, VkBuffer src, VkBuffer dst, size_t size)
@@ -43,7 +47,7 @@ void DeviceFunctions::device_memcpy(VkDevice device, uint32_t transfer_queue_fam
copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO; copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
copy_pool_info.queueFamilyIndex = transfer_queue_family; copy_pool_info.queueFamilyIndex = transfer_queue_family;
copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT; copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
VK_CHECK(vkCreateCommandPool(device, &copy_pool_info, nullptr, &copy_pool)); VK_CHECK(vkCreateCommandPool(device, &copy_pool_info, nullptr, &copy_pool))
VkCommandBufferAllocateInfo command_buffer_allocate_info{}; VkCommandBufferAllocateInfo command_buffer_allocate_info{};
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO; command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
@@ -52,15 +56,15 @@ void DeviceFunctions::device_memcpy(VkDevice device, uint32_t transfer_queue_fam
command_buffer_allocate_info.commandBufferCount = 1; command_buffer_allocate_info.commandBufferCount = 1;
VkCommandBuffer copy_buffer; VkCommandBuffer copy_buffer;
VK_CHECK(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &copy_buffer)); VK_CHECK(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, &copy_buffer))
VkCommandBufferBeginInfo command_buffer_begin_info{}; VkCommandBufferBeginInfo command_buffer_begin_info{};
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_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; command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info)); VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info))
VkBufferCopy buffer_copy{}; VkBufferCopy buffer_copy;
buffer_copy.srcOffset = 0; buffer_copy.srcOffset = 0;
buffer_copy.dstOffset = 0; buffer_copy.dstOffset = 0;
buffer_copy.size = size; buffer_copy.size = size;
@@ -105,7 +109,7 @@ VkBuffer DeviceFunctions::create_buffer(VkDevice device, VkDeviceSize size, VkBu
} }
VkBuffer buffer; VkBuffer buffer;
VK_CHECK(vkCreateBuffer(device, &buffer_info, nullptr, &buffer)); VK_CHECK(vkCreateBuffer(device, &buffer_info, nullptr, &buffer))
return buffer; return buffer;
} }
@@ -120,6 +124,6 @@ VkDeviceMemory DeviceFunctions::allocate_device_memory(VkPhysicalDevice physical
allocate_info.memoryTypeIndex = find_memory_type(physical_device, requirements.memoryTypeBits, property); allocate_info.memoryTypeIndex = find_memory_type(physical_device, requirements.memoryTypeBits, property);
VkDeviceMemory device_memory; VkDeviceMemory device_memory;
VK_CHECK(vkAllocateMemory(device, &allocate_info, nullptr, &device_memory)); VK_CHECK(vkAllocateMemory(device, &allocate_info, nullptr, &device_memory))
return device_memory; return device_memory;
} }
+4 -2
View File
@@ -2,7 +2,9 @@
#include <stdexcept> #include <stdexcept>
RenderEngineBase::RenderEngineBase() #include "Core/CoreInstance.hpp"
RenderEngineBase::RenderEngineBase(CoreInstance& core)
{ {
if (!glfwInit()) if (!glfwInit())
throw std::runtime_error("Fail init glfw"); throw std::runtime_error("Fail init glfw");
@@ -10,7 +12,7 @@ RenderEngineBase::RenderEngineBase()
glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE);
glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); 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) if (window_ == nullptr)
throw std::runtime_error("Fail create window"); throw std::runtime_error("Fail create window");
} }
+1 -1
View File
@@ -10,7 +10,7 @@ class RenderEngineBase
GLFWwindow* window_ = nullptr; GLFWwindow* window_ = nullptr;
public: public:
explicit RenderEngineBase(); explicit RenderEngineBase(CoreInstance& core);
virtual ~RenderEngineBase(); virtual ~RenderEngineBase();
virtual void start() = 0; virtual void start() = 0;
+77 -47
View File
@@ -1,33 +1,67 @@
{ {
"Class name": "TestWorld", "Class name": "TestWorld",
"dtime": 5.000000, "dtime": 5,
"Parent parameters": { "Parent parameters": {
"Class name":"World", "Class name": "World",
"vsActorsIDs": ["MainCamera", "TestMesh1","TestMesh2"], "vsActorsIDs": [
"TestMesh1",
"MainCamera",
"TestMesh2",
"TestActor1"
],
"loActors": [ "loActors": [
{
"Class name": "StaticMesh",
"Parent parameters": {
"Class name": "Mesh",
"smodel_name_": "TestModel",
"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": "Camera", "Class name": "Camera",
"Parent parameters": { "Parent parameters": {
"Class name":"Actor", "Class name": "Actor",
"oloc": { "oloc": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":2.0, "dx": 2,
"dy":2.0, "dy": 2,
"dz":2.0 "dz": 2
}, },
"orot": { "orot": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":-2.335, "dx": -2.335,
"dy":-0.785, "dy": -0.785,
"dz":0.0 "dz": 0
}, },
"oscale": { "oscale": {
"Class name": "Vector3D", "Class name": "Vector3D",
"dx": 1.0, "dx": 1,
"dy": 1.0, "dy": 1,
"dz": 1.0 "dz": 1
}, },
"tags":[] "lstags": []
} }
}, },
{ {
@@ -36,56 +70,52 @@
"Class name": "Mesh", "Class name": "Mesh",
"smodel_name_": "TestModel", "smodel_name_": "TestModel",
"Parent parameters": { "Parent parameters": {
"Class name":"Actor", "Class name": "Actor",
"oloc": { "oloc": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":1.0, "dx": 0,
"dy":-1.0, "dy": -1,
"dz":1.0 "dz": 1
}, },
"orot": { "orot": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":0.0, "dx": 0,
"dy":0.0, "dy": 0,
"dz":0.0 "dz": 0
}, },
"oscale": { "oscale": {
"Class name": "Vector3D", "Class name": "Vector3D",
"dx": 1.0, "dx": 1,
"dy": 1.0, "dy": 1,
"dz": 1.0 "dz": 1
}, },
"tags":[] "lstags": []
} }
} }
}, },
{ {
"Class name": "StaticMesh", "Class name": "TestActor",
"Parent parameters": { "Parent parameters": {
"Class name": "Mesh", "Class name": "Actor",
"smodel_name_": "TestModel",
"Parent parameters": {
"Class name":"Actor",
"oloc": { "oloc": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":0.0, "dx": 0,
"dy":-1.0, "dy": 0,
"dz":1.0 "dz": 0
}, },
"orot": { "orot": {
"Class name":"Vector3D", "Class name": "Vector3D",
"dx":0.0, "dx": 0,
"dy":0.0, "dy": 0,
"dz":0.0 "dz": 0
}, },
"oscale": { "oscale": {
"Class name": "Vector3D", "Class name": "Vector3D",
"dx": 1.0, "dx": 0,
"dy": 1.0, "dy": 0,
"dz": 1.0 "dz": 0
}, },
"tags":[] "lstags": []
}
} }
} }
] ]
+27
View File
@@ -1,9 +1,36 @@
#include "TestActor.h" #include "TestActor.h"
#include "Game/Actors/Camera.hpp"
#include "Game/SaveMap/SaveMap.hpp"
#include "Game/World/World.hpp"
#include "Log/Log.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() void TestActor::BeginPlay()
{ {
Actor::BeginPlay(); Actor::BeginPlay();
Loging::Log("TestActor::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
View File
@@ -5,6 +5,11 @@
GENERATE_META(TestActor) GENERATE_META(TestActor)
class TestActor final : public Actor class TestActor final : public Actor
{ {
const std::string name_ = "First test actor";
void print_when_main_camera_rotate(const Vector3D& rot);
public: public:
void BeginPlay() override; void BeginPlay() override;
std::shared_ptr<SaveMap> save() override;
void load(std::shared_ptr<SaveMap> save) override;
}; };
-2
View File
@@ -1,9 +1,7 @@
#include "TestGameInstance.h" #include "TestGameInstance.h"
#include "Game/Resource/Resource.hpp"
#include <iostream> #include <iostream>
#include "Game/SaveMap/SaveMap.hpp"
#include "Game/World/World.hpp" #include "Game/World/World.hpp"
GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance) GENERATE_FACTORY_GAME_INSTANCE(TestGameInstance)
+27 -6
View File
@@ -1,14 +1,22 @@
#include "TestWorld.h" #include "TestWorld.h"
#include <glm/glm.hpp>
#include <glm/ext/scalar_constants.hpp> #include <glm/ext/scalar_constants.hpp>
#include "../Actors/TestActor.h"
#include "Game/GameInstance.hpp" #include "Game/GameInstance.hpp"
#include "Game/Actors/Camera.hpp" #include "Game/Actors/Camera.hpp"
#include "Game/SaveMap/SaveMap.hpp" #include "Game/SaveMap/SaveMap.hpp"
#include "Log/Log.hpp" #include "Log/Log.hpp"
#include "Game/Actors/Mesh/Mesh.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) TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
{} {}
@@ -18,10 +26,18 @@ void TestWorld::BeginPlay()
std::vector<std::weak_ptr<Actor>> meshes = GetActorsByClass<Actor>(); std::vector<std::weak_ptr<Actor>> meshes = GetActorsByClass<Actor>();
for (const auto& i : meshes) for (const auto& i : meshes)
{ {
Loging::Log("Load actor: " + i.lock()->GetName()); Loging::Message("Load actor: " + i.lock()->GetName());
} }
GetActorsByClass<Camera>()[0].lock()->SetActive(); 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) void TestWorld::Tick(double delta_time)
@@ -32,8 +48,12 @@ void TestWorld::Tick(double delta_time)
time1 += delta_time; time1 += delta_time;
double delta1 = sin(time1); double delta1 = sin(time1);
double delta2 = sin(3*time1); double delta2 = sin(3*time1);
GetActorsByClass<Camera>()[0].lock()->SetActorLocate(Vector3D{2 + delta2, 2 + delta2, 2 + delta2}); std::shared_ptr<Camera> lock_main_camera = main_camera_.lock();
GetActorsByClass<Camera>()[0].lock()->SetActorRotate(Vector3D{-3*glm::pi<double>()/4 + glm::pi<double>()/4 * delta1, glm::pi<double>() / -4, 0}); 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; time += delta_time;
if (time >= 10.0) if (time >= 10.0)
@@ -56,7 +76,8 @@ std::shared_ptr<SaveMap> TestWorld::save()
{ {
std::shared_ptr<SaveMap> save = World::save(); std::shared_ptr<SaveMap> save = World::save();
std::shared_ptr<SaveMap> my_save = std::make_shared<SaveMap>("TestWorld"); 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; return my_save;
} }
+6
View File
@@ -2,10 +2,16 @@
#include "Game/World/World.hpp" #include "Game/World/World.hpp"
class Camera;
GENERATE_META(TestWorld) GENERATE_META(TestWorld)
class TestWorld final : public World class TestWorld final : public World
{ {
double time = 0; 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: public:
TestWorld(GameInstance& game_instance); TestWorld(GameInstance& game_instance);
+6 -8
View File
@@ -1,4 +1,4 @@
set(CMAKE_CXX_STANDARD 17) set(CMAKE_CXX_STANDARD 20)
include(FetchContent) include(FetchContent)
FetchContent_Declare( FetchContent_Declare(
googletest googletest
@@ -11,18 +11,16 @@ FetchContent_MakeAvailable(googletest)
enable_testing() enable_testing()
file(GLOB SRC file(GLOB SRC
"SaveMapTest.cpp" "ObjectFactory.cpp" "WorldFactory.cpp" "TestRenderEngine.cpp" "TestRenderEngine.h" "TestGameInstance.cpp" "TestGameInstance.h"
"ObjectPtrTest.cpp" "SaveMap/SaveMapTest.cpp" "SaveMap/CustomObject.h"
"World/WorldTest.cpp" "World/TestWorld.h" "World/TestActor.cpp" "World/TestActor.h"
"${PROJECT_SOURCE_DIR}/Core/Game/SaveMap/SaveMap.cpp"
) )
add_executable(Tests ${SRC}) add_executable(Tests ${SRC})
target_link_libraries(Tests PRIVATE target_link_libraries(Tests PRIVATE GTest::gtest_main Core RenderEngineSDK)
GTest::gtest_main
)
target_include_directories(Tests PRIVATE target_include_directories(Tests PRIVATE
${PROJECT_SOURCE_DIR}/Core ${PROJECT_SOURCE_DIR}/Core
${PROJECT_SOURCE_DIR}/RenderEngineSDK
) )
+10
View File
@@ -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)
};
+18
View File
@@ -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 <gtest/gtest.h>
#include <iostream>
#include "Game/ObjectFactory.hpp" #include "Game/ObjectFactory.hpp"
#include "Game/SaveMap/SaveMap.hpp" #include "Game/SaveMap/SaveMap.hpp"
#include "CustomObject.h"
class CustomObject : public ISave std::shared_ptr<SaveMap> CustomObject::save()
{ {
public: std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("CustomObject");
int num; save->SaveInteger("num", num);
std::string str; save->SaveString("str", str);
double dbl; save->SaveDouble("dbl", dbl);
return save;
}
std::shared_ptr<SaveMap> save() override void CustomObject::load(std::shared_ptr<SaveMap> save)
{ {
return std::make_shared<SaveMap>("CustomObject")->SaveInteger("num", num)->SaveString("str", str)->SaveDouble("dbl", dbl);
}
void load(std::shared_ptr<SaveMap> save) override
{
num = static_cast<int>(save->GetInteger("num")); num = static_cast<int>(save->GetInteger("num"));
str = save->GetString("str"); str = save->GetString("str");
dbl = save->GetDouble("dbl"); 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; 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) TEST(SaveMapTest, check_clean)
{ {
+10
View File
@@ -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)
{
}
+9
View File
@@ -0,0 +1,9 @@
#pragma once
#include "Game/GameInstance.hpp"
class TestGameInstance : public GameInstance
{
public:
TestGameInstance(CoreInstance& core);
};
+15
View File
@@ -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
{
}
+12
View File
@@ -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;
};
+19
View File
@@ -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());
}
+14
View File
@@ -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;
};
+12
View File
@@ -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;
};
+265
View File
@@ -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 (...) {}
}
+8
View File
@@ -0,0 +1,8 @@
#include <Game/WorldFactory.hpp>
#include "World/TestWorld.h"
WORLDS_LIST
{
GENERATE_WORLD_FACTORY(TestWorld, tests)
};
+4 -2
View File
@@ -13,7 +13,9 @@ Camera::Camera()
std::shared_ptr<SaveMap> Camera::save() std::shared_ptr<SaveMap> Camera::save()
{ {
return std::make_shared<SaveMap>("Camera")->connect_to(Actor::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) void Camera::load(std::shared_ptr<SaveMap> save)
@@ -23,5 +25,5 @@ void Camera::load(std::shared_ptr<SaveMap> save)
void Camera::SetActive() const noexcept void Camera::SetActive() const noexcept
{ {
GET_RENDER_ENGINE->SetActiveCamera(GetWorld()->GetActorByID<Camera>(GetName())); GET_RENDER_ENGINE->SetActiveCamera(GetWorld()->GetActorByName<Camera>(GetName()));
} }
+4 -3
View File
@@ -9,9 +9,10 @@ Mesh::Mesh()
std::shared_ptr<SaveMap> Mesh::save() std::shared_ptr<SaveMap> Mesh::save()
{ {
return std::make_shared<SaveMap>("Mesh") std::shared_ptr<SaveMap> save = std::make_shared<SaveMap>("Mesh");
->SaveString("model_name_", model_name_) save->SaveString("model_name_", model_name_);
->connect_to(Actor::save()); save->connect_to(Actor::save());
return save;
} }
void Mesh::load(std::shared_ptr<SaveMap> save) void Mesh::load(std::shared_ptr<SaveMap> save)
@@ -13,7 +13,9 @@ StaticMesh::StaticMesh()
std::shared_ptr<SaveMap> StaticMesh::save() 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) void StaticMesh::load(std::shared_ptr<SaveMap> save)
@@ -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;
}
};
File diff suppressed because it is too large Load Diff
@@ -4,35 +4,29 @@
#include "ModelManager.hpp" #include "ModelManager.hpp"
#include <vector> #include <vector>
#include <string>
#include <memory> #include <memory>
#include <mutex>
#define GLM_FORCE_RADIANS #define GLM_FORCE_RADIANS
#include <mutex>
#include <glm/glm.hpp> #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 Camera;
class GPU_GarbageCollector; class GPU_GarbageCollector;
#define GET_RENDER_ENGINE static_cast<UwURenderEngine*>(GetWorld()->GetGameInstance().GetCore().GetRenderEngine()) #define GET_RENDER_ENGINE static_cast<UwURenderEngine*>(GetWorld()->GetGameInstance().GetCore().GetRenderEngine())
class UwURenderEngine : public RenderEngineBase class UwURenderEngine final : public RenderEngineBase
{ {
struct QueueFamilyIndices
{
uint32_t graphics_family = 0;
uint32_t present_family = 0;
uint32_t transfer_family = 0;
bool is_find_graphics_family = false;
bool is_find_present_family = false;
bool is_find_transfer_family = false;
};
struct SwapchainSupportDetails
{
std::vector<VkSurfaceFormatKHR> formats;
std::vector<VkPresentModeKHR> present_modes;
VkSurfaceCapabilitiesKHR capabilities;
};
struct UniformBufferObject { struct UniformBufferObject {
glm::mat4 model; glm::mat4 model;
glm::mat4 view; glm::mat4 view;
@@ -58,7 +52,9 @@ class UwURenderEngine : public RenderEngineBase
4, 5, 1, 1, 0, 4 4, 5, 1, 1, 0, 4
}; };
static const std::vector<const char*> deviceExtensions; const std::vector<const char*> deviceExtensions = {
VK_KHR_SWAPCHAIN_EXTENSION_NAME
};
// Counting frame from the beginning // Counting frame from the beginning
unsigned int current_frame_ = 0; unsigned int current_frame_ = 0;
@@ -69,24 +65,16 @@ class UwURenderEngine : public RenderEngineBase
std::weak_ptr<Camera> active_camera_; std::weak_ptr<Camera> active_camera_;
std::mutex m_active_camera_; std::mutex m_active_camera_;
VkInstance instance_ = VK_NULL_HANDLE; VkObjects::Instance instance_;
VkSurfaceKHR surface_ = VK_NULL_HANDLE; VkObjects::Surface surface_;
VkPhysicalDevice physical_device_ = VK_NULL_HANDLE; VkObjects::PhysicalDevice physical_device_;
VkDevice device_ = VK_NULL_HANDLE; VkObjects::Device device_;
VkQueue graphics_queue_ = VK_NULL_HANDLE; VkObjects::Swapchain swapchain_;
VkQueue present_queue_ = VK_NULL_HANDLE; VkObjects::RenderPass render_pass_;
VkQueue transfer_queue_ = VK_NULL_HANDLE; VkObjects::DescriptorSetLayout layout_binding_;
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; VkDescriptorPool descriptor_pool_ = VK_NULL_HANDLE;
std::vector<VkDescriptorSet> descriptor_sets_; std::vector<VkDescriptorSet> descriptor_sets_;
VkPipelineLayout pipeline_layout_ = VK_NULL_HANDLE; VkObjects::Pipeline pipeline_;
VkPipeline graphics_pipeline_ = VK_NULL_HANDLE;
std::vector<VkFramebuffer> framebuffers_; std::vector<VkFramebuffer> framebuffers_;
VkCommandPool command_pool_ = VK_NULL_HANDLE; VkCommandPool command_pool_ = VK_NULL_HANDLE;
std::vector<VkCommandBuffer> command_buffers_; std::vector<VkCommandBuffer> command_buffers_;
@@ -94,41 +82,15 @@ class UwURenderEngine : public RenderEngineBase
VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE; VkDeviceMemory vertex_buffer_memory_ = VK_NULL_HANDLE;
VkBuffer index_buffer_ = VK_NULL_HANDLE; VkBuffer index_buffer_ = VK_NULL_HANDLE;
VkDeviceMemory index_buffer_memory_ = VK_NULL_HANDLE; VkDeviceMemory index_buffer_memory_ = VK_NULL_HANDLE;
std::vector<VkBuffer> uniform_buffers_; std::vector<std::unique_ptr<UniformBuffer<UniformBufferObject>>> uniform_buffers_;
std::vector<VkDeviceMemory> uniform_buffers_memory_;
std::vector<void*> uniform_buffers_mapped_;
// Sync objects // Sync objects
std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_; std::vector<VkSemaphore> image_available_semaphores_, render_finished_semaphores_;
std::vector<VkFence> in_flight_fences_; 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);
VkShaderModule create_shader_module(const std::string& code) const;
static 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_uniform_buffers();
void create_descriptor_pool(); void create_descriptor_pool();
void create_descriptor_sets(); void update_descriptor_sets();
void create_graphics_pipeline();
void create_framebuffers(); void create_framebuffers();
void create_command_pool(); void create_command_pool();
void allocate_command_buffers(); void allocate_command_buffers();
@@ -149,5 +111,5 @@ public:
std::shared_ptr<ModelManager> GetModelManager() const { return model_manager_; } std::shared_ptr<ModelManager> GetModelManager() const { return model_manager_; }
void SetActiveCamera(std::weak_ptr<Camera> camera); 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_; }
};
}