Merge pull request 'Merge pull request #5 from Jiga228/main' (#1) from render into main
CMake on a single platform / build (push) Successful in 1m31s
CMake on a single platform / build (push) Successful in 1m31s
Reviewed-on: #1
This commit was merged in pull request #1.
This commit is contained in:
+2
-1
@@ -1,3 +1,4 @@
|
|||||||
|
|
||||||
[submodule "glfw"]
|
[submodule "glfw"]
|
||||||
path = glfw
|
path = glfw
|
||||||
url = https://github.com/glfw/glfw.git
|
url = https://git.burntroosters.twc1.net/Jiga228/glfw.git
|
||||||
|
|||||||
+33
-8
@@ -4,23 +4,48 @@ find_package(Vulkan REQUIRED)
|
|||||||
|
|
||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||||
|
|
||||||
add_library(${CORE_NAME} STATIC ${SRC})
|
add_library(Core STATIC ${SRC})
|
||||||
target_compile_features(${CORE_NAME} PRIVATE cxx_std_17)
|
target_compile_features(Core PRIVATE cxx_std_17)
|
||||||
target_include_directories(${CORE_NAME} PUBLIC
|
target_include_directories(Core PUBLIC
|
||||||
${PROJECT_SOURCE_DIR}/FastRTTI
|
${PROJECT_SOURCE_DIR}/FastRTTI
|
||||||
${PROJECT_SOURCE_DIR}/Delegate
|
|
||||||
)
|
)
|
||||||
target_include_directories(${CORE_NAME}
|
target_include_directories(Core
|
||||||
PRIVATE
|
PRIVATE
|
||||||
${CMAKE_CURRENT_SOURCE_DIR}
|
${CMAKE_CURRENT_SOURCE_DIR}
|
||||||
${PROJECT_SOURCE_DIR}/glfw/Include
|
${PROJECT_SOURCE_DIR}/glfw/Include
|
||||||
${PROJECT_SOURCE_DIR}/RenderEngineSDK
|
${PROJECT_SOURCE_DIR}/RenderEngineSDK
|
||||||
${Vulkan_INCLUDE_DIRS}
|
${Vulkan_INCLUDE_DIRS}
|
||||||
)
|
)
|
||||||
|
|
||||||
target_link_libraries(${CORE_NAME} PRIVATE
|
target_link_libraries(Core PRIVATE
|
||||||
${CMAKE_DL_LIBS} # For linux
|
${CMAKE_DL_LIBS} # For linux
|
||||||
FastRTTI
|
FastRTTI
|
||||||
glfw
|
glfw
|
||||||
Vulkan::Vulkan
|
Vulkan::Vulkan
|
||||||
)
|
)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HEADERS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach (HEADER ${HEADERS})
|
||||||
|
file(RELATIVE_PATH R_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}"
|
||||||
|
"${HEADER}"
|
||||||
|
)
|
||||||
|
|
||||||
|
get_filename_component(HEADER_DIR ${R_PATH} DIRECTORY)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET Core
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||||
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${HEADER_DIR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${HEADER}"
|
||||||
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${R_PATH}"
|
||||||
|
|
||||||
|
COMMENT "Copy Core headers"
|
||||||
|
)
|
||||||
|
endforeach ()
|
||||||
@@ -74,6 +74,7 @@ CoreInstance::CoreInstance()
|
|||||||
render_engine_ = RenderEngineFactory(*this);
|
render_engine_ = RenderEngineFactory(*this);
|
||||||
} catch (const std::exception& e)
|
} catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
render_engine_ = nullptr;
|
||||||
std::cerr << "[!] Init render engine: " << e.what() << '\n';
|
std::cerr << "[!] Init render engine: " << e.what() << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -83,6 +84,7 @@ CoreInstance::CoreInstance()
|
|||||||
game_ = GameFactory(*this);
|
game_ = GameFactory(*this);
|
||||||
} catch (const std::exception& e)
|
} catch (const std::exception& e)
|
||||||
{
|
{
|
||||||
|
game_ = nullptr;
|
||||||
std::cout << "[!] Init game instance: " << e.what() << '\n';
|
std::cout << "[!] Init game instance: " << e.what() << '\n';
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -2,7 +2,6 @@
|
|||||||
|
|
||||||
#include "Game/SaveMap/SaveMap.hpp"
|
#include "Game/SaveMap/SaveMap.hpp"
|
||||||
#include "Game/World/World.hpp"
|
#include "Game/World/World.hpp"
|
||||||
#include "Log/Log.hpp"
|
|
||||||
|
|
||||||
void Actor::OnDestroy()
|
void Actor::OnDestroy()
|
||||||
{
|
{
|
||||||
@@ -16,17 +15,17 @@ 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")
|
return std::make_shared<SaveMap>("Actor")
|
||||||
->SaveObject("loc", static_cast<UType::object_ptr<ISave>>(loc_))
|
->SaveObject("loc", loc_)
|
||||||
->SaveObject("rot", static_cast<UType::object_ptr<ISave>>(rot_))
|
->SaveObject("rot", rot_)
|
||||||
->SaveObject("scale", UType::object_ptr<ISave>(scale_))
|
->SaveObject("scale", scale_)
|
||||||
->SaveListStrings("tags", std::move(tags));
|
->SaveListStrings("tags", std::move(tags));
|
||||||
}
|
}
|
||||||
|
|
||||||
void Actor::load(std::shared_ptr<SaveMap> save)
|
void Actor::load(std::shared_ptr<SaveMap> save)
|
||||||
{
|
{
|
||||||
loc_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("loc"));
|
loc_ = std::static_pointer_cast<Vector3D>(save->GetObject("loc"));
|
||||||
rot_ = static_cast<UType::object_ptr<Vector3D>>(save->GetObject("rot"));
|
rot_ = std::static_pointer_cast<Vector3D>(save->GetObject("rot"));
|
||||||
scale_ = static_cast<UType::object_ptr<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"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,6 @@
|
|||||||
#include "Game/SaveMap/ISave.h"
|
#include "Game/SaveMap/ISave.h"
|
||||||
#include "Delegate/Delegate.h"
|
#include "Delegate/Delegate.h"
|
||||||
#include "Math/Vector.hpp"
|
#include "Math/Vector.hpp"
|
||||||
#include "Types/object_ptr.hpp"
|
|
||||||
|
|
||||||
class World;
|
class World;
|
||||||
GENERATE_META(Actor)
|
GENERATE_META(Actor)
|
||||||
@@ -17,7 +16,7 @@ class Actor : public ISave, public IRTTI
|
|||||||
World* world_;
|
World* world_;
|
||||||
std::string name_;
|
std::string name_;
|
||||||
|
|
||||||
UType::object_ptr<Vector3D> loc_, rot_, scale_;
|
std::shared_ptr<Vector3D> loc_, rot_, scale_;
|
||||||
|
|
||||||
std::list<std::string> tags;
|
std::list<std::string> tags;
|
||||||
|
|
||||||
@@ -42,14 +41,14 @@ public:
|
|||||||
* Вызывает делегат OnSetActorLocate
|
* Вызывает делегат OnSetActorLocate
|
||||||
*/
|
*/
|
||||||
void SetActorLocate(const Vector3D& loc) noexcept;
|
void SetActorLocate(const Vector3D& loc) noexcept;
|
||||||
inline const UType::object_ptr<Vector3D> GetActorLocate() const { return loc_; }
|
inline Vector3D GetActorLocate() const { return *loc_; }
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Изменяет ориентацию в пространстве
|
* Изменяет ориентацию в пространстве
|
||||||
* Вызывает делегат OnSetActorRotate
|
* Вызывает делегат OnSetActorRotate
|
||||||
*/
|
*/
|
||||||
void SetActorRotate(const Vector3D& rot) noexcept;
|
void SetActorRotate(const Vector3D& rot) noexcept;
|
||||||
inline const UType::object_ptr<Vector3D> GetActorRotate() const { return rot_; }
|
inline Vector3D GetActorRotate() const { return *rot_; }
|
||||||
|
|
||||||
void AddTag(const std::string& tag) noexcept;
|
void AddTag(const std::string& tag) noexcept;
|
||||||
void RemoveTag(const std::string& tag) noexcept;
|
void RemoveTag(const std::string& tag) noexcept;
|
||||||
|
|||||||
@@ -1,12 +1,10 @@
|
|||||||
#include "ObjectFactory.hpp"
|
#include "ObjectFactory.hpp"
|
||||||
#include "Actors/Mesh/StaticMesh.hpp"
|
|
||||||
|
|
||||||
#include "Game/Actors/Actor.hpp"
|
#include "Game/Actors/Actor.hpp"
|
||||||
#include "Math/Vector.hpp"
|
#include "Math/Vector.hpp"
|
||||||
|
|
||||||
std::vector<ObjectFactory> base_object_factories = {
|
std::vector<ObjectFactory> base_object_factories = {
|
||||||
GENERATE_FACTORY_OBJECT(Actor)
|
GENERATE_FACTORY_OBJECT(Actor)
|
||||||
GENERATE_FACTORY_OBJECT(StaticMesh)
|
|
||||||
GENERATE_FACTORY_OBJECT(Vector2D)
|
GENERATE_FACTORY_OBJECT(Vector2D)
|
||||||
GENERATE_FACTORY_OBJECT(Vector3D)
|
GENERATE_FACTORY_OBJECT(Vector3D)
|
||||||
};
|
};
|
||||||
@@ -1,11 +1,9 @@
|
|||||||
#include "GameInstance.hpp"
|
#include "GameInstance.hpp"
|
||||||
|
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fstream>
|
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
#include "ModelManager.hpp"
|
|
||||||
#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"
|
||||||
@@ -19,8 +17,6 @@ GameInstance::GameInstance(CoreInstance& core) : core(core)
|
|||||||
// Init directories
|
// Init directories
|
||||||
std::filesystem::create_directories(std::filesystem::path("./Resources"));
|
std::filesystem::create_directories(std::filesystem::path("./Resources"));
|
||||||
|
|
||||||
current_model_manager_ = new ModelManager();
|
|
||||||
|
|
||||||
for (auto& factories : world_factories)
|
for (auto& factories : world_factories)
|
||||||
{
|
{
|
||||||
if (factories.world_name == base_world)
|
if (factories.world_name == base_world)
|
||||||
@@ -38,7 +34,6 @@ GameInstance::GameInstance(CoreInstance& core) : core(core)
|
|||||||
GameInstance::~GameInstance()
|
GameInstance::~GameInstance()
|
||||||
{
|
{
|
||||||
delete world;
|
delete world;
|
||||||
delete current_model_manager_;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameInstance::start()
|
void GameInstance::start()
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
class CoreInstance;
|
class CoreInstance;
|
||||||
class World;
|
class World;
|
||||||
class ModelManager;
|
|
||||||
|
|
||||||
#define GENERATE_FACTORY_GAME_INSTANCE(Class) \
|
#define GENERATE_FACTORY_GAME_INSTANCE(Class) \
|
||||||
GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
|
GameInstance* GameFactory(CoreInstance& core) { return new Class(core); }
|
||||||
@@ -14,7 +13,6 @@ class GameInstance
|
|||||||
{
|
{
|
||||||
CoreInstance& core;
|
CoreInstance& core;
|
||||||
World* world = nullptr;
|
World* world = nullptr;
|
||||||
ModelManager* current_model_manager_ = nullptr;
|
|
||||||
|
|
||||||
std::atomic<bool> is_running = true;
|
std::atomic<bool> is_running = true;
|
||||||
|
|
||||||
@@ -31,7 +29,6 @@ public:
|
|||||||
|
|
||||||
World* GetWorld() const { return world; }
|
World* GetWorld() const { return world; }
|
||||||
CoreInstance& GetCore() const { return core; }
|
CoreInstance& GetCore() const { return core; }
|
||||||
ModelManager* GetCurrentModelManager() const { return current_model_manager_; }
|
|
||||||
|
|
||||||
friend class CoreInstance;
|
friend class CoreInstance;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,107 +0,0 @@
|
|||||||
#include "ModelManager.hpp"
|
|
||||||
|
|
||||||
#include "Log/Log.hpp"
|
|
||||||
|
|
||||||
ModelManager::StaticModel::StaticModel(const std::vector<Voxel>& voxels, std::string name):
|
|
||||||
name_(std::move(name)),
|
|
||||||
voxels_(voxels)
|
|
||||||
{
|
|
||||||
glm::ivec3 sum_moments{0, 0, 0};
|
|
||||||
int sum_masses = 0;
|
|
||||||
|
|
||||||
for (auto& i : voxels_)
|
|
||||||
{
|
|
||||||
sum_moments += glm::ivec3{i.loc.x * i.mass, i.loc.y * i.mass, i.loc.z * i.mass};
|
|
||||||
sum_masses += i.mass;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(sum_masses != 0)
|
|
||||||
sum_moments /= sum_masses;
|
|
||||||
else if (!voxels_.empty())
|
|
||||||
{
|
|
||||||
sum_moments.x /= static_cast<int>(voxels_.size());
|
|
||||||
sum_moments.y /= static_cast<int>(voxels_.size());
|
|
||||||
sum_moments.z /= static_cast<int>(voxels_.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
mass_center_ = sum_moments;
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelManager::StaticModel::~StaticModel()
|
|
||||||
{
|
|
||||||
OnDestroy.Call(name_);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelManager::owner_counter::owner_counter(const owner_counter& other) : counter(other.counter.load()), model(other.model)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int ModelManager::FNV1aHash(const char* buf)
|
|
||||||
{
|
|
||||||
unsigned int h_val = 0x811c9dc5;
|
|
||||||
|
|
||||||
while (*buf)
|
|
||||||
{
|
|
||||||
h_val ^= static_cast<unsigned int>(*buf++);
|
|
||||||
h_val *= 0x01000193;
|
|
||||||
}
|
|
||||||
|
|
||||||
return h_val;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelManager::OnDestroySometimeModelCaller(const std::string& name)
|
|
||||||
{
|
|
||||||
Loging::Log("Free model: " + name);
|
|
||||||
OnDestroySometimeModel.Call(name);
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelManager::~ModelManager()
|
|
||||||
{
|
|
||||||
for (const auto& [it, counter] : models)
|
|
||||||
{
|
|
||||||
counter.model->OnDestroy.unbind(this, &ModelManager::OnDestroySometimeModelCaller);
|
|
||||||
}
|
|
||||||
models.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
ModelManager::StaticModel* ModelManager::LoadModel(const std::string& name)
|
|
||||||
{
|
|
||||||
if (name.empty())
|
|
||||||
return nullptr;
|
|
||||||
unsigned int hash = FNV1aHash(name.c_str());
|
|
||||||
auto counter = models.find(hash);
|
|
||||||
if (counter != models.cend())
|
|
||||||
{
|
|
||||||
++counter->second.counter;
|
|
||||||
return counter->second.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
Loging::Log("Load new model: " + name);
|
|
||||||
|
|
||||||
std::vector<Voxel> model_data;
|
|
||||||
// Load model_data
|
|
||||||
owner_counter new_counter;
|
|
||||||
new_counter.counter.store(1);
|
|
||||||
new_counter.model = new StaticModel(model_data, name);
|
|
||||||
new_counter.model->OnDestroy.bind(this, &ModelManager::OnDestroySometimeModelCaller);
|
|
||||||
models.try_emplace(hash, new_counter);
|
|
||||||
OnLoadSometimeModel.Call(new_counter.model);
|
|
||||||
return new_counter.model;
|
|
||||||
}
|
|
||||||
|
|
||||||
void ModelManager::FreeModel(const std::string& name)
|
|
||||||
{
|
|
||||||
if (name.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
unsigned int hash = FNV1aHash(name.c_str());
|
|
||||||
auto counter = models.find(hash);
|
|
||||||
--counter->second.counter;
|
|
||||||
|
|
||||||
StaticModel* model = counter->second.model;
|
|
||||||
if (counter->second.counter.load() == 0)
|
|
||||||
{
|
|
||||||
models.erase(hash);
|
|
||||||
delete model;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,58 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <vector>
|
|
||||||
#include <string>
|
|
||||||
#include <Delegate/Delegate.h>
|
|
||||||
#include <glm/glm.hpp>
|
|
||||||
|
|
||||||
class ModelManager
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
struct Voxel
|
|
||||||
{
|
|
||||||
glm::vec3 loc, color;
|
|
||||||
int mass;
|
|
||||||
};
|
|
||||||
class StaticModel
|
|
||||||
{
|
|
||||||
std::string name_;
|
|
||||||
std::vector<Voxel> voxels_;
|
|
||||||
glm::vec3 mass_center_;
|
|
||||||
public:
|
|
||||||
Delegate<const std::string&> OnDestroy;
|
|
||||||
|
|
||||||
StaticModel(const std::vector<Voxel>& voxels, std::string name);
|
|
||||||
~StaticModel();
|
|
||||||
|
|
||||||
const std::vector<Voxel>& GetVoxels() const { return voxels_; }
|
|
||||||
glm::vec3 GetMassCenter() const { return mass_center_; }
|
|
||||||
const std::string& GetName() const { return name_; }
|
|
||||||
};
|
|
||||||
|
|
||||||
struct owner_counter
|
|
||||||
{
|
|
||||||
std::atomic_ullong counter;
|
|
||||||
StaticModel* model;
|
|
||||||
|
|
||||||
owner_counter() = default;
|
|
||||||
owner_counter(const owner_counter& other);
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
std::unordered_map<unsigned int, owner_counter> models;
|
|
||||||
|
|
||||||
static unsigned int FNV1aHash (const char *buf);
|
|
||||||
|
|
||||||
void OnDestroySometimeModelCaller(const std::string& name);
|
|
||||||
|
|
||||||
public:
|
|
||||||
Delegate<std::string> OnDestroySometimeModel;
|
|
||||||
Delegate<StaticModel*> OnLoadSometimeModel;
|
|
||||||
|
|
||||||
~ModelManager();
|
|
||||||
|
|
||||||
StaticModel* LoadModel(const std::string& name);
|
|
||||||
void FreeModel(const std::string& name);
|
|
||||||
};
|
|
||||||
@@ -97,7 +97,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
end = object_json.find('\"', begin);
|
end = object_json.find('\"', begin);
|
||||||
|
|
||||||
std::string object_name = object_json.substr(begin, end - begin);
|
std::string object_name = object_json.substr(begin, end - begin);
|
||||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||||
|
|
||||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
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;
|
||||||
@@ -171,10 +171,10 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
}
|
}
|
||||||
} else if (name[1] == 'o')
|
} else if (name[1] == 'o')
|
||||||
{
|
{
|
||||||
save_vector_objects[key] = std::vector<UType::object_ptr<ISave>>();
|
save_vector_objects[key] = std::vector<std::shared_ptr<ISave>>();
|
||||||
if (arr_data.length() == 2)
|
if (arr_data.length() == 2)
|
||||||
continue;
|
continue;
|
||||||
std::vector<UType::object_ptr<ISave>>& vector_object = save_vector_objects[key];
|
std::vector<std::shared_ptr<ISave>>& vector_object = save_vector_objects[key];
|
||||||
|
|
||||||
size_t j = 1;
|
size_t j = 1;
|
||||||
while (j < arr_data.length())
|
while (j < arr_data.length())
|
||||||
@@ -198,7 +198,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
size_t end_name = object_json.find('\"', begin_name);
|
size_t end_name = object_json.find('\"', begin_name);
|
||||||
|
|
||||||
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
||||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||||
|
|
||||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||||
vector_object.push_back(object_ptr);
|
vector_object.push_back(object_ptr);
|
||||||
@@ -272,10 +272,10 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
}
|
}
|
||||||
} else if (name[1] == 'o')
|
} else if (name[1] == 'o')
|
||||||
{
|
{
|
||||||
save_list_objects[key] = std::list<UType::object_ptr<ISave>>();
|
save_list_objects[key] = std::list<std::shared_ptr<ISave>>();
|
||||||
if (arr_data.length() == 2)
|
if (arr_data.length() == 2)
|
||||||
continue;
|
continue;
|
||||||
std::list<UType::object_ptr<ISave>>& list_object = save_list_objects[key];
|
std::list<std::shared_ptr<ISave>>& list_object = save_list_objects[key];
|
||||||
|
|
||||||
size_t j = 1;
|
size_t j = 1;
|
||||||
while (j < arr_data.length())
|
while (j < arr_data.length())
|
||||||
@@ -299,7 +299,7 @@ SaveMap::SaveMap(const std::string& json_data)
|
|||||||
size_t end_name = object_json.find('\"', begin_name);
|
size_t end_name = object_json.find('\"', begin_name);
|
||||||
|
|
||||||
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
std::string object_name = object_json.substr(begin_name, end_name - begin_name);
|
||||||
UType::object_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
std::shared_ptr<ISave> object_ptr(MakeObjectByName(object_name));
|
||||||
|
|
||||||
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
object_ptr->load(std::make_shared<SaveMap>(object_json));
|
||||||
list_object.push_back(object_ptr);
|
list_object.push_back(object_ptr);
|
||||||
@@ -389,7 +389,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveString(const char* name, const std::string
|
|||||||
return std::shared_ptr<SaveMap>(this);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> SaveMap::SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept
|
std::shared_ptr<SaveMap> 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);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
@@ -413,7 +413,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveVectorStrings(const char* name, std::vecto
|
|||||||
return std::shared_ptr<SaveMap>(this);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> SaveMap::SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept
|
std::shared_ptr<SaveMap> 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);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
@@ -437,7 +437,7 @@ std::shared_ptr<SaveMap> SaveMap::SaveListStrings(const char* name, std::list<st
|
|||||||
return std::shared_ptr<SaveMap>(this);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> SaveMap::SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& value) noexcept
|
std::shared_ptr<SaveMap> 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);
|
return std::shared_ptr<SaveMap>(this);
|
||||||
@@ -458,7 +458,7 @@ std::string SaveMap::GetString(const char* name)
|
|||||||
return save_string[name];
|
return save_string[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
UType::object_ptr<ISave> SaveMap::GetObject(const char* name)
|
std::shared_ptr<ISave> SaveMap::GetObject(const char* name)
|
||||||
{
|
{
|
||||||
return save_objects[name];
|
return save_objects[name];
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,7 @@ std::vector<std::string> SaveMap::GetVectorString(const char* name)
|
|||||||
return save_vector_strings[name];
|
return save_vector_strings[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<UType::object_ptr<ISave>>& SaveMap::GetVectorObject(const char* name)
|
std::vector<std::shared_ptr<ISave>>& SaveMap::GetVectorObject(const char* name)
|
||||||
{
|
{
|
||||||
return save_vector_objects[name];
|
return save_vector_objects[name];
|
||||||
}
|
}
|
||||||
@@ -498,7 +498,7 @@ std::list<std::string>& SaveMap::GetListString(const char* name)
|
|||||||
return save_list_strings[name];
|
return save_list_strings[name];
|
||||||
}
|
}
|
||||||
|
|
||||||
std::list<UType::object_ptr<ISave>>& SaveMap::GetListObject(const char* name)
|
std::list<std::shared_ptr<ISave>>& SaveMap::GetListObject(const char* name)
|
||||||
{
|
{
|
||||||
return save_list_objects[name];
|
return save_list_objects[name];
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "ISave.h"
|
#include "ISave.h"
|
||||||
#include "Types/object_ptr.hpp"
|
|
||||||
|
|
||||||
#include <unordered_map>
|
#include <unordered_map>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -18,18 +17,18 @@ class SaveMap final
|
|||||||
std::unordered_map<std::string, long long> save_long;
|
std::unordered_map<std::string, long long> save_long;
|
||||||
std::unordered_map<std::string, double> save_double;
|
std::unordered_map<std::string, double> save_double;
|
||||||
std::unordered_map<std::string, std::string> save_string;
|
std::unordered_map<std::string, std::string> save_string;
|
||||||
std::unordered_map<std::string, UType::object_ptr<ISave>> save_objects;
|
std::unordered_map<std::string, std::shared_ptr<ISave>> save_objects;
|
||||||
|
|
||||||
// Массивы
|
// Массивы
|
||||||
std::unordered_map<std::string, std::vector<long long>> save_vector_integer;
|
std::unordered_map<std::string, std::vector<long long>> save_vector_integer;
|
||||||
std::unordered_map<std::string, std::vector<double>> save_vector_double;
|
std::unordered_map<std::string, std::vector<double>> save_vector_double;
|
||||||
std::unordered_map<std::string, std::vector<UType::object_ptr<ISave>>> save_vector_objects;
|
std::unordered_map<std::string, std::vector<std::shared_ptr<ISave>>> save_vector_objects;
|
||||||
std::unordered_map<std::string, std::vector<std::string>> save_vector_strings;
|
std::unordered_map<std::string, std::vector<std::string>> save_vector_strings;
|
||||||
|
|
||||||
// Связаные списки
|
// Связаные списки
|
||||||
std::unordered_map<std::string, std::list<long long>> save_list_integer;
|
std::unordered_map<std::string, std::list<long long>> save_list_integer;
|
||||||
std::unordered_map<std::string, std::list<double>> save_list_double;
|
std::unordered_map<std::string, std::list<double>> save_list_double;
|
||||||
std::unordered_map<std::string, std::list<UType::object_ptr<ISave>>> save_list_objects;
|
std::unordered_map<std::string, std::list<std::shared_ptr<ISave>>> save_list_objects;
|
||||||
std::unordered_map<std::string, std::list<std::string>> save_list_strings;
|
std::unordered_map<std::string, std::list<std::string>> save_list_strings;
|
||||||
|
|
||||||
static ISave* MakeObjectByName(const std::string& name);
|
static ISave* MakeObjectByName(const std::string& name);
|
||||||
@@ -48,29 +47,29 @@ public:
|
|||||||
std::shared_ptr<SaveMap> SaveInteger(const char* name, int value) noexcept;
|
std::shared_ptr<SaveMap> SaveInteger(const char* name, int value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveDouble(const char* name, double value) noexcept;
|
std::shared_ptr<SaveMap> SaveDouble(const char* name, double value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveString(const char* name, const std::string& value) noexcept;
|
std::shared_ptr<SaveMap> SaveString(const char* name, const std::string& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveObject(const char* name, UType::object_ptr<ISave> object) noexcept;
|
std::shared_ptr<SaveMap> SaveObject(const char* name, std::shared_ptr<ISave> object) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveVectorInteger(const char* name, std::vector<long long>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveVectorDouble(const char* name, std::vector<double>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveVectorStrings(const char* name, std::vector<std::string>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveVectorObject(const char* name, std::vector<UType::object_ptr<ISave>>&& value) noexcept;
|
std::shared_ptr<SaveMap> 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;
|
std::shared_ptr<SaveMap> SaveListInteger(const char* name, std::list<long long>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveListDouble(const char* name, std::list<double>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveListDouble(const char* name, std::list<double>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveListStrings(const char* name, std::list<std::string>&& value) noexcept;
|
||||||
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<UType::object_ptr<ISave>>&& value) noexcept;
|
std::shared_ptr<SaveMap> SaveListObject(const char* name, std::list<std::shared_ptr<ISave>>&& value) noexcept;
|
||||||
|
|
||||||
// Методы получения значенй
|
// Методы получения значенй
|
||||||
long long GetInteger(const char* name);
|
long long GetInteger(const char* name);
|
||||||
double GetDouble(const char* name);
|
double GetDouble(const char* name);
|
||||||
std::string GetString(const char* name);
|
std::string GetString(const char* name);
|
||||||
UType::object_ptr<ISave> GetObject(const char* name);
|
std::shared_ptr<ISave> GetObject(const char* name);
|
||||||
std::vector<long long>& GetVectorInteger(const char* name);
|
std::vector<long long>& GetVectorInteger(const char* name);
|
||||||
std::vector<double>& GetVectorDouble(const char* name);
|
std::vector<double>& GetVectorDouble(const char* name);
|
||||||
std::vector<std::string> GetVectorString(const char* name);
|
std::vector<std::string> GetVectorString(const char* name);
|
||||||
std::vector<UType::object_ptr<ISave>>& GetVectorObject(const char* name);
|
std::vector<std::shared_ptr<ISave>>& GetVectorObject(const char* name);
|
||||||
std::list<long long>& GetListInteger(const char* name);
|
std::list<long long>& GetListInteger(const char* name);
|
||||||
std::list<double>& GetListDouble(const char* name);
|
std::list<double>& GetListDouble(const char* name);
|
||||||
std::list<std::string>& GetListString(const char* name);
|
std::list<std::string>& GetListString(const char* name);
|
||||||
std::list<UType::object_ptr<ISave>>& GetListObject(const char* name);
|
std::list<std::shared_ptr<ISave>>& GetListObject(const char* name);
|
||||||
|
|
||||||
std::shared_ptr<SaveMap> getParent() const { return parent_; }
|
std::shared_ptr<SaveMap> getParent() const { return parent_; }
|
||||||
const std::string& getClassName() const { return class_name; }
|
const std::string& getClassName() const { return class_name; }
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "Game/SaveMap/SaveMap.hpp"
|
#include "Game/SaveMap/SaveMap.hpp"
|
||||||
|
|
||||||
World::World(GameInstance& game_instance) : game_instance(game_instance)
|
World::World(GameInstance& game_instance) : game_instance_(game_instance)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -34,7 +34,7 @@ std::shared_ptr<SaveMap> World::save()
|
|||||||
void World::load(std::shared_ptr<SaveMap> save)
|
void World::load(std::shared_ptr<SaveMap> save)
|
||||||
{
|
{
|
||||||
std::vector<std::string> actors_IDs = save->GetVectorString("ActorsIDs");
|
std::vector<std::string> actors_IDs = save->GetVectorString("ActorsIDs");
|
||||||
std::list<UType::object_ptr<Actor>> act = std::move(reinterpret_cast<std::list<UType::object_ptr<Actor>>&>(save->GetListObject("Actors")));
|
std::list<std::shared_ptr<Actor>> act = std::move(reinterpret_cast<std::list<std::shared_ptr<Actor>>&>(save->GetListObject("Actors")));
|
||||||
|
|
||||||
size_t i_id = 0;
|
size_t i_id = 0;
|
||||||
for (auto& i : act)
|
for (auto& i : act)
|
||||||
@@ -46,13 +46,13 @@ void World::load(std::shared_ptr<SaveMap> save)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void World::DestroyActor(UType::object_ptr<Actor> ptr)
|
void World::DestroyActor(std::weak_ptr<Actor> ptr)
|
||||||
{
|
{
|
||||||
if (ptr.get() == nullptr)
|
std::shared_ptr<Actor> actor = ptr.lock();
|
||||||
|
if (actor.get() == nullptr)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
std::string name = ptr->GetName();
|
std::string name = actor->GetName();
|
||||||
|
actor->OnDestroy();
|
||||||
actors_map.erase(name);
|
actors_map.erase(name);
|
||||||
ptr->OnDestroy();
|
|
||||||
ptr.destroy();
|
|
||||||
}
|
}
|
||||||
|
|||||||
+17
-14
@@ -7,17 +7,15 @@
|
|||||||
|
|
||||||
#include "RTTI.h"
|
#include "RTTI.h"
|
||||||
#include "Game/Actors/Actor.hpp"
|
#include "Game/Actors/Actor.hpp"
|
||||||
#include "Game/Actors/Mesh/Mesh.hpp"
|
|
||||||
#include "Types/object_ptr.hpp"
|
|
||||||
|
|
||||||
class GameInstance;
|
class GameInstance;
|
||||||
|
|
||||||
GENERATE_META(World);
|
GENERATE_META(World);
|
||||||
class World : public ISave
|
class World : public ISave
|
||||||
{
|
{
|
||||||
GameInstance& game_instance;
|
GameInstance& game_instance_;
|
||||||
|
|
||||||
std::unordered_map<std::string, UType::object_ptr<Actor>> actors_map;
|
std::unordered_map<std::string, std::shared_ptr<Actor>> actors_map;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
World(GameInstance& game_instance);
|
World(GameInstance& game_instance);
|
||||||
@@ -26,7 +24,7 @@ public:
|
|||||||
virtual void BeginPlay();
|
virtual void BeginPlay();
|
||||||
virtual void Tick(double delta_time);
|
virtual void Tick(double delta_time);
|
||||||
|
|
||||||
GameInstance& GetGameInstance() const { return game_instance; }
|
GameInstance& GetGameInstance() const { return game_instance_; }
|
||||||
|
|
||||||
#pragma region ISave
|
#pragma region ISave
|
||||||
std::shared_ptr<SaveMap> save() override;
|
std::shared_ptr<SaveMap> save() override;
|
||||||
@@ -34,29 +32,30 @@ public:
|
|||||||
#pragma endregion
|
#pragma endregion
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
std::vector<UType::object_ptr<T>> GetActorsByClass()
|
std::vector<std::weak_ptr<T>> GetActorsByClass()
|
||||||
{
|
{
|
||||||
std::vector<UType::object_ptr<T>> list;
|
std::vector<std::weak_ptr<T>> list;
|
||||||
for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i)
|
for (auto i = actors_map.cbegin(); i != actors_map.cend(); ++i)
|
||||||
{
|
{
|
||||||
if (T* cast_object = RTTI::dyn_cast<T, Actor>(i->second.get()))
|
if (RTTI::dyn_cast<T, Actor>(i->second.get()))
|
||||||
list.push_back(UType::object_ptr<T>(cast_object));
|
list.push_back(std::static_pointer_cast<T>(i->second));
|
||||||
}
|
}
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
UType::object_ptr<T> SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 })
|
std::weak_ptr<T> SpawnActorFormClass(std::string name, const Vector3D& loc = { 0, 0, 0 }, const Vector3D& rot = { 0, 0, 0 })
|
||||||
{
|
{
|
||||||
UType::object_ptr<T> object(new T());
|
std::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;
|
static_cast<Actor*>(object)->world_ = this;
|
||||||
|
static_cast<Actor*>(object)->name_ = name;
|
||||||
actors_map.try_emplace(name, object);
|
actors_map.try_emplace(name, object);
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
void DestroyActor(UType::object_ptr<Actor> ptr);
|
void DestroyActor(std::weak_ptr<Actor> ptr);
|
||||||
|
|
||||||
template<class T, class Container = std::vector<T*>>
|
template<class T, class Container = std::vector<T*>>
|
||||||
Container GetActorsByTag(std::string tag)
|
Container GetActorsByTag(std::string tag)
|
||||||
@@ -77,9 +76,13 @@ public:
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<class T>
|
template<class T>
|
||||||
UType::object_ptr<T> GetActorByID(const std::string& id)
|
std::weak_ptr<T> GetActorByID(const std::string& id)
|
||||||
{
|
{
|
||||||
return actors_map[id];
|
auto it = actors_map.find(id);
|
||||||
|
if (it == actors_map.end() || it->second == nullptr)
|
||||||
|
return {};
|
||||||
|
|
||||||
|
return std::static_pointer_cast<T>(it->second);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include "Game/SaveMap/SaveMap.hpp"
|
#include "Game/SaveMap/SaveMap.hpp"
|
||||||
|
|
||||||
Vector2D::Vector2D(const double x, const double y) : x(x), y(y)
|
Vector2D::Vector2D(double x, double y) : x(x), y(y)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Vector2D::Vector2D(const Vector3D& vec3D) : x(vec3D.x), y(vec3D.y)
|
Vector2D::Vector2D(const Vector3D& vec3D) : x(vec3D.x), y(vec3D.y)
|
||||||
@@ -31,7 +31,7 @@ void Vector2D::load(std::shared_ptr<SaveMap> save)
|
|||||||
y = save->GetDouble("y");
|
y = save->GetDouble("y");
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3D::Vector3D(const double x, const double y, const double z) : x(x), y(y), z(z)
|
Vector3D::Vector3D(double x, double y, double z) : x(x), y(y), z(z)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Vector3D::Vector3D(const Vector2D& vec2D) : x(vec2D.x), y(vec2D.y)
|
Vector3D::Vector3D(const Vector2D& vec2D) : x(vec2D.x), y(vec2D.y)
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
#include "object_ptr.hpp"
|
|
||||||
|
|
||||||
std::unordered_map<void*, UType::counter::counter_owners> UType::counter::owners_map;
|
|
||||||
@@ -1,185 +0,0 @@
|
|||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <mutex>
|
|
||||||
#include <unordered_map>
|
|
||||||
#include <list>
|
|
||||||
|
|
||||||
namespace UType
|
|
||||||
{
|
|
||||||
template<typename Ty>
|
|
||||||
class object_ptr;
|
|
||||||
|
|
||||||
class counter
|
|
||||||
{
|
|
||||||
struct counter_owners
|
|
||||||
{
|
|
||||||
std::atomic_bool is_destroyed;
|
|
||||||
std::mutex mutex;
|
|
||||||
std::list<void*> owners;
|
|
||||||
|
|
||||||
counter_owners()
|
|
||||||
: is_destroyed(false)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
counter_owners(const counter_owners&) = delete;
|
|
||||||
counter_owners& operator=(const counter_owners&) = delete;
|
|
||||||
|
|
||||||
counter_owners(counter_owners&& other) noexcept
|
|
||||||
: is_destroyed(other.is_destroyed.load())
|
|
||||||
, owners(std::move(other.owners))
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
counter_owners& operator=(counter_owners&& other) noexcept
|
|
||||||
{
|
|
||||||
if (this != &other)
|
|
||||||
{
|
|
||||||
is_destroyed.store(other.is_destroyed.load());
|
|
||||||
owners = std::move(other.owners);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
static std::unordered_map<void*, counter_owners> owners_map;
|
|
||||||
|
|
||||||
public:
|
|
||||||
template<typename Ty>
|
|
||||||
static void add_owner(object_ptr<Ty>& ptr)
|
|
||||||
{
|
|
||||||
auto counter = owners_map.find(ptr.ptr_.load());
|
|
||||||
if (counter == owners_map.end())
|
|
||||||
{
|
|
||||||
counter_owners owners;
|
|
||||||
owners.owners.push_back(&ptr);
|
|
||||||
auto [it, inserted] = owners_map.try_emplace(ptr.ptr_.load(), std::move(owners));
|
|
||||||
if (!inserted)
|
|
||||||
{
|
|
||||||
ptr.ptr_.store(nullptr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (!counter->second.is_destroyed)
|
|
||||||
{
|
|
||||||
std::lock_guard<std::mutex> lock(counter->second.mutex);
|
|
||||||
counter->second.owners.push_back(&ptr);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
ptr.ptr_.store(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ty>
|
|
||||||
static void remove_owner(object_ptr<Ty>& ptr)
|
|
||||||
{
|
|
||||||
auto counter = owners_map.find(ptr.ptr_);
|
|
||||||
if (counter != owners_map.end())
|
|
||||||
{
|
|
||||||
counter->second.owners.remove(&ptr);
|
|
||||||
|
|
||||||
if (counter->second.is_destroyed)
|
|
||||||
{
|
|
||||||
ptr.ptr_.store(nullptr);
|
|
||||||
}
|
|
||||||
else if (counter->second.owners.empty())
|
|
||||||
{
|
|
||||||
counter->second.is_destroyed.store(true);
|
|
||||||
for (auto& owner : counter->second.owners)
|
|
||||||
static_cast<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
|
|
||||||
delete static_cast<Ty*>(counter->first);
|
|
||||||
owners_map.erase(counter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Ty>
|
|
||||||
static void remove_object(Ty* ptr)
|
|
||||||
{
|
|
||||||
auto counter = owners_map.find(ptr);
|
|
||||||
if (counter != owners_map.end())
|
|
||||||
{
|
|
||||||
counter->second.is_destroyed.store(true);
|
|
||||||
for (auto& owner : counter->second.owners)
|
|
||||||
static_cast<object_ptr<Ty>*>(owner)->ptr_.store(nullptr);
|
|
||||||
delete ptr;
|
|
||||||
owners_map.erase(counter);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template<typename Ty>
|
|
||||||
class object_ptr
|
|
||||||
{
|
|
||||||
std::atomic<Ty*> ptr_;
|
|
||||||
public:
|
|
||||||
explicit object_ptr(Ty* ptr = nullptr)
|
|
||||||
{
|
|
||||||
ptr_.store(ptr);
|
|
||||||
if (ptr) counter::add_owner<Ty>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_ptr(const object_ptr& ptr)
|
|
||||||
{
|
|
||||||
ptr_.store(ptr.ptr_);
|
|
||||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
object_ptr(object_ptr&& ptr) noexcept
|
|
||||||
{
|
|
||||||
ptr_.store(ptr.ptr_);
|
|
||||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
|
||||||
ptr.ptr_.store(nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
~object_ptr()
|
|
||||||
{
|
|
||||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(Ty* new_ptr = nullptr)
|
|
||||||
{
|
|
||||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
|
||||||
ptr_.store(new_ptr);
|
|
||||||
if (new_ptr) counter::add_owner<Ty>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void reset(const object_ptr& ptr)
|
|
||||||
{
|
|
||||||
if (ptr_) counter::remove_owner<Ty>(*this);
|
|
||||||
ptr_.store(ptr.ptr_);
|
|
||||||
if (ptr.ptr_) counter::add_owner<Ty>(*this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void destroy()
|
|
||||||
{
|
|
||||||
if (ptr_) counter::remove_object<Ty>(ptr_);
|
|
||||||
}
|
|
||||||
|
|
||||||
Ty* get() const { return ptr_.load(); }
|
|
||||||
Ty& operator*() const
|
|
||||||
{
|
|
||||||
if (!ptr_.load())
|
|
||||||
throw std::runtime_error("Null pointer");
|
|
||||||
return *ptr_;
|
|
||||||
}
|
|
||||||
Ty* operator->() const
|
|
||||||
{
|
|
||||||
if (!ptr_.load())
|
|
||||||
throw std::runtime_error("Null pointer");
|
|
||||||
return ptr_.load();
|
|
||||||
}
|
|
||||||
operator bool() const noexcept { return ptr_.load() != nullptr; }
|
|
||||||
object_ptr<Ty>& operator=(const object_ptr<Ty>& ptr)
|
|
||||||
{
|
|
||||||
reset(ptr);
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename target_Ty>
|
|
||||||
explicit operator object_ptr<target_Ty>() const noexcept
|
|
||||||
{
|
|
||||||
return object_ptr<target_Ty>(reinterpret_cast<target_Ty*>(ptr_.load()));
|
|
||||||
}
|
|
||||||
|
|
||||||
friend class counter;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
@@ -13,5 +13,5 @@ template<class T> struct Meta;
|
|||||||
// Enum type classes
|
// Enum type classes
|
||||||
enum class Classes
|
enum class Classes
|
||||||
{
|
{
|
||||||
IRTTI, IResource, Actor, TestActor, Mesh, StaticMesh, World, TestWorld
|
IRTTI, IResource, Actor, World, Mesh, StaticMesh, Camera, TestWorld, TestActor
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -2,4 +2,19 @@ set(CMAKE_CXX_STANDARD 20)
|
|||||||
|
|
||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.h" "*.hpp")
|
||||||
|
|
||||||
add_executable(ProjectGenerator ${SRC})
|
add_executable(ProjectGenerator ${SRC})
|
||||||
|
|
||||||
|
if(MSVC)
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/$<CONFIG>)
|
||||||
|
else()
|
||||||
|
set(OUTPUT_PATH ${CMAKE_RUNTIME_OUTPUT_DIRECTORY})
|
||||||
|
endif()
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET ProjectGenerator
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
${CMAKE_CURRENT_SOURCE_DIR}/ProjectFile.txt
|
||||||
|
${OUTPUT_PATH}/ProjectFile.txt
|
||||||
|
COMMENT "Copying project files"
|
||||||
|
)
|
||||||
@@ -0,0 +1,125 @@
|
|||||||
|
#include "DeviceFunctions.hpp"
|
||||||
|
|
||||||
|
#include <stdexcept>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
VkExtent2D DeviceFunctions::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
|
||||||
|
{
|
||||||
|
// The acceptable rendering sparsity is calculated here
|
||||||
|
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
||||||
|
return capabilities.currentExtent;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int width, height;
|
||||||
|
glfwGetFramebufferSize(window, &width, &height);
|
||||||
|
VkExtent2D actualExtent = {
|
||||||
|
static_cast<uint32_t>(width),
|
||||||
|
static_cast<uint32_t>(height)
|
||||||
|
};
|
||||||
|
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
||||||
|
return actualExtent;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t DeviceFunctions::find_memory_type(VkPhysicalDevice physical_device, uint32_t typeFilter,
|
||||||
|
VkMemoryPropertyFlags properties)
|
||||||
|
{
|
||||||
|
VkPhysicalDeviceMemoryProperties memory_properties{};
|
||||||
|
vkGetPhysicalDeviceMemoryProperties(physical_device, &memory_properties);
|
||||||
|
|
||||||
|
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i)
|
||||||
|
{
|
||||||
|
if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties)
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
|
||||||
|
throw std::runtime_error("failed to find suitable memory type!");
|
||||||
|
}
|
||||||
|
|
||||||
|
void DeviceFunctions::device_memcpy(VkDevice device, uint32_t transfer_queue_family, VkBuffer src, VkBuffer dst, size_t size)
|
||||||
|
{
|
||||||
|
VkCommandPool copy_pool;
|
||||||
|
VkCommandPoolCreateInfo copy_pool_info{};
|
||||||
|
copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
|
copy_pool_info.queueFamilyIndex = transfer_queue_family;
|
||||||
|
copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
VK_CHECK(vkCreateCommandPool(device, ©_pool_info, nullptr, ©_pool));
|
||||||
|
|
||||||
|
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
||||||
|
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
||||||
|
command_buffer_allocate_info.commandPool = copy_pool;
|
||||||
|
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
|
command_buffer_allocate_info.commandBufferCount = 1;
|
||||||
|
|
||||||
|
VkCommandBuffer copy_buffer;
|
||||||
|
VK_CHECK(vkAllocateCommandBuffers(device, &command_buffer_allocate_info, ©_buffer));
|
||||||
|
|
||||||
|
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
||||||
|
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
||||||
|
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
||||||
|
|
||||||
|
VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info));
|
||||||
|
|
||||||
|
VkBufferCopy buffer_copy{};
|
||||||
|
buffer_copy.srcOffset = 0;
|
||||||
|
buffer_copy.dstOffset = 0;
|
||||||
|
buffer_copy.size = size;
|
||||||
|
vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy);
|
||||||
|
|
||||||
|
vkEndCommandBuffer(copy_buffer);
|
||||||
|
|
||||||
|
VkSubmitInfo submit_info{};
|
||||||
|
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
||||||
|
submit_info.commandBufferCount = 1;
|
||||||
|
submit_info.pCommandBuffers = ©_buffer;
|
||||||
|
|
||||||
|
VkQueue transfer_queue;
|
||||||
|
vkGetDeviceQueue(device, transfer_queue_family, 0, &transfer_queue);
|
||||||
|
|
||||||
|
vkQueueSubmit(transfer_queue, 1, &submit_info, VK_NULL_HANDLE);
|
||||||
|
vkQueueWaitIdle(transfer_queue);
|
||||||
|
|
||||||
|
vkFreeCommandBuffers(device, copy_pool, 1, ©_buffer);
|
||||||
|
vkDestroyCommandPool(device, copy_pool, nullptr);
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBuffer DeviceFunctions::create_buffer(VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage,
|
||||||
|
const std::vector<uint32_t>& queue_families)
|
||||||
|
{
|
||||||
|
VkBufferCreateInfo buffer_info{};
|
||||||
|
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
buffer_info.size = size;
|
||||||
|
buffer_info.usage = usage;
|
||||||
|
|
||||||
|
if (queue_families.size() > 1)
|
||||||
|
{
|
||||||
|
buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
||||||
|
buffer_info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
|
||||||
|
buffer_info.pQueueFamilyIndices = queue_families.data();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
||||||
|
buffer_info.queueFamilyIndexCount = 0;
|
||||||
|
buffer_info.pQueueFamilyIndices = nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkBuffer buffer;
|
||||||
|
VK_CHECK(vkCreateBuffer(device, &buffer_info, nullptr, &buffer));
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
VkDeviceMemory DeviceFunctions::allocate_device_memory(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkMemoryPropertyFlags property)
|
||||||
|
{
|
||||||
|
VkMemoryRequirements requirements{};
|
||||||
|
vkGetBufferMemoryRequirements(device, buffer, &requirements);
|
||||||
|
|
||||||
|
VkMemoryAllocateInfo allocate_info{};
|
||||||
|
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
||||||
|
allocate_info.allocationSize = requirements.size;
|
||||||
|
allocate_info.memoryTypeIndex = find_memory_type(physical_device, requirements.memoryTypeBits, property);
|
||||||
|
|
||||||
|
VkDeviceMemory device_memory;
|
||||||
|
VK_CHECK(vkAllocateMemory(device, &allocate_info, nullptr, &device_memory));
|
||||||
|
return device_memory;
|
||||||
|
}
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#define GLFW_INCLUDE_VULKAN
|
||||||
|
#include <GLFW/glfw3.h>
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
|
#ifdef _DEBUG
|
||||||
|
#include <assert.h>
|
||||||
|
#define VK_CHECK(res) assert(res == VK_SUCCESS);
|
||||||
|
#else
|
||||||
|
#define VK_CHECK(val) {int res = (val); if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(static_cast<int>(res)));}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
namespace DeviceFunctions
|
||||||
|
{
|
||||||
|
VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window);
|
||||||
|
uint32_t find_memory_type(VkPhysicalDevice physical_device, uint32_t typeFilter, VkMemoryPropertyFlags properties);
|
||||||
|
void device_memcpy(VkDevice device, uint32_t transfer_queue_family, VkBuffer src, VkBuffer dst, size_t size);
|
||||||
|
VkBuffer create_buffer(VkDevice device, VkDeviceSize size, VkBufferUsageFlags usage, const std::vector<uint32_t>& queue_families);
|
||||||
|
VkDeviceMemory allocate_device_memory(VkPhysicalDevice physical_device, VkDevice device, VkBuffer buffer, VkMemoryPropertyFlags property);
|
||||||
|
}
|
||||||
@@ -8,6 +8,7 @@ add_executable(${GAME_NAME} ${SRC})
|
|||||||
target_link_libraries(${GAME_NAME} PRIVATE Core UwURenderEngine)
|
target_link_libraries(${GAME_NAME} PRIVATE Core UwURenderEngine)
|
||||||
target_include_directories(${GAME_NAME} PRIVATE
|
target_include_directories(${GAME_NAME} PRIVATE
|
||||||
${PROJECT_SOURCE_DIR}/Core
|
${PROJECT_SOURCE_DIR}/Core
|
||||||
|
${PROJECT_SOURCE_DIR}/UwURenderEngine
|
||||||
)
|
)
|
||||||
|
|
||||||
if(MSVC)
|
if(MSVC)
|
||||||
|
|||||||
@@ -3,8 +3,33 @@
|
|||||||
"dtime": 5.000000,
|
"dtime": 5.000000,
|
||||||
"Parent parameters": {
|
"Parent parameters": {
|
||||||
"Class name":"World",
|
"Class name":"World",
|
||||||
"vsActorsIDs": ["TestMesh1","TestMesh2"],
|
"vsActorsIDs": ["MainCamera", "TestMesh1","TestMesh2"],
|
||||||
"loActors": [
|
"loActors": [
|
||||||
|
{
|
||||||
|
"Class name": "Camera",
|
||||||
|
"Parent parameters": {
|
||||||
|
"Class name":"Actor",
|
||||||
|
"oloc": {
|
||||||
|
"Class name":"Vector3D",
|
||||||
|
"dx":2.0,
|
||||||
|
"dy":2.0,
|
||||||
|
"dz":2.0
|
||||||
|
},
|
||||||
|
"orot": {
|
||||||
|
"Class name":"Vector3D",
|
||||||
|
"dx":-2.335,
|
||||||
|
"dy":-0.785,
|
||||||
|
"dz":0.0
|
||||||
|
},
|
||||||
|
"oscale": {
|
||||||
|
"Class name": "Vector3D",
|
||||||
|
"dx": 1.0,
|
||||||
|
"dy": 1.0,
|
||||||
|
"dz": 1.0
|
||||||
|
},
|
||||||
|
"tags":[]
|
||||||
|
}
|
||||||
|
},
|
||||||
{
|
{
|
||||||
"Class name": "StaticMesh",
|
"Class name": "StaticMesh",
|
||||||
"Parent parameters": {
|
"Parent parameters": {
|
||||||
|
|||||||
@@ -1,7 +1,11 @@
|
|||||||
#include "Game/ObjectFactory.hpp"
|
#include "Game/ObjectFactory.hpp"
|
||||||
|
|
||||||
#include "../Actors/TestActor.h"
|
#include "../Actors/TestActor.h"
|
||||||
|
#include "Game/Actors/Camera.hpp"
|
||||||
|
#include "Game/Actors/Mesh/StaticMesh.hpp"
|
||||||
|
|
||||||
FACTORIES_LIST{
|
FACTORIES_LIST{
|
||||||
|
GENERATE_FACTORY_OBJECT(StaticMesh)
|
||||||
GENERATE_FACTORY_OBJECT(TestActor)
|
GENERATE_FACTORY_OBJECT(TestActor)
|
||||||
|
GENERATE_FACTORY_OBJECT(Camera)
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,8 +1,13 @@
|
|||||||
#include "TestWorld.h"
|
#include "TestWorld.h"
|
||||||
|
|
||||||
|
#include <glm/glm.hpp>
|
||||||
|
#include <glm/ext/scalar_constants.hpp>
|
||||||
|
|
||||||
#include "Game/GameInstance.hpp"
|
#include "Game/GameInstance.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"
|
||||||
|
|
||||||
TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
||||||
{}
|
{}
|
||||||
@@ -10,23 +15,35 @@ TestWorld::TestWorld(GameInstance& game_instance) : World(game_instance)
|
|||||||
void TestWorld::BeginPlay()
|
void TestWorld::BeginPlay()
|
||||||
{
|
{
|
||||||
World::BeginPlay();
|
World::BeginPlay();
|
||||||
std::vector<UType::object_ptr<Actor>> meshes = GetActorsByClass<Actor>();
|
std::vector<std::weak_ptr<Actor>> meshes = GetActorsByClass<Actor>();
|
||||||
for (const auto& i : meshes)
|
for (const auto& i : meshes)
|
||||||
Loging::Log("Load actor: " + i->GetName());
|
{
|
||||||
|
Loging::Log("Load actor: " + i.lock()->GetName());
|
||||||
|
}
|
||||||
|
|
||||||
|
GetActorsByClass<Camera>()[0].lock()->SetActive();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TestWorld::Tick(double delta_time)
|
void TestWorld::Tick(double delta_time)
|
||||||
{
|
{
|
||||||
World::Tick(delta_time);
|
World::Tick(delta_time);
|
||||||
|
|
||||||
|
static double time1 = 0.0;
|
||||||
|
time1 += delta_time;
|
||||||
|
double delta1 = sin(time1);
|
||||||
|
double delta2 = sin(3*time1);
|
||||||
|
GetActorsByClass<Camera>()[0].lock()->SetActorLocate(Vector3D{2 + delta2, 2 + delta2, 2 + delta2});
|
||||||
|
GetActorsByClass<Camera>()[0].lock()->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)
|
||||||
{
|
{
|
||||||
std::vector<UType::object_ptr<Mesh>> meshes = GetActorsByClass<Mesh>();
|
std::vector<std::weak_ptr<Mesh>> meshes = GetActorsByClass<Mesh>();
|
||||||
if (!meshes.empty())
|
if (!meshes.empty())
|
||||||
{
|
{
|
||||||
Loging::Message("TestWorld destroy: " + meshes[0]->GetName());
|
std::shared_ptr<Mesh> mesh = meshes[0].lock();
|
||||||
DestroyActor(static_cast<UType::object_ptr<Actor>>(meshes[0]));
|
Loging::Message("TestWorld destroy: " + mesh->GetName());
|
||||||
|
DestroyActor(meshes[0]);
|
||||||
time = 7.0;
|
time = 7.0;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ file(GLOB SRC
|
|||||||
"ObjectPtrTest.cpp"
|
"ObjectPtrTest.cpp"
|
||||||
|
|
||||||
"${PROJECT_SOURCE_DIR}/Core/Game/SaveMap/SaveMap.cpp"
|
"${PROJECT_SOURCE_DIR}/Core/Game/SaveMap/SaveMap.cpp"
|
||||||
"${PROJECT_SOURCE_DIR}/Core/Types/object_ptr.cpp"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
add_executable(Tests ${SRC})
|
add_executable(Tests ${SRC})
|
||||||
|
|||||||
@@ -1,59 +0,0 @@
|
|||||||
#include <gtest/gtest.h>
|
|
||||||
#include "Types/object_ptr.hpp"
|
|
||||||
|
|
||||||
class TestClass
|
|
||||||
{
|
|
||||||
int* test_ptr_;
|
|
||||||
public:
|
|
||||||
TestClass(int* test_ptr) : test_ptr_(test_ptr)
|
|
||||||
{
|
|
||||||
*test_ptr_ = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
~TestClass()
|
|
||||||
{
|
|
||||||
*test_ptr_ = 2;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
TEST(object_ptr_test, base_test)
|
|
||||||
{
|
|
||||||
int* test = new int(123);
|
|
||||||
UType::object_ptr<int> ptr(test);
|
|
||||||
EXPECT_EQ(*ptr.get(), 123);
|
|
||||||
|
|
||||||
UType::object_ptr<int> ptr2(ptr);
|
|
||||||
EXPECT_EQ(*ptr2.get(), 123);
|
|
||||||
EXPECT_EQ(ptr2.get(), ptr.get());
|
|
||||||
|
|
||||||
ptr.destroy();
|
|
||||||
EXPECT_EQ(ptr.get(), nullptr);
|
|
||||||
EXPECT_EQ(ptr2.get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(object_ptr_test, check_destry)
|
|
||||||
{
|
|
||||||
UType::object_ptr<int> ptr(new int(123)), ptr2(ptr);
|
|
||||||
|
|
||||||
ptr.destroy();
|
|
||||||
EXPECT_EQ(ptr.get(), nullptr);
|
|
||||||
EXPECT_EQ(ptr2.get(), nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
TEST(object_ptr_test, check_destroy)
|
|
||||||
{
|
|
||||||
int* test = new int(0);
|
|
||||||
{
|
|
||||||
UType::object_ptr<TestClass> ptr(new TestClass(test));
|
|
||||||
EXPECT_EQ(*test, 1);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(*test, 2);
|
|
||||||
|
|
||||||
*test = 0;
|
|
||||||
{
|
|
||||||
UType::object_ptr<TestClass> ptr(new TestClass(test));
|
|
||||||
UType::object_ptr<TestClass> ptr2(ptr);
|
|
||||||
EXPECT_EQ(*test, 1);
|
|
||||||
}
|
|
||||||
EXPECT_EQ(*test, 2);
|
|
||||||
}
|
|
||||||
@@ -158,14 +158,15 @@ TEST(SaveMapTest, check_load_with_custom_type)
|
|||||||
EXPECT_EQ(test_vector_string[i], save_map.GetVectorString("TestVectorString")[i]);
|
EXPECT_EQ(test_vector_string[i], save_map.GetVectorString("TestVectorString")[i]);
|
||||||
}
|
}
|
||||||
|
|
||||||
UType::object_ptr<CustomObject> obj = static_cast<UType::object_ptr<CustomObject>>(save_map.GetObject("CustomObject"));
|
std::shared_ptr obj = std::static_pointer_cast<CustomObject>(save_map.GetObject("CustomObject"));
|
||||||
|
|
||||||
CustomObject test_obj;
|
CustomObject test_obj;
|
||||||
test_obj.num = 123;
|
test_obj.num = 123;
|
||||||
test_obj.str = "str123";
|
test_obj.str = "str123";
|
||||||
test_obj.dbl = 123.45;
|
test_obj.dbl = 123.45;
|
||||||
EXPECT_EQ(*obj.get(), test_obj);
|
EXPECT_EQ(*obj.get(), test_obj);
|
||||||
|
|
||||||
std::vector<UType::object_ptr<CustomObject>> vec_obj = reinterpret_cast<std::vector<UType::object_ptr<CustomObject>>&>(save_map.GetVectorObject("CustomObjects"));
|
std::vector<std::shared_ptr<CustomObject>> vec_obj = reinterpret_cast<std::vector<std::shared_ptr<CustomObject>>&>(save_map.GetVectorObject("CustomObjects"));
|
||||||
std::vector<CustomObject*> vec_obj_test = {
|
std::vector<CustomObject*> vec_obj_test = {
|
||||||
new CustomObject,
|
new CustomObject,
|
||||||
new CustomObject,
|
new CustomObject,
|
||||||
@@ -179,7 +180,6 @@ TEST(SaveMapTest, check_load_with_custom_type)
|
|||||||
for (auto i = 0; i < 2; i++)
|
for (auto i = 0; i < 2; i++)
|
||||||
{
|
{
|
||||||
EXPECT_EQ(*vec_obj[i].get(), *vec_obj_test[i]);
|
EXPECT_EQ(*vec_obj[i].get(), *vec_obj_test[i]);
|
||||||
vec_obj[i].destroy();
|
|
||||||
delete vec_obj_test[i];
|
delete vec_obj_test[i];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,7 +1,33 @@
|
|||||||
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.hpp" "*.h")
|
file(GLOB_RECURSE SRC "*.cpp" "*.c" "*.hpp" "*.h")
|
||||||
|
|
||||||
add_library(UwURenderEngine ${SRC})
|
add_library(UwURenderEngine ${SRC})
|
||||||
target_include_directories(UwURenderEngine PRIVATE ${PROJECT_SOURCE_DIR}/RenderEngineSDK)
|
target_include_directories(UwURenderEngine PUBLIC ${PROJECT_SOURCE_DIR}/RenderEngineSDK)
|
||||||
target_link_libraries(UwURenderEngine PRIVATE RenderEngineSDK)
|
target_link_libraries(UwURenderEngine PUBLIC RenderEngineSDK)
|
||||||
|
|
||||||
target_compile_features(UwURenderEngine PRIVATE cxx_std_17)
|
target_compile_features(UwURenderEngine PRIVATE cxx_std_17)
|
||||||
|
|
||||||
|
file(GLOB_RECURSE HEADERS
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.h"
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/*.hpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
foreach (HEADER ${HEADERS})
|
||||||
|
file(RELATIVE_PATH R_PATH
|
||||||
|
"${CMAKE_CURRENT_SOURCE_DIR}/"
|
||||||
|
"${HEADER}"
|
||||||
|
)
|
||||||
|
|
||||||
|
get_filename_component(HEADER_DIR "${R_PATH}" DIRECTORY)
|
||||||
|
|
||||||
|
add_custom_command(
|
||||||
|
TARGET UwURenderEngine
|
||||||
|
POST_BUILD
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E make_directory
|
||||||
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${HEADER_DIR}"
|
||||||
|
COMMAND ${CMAKE_COMMAND} -E copy_if_different
|
||||||
|
"${HEADER}"
|
||||||
|
"${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/include/${R_PATH}"
|
||||||
|
|
||||||
|
COMMENT "Copy UwURenderEngine headers"
|
||||||
|
)
|
||||||
|
endforeach ()
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#include "Camera.hpp"
|
||||||
|
|
||||||
|
#include "../../RenderEngine/UwURenderEngine.hpp"
|
||||||
|
#include "Core/CoreInstance.hpp"
|
||||||
|
#include "Game/GameInstance.hpp"
|
||||||
|
#include "Game/SaveMap/SaveMap.hpp"
|
||||||
|
#include "Game/World/World.hpp"
|
||||||
|
|
||||||
|
Camera::Camera()
|
||||||
|
{
|
||||||
|
SetType(Classes::Camera);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> Camera::save()
|
||||||
|
{
|
||||||
|
return std::make_shared<SaveMap>("Camera")->connect_to(Actor::save());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::load(std::shared_ptr<SaveMap> save)
|
||||||
|
{
|
||||||
|
Actor::load(save->getParent());
|
||||||
|
}
|
||||||
|
|
||||||
|
void Camera::SetActive() const noexcept
|
||||||
|
{
|
||||||
|
GET_RENDER_ENGINE->SetActiveCamera(GetWorld()->GetActorByID<Camera>(GetName()));
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
#pragma once
|
||||||
|
#include "RTTI_Meta.h"
|
||||||
|
#include "Game/Actors/Actor.hpp"
|
||||||
|
|
||||||
|
GENERATE_META(Camera)
|
||||||
|
|
||||||
|
class Camera : public Actor
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
Camera();
|
||||||
|
|
||||||
|
std::shared_ptr<SaveMap> save() override;
|
||||||
|
void load(std::shared_ptr<SaveMap> save) override;
|
||||||
|
|
||||||
|
void SetActive() const noexcept;
|
||||||
|
};
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include "../Actor.hpp"
|
#include "Game/Actors/Actor.hpp"
|
||||||
|
|
||||||
GENERATE_META(Mesh)
|
GENERATE_META(Mesh)
|
||||||
class Mesh : public Actor
|
class Mesh : public Actor
|
||||||
+4
-2
@@ -4,6 +4,7 @@
|
|||||||
#include "Game/GameInstance.hpp"
|
#include "Game/GameInstance.hpp"
|
||||||
#include "Game/SaveMap/SaveMap.hpp"
|
#include "Game/SaveMap/SaveMap.hpp"
|
||||||
#include "Game/World/World.hpp"
|
#include "Game/World/World.hpp"
|
||||||
|
#include "../../../RenderEngine/UwURenderEngine.hpp"
|
||||||
|
|
||||||
StaticMesh::StaticMesh()
|
StaticMesh::StaticMesh()
|
||||||
{
|
{
|
||||||
@@ -23,12 +24,13 @@ void StaticMesh::load(std::shared_ptr<SaveMap> save)
|
|||||||
void StaticMesh::load_model(const std::string& model_name)
|
void StaticMesh::load_model(const std::string& model_name)
|
||||||
{
|
{
|
||||||
model_name_ = model_name;
|
model_name_ = model_name;
|
||||||
|
model_ = GET_RENDER_ENGINE->GetModelManager()->LoadModel(model_name);
|
||||||
SetModelName(model_name);
|
SetModelName(model_name);
|
||||||
model_ = GetWorld()->GetGameInstance().GetCurrentModelManager()->LoadModel(model_name);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void StaticMesh::OnDestroy()
|
void StaticMesh::OnDestroy()
|
||||||
{
|
{
|
||||||
Mesh::OnDestroy();
|
Mesh::OnDestroy();
|
||||||
GetWorld()->GetGameInstance().GetCurrentModelManager()->FreeModel(model_name_);
|
|
||||||
|
GET_RENDER_ENGINE->GetModelManager()->FreeModel(model_name_);
|
||||||
}
|
}
|
||||||
+1
-1
@@ -1,7 +1,7 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "Mesh.hpp"
|
#include "Mesh.hpp"
|
||||||
#include "Game/ModelManager.hpp"
|
#include "../../../RenderEngine/ModelManager.hpp"
|
||||||
|
|
||||||
GENERATE_META(StaticMesh)
|
GENERATE_META(StaticMesh)
|
||||||
|
|
||||||
@@ -0,0 +1,22 @@
|
|||||||
|
#include "GPU_GarbageCollector.h"
|
||||||
|
|
||||||
|
|
||||||
|
GPU_GarbageCollector::GPU_GarbageCollector(VkDevice device) : device_(device)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void GPU_GarbageCollector::AddGarbage(Garbage garbage)
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(m_heap_);
|
||||||
|
heap_.push_back(garbage);
|
||||||
|
}
|
||||||
|
|
||||||
|
void GPU_GarbageCollector::FreeHeap()
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(m_heap_);
|
||||||
|
for (auto& i : heap_)
|
||||||
|
{
|
||||||
|
vkFreeMemory(device_, i.device_memory, nullptr);
|
||||||
|
vkDestroyBuffer(device_, i.buffer, nullptr);
|
||||||
|
}
|
||||||
|
heap_.clear();
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <list>
|
||||||
|
#include <mutex>
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class GPU_GarbageCollector
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Garbage
|
||||||
|
{
|
||||||
|
VkBuffer buffer;
|
||||||
|
VkDeviceMemory device_memory;
|
||||||
|
};
|
||||||
|
private:
|
||||||
|
VkDevice device_ = VK_NULL_HANDLE;
|
||||||
|
|
||||||
|
std::list<Garbage> heap_;
|
||||||
|
std::mutex m_heap_;
|
||||||
|
public:
|
||||||
|
GPU_GarbageCollector() = default;
|
||||||
|
|
||||||
|
explicit GPU_GarbageCollector(VkDevice device);
|
||||||
|
|
||||||
|
void AddGarbage(Garbage garbage);
|
||||||
|
void FreeHeap();
|
||||||
|
};
|
||||||
@@ -0,0 +1,113 @@
|
|||||||
|
#include "ModelManager.hpp"
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
|
||||||
|
#include "Log/Log.hpp"
|
||||||
|
|
||||||
|
ModelManager::StaticModel::StaticModel(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices,
|
||||||
|
VkPhysicalDevice physical_device, VkDevice device):
|
||||||
|
physical_device_(physical_device),
|
||||||
|
device_(device)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelManager::StaticModel::~StaticModel()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
VkVertexInputBindingDescription ModelManager::Vertex::get_binding_description()
|
||||||
|
{
|
||||||
|
VkVertexInputBindingDescription description;
|
||||||
|
description.binding = 0;
|
||||||
|
description.stride = sizeof(Vertex);
|
||||||
|
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> ModelManager::Vertex::get_vertex_attribute_descriptions()
|
||||||
|
{
|
||||||
|
std::array<VkVertexInputAttributeDescription, 2> descriptions;
|
||||||
|
// Bind vertex loc
|
||||||
|
descriptions[0].binding = 0;
|
||||||
|
descriptions[0].location = 0;
|
||||||
|
descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
descriptions[0].offset = offsetof(Vertex, pos);
|
||||||
|
|
||||||
|
// Bind color
|
||||||
|
descriptions[1].binding = 0;
|
||||||
|
descriptions[1].location = 1;
|
||||||
|
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
||||||
|
descriptions[1].offset = offsetof(Vertex, color);
|
||||||
|
|
||||||
|
return descriptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelManager::owner_counter::owner_counter(const owner_counter& other) : counter(other.counter.load()), model(other.model)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int ModelManager::FNV1aHash(const char* buf)
|
||||||
|
{
|
||||||
|
unsigned int h_val = 0x811c9dc5;
|
||||||
|
|
||||||
|
while (*buf)
|
||||||
|
{
|
||||||
|
h_val ^= static_cast<unsigned int>(*buf++);
|
||||||
|
h_val *= 0x01000193;
|
||||||
|
}
|
||||||
|
|
||||||
|
return h_val;
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelManager::ModelManager(VkPhysicalDevice physical_device, VkDevice device):
|
||||||
|
physical_device_(physical_device),
|
||||||
|
device_(device)
|
||||||
|
{}
|
||||||
|
|
||||||
|
ModelManager::~ModelManager()
|
||||||
|
{
|
||||||
|
models.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
ModelManager::StaticModel* ModelManager::LoadModel(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name.empty())
|
||||||
|
return nullptr;
|
||||||
|
unsigned int hash = FNV1aHash(name.c_str());
|
||||||
|
auto counter = models.find(hash);
|
||||||
|
if (counter != models.cend())
|
||||||
|
{
|
||||||
|
++counter->second.counter;
|
||||||
|
return counter->second.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
Loging::Log("Load new model: " + name);
|
||||||
|
|
||||||
|
std::vector<Vertex> vertices;
|
||||||
|
std::vector<uint32_t> indices;
|
||||||
|
// Load model_data
|
||||||
|
|
||||||
|
owner_counter new_counter;
|
||||||
|
new_counter.counter.store(1);
|
||||||
|
new_counter.model = new StaticModel(vertices, indices, physical_device_, device_);
|
||||||
|
models.try_emplace(hash, new_counter);
|
||||||
|
return new_counter.model;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ModelManager::FreeModel(const std::string& name)
|
||||||
|
{
|
||||||
|
if (name.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
unsigned int hash = FNV1aHash(name.c_str());
|
||||||
|
auto counter = models.find(hash);
|
||||||
|
--counter->second.counter;
|
||||||
|
|
||||||
|
StaticModel* model = counter->second.model;
|
||||||
|
if (counter->second.counter.load() == 0)
|
||||||
|
{
|
||||||
|
Loging::Log("Free model: " + name);
|
||||||
|
models.erase(hash);
|
||||||
|
delete model;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,57 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <unordered_map>
|
||||||
|
#include <string>
|
||||||
|
#include <atomic>
|
||||||
|
#include <glm/vec3.hpp>
|
||||||
|
|
||||||
|
#include <vulkan/vulkan.h>
|
||||||
|
|
||||||
|
class ModelManager
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct Vertex
|
||||||
|
{
|
||||||
|
glm::vec3 pos, color;
|
||||||
|
static VkVertexInputBindingDescription get_binding_description();
|
||||||
|
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
||||||
|
|
||||||
|
};
|
||||||
|
class StaticModel
|
||||||
|
{
|
||||||
|
VkPhysicalDevice physical_device_;
|
||||||
|
VkDevice device_;
|
||||||
|
VkBuffer vertex_buffer_;
|
||||||
|
VkBuffer index_buffer_;
|
||||||
|
|
||||||
|
|
||||||
|
public:
|
||||||
|
StaticModel(const std::vector<Vertex>& vertices, const std::vector<uint32_t>& indices,
|
||||||
|
VkPhysicalDevice physical_device, VkDevice device);
|
||||||
|
~StaticModel();
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct owner_counter
|
||||||
|
{
|
||||||
|
std::atomic_ullong counter;
|
||||||
|
StaticModel* model;
|
||||||
|
|
||||||
|
owner_counter() = default;
|
||||||
|
owner_counter(const owner_counter& other);
|
||||||
|
};
|
||||||
|
|
||||||
|
private:
|
||||||
|
VkPhysicalDevice physical_device_;
|
||||||
|
VkDevice device_;
|
||||||
|
std::unordered_map<unsigned int, owner_counter> models;
|
||||||
|
|
||||||
|
static unsigned int FNV1aHash (const char *buf);
|
||||||
|
|
||||||
|
public:
|
||||||
|
ModelManager(VkPhysicalDevice physical_device, VkDevice device);
|
||||||
|
~ModelManager();
|
||||||
|
|
||||||
|
StaticModel* LoadModel(const std::string& name);
|
||||||
|
void FreeModel(const std::string& name);
|
||||||
|
};
|
||||||
+143
-237
@@ -1,25 +1,29 @@
|
|||||||
#include "UwURenderEngine.hpp"
|
#include "UwURenderEngine.hpp"
|
||||||
|
|
||||||
#include <array>
|
#include <array>
|
||||||
#include <queue>
|
|
||||||
#include <set>
|
#include <set>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
#include <chrono>
|
#include <chrono>
|
||||||
|
|
||||||
|
#include <glm/gtc/matrix_transform.hpp>
|
||||||
|
|
||||||
|
#include "GPU_GarbageCollector.h"
|
||||||
|
#include "../Game/Actors/Camera.hpp"
|
||||||
#include "Core/CoreInstance.hpp"
|
#include "Core/CoreInstance.hpp"
|
||||||
#include "Log/Log.hpp"
|
#include "Log/Log.hpp"
|
||||||
|
|
||||||
#include "Game/GameInstance.hpp"
|
#include "Game/GameInstance.hpp"
|
||||||
#include "Game/World/World.hpp"
|
#include "Game/World/World.hpp"
|
||||||
#include "Game/Actors/Mesh/Mesh.hpp"
|
#include "../Game/Actors/Mesh/Mesh.hpp"
|
||||||
|
#include "DeviceFunctions/DeviceFunctions.hpp"
|
||||||
#include "GLFW/glfw3.h"
|
|
||||||
|
|
||||||
const std::vector<const char*> UwURenderEngine::deviceExtensions = {
|
const std::vector<const char*> UwURenderEngine::deviceExtensions = {
|
||||||
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
VK_KHR_SWAPCHAIN_EXTENSION_NAME
|
||||||
};
|
};
|
||||||
|
|
||||||
|
RENDER_ENGINE_FACTORY_GENERATE(UwURenderEngine)
|
||||||
|
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
static VKAPI_ATTR VkBool32 VKAPI_CALL debugCallback(
|
||||||
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
VkDebugUtilsMessageSeverityFlagBitsEXT messageSeverity,
|
||||||
@@ -48,14 +52,14 @@ UwURenderEngine::SwapchainSupportDetails UwURenderEngine::query_swapchain_detail
|
|||||||
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities);
|
vkGetPhysicalDeviceSurfaceCapabilitiesKHR(physical_device_, surface_, &details.capabilities);
|
||||||
|
|
||||||
uint32_t surface_format_cnt = 0;
|
uint32_t surface_format_cnt = 0;
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr));
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, nullptr))
|
||||||
details.formats.resize(surface_format_cnt);
|
details.formats.resize(surface_format_cnt);
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data()));
|
VK_CHECK(vkGetPhysicalDeviceSurfaceFormatsKHR(physical_device_, surface_, &surface_format_cnt, details.formats.data()))
|
||||||
|
|
||||||
uint32_t present_modes_cnt = 0;
|
uint32_t present_modes_cnt = 0;
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr));
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, nullptr))
|
||||||
details.present_modes.resize(surface_format_cnt);
|
details.present_modes.resize(surface_format_cnt);
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data()));
|
VK_CHECK(vkGetPhysicalDeviceSurfacePresentModesKHR(physical_device_, surface_, &present_modes_cnt, details.present_modes.data()))
|
||||||
|
|
||||||
return details;
|
return details;
|
||||||
}
|
}
|
||||||
@@ -72,33 +76,6 @@ std::vector<const char*> UwURenderEngine::get_required_extensions()
|
|||||||
return extensions;
|
return extensions;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkVertexInputBindingDescription UwURenderEngine::Vertex::get_binding_description()
|
|
||||||
{
|
|
||||||
VkVertexInputBindingDescription description;
|
|
||||||
description.binding = 0;
|
|
||||||
description.stride = sizeof(Vertex);
|
|
||||||
description.inputRate = VK_VERTEX_INPUT_RATE_VERTEX;
|
|
||||||
return description;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::array<VkVertexInputAttributeDescription, 2> UwURenderEngine::Vertex::get_vertex_attribute_descriptions()
|
|
||||||
{
|
|
||||||
std::array<VkVertexInputAttributeDescription, 2> descriptions;
|
|
||||||
// Bind vertex loc
|
|
||||||
descriptions[0].binding = 0;
|
|
||||||
descriptions[0].location = 0;
|
|
||||||
descriptions[0].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
descriptions[0].offset = offsetof(Vertex, pos);
|
|
||||||
|
|
||||||
// Bind color
|
|
||||||
descriptions[1].binding = 0;
|
|
||||||
descriptions[1].location = 1;
|
|
||||||
descriptions[1].format = VK_FORMAT_R32G32B32_SFLOAT;
|
|
||||||
descriptions[1].offset = offsetof(Vertex, color);
|
|
||||||
|
|
||||||
return descriptions;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool UwURenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface)
|
bool UwURenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR surface)
|
||||||
{
|
{
|
||||||
VkPhysicalDeviceProperties device_properties;
|
VkPhysicalDeviceProperties device_properties;
|
||||||
@@ -108,7 +85,7 @@ bool UwURenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR s
|
|||||||
|
|
||||||
try {
|
try {
|
||||||
// Ловить исключения имеет смысыл только здесь
|
// Ловить исключения имеет смысыл только здесь
|
||||||
QueueFamilyIndices indices = find_queue_family_indices(device, surface);
|
find_queue_family_indices(device, surface);
|
||||||
} catch (...) {
|
} catch (...) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@@ -119,9 +96,9 @@ bool UwURenderEngine::is_device_suitable(VkPhysicalDevice device, VkSurfaceKHR s
|
|||||||
bool UwURenderEngine::check_device_extensions_support(VkPhysicalDevice device)
|
bool UwURenderEngine::check_device_extensions_support(VkPhysicalDevice device)
|
||||||
{
|
{
|
||||||
uint32_t extension_count;
|
uint32_t extension_count;
|
||||||
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr));
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, nullptr))
|
||||||
std::vector<VkExtensionProperties> available_extensions(extension_count);
|
std::vector<VkExtensionProperties> available_extensions(extension_count);
|
||||||
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data()));
|
VK_CHECK(vkEnumerateDeviceExtensionProperties(device, nullptr, &extension_count, available_extensions.data()))
|
||||||
|
|
||||||
for (const auto& extension : deviceExtensions)
|
for (const auto& extension : deviceExtensions)
|
||||||
{
|
{
|
||||||
@@ -155,49 +132,60 @@ UwURenderEngine::QueueFamilyIndices UwURenderEngine::find_queue_family_indices(V
|
|||||||
if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
if (family_properties[i].queueFlags & VK_QUEUE_GRAPHICS_BIT)
|
||||||
{
|
{
|
||||||
queue_family_indices.graphics_family = i;
|
queue_family_indices.graphics_family = i;
|
||||||
|
queue_family_indices.is_find_graphics_family = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue_family_indices.graphics_family.has_value() == false)
|
if (queue_family_indices.is_find_graphics_family == false)
|
||||||
throw std::runtime_error("Failed to find a graphics queue family");
|
throw std::runtime_error("Failed to find a graphics queue family");
|
||||||
|
|
||||||
// Find present
|
// Find present
|
||||||
VkBool32 present_support = false;
|
VkBool32 present_support = false;
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family.value(), surface, &present_support));
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, queue_family_indices.graphics_family, surface, &present_support))
|
||||||
// Если графическая очередь поддерживет презентацию кадров, то используем её
|
// Если графическая очередь поддерживет презентацию кадров, то используем её
|
||||||
if (present_support == VK_TRUE)
|
if (present_support == VK_TRUE)
|
||||||
|
{
|
||||||
queue_family_indices.present_family = queue_family_indices.graphics_family;
|
queue_family_indices.present_family = queue_family_indices.graphics_family;
|
||||||
|
queue_family_indices.is_find_present_family = true;
|
||||||
|
}
|
||||||
// иначе ищем другую подходящую очередь
|
// иначе ищем другую подходящую очередь
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||||
{
|
{
|
||||||
present_support = false;
|
present_support = false;
|
||||||
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support));
|
VK_CHECK(vkGetPhysicalDeviceSurfaceSupportKHR(physical_device, i, surface, &present_support))
|
||||||
if (present_support == VK_TRUE)
|
if (present_support == VK_TRUE)
|
||||||
{
|
{
|
||||||
queue_family_indices.present_family = i;
|
queue_family_indices.present_family = i;
|
||||||
|
queue_family_indices.is_find_present_family = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queue_family_indices.present_family.has_value() == false)
|
if (queue_family_indices.is_find_present_family == false)
|
||||||
throw std::runtime_error("Failed to find a present queue family");
|
throw std::runtime_error("Failed to find a present queue family");
|
||||||
|
|
||||||
// С начала пытаемся найти очередь специалезированную
|
// С начала пытаемся найти очередь специалезированную
|
||||||
// для копирования отличную от графической
|
// для копирования отличную от графической
|
||||||
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
for(uint32_t i = 0; i < family_properties.size(); ++i)
|
||||||
{
|
{
|
||||||
if (i == queue_family_indices.graphics_family.value())
|
if (i == queue_family_indices.graphics_family)
|
||||||
continue;
|
continue;
|
||||||
if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
if (family_properties[i].queueFlags & VK_QUEUE_TRANSFER_BIT)
|
||||||
|
{
|
||||||
queue_family_indices.transfer_family = i;
|
queue_family_indices.transfer_family = i;
|
||||||
|
queue_family_indices.is_find_transfer_family = true;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Если не находим, то используем графическую
|
// Если не находим, то используем графическую
|
||||||
if (queue_family_indices.transfer_family.has_value() == false)
|
if (queue_family_indices.is_find_transfer_family == false)
|
||||||
|
{
|
||||||
queue_family_indices.transfer_family = queue_family_indices.graphics_family;
|
queue_family_indices.transfer_family = queue_family_indices.graphics_family;
|
||||||
|
queue_family_indices.is_find_transfer_family = true;
|
||||||
|
}
|
||||||
return queue_family_indices;
|
return queue_family_indices;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -221,24 +209,6 @@ VkPresentModeKHR UwURenderEngine::choose_present_mode(const std::vector<VkPresen
|
|||||||
return VK_PRESENT_MODE_FIFO_KHR;
|
return VK_PRESENT_MODE_FIFO_KHR;
|
||||||
}
|
}
|
||||||
|
|
||||||
VkExtent2D UwURenderEngine::choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window)
|
|
||||||
{
|
|
||||||
// Здесь вычисляется допустимое разрешение рендера
|
|
||||||
if (capabilities.currentExtent.width != std::numeric_limits<uint32_t>::max())
|
|
||||||
return capabilities.currentExtent;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
int width, height;
|
|
||||||
glfwGetFramebufferSize(window, &width, &height);
|
|
||||||
VkExtent2D actualExtent = {
|
|
||||||
static_cast<uint32_t>(width),
|
|
||||||
static_cast<uint32_t>(height)
|
|
||||||
};
|
|
||||||
actualExtent.width = std::max(capabilities.minImageExtent.width, std::min(capabilities.maxImageExtent.width, actualExtent.width));
|
|
||||||
return actualExtent;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
VkShaderModule UwURenderEngine::create_shader_module(const std::string& code) const
|
VkShaderModule UwURenderEngine::create_shader_module(const std::string& code) const
|
||||||
{
|
{
|
||||||
VkShaderModuleCreateInfo shader_module_info{};
|
VkShaderModuleCreateInfo shader_module_info{};
|
||||||
@@ -247,47 +217,10 @@ VkShaderModule UwURenderEngine::create_shader_module(const std::string& code) co
|
|||||||
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(code.c_str());
|
shader_module_info.pCode = reinterpret_cast<const uint32_t*>(code.c_str());
|
||||||
|
|
||||||
VkShaderModule shader_module;
|
VkShaderModule shader_module;
|
||||||
VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module));
|
VK_CHECK(vkCreateShaderModule(device_, &shader_module_info, nullptr, &shader_module))
|
||||||
return shader_module;
|
return shader_module;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
|
||||||
VkBuffer* buffer, const std::vector<uint32_t>& queue_families)
|
|
||||||
{
|
|
||||||
VkBufferCreateInfo buffer_info{};
|
|
||||||
buffer_info.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
|
||||||
buffer_info.size = size;
|
|
||||||
buffer_info.usage = usage;
|
|
||||||
|
|
||||||
if (queue_families.size() > 1)
|
|
||||||
{
|
|
||||||
buffer_info.sharingMode = VK_SHARING_MODE_CONCURRENT;
|
|
||||||
buffer_info.queueFamilyIndexCount = static_cast<uint32_t>(queue_families.size());
|
|
||||||
buffer_info.pQueueFamilyIndices = queue_families.data();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
buffer_info.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
|
|
||||||
buffer_info.queueFamilyIndexCount = 0;
|
|
||||||
buffer_info.pQueueFamilyIndices = nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
VK_CHECK(vkCreateBuffer(device_, &buffer_info, nullptr, buffer));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UwURenderEngine::allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory)
|
|
||||||
{
|
|
||||||
VkMemoryRequirements requirements{};
|
|
||||||
vkGetBufferMemoryRequirements(device_, buffer, &requirements);
|
|
||||||
|
|
||||||
VkMemoryAllocateInfo allocate_info{};
|
|
||||||
allocate_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO;
|
|
||||||
allocate_info.allocationSize = requirements.size;
|
|
||||||
allocate_info.memoryTypeIndex = find_memory_type(requirements.memoryTypeBits, property);
|
|
||||||
|
|
||||||
VK_CHECK(vkAllocateMemory(device_, &allocate_info, nullptr, device_memory));
|
|
||||||
}
|
|
||||||
|
|
||||||
void UwURenderEngine::create_instance()
|
void UwURenderEngine::create_instance()
|
||||||
{
|
{
|
||||||
std::vector<const char*> extensions = get_required_extensions();
|
std::vector<const char*> extensions = get_required_extensions();
|
||||||
@@ -319,9 +252,9 @@ void UwURenderEngine::create_instance()
|
|||||||
debug_messenger_create_info.pfnUserCallback = &debugCallback;
|
debug_messenger_create_info.pfnUserCallback = &debugCallback;
|
||||||
instance_create_info.pNext = &debug_messenger_create_info;
|
instance_create_info.pNext = &debug_messenger_create_info;
|
||||||
#endif
|
#endif
|
||||||
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_));
|
VK_CHECK(vkCreateInstance(&instance_create_info, nullptr, &instance_))
|
||||||
#ifdef _DEBUG
|
#ifdef _DEBUG
|
||||||
VK_CHECK(enable_layer_validation(&debug_messenger_create_info));
|
VK_CHECK(enable_layer_validation(&debug_messenger_create_info))
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -329,9 +262,9 @@ void UwURenderEngine::pick_physical_device()
|
|||||||
{
|
{
|
||||||
uint32_t device_count = 0;
|
uint32_t device_count = 0;
|
||||||
std::vector<VkPhysicalDevice> devices;
|
std::vector<VkPhysicalDevice> devices;
|
||||||
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr));
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, nullptr))
|
||||||
devices.resize(device_count);
|
devices.resize(device_count);
|
||||||
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()));
|
VK_CHECK(vkEnumeratePhysicalDevices(instance_, &device_count, devices.data()))
|
||||||
|
|
||||||
for (const auto& device : devices)
|
for (const auto& device : devices)
|
||||||
{
|
{
|
||||||
@@ -356,9 +289,9 @@ void UwURenderEngine::create_logical_device()
|
|||||||
VkPhysicalDeviceFeatures device_features{};
|
VkPhysicalDeviceFeatures device_features{};
|
||||||
|
|
||||||
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
std::vector<VkDeviceQueueCreateInfo> queue_create_infos;
|
||||||
std::set<uint32_t> unique_queue_families = {indices.graphics_family.value(),
|
std::set<uint32_t> unique_queue_families = {indices.graphics_family,
|
||||||
indices.present_family.value(),
|
indices.present_family,
|
||||||
indices.transfer_family.value()};
|
indices.transfer_family};
|
||||||
|
|
||||||
float queue_priority = 1.0f;
|
float queue_priority = 1.0f;
|
||||||
VkDeviceQueueCreateInfo device_queue_create_info{};
|
VkDeviceQueueCreateInfo device_queue_create_info{};
|
||||||
@@ -390,10 +323,10 @@ void UwURenderEngine::create_logical_device()
|
|||||||
device_create_info.ppEnabledLayerNames = nullptr;
|
device_create_info.ppEnabledLayerNames = nullptr;
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_));
|
VK_CHECK(vkCreateDevice(physical_device_, &device_create_info, nullptr, &device_))
|
||||||
vkGetDeviceQueue(device_, indices.graphics_family.value(), 0, &graphics_queue_);
|
vkGetDeviceQueue(device_, indices.graphics_family, 0, &graphics_queue_);
|
||||||
vkGetDeviceQueue(device_, indices.present_family.value(), 0, &present_queue_);
|
vkGetDeviceQueue(device_, indices.present_family, 0, &present_queue_);
|
||||||
vkGetDeviceQueue(device_, indices.transfer_family.value(), 0, &transfer_queue_);
|
vkGetDeviceQueue(device_, indices.transfer_family, 0, &transfer_queue_);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_swapchain()
|
void UwURenderEngine::create_swapchain()
|
||||||
@@ -401,7 +334,7 @@ void UwURenderEngine::create_swapchain()
|
|||||||
SwapchainSupportDetails swapchain_support = query_swapchain_details();
|
SwapchainSupportDetails swapchain_support = query_swapchain_details();
|
||||||
VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats);
|
VkSurfaceFormatKHR surface_format = choose_surface_format(swapchain_support.formats);
|
||||||
VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, VK_PRESENT_MODE_MAILBOX_KHR);
|
VkPresentModeKHR present_mode = choose_present_mode(swapchain_support.present_modes, VK_PRESENT_MODE_MAILBOX_KHR);
|
||||||
VkExtent2D extent = choose_extent(swapchain_support.capabilities, get_window());
|
VkExtent2D extent = DeviceFunctions::choose_extent(swapchain_support.capabilities, get_window());
|
||||||
|
|
||||||
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
uint32_t image_count = swapchain_support.capabilities.minImageCount + 1;
|
||||||
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount)
|
if (swapchain_support.capabilities.maxImageCount > 0 && image_count > swapchain_support.capabilities.maxImageCount)
|
||||||
@@ -423,9 +356,9 @@ void UwURenderEngine::create_swapchain()
|
|||||||
swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
|
swapchain_create_info.oldSwapchain = VK_NULL_HANDLE;
|
||||||
|
|
||||||
QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_);
|
QueueFamilyIndices family_indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
const std::set<uint32_t> queue_family_indices = { family_indices.graphics_family.value(),
|
const std::set<uint32_t> queue_family_indices = { family_indices.graphics_family,
|
||||||
family_indices.present_family.value(),
|
family_indices.present_family,
|
||||||
family_indices.transfer_family.value() };
|
family_indices.transfer_family };
|
||||||
std::vector<uint32_t> arr_families;
|
std::vector<uint32_t> arr_families;
|
||||||
if (queue_family_indices.size() > 1)
|
if (queue_family_indices.size() > 1)
|
||||||
{
|
{
|
||||||
@@ -445,7 +378,7 @@ void UwURenderEngine::create_swapchain()
|
|||||||
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
swapchain_create_info.pQueueFamilyIndices = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_));
|
VK_CHECK(vkCreateSwapchainKHR(device_, &swapchain_create_info, nullptr, &swapchain_))
|
||||||
|
|
||||||
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr);
|
vkGetSwapchainImagesKHR(device_, swapchain_, &image_count, nullptr);
|
||||||
swapchain_images_.resize(image_count);
|
swapchain_images_.resize(image_count);
|
||||||
@@ -475,7 +408,7 @@ void UwURenderEngine::create_image_views()
|
|||||||
for (uint32_t i = 0; i < swapchain_images_.size(); ++i)
|
for (uint32_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
{
|
{
|
||||||
image_view_info.image = swapchain_images_[i];
|
image_view_info.image = swapchain_images_[i];
|
||||||
VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i]));
|
VK_CHECK(vkCreateImageView(device_, &image_view_info, nullptr, &swapchain_image_views_[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -517,12 +450,12 @@ void UwURenderEngine::create_render_pass()
|
|||||||
render_pass_info.dependencyCount = 1;
|
render_pass_info.dependencyCount = 1;
|
||||||
render_pass_info.pDependencies = &dependency;
|
render_pass_info.pDependencies = &dependency;
|
||||||
|
|
||||||
VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_));
|
VK_CHECK(vkCreateRenderPass(device_, &render_pass_info, nullptr, &render_pass_))
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_description_set_layout()
|
void UwURenderEngine::create_description_set_layout()
|
||||||
{
|
{
|
||||||
VkDescriptorSetLayoutBinding ubo_layout_binding{};
|
VkDescriptorSetLayoutBinding ubo_layout_binding;
|
||||||
ubo_layout_binding.binding = 0;
|
ubo_layout_binding.binding = 0;
|
||||||
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
ubo_layout_binding.descriptorType = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
ubo_layout_binding.descriptorCount = 1;
|
ubo_layout_binding.descriptorCount = 1;
|
||||||
@@ -534,7 +467,7 @@ void UwURenderEngine::create_description_set_layout()
|
|||||||
ubo_layout_info.bindingCount = 1;
|
ubo_layout_info.bindingCount = 1;
|
||||||
ubo_layout_info.pBindings = &ubo_layout_binding;
|
ubo_layout_info.pBindings = &ubo_layout_binding;
|
||||||
|
|
||||||
VK_CHECK(vkCreateDescriptorSetLayout(device_, &ubo_layout_info, nullptr, &ubo_layout_binding_));
|
VK_CHECK(vkCreateDescriptorSetLayout(device_, &ubo_layout_info, nullptr, &ubo_layout_binding_))
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_uniform_buffers()
|
void UwURenderEngine::create_uniform_buffers()
|
||||||
@@ -547,8 +480,8 @@ void UwURenderEngine::create_uniform_buffers()
|
|||||||
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
{
|
{
|
||||||
const VkDeviceSize size = sizeof(UniformBufferObject);
|
const VkDeviceSize size = sizeof(UniformBufferObject);
|
||||||
create_buffer(size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, &uniform_buffers_[i], arr_indices);
|
uniform_buffers_[i] = DeviceFunctions::create_buffer(device_, size, VK_BUFFER_USAGE_UNIFORM_BUFFER_BIT, arr_indices);
|
||||||
allocate_memory(uniform_buffers_[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &uniform_buffers_memory_[i]);
|
uniform_buffers_memory_[i] = DeviceFunctions::allocate_device_memory(physical_device_, device_, uniform_buffers_[i], VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
vkBindBufferMemory(device_, uniform_buffers_[i], uniform_buffers_memory_[i], 0);
|
vkBindBufferMemory(device_, uniform_buffers_[i], uniform_buffers_memory_[i], 0);
|
||||||
|
|
||||||
vkMapMemory(device_, uniform_buffers_memory_[i], 0, size, 0, &uniform_buffers_mapped_[i]);
|
vkMapMemory(device_, uniform_buffers_memory_[i], 0, size, 0, &uniform_buffers_mapped_[i]);
|
||||||
@@ -557,7 +490,7 @@ void UwURenderEngine::create_uniform_buffers()
|
|||||||
|
|
||||||
void UwURenderEngine::create_descriptor_pool()
|
void UwURenderEngine::create_descriptor_pool()
|
||||||
{
|
{
|
||||||
VkDescriptorPoolSize pool_size{};
|
VkDescriptorPoolSize pool_size;
|
||||||
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
pool_size.type = VK_DESCRIPTOR_TYPE_UNIFORM_BUFFER;
|
||||||
pool_size.descriptorCount = static_cast<uint32_t>(swapchain_images_.size());
|
pool_size.descriptorCount = static_cast<uint32_t>(swapchain_images_.size());
|
||||||
|
|
||||||
@@ -567,7 +500,7 @@ void UwURenderEngine::create_descriptor_pool()
|
|||||||
descriptor_pool_info.pPoolSizes = &pool_size;
|
descriptor_pool_info.pPoolSizes = &pool_size;
|
||||||
descriptor_pool_info.maxSets = static_cast<uint32_t>(swapchain_images_.size());
|
descriptor_pool_info.maxSets = static_cast<uint32_t>(swapchain_images_.size());
|
||||||
|
|
||||||
VK_CHECK(vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr, &descriptor_pool_));
|
VK_CHECK(vkCreateDescriptorPool(device_, &descriptor_pool_info, nullptr, &descriptor_pool_))
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_descriptor_sets()
|
void UwURenderEngine::create_descriptor_sets()
|
||||||
@@ -580,7 +513,7 @@ void UwURenderEngine::create_descriptor_sets()
|
|||||||
descriptor_set_allocate_info.pSetLayouts = layouts.data();
|
descriptor_set_allocate_info.pSetLayouts = layouts.data();
|
||||||
|
|
||||||
descriptor_sets_.resize(swapchain_images_.size());
|
descriptor_sets_.resize(swapchain_images_.size());
|
||||||
VK_CHECK(vkAllocateDescriptorSets(device_, &descriptor_set_allocate_info, descriptor_sets_.data()));
|
VK_CHECK(vkAllocateDescriptorSets(device_, &descriptor_set_allocate_info, descriptor_sets_.data()))
|
||||||
|
|
||||||
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
{
|
{
|
||||||
@@ -646,8 +579,8 @@ void UwURenderEngine::create_graphics_pipeline()
|
|||||||
dynamic_state_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
dynamic_state_info.dynamicStateCount = static_cast<uint32_t>(dynamic_states.size());
|
||||||
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
dynamic_state_info.pDynamicStates = dynamic_states.data();
|
||||||
|
|
||||||
VkVertexInputBindingDescription binding_description = Vertex::get_binding_description();
|
VkVertexInputBindingDescription binding_description = ModelManager::Vertex::get_binding_description();
|
||||||
std::array<VkVertexInputAttributeDescription, 2> attribute_descriptions = Vertex::get_vertex_attribute_descriptions();
|
std::array<VkVertexInputAttributeDescription, 2> attribute_descriptions = ModelManager::Vertex::get_vertex_attribute_descriptions();
|
||||||
|
|
||||||
VkPipelineVertexInputStateCreateInfo vertex_input_info{};
|
VkPipelineVertexInputStateCreateInfo vertex_input_info{};
|
||||||
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
vertex_input_info.sType = VK_STRUCTURE_TYPE_PIPELINE_VERTEX_INPUT_STATE_CREATE_INFO;
|
||||||
@@ -720,7 +653,7 @@ void UwURenderEngine::create_graphics_pipeline()
|
|||||||
pipeline_layout_info.setLayoutCount = 1;
|
pipeline_layout_info.setLayoutCount = 1;
|
||||||
pipeline_layout_info.pSetLayouts = &ubo_layout_binding_;
|
pipeline_layout_info.pSetLayouts = &ubo_layout_binding_;
|
||||||
|
|
||||||
VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_));
|
VK_CHECK(vkCreatePipelineLayout(device_, &pipeline_layout_info, nullptr, &pipeline_layout_))
|
||||||
|
|
||||||
VkGraphicsPipelineCreateInfo graphics_pipeline_info{};
|
VkGraphicsPipelineCreateInfo graphics_pipeline_info{};
|
||||||
graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
graphics_pipeline_info.sType = VK_STRUCTURE_TYPE_GRAPHICS_PIPELINE_CREATE_INFO;
|
||||||
@@ -740,7 +673,7 @@ void UwURenderEngine::create_graphics_pipeline()
|
|||||||
graphics_pipeline_info.basePipelineHandle = nullptr;
|
graphics_pipeline_info.basePipelineHandle = nullptr;
|
||||||
graphics_pipeline_info.basePipelineIndex = -1;
|
graphics_pipeline_info.basePipelineIndex = -1;
|
||||||
|
|
||||||
VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_));
|
VK_CHECK(vkCreateGraphicsPipelines(device_, nullptr, 1, &graphics_pipeline_info, nullptr, &graphics_pipeline_))
|
||||||
|
|
||||||
vkDestroyShaderModule(device_, vertex_shader, nullptr);
|
vkDestroyShaderModule(device_, vertex_shader, nullptr);
|
||||||
vkDestroyShaderModule(device_, fragment_shader, nullptr);
|
vkDestroyShaderModule(device_, fragment_shader, nullptr);
|
||||||
@@ -761,7 +694,7 @@ void UwURenderEngine::create_framebuffers()
|
|||||||
for (size_t i = 0; i < framebuffers_.size(); ++i)
|
for (size_t i = 0; i < framebuffers_.size(); ++i)
|
||||||
{
|
{
|
||||||
framebuffer_info.pAttachments = &swapchain_image_views_[i];
|
framebuffer_info.pAttachments = &swapchain_image_views_[i];
|
||||||
VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i]));
|
VK_CHECK(vkCreateFramebuffer(device_, &framebuffer_info, nullptr, &framebuffers_[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -771,31 +704,17 @@ void UwURenderEngine::create_command_pool()
|
|||||||
|
|
||||||
VkCommandPoolCreateInfo command_pool_info{};
|
VkCommandPoolCreateInfo command_pool_info{};
|
||||||
command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
command_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
||||||
command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family.value();
|
command_pool_info.queueFamilyIndex = queue_family_indices.graphics_family;
|
||||||
command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
command_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
||||||
|
|
||||||
VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_));
|
VK_CHECK(vkCreateCommandPool(device_, &command_pool_info, nullptr, &command_pool_))
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t UwURenderEngine::find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const
|
|
||||||
{
|
|
||||||
VkPhysicalDeviceMemoryProperties memory_properties{};
|
|
||||||
vkGetPhysicalDeviceMemoryProperties(physical_device_, &memory_properties);
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < memory_properties.memoryTypeCount; ++i)
|
|
||||||
{
|
|
||||||
if (typeFilter & (1 << i) && (memory_properties.memoryTypes[i].propertyFlags & properties) == properties)
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw std::runtime_error("failed to find suitable memory type!");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<uint32_t> UwURenderEngine::get_unique_family_indices(const QueueFamilyIndices& indices)
|
std::vector<uint32_t> UwURenderEngine::get_unique_family_indices(const QueueFamilyIndices& indices)
|
||||||
{
|
{
|
||||||
std::set<uint32_t> set_indices = {indices.graphics_family.value(),
|
std::set<uint32_t> set_indices = {indices.graphics_family,
|
||||||
indices.present_family.value(),
|
indices.present_family,
|
||||||
indices.transfer_family.value()};
|
indices.transfer_family};
|
||||||
|
|
||||||
std::vector<uint32_t> arr_indices;
|
std::vector<uint32_t> arr_indices;
|
||||||
arr_indices.reserve(set_indices.size());
|
arr_indices.reserve(set_indices.size());
|
||||||
@@ -810,27 +729,27 @@ void UwURenderEngine::allocate_vertex_buffer()
|
|||||||
|
|
||||||
|
|
||||||
std::vector<uint32_t> arr_indices = get_unique_family_indices(indices);
|
std::vector<uint32_t> arr_indices = get_unique_family_indices(indices);
|
||||||
std::vector<uint32_t> transfer_index = {indices.transfer_family.value()};
|
std::vector<uint32_t> transfer_index = {indices.transfer_family};
|
||||||
|
|
||||||
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE;
|
|
||||||
|
|
||||||
VkDeviceSize size_buffer = sizeof(vertices_[0]) * vertices_.size();
|
VkDeviceSize size_buffer = sizeof(vertices_[0]) * vertices_.size();
|
||||||
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index);
|
VkBuffer staging_buffer = DeviceFunctions::create_buffer(device_, size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory);
|
transfer_index);
|
||||||
|
VkDeviceMemory staging_buffer_memory = DeviceFunctions::allocate_device_memory(
|
||||||
|
physical_device_, device_, staging_buffer,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
|
|
||||||
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, &vertex_buffer_, arr_indices);
|
vertex_buffer_ = DeviceFunctions::create_buffer(device_, size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_VERTEX_BUFFER_BIT, arr_indices);
|
||||||
allocate_memory(vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &vertex_buffer_memory_);
|
vertex_buffer_memory_ = DeviceFunctions::allocate_device_memory(physical_device_, device_, vertex_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
|
|
||||||
VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0));
|
VK_CHECK(vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0))
|
||||||
VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0));
|
VK_CHECK(vkBindBufferMemory(device_, vertex_buffer_, vertex_buffer_memory_, 0))
|
||||||
|
|
||||||
void* data;
|
void* data;
|
||||||
VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data));
|
VK_CHECK(vkMapMemory(device_, staging_buffer_memory, 0, size_buffer, 0, &data))
|
||||||
memcpy(data, vertices_.data(), size_buffer);
|
memcpy(data, vertices_.data(), size_buffer);
|
||||||
vkUnmapMemory(device_, staging_buffer_memory);
|
vkUnmapMemory(device_, staging_buffer_memory);
|
||||||
|
|
||||||
copy_memory(staging_buffer, vertex_buffer_, size_buffer);
|
DeviceFunctions::device_memcpy(device_, indices.transfer_family, staging_buffer, vertex_buffer_, size_buffer);
|
||||||
|
|
||||||
vkFreeMemory(device_, staging_buffer_memory, nullptr);
|
vkFreeMemory(device_, staging_buffer_memory, nullptr);
|
||||||
vkDestroyBuffer(device_, staging_buffer, nullptr);
|
vkDestroyBuffer(device_, staging_buffer, nullptr);
|
||||||
@@ -839,18 +758,19 @@ void UwURenderEngine::allocate_vertex_buffer()
|
|||||||
void UwURenderEngine::allocate_index_buffer()
|
void UwURenderEngine::allocate_index_buffer()
|
||||||
{
|
{
|
||||||
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
||||||
std::set<uint32_t> set_indices = {indices.graphics_family.value(),
|
std::set<uint32_t> set_indices = {indices.graphics_family,
|
||||||
indices.present_family.value(),
|
indices.present_family,
|
||||||
indices.transfer_family.value()};
|
indices.transfer_family};
|
||||||
|
|
||||||
std::vector<uint32_t> arr_indices = get_unique_family_indices(indices);
|
std::vector<uint32_t> arr_indices = get_unique_family_indices(indices);
|
||||||
std::vector<uint32_t> transfer_index = {indices.transfer_family.value()};
|
std::vector<uint32_t> transfer_index = {indices.transfer_family};
|
||||||
|
|
||||||
VkBuffer staging_buffer = VK_NULL_HANDLE;
|
|
||||||
VkDeviceMemory staging_buffer_memory = VK_NULL_HANDLE;
|
|
||||||
VkDeviceSize size_buffer = sizeof(indices_[0]) * indices_.size();
|
VkDeviceSize size_buffer = sizeof(indices_[0]) * indices_.size();
|
||||||
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT, &staging_buffer, transfer_index);
|
VkBuffer staging_buffer = DeviceFunctions::create_buffer(device_, size_buffer, VK_BUFFER_USAGE_TRANSFER_SRC_BIT,
|
||||||
allocate_memory(staging_buffer, VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT, &staging_buffer_memory);
|
transfer_index);
|
||||||
|
VkDeviceMemory staging_buffer_memory = DeviceFunctions::allocate_device_memory(
|
||||||
|
physical_device_, device_, staging_buffer,
|
||||||
|
VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT);
|
||||||
vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0);
|
vkBindBufferMemory(device_, staging_buffer, staging_buffer_memory, 0);
|
||||||
|
|
||||||
void* data;
|
void* data;
|
||||||
@@ -858,61 +778,16 @@ void UwURenderEngine::allocate_index_buffer()
|
|||||||
memcpy(data, indices_.data(), size_buffer);
|
memcpy(data, indices_.data(), size_buffer);
|
||||||
vkUnmapMemory(device_, staging_buffer_memory);
|
vkUnmapMemory(device_, staging_buffer_memory);
|
||||||
|
|
||||||
create_buffer(size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, &index_buffer_, arr_indices);
|
index_buffer_ = DeviceFunctions::create_buffer(device_, size_buffer, VK_BUFFER_USAGE_TRANSFER_DST_BIT | VK_BUFFER_USAGE_INDEX_BUFFER_BIT, arr_indices);
|
||||||
allocate_memory(index_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT, &index_buffer_memory_);
|
index_buffer_memory_ = DeviceFunctions::allocate_device_memory(physical_device_, device_, index_buffer_, VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT);
|
||||||
vkBindBufferMemory(device_, index_buffer_, index_buffer_memory_, 0);
|
vkBindBufferMemory(device_, index_buffer_, index_buffer_memory_, 0);
|
||||||
|
|
||||||
copy_memory(staging_buffer, index_buffer_, size_buffer);
|
DeviceFunctions::device_memcpy(device_, indices.transfer_family,staging_buffer, index_buffer_, size_buffer);
|
||||||
|
|
||||||
vkDestroyBuffer(device_, staging_buffer, nullptr);
|
vkDestroyBuffer(device_, staging_buffer, nullptr);
|
||||||
vkFreeMemory(device_, staging_buffer_memory, nullptr);
|
vkFreeMemory(device_, staging_buffer_memory, nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size)
|
|
||||||
{
|
|
||||||
QueueFamilyIndices indices = find_queue_family_indices(physical_device_, surface_);
|
|
||||||
VkCommandPool copy_pool;
|
|
||||||
VkCommandPoolCreateInfo copy_pool_info{};
|
|
||||||
copy_pool_info.sType = VK_STRUCTURE_TYPE_COMMAND_POOL_CREATE_INFO;
|
|
||||||
copy_pool_info.queueFamilyIndex = indices.transfer_family.value();
|
|
||||||
copy_pool_info.flags = VK_COMMAND_POOL_CREATE_RESET_COMMAND_BUFFER_BIT;
|
|
||||||
VK_CHECK(vkCreateCommandPool(device_, ©_pool_info, nullptr, ©_pool));
|
|
||||||
|
|
||||||
VkCommandBufferAllocateInfo command_buffer_allocate_info{};
|
|
||||||
command_buffer_allocate_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_ALLOCATE_INFO;
|
|
||||||
command_buffer_allocate_info.commandPool = copy_pool;
|
|
||||||
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
|
||||||
command_buffer_allocate_info.commandBufferCount = 1;
|
|
||||||
|
|
||||||
VkCommandBuffer copy_buffer;
|
|
||||||
VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, ©_buffer));
|
|
||||||
|
|
||||||
VkCommandBufferBeginInfo command_buffer_begin_info{};
|
|
||||||
command_buffer_begin_info.sType = VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO;
|
|
||||||
command_buffer_begin_info.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT;
|
|
||||||
|
|
||||||
VK_CHECK(vkBeginCommandBuffer(copy_buffer, &command_buffer_begin_info));
|
|
||||||
|
|
||||||
VkBufferCopy buffer_copy{};
|
|
||||||
buffer_copy.srcOffset = 0;
|
|
||||||
buffer_copy.dstOffset = 0;
|
|
||||||
buffer_copy.size = size;
|
|
||||||
vkCmdCopyBuffer(copy_buffer, src, dst, 1, &buffer_copy);
|
|
||||||
|
|
||||||
vkEndCommandBuffer(copy_buffer);
|
|
||||||
|
|
||||||
VkSubmitInfo submit_info{};
|
|
||||||
submit_info.sType = VK_STRUCTURE_TYPE_SUBMIT_INFO;
|
|
||||||
submit_info.commandBufferCount = 1;
|
|
||||||
submit_info.pCommandBuffers = ©_buffer;
|
|
||||||
|
|
||||||
vkQueueSubmit(transfer_queue_, 1, &submit_info, VK_NULL_HANDLE);
|
|
||||||
vkQueueWaitIdle(transfer_queue_);
|
|
||||||
|
|
||||||
vkFreeCommandBuffers(device_, copy_pool, 1, ©_buffer);
|
|
||||||
vkDestroyCommandPool(device_, copy_pool, nullptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void UwURenderEngine::allocate_command_buffers()
|
void UwURenderEngine::allocate_command_buffers()
|
||||||
{
|
{
|
||||||
command_buffers_.resize(swapchain_images_.size());
|
command_buffers_.resize(swapchain_images_.size());
|
||||||
@@ -923,7 +798,7 @@ void UwURenderEngine::allocate_command_buffers()
|
|||||||
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
command_buffer_allocate_info.level = VK_COMMAND_BUFFER_LEVEL_PRIMARY;
|
||||||
command_buffer_allocate_info.commandBufferCount = static_cast<uint32_t>(command_buffers_.size());
|
command_buffer_allocate_info.commandBufferCount = static_cast<uint32_t>(command_buffers_.size());
|
||||||
|
|
||||||
VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data()));
|
VK_CHECK(vkAllocateCommandBuffers(device_, &command_buffer_allocate_info, command_buffers_.data()))
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_sync_objects()
|
void UwURenderEngine::create_sync_objects()
|
||||||
@@ -941,9 +816,9 @@ void UwURenderEngine::create_sync_objects()
|
|||||||
|
|
||||||
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
for (size_t i = 0; i < swapchain_images_.size(); ++i)
|
||||||
{
|
{
|
||||||
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i]));
|
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &image_available_semaphores_[i]))
|
||||||
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i]));
|
VK_CHECK(vkCreateSemaphore(device_, &semaphore_info, nullptr, &render_finished_semaphores_[i]))
|
||||||
VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i]));
|
VK_CHECK(vkCreateFence(device_, &fence_info, nullptr, &in_flight_fences_[i]))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -951,7 +826,7 @@ void UwURenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint
|
|||||||
{
|
{
|
||||||
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;
|
||||||
VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info));
|
VK_CHECK(vkBeginCommandBuffer(command_buffer, &command_buffer_begin_info))
|
||||||
|
|
||||||
constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
constexpr VkClearValue clear_color = {{{0.0f, 0.0f, 0.0f, 1.0f}}};
|
||||||
VkRenderPassBeginInfo render_pass_begin_info{};
|
VkRenderPassBeginInfo render_pass_begin_info{};
|
||||||
@@ -991,17 +866,33 @@ void UwURenderEngine::record_command_buffer(VkCommandBuffer command_buffer, uint
|
|||||||
vkCmdDrawIndexed(command_buffer, static_cast<uint32_t>(indices_.size()), 1, 0, 0, 0);
|
vkCmdDrawIndexed(command_buffer, static_cast<uint32_t>(indices_.size()), 1, 0, 0, 0);
|
||||||
|
|
||||||
vkCmdEndRenderPass(command_buffer);
|
vkCmdEndRenderPass(command_buffer);
|
||||||
VK_CHECK(vkEndCommandBuffer(command_buffer));
|
VK_CHECK(vkEndCommandBuffer(command_buffer))
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::update_uniform_buffer(uint32_t current_frame)
|
void UwURenderEngine::update_uniform_buffer(uint32_t current_frame) const
|
||||||
{
|
{
|
||||||
|
glm::vec3 eye{0, 0, 0};
|
||||||
|
glm::vec3 center{0, 0, 0};
|
||||||
|
glm::vec3 up{0, 1, 0};
|
||||||
|
if (active_camera_.expired() == false)
|
||||||
|
{
|
||||||
|
std::shared_ptr<Camera> camera = active_camera_.lock();
|
||||||
|
Vector3D loc = camera->GetActorLocate();
|
||||||
|
eye = {loc.x, loc.y, loc.z};
|
||||||
|
|
||||||
|
Vector3D rot = camera->GetActorRotate();
|
||||||
|
glm::vec3 direction{glm::cos(rot.x)*glm::cos(rot.y), glm::sin(rot.x)*glm::cos(rot.y), glm::sin(rot.y)};
|
||||||
|
center = eye + direction;
|
||||||
|
|
||||||
|
up = {0, glm::sin(rot.z), glm::cos(rot.z)};
|
||||||
|
}
|
||||||
|
|
||||||
static auto start_time = std::chrono::high_resolution_clock::now();
|
static auto start_time = std::chrono::high_resolution_clock::now();
|
||||||
auto current_time = std::chrono::high_resolution_clock::now();
|
auto current_time = std::chrono::high_resolution_clock::now();
|
||||||
float time = std::chrono::duration_cast<std::chrono::duration<float>>(current_time - start_time).count();
|
float time = std::chrono::duration_cast<std::chrono::duration<float>>(current_time - start_time).count();
|
||||||
UniformBufferObject ubo{};
|
UniformBufferObject ubo;
|
||||||
ubo.model = glm::rotate(glm::mat4(1.0f), time * glm::radians(45.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
ubo.model = glm::rotate(glm::mat4(1.0f), /*time * glm::radians(45.0f)*/0.f, glm::vec3(0.0f, 0.0f, 1.0f));
|
||||||
ubo.view = glm::lookAt(glm::vec3(2.0f, 2.0f, 2.0f), glm::vec3(0.0f, 0.0f, 0.0f), glm::vec3(0.0f, 0.0f, 1.0f));
|
ubo.view = glm::lookAt(eye, center, up);
|
||||||
ubo.proj = glm::perspective(glm::radians(45.0f), static_cast<float>(swapchain_extent_.width) / static_cast<float>(swapchain_extent_.height), 0.1f, 256.0f);
|
ubo.proj = glm::perspective(glm::radians(45.0f), static_cast<float>(swapchain_extent_.width) / static_cast<float>(swapchain_extent_.height), 0.1f, 256.0f);
|
||||||
ubo.proj[1][1] *= -1;
|
ubo.proj[1][1] *= -1;
|
||||||
memcpy(uniform_buffers_mapped_[current_frame], &ubo, sizeof(ubo));
|
memcpy(uniform_buffers_mapped_[current_frame], &ubo, sizeof(ubo));
|
||||||
@@ -1012,13 +903,16 @@ void UwURenderEngine::draw_frame()
|
|||||||
vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX);
|
vkWaitForFences(device_, 1, &in_flight_fences_[current_frame_], VK_TRUE, UINT64_MAX);
|
||||||
vkResetFences(device_, 1, &in_flight_fences_[current_frame_]);
|
vkResetFences(device_, 1, &in_flight_fences_[current_frame_]);
|
||||||
|
|
||||||
|
// Free video memory
|
||||||
|
garbage_collector_->FreeHeap();
|
||||||
|
|
||||||
uint32_t image_index;
|
uint32_t image_index;
|
||||||
vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index);
|
vkAcquireNextImageKHR(device_, swapchain_, UINT64_MAX, image_available_semaphores_[current_frame_], VK_NULL_HANDLE, &image_index);
|
||||||
|
|
||||||
vkResetCommandBuffer(command_buffers_[current_frame_], 0);
|
vkResetCommandBuffer(command_buffers_[current_frame_], 0);
|
||||||
record_command_buffer(command_buffers_[current_frame_], image_index);
|
|
||||||
|
|
||||||
update_uniform_buffer(current_frame_);
|
update_uniform_buffer(current_frame_);
|
||||||
|
record_command_buffer(command_buffers_[current_frame_], image_index);
|
||||||
|
|
||||||
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
VkPipelineStageFlags wait_stage = VK_PIPELINE_STAGE_COLOR_ATTACHMENT_OUTPUT_BIT;
|
||||||
VkSubmitInfo submit_info{};
|
VkSubmitInfo submit_info{};
|
||||||
@@ -1031,7 +925,7 @@ void UwURenderEngine::draw_frame()
|
|||||||
submit_info.signalSemaphoreCount = 1;
|
submit_info.signalSemaphoreCount = 1;
|
||||||
submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_];
|
submit_info.pSignalSemaphores = &render_finished_semaphores_[current_frame_];
|
||||||
|
|
||||||
VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_]));
|
VK_CHECK(vkQueueSubmit(graphics_queue_, 1, &submit_info, in_flight_fences_[current_frame_]))
|
||||||
|
|
||||||
VkPresentInfoKHR present_info{};
|
VkPresentInfoKHR present_info{};
|
||||||
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
present_info.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR;
|
||||||
@@ -1044,12 +938,12 @@ void UwURenderEngine::draw_frame()
|
|||||||
|
|
||||||
vkQueuePresentKHR(present_queue_, &present_info);
|
vkQueuePresentKHR(present_queue_, &present_info);
|
||||||
|
|
||||||
current_frame_ = (current_frame_ + 1) % static_cast<int>(swapchain_images_.size());
|
current_frame_ = (current_frame_ + 1) % static_cast<unsigned int>(swapchain_images_.size());
|
||||||
}
|
}
|
||||||
|
|
||||||
void UwURenderEngine::create_surface()
|
void UwURenderEngine::create_surface()
|
||||||
{
|
{
|
||||||
VK_CHECK(glfwCreateWindowSurface(instance_, get_window(), nullptr, &surface_));
|
VK_CHECK(glfwCreateWindowSurface(instance_, get_window(), nullptr, &surface_))
|
||||||
}
|
}
|
||||||
|
|
||||||
UwURenderEngine::UwURenderEngine(CoreInstance& core):
|
UwURenderEngine::UwURenderEngine(CoreInstance& core):
|
||||||
@@ -1076,6 +970,9 @@ core_(core)
|
|||||||
allocate_command_buffers();
|
allocate_command_buffers();
|
||||||
allocate_index_buffer();
|
allocate_index_buffer();
|
||||||
create_sync_objects();
|
create_sync_objects();
|
||||||
|
|
||||||
|
garbage_collector_.reset(new GPU_GarbageCollector(device_));
|
||||||
|
model_manager_.reset(new ModelManager(physical_device_, device_));
|
||||||
}
|
}
|
||||||
|
|
||||||
UwURenderEngine::~UwURenderEngine()
|
UwURenderEngine::~UwURenderEngine()
|
||||||
@@ -1083,7 +980,7 @@ UwURenderEngine::~UwURenderEngine()
|
|||||||
vkDeviceWaitIdle(device_);
|
vkDeviceWaitIdle(device_);
|
||||||
|
|
||||||
if (index_buffer_memory_ != VK_NULL_HANDLE)
|
if (index_buffer_memory_ != VK_NULL_HANDLE)
|
||||||
vkFreeMemory(device_, index_buffer_memory_, nullptr);
|
vkFreeMemory(device_, index_buffer_memory_, nullptr);
|
||||||
|
|
||||||
if (index_buffer_ != VK_NULL_HANDLE)
|
if (index_buffer_ != VK_NULL_HANDLE)
|
||||||
vkDestroyBuffer(device_, index_buffer_, nullptr);
|
vkDestroyBuffer(device_, index_buffer_, nullptr);
|
||||||
@@ -1163,9 +1060,12 @@ UwURenderEngine::~UwURenderEngine()
|
|||||||
void UwURenderEngine::start()
|
void UwURenderEngine::start()
|
||||||
{
|
{
|
||||||
World* world = core_.GetGameInstance()->GetWorld();
|
World* world = core_.GetGameInstance()->GetWorld();
|
||||||
std::vector<UType::object_ptr<Mesh>> meshes = world->GetActorsByClass<Mesh>();
|
std::vector<std::weak_ptr<Mesh>> meshes = world->GetActorsByClass<Mesh>();
|
||||||
for (auto& i : meshes)
|
for (auto& i : meshes)
|
||||||
i->load_model(i->GetModelName());
|
{
|
||||||
|
std::shared_ptr<Mesh> mesh = i.lock();
|
||||||
|
mesh->load_model(mesh->GetModelName());
|
||||||
|
}
|
||||||
|
|
||||||
while (!glfwWindowShouldClose(get_window()))
|
while (!glfwWindowShouldClose(get_window()))
|
||||||
{
|
{
|
||||||
@@ -1179,3 +1079,9 @@ void UwURenderEngine::stop_render() const
|
|||||||
if (!glfwWindowShouldClose(get_window()))
|
if (!glfwWindowShouldClose(get_window()))
|
||||||
glfwSetWindowShouldClose(get_window(), true);
|
glfwSetWindowShouldClose(get_window(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UwURenderEngine::SetActiveCamera(std::weak_ptr<Camera> camera)
|
||||||
|
{
|
||||||
|
std::scoped_lock lock(m_active_camera_);
|
||||||
|
active_camera_ = camera;
|
||||||
|
}
|
||||||
+28
-33
@@ -1,42 +1,37 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "RenderEngineBase.hpp"
|
#include "RenderEngineBase.hpp"
|
||||||
|
#include "ModelManager.hpp"
|
||||||
|
|
||||||
#include <optional>
|
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
#define GLM_FORCE_RADIANS
|
#define GLM_FORCE_RADIANS
|
||||||
|
#include <mutex>
|
||||||
#include <glm/glm.hpp>
|
#include <glm/glm.hpp>
|
||||||
#include <glm/gtc/matrix_transform.hpp>
|
|
||||||
|
|
||||||
#ifdef _DEBUG
|
class Camera;
|
||||||
#include <assert.h>
|
class GPU_GarbageCollector;
|
||||||
#define VK_CHECK(res) assert(res == VK_SUCCESS)
|
|
||||||
#else
|
#define GET_RENDER_ENGINE static_cast<UwURenderEngine*>(GetWorld()->GetGameInstance().GetCore().GetRenderEngine())
|
||||||
#define VK_CHECK(res) if ((res) != VK_SUCCESS) throw std::runtime_error("Vulkan error: " + std::to_string(res))
|
|
||||||
#endif
|
|
||||||
|
|
||||||
class UwURenderEngine : public RenderEngineBase
|
class UwURenderEngine : public RenderEngineBase
|
||||||
{
|
{
|
||||||
struct QueueFamilyIndices
|
struct QueueFamilyIndices
|
||||||
{
|
{
|
||||||
std::optional<uint32_t> graphics_family;
|
uint32_t graphics_family = 0;
|
||||||
std::optional<uint32_t> present_family;
|
uint32_t present_family = 0;
|
||||||
std::optional<uint32_t> transfer_family;
|
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
|
struct SwapchainSupportDetails
|
||||||
{
|
{
|
||||||
VkSurfaceCapabilitiesKHR capabilities;
|
|
||||||
std::vector<VkSurfaceFormatKHR> formats;
|
std::vector<VkSurfaceFormatKHR> formats;
|
||||||
std::vector<VkPresentModeKHR> present_modes;
|
std::vector<VkPresentModeKHR> present_modes;
|
||||||
};
|
VkSurfaceCapabilitiesKHR capabilities;
|
||||||
struct Vertex
|
|
||||||
{
|
|
||||||
glm::vec3 pos;
|
|
||||||
glm::vec3 color;
|
|
||||||
static VkVertexInputBindingDescription get_binding_description();
|
|
||||||
static std::array<VkVertexInputAttributeDescription, 2> get_vertex_attribute_descriptions();
|
|
||||||
};
|
};
|
||||||
struct UniformBufferObject {
|
struct UniformBufferObject {
|
||||||
glm::mat4 model;
|
glm::mat4 model;
|
||||||
@@ -44,7 +39,7 @@ class UwURenderEngine : public RenderEngineBase
|
|||||||
glm::mat4 proj;
|
glm::mat4 proj;
|
||||||
};
|
};
|
||||||
|
|
||||||
const std::vector<Vertex> vertices_ = {
|
const std::vector<ModelManager::Vertex> vertices_ = {
|
||||||
{{-0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
{{-0.5f, -0.5f, 0.5f}, {1.0f, 0.0f, 0.0f}},
|
||||||
{{0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
{{0.5f, -0.5f, 0.5f}, {0.0f, 1.0f, 0.0f}},
|
||||||
{{0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
{{0.5f, 0.5f, 0.5f}, {0.0f, 0.0f, 1.0f}},
|
||||||
@@ -64,10 +59,15 @@ class UwURenderEngine : public RenderEngineBase
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const std::vector<const char*> deviceExtensions;
|
static const std::vector<const char*> deviceExtensions;
|
||||||
|
|
||||||
int current_frame_ = 0;
|
// Counting frame from the beginning
|
||||||
|
unsigned int current_frame_ = 0;
|
||||||
|
|
||||||
CoreInstance& core_;
|
CoreInstance& core_;
|
||||||
|
std::shared_ptr<ModelManager> model_manager_;
|
||||||
|
std::shared_ptr<GPU_GarbageCollector> garbage_collector_;
|
||||||
|
std::weak_ptr<Camera> active_camera_;
|
||||||
|
std::mutex m_active_camera_;
|
||||||
|
|
||||||
VkInstance instance_ = VK_NULL_HANDLE;
|
VkInstance instance_ = VK_NULL_HANDLE;
|
||||||
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
VkSurfaceKHR surface_ = VK_NULL_HANDLE;
|
||||||
@@ -114,13 +114,8 @@ class UwURenderEngine : public RenderEngineBase
|
|||||||
static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface);
|
static QueueFamilyIndices find_queue_family_indices(VkPhysicalDevice physical_device, VkSurfaceKHR surface);
|
||||||
static VkSurfaceFormatKHR choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats);
|
static VkSurfaceFormatKHR choose_surface_format(const std::vector<VkSurfaceFormatKHR>& surface_formats);
|
||||||
static VkPresentModeKHR choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode);
|
static VkPresentModeKHR choose_present_mode(const std::vector<VkPresentModeKHR>& present_modes, VkPresentModeKHR desired_present_mode);
|
||||||
static VkExtent2D choose_extent(const VkSurfaceCapabilitiesKHR& capabilities, GLFWwindow* window);
|
|
||||||
VkShaderModule create_shader_module(const std::string& code) const;
|
VkShaderModule create_shader_module(const std::string& code) const;
|
||||||
void create_buffer(VkDeviceSize size, VkBufferUsageFlags usage,
|
static std::vector<uint32_t> get_unique_family_indices(const QueueFamilyIndices& indices);
|
||||||
VkBuffer* buffer, const std::vector<uint32_t>& queue_families);
|
|
||||||
void allocate_memory(VkBuffer buffer, VkMemoryPropertyFlags property, VkDeviceMemory* device_memory);
|
|
||||||
uint32_t find_memory_type(uint32_t typeFilter, VkMemoryPropertyFlags properties) const;
|
|
||||||
std::vector<uint32_t> get_unique_family_indices(const QueueFamilyIndices& indices);
|
|
||||||
|
|
||||||
void create_instance();
|
void create_instance();
|
||||||
void create_surface();
|
void create_surface();
|
||||||
@@ -141,18 +136,18 @@ class UwURenderEngine : public RenderEngineBase
|
|||||||
void allocate_vertex_buffer();
|
void allocate_vertex_buffer();
|
||||||
void allocate_index_buffer();
|
void allocate_index_buffer();
|
||||||
|
|
||||||
void copy_memory(VkBuffer src, VkBuffer dst, VkDeviceSize size);
|
|
||||||
void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const;
|
void record_command_buffer(VkCommandBuffer command_buffer, uint32_t image_index) const;
|
||||||
void update_uniform_buffer(uint32_t current_frame);
|
void update_uniform_buffer(uint32_t current_frame) const;
|
||||||
void draw_frame();
|
void draw_frame();
|
||||||
public:
|
public:
|
||||||
// Can throw the exception
|
// Can throw the exception
|
||||||
UwURenderEngine(CoreInstance& core);
|
explicit UwURenderEngine(CoreInstance& core);
|
||||||
~UwURenderEngine() override;
|
~UwURenderEngine() override;
|
||||||
|
|
||||||
void start() override;
|
void start() override;
|
||||||
void stop_render() const override;
|
void stop_render() const override;
|
||||||
|
|
||||||
};
|
std::shared_ptr<ModelManager> GetModelManager() const { return model_manager_; }
|
||||||
|
|
||||||
RENDER_ENGINE_FACTORY_GENERATE(UwURenderEngine)
|
void SetActiveCamera(std::weak_ptr<Camera> camera);
|
||||||
|
};
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,4 +1,5 @@
|
|||||||
@echo off
|
@echo off
|
||||||
cd build
|
cd build
|
||||||
|
cmake -DBUILD_MODE=All ..
|
||||||
cmake --build . --config Release
|
cmake --build . --config Release
|
||||||
pause
|
pause
|
||||||
@@ -3,9 +3,4 @@ mkdir .\build
|
|||||||
cd build
|
cd build
|
||||||
cmake -DBUILD_MODE=Engine ..
|
cmake -DBUILD_MODE=Engine ..
|
||||||
cmake --build . --config Release
|
cmake --build . --config Release
|
||||||
cd ..
|
|
||||||
mkdir ".\build\bin\include"
|
|
||||||
robocopy ".\Core" ".\build\bin\include\Core" *.h *.hpp /S
|
|
||||||
robocopy ".\Delegate" ".\build\bin\include\Delegate" *.h *.hpp /S
|
|
||||||
robocopy ".\FastRTTI" ".\build\bin\include\FastRTTI" *.h *.hpp /S
|
|
||||||
pause
|
pause
|
||||||
+1
-1
Submodule glfw updated: 8e15281d34...b00e6a8a88
Reference in New Issue
Block a user