Merge pull request 'Label Update' (#184) from LabelUpdate into master

Reviewed-on: https://git.madvoxel.net/OpenVulkano/OpenVulkano/pulls/184
This commit is contained in:
Georg Hagen
2025-01-07 13:43:31 +01:00
66 changed files with 1064 additions and 1077 deletions

View File

@@ -31,10 +31,9 @@ namespace OpenVulkano
class BillboardExampleAppImpl final : public BillboardExampleApp class BillboardExampleAppImpl final : public BillboardExampleApp
{ {
public: public:
void Init() override void Init() override
{ {
auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); auto engineConfig = EngineConfiguration::GetEngineConfiguration();
engineConfig->SetPreferFramebufferFormatSRGB(false); engineConfig->SetPreferFramebufferFormatSRGB(false);
engineConfig->SetFpsCap(0); // monitor's refresh rate engineConfig->SetFpsCap(0); // monitor's refresh rate
engineConfig->SetVSync(true); engineConfig->SetVSync(true);
@@ -44,17 +43,17 @@ namespace OpenVulkano
m_cam.Init(70, 16, 9, 0.1f, 100); m_cam.Init(70, 16, 9, 0.1f, 100);
m_scene.SetCamera(&m_cam); m_scene.SetCamera(&m_cam);
m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboardFromSinglePoint"); m_quadBillboardShader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/billboardFromSinglePoint");
m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::GEOMETRY, "Shader/billboardFromSinglePoint"); m_quadBillboardShader.AddShaderProgram(ShaderProgramType::GEOMETRY, "Shader/billboardFromSinglePoint");
m_quadBillboardShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basic"); m_quadBillboardShader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basic");
m_quadBillboardShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); m_quadBillboardShader.AddVertexInputDescription(Vertex::GetVertexInputDescription());
m_quadBillboardShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); m_quadBillboardShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
m_quadBillboardShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4); m_quadBillboardShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4);
m_quadBillboardShader.topology = Topology::POINT_LIST; m_quadBillboardShader.topology = Topology::POINT_LIST;
m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboard"); m_shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/billboard");
m_shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basic"); m_shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basic");
m_shader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); m_shader.AddVertexInputDescription(Vertex::GetVertexInputDescription());
m_shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); m_shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
m_shader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4); m_shader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4);
m_shader.cullMode = CullMode::NONE; m_shader.cullMode = CullMode::NONE;
@@ -85,13 +84,13 @@ namespace OpenVulkano
geo->vertices[0].color = glm::vec4(1, 1, 1, 1); geo->vertices[0].color = glm::vec4(1, 1, 1, 1);
else else
geo->vertices[0].color = glm::vec4(1, 0, 0, 1); geo->vertices[0].color = glm::vec4(1, 0, 0, 1);
m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, std::rand() % 5))); m_nodesPool[i].SetMatrix(translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, std::rand() % 5)));
m_drawablesPool[i].Init(&m_quadBillboardShader, geo, &m_texturedMat, &m_uniBuffer); m_drawablesPool[i].Init(&m_quadBillboardShader, geo, &m_texturedMat, &m_uniBuffer);
} }
else else
{ {
*geo = GeometryFactory::MakePyramid(1, 1, glm::vec4(0, 1, 0, 1)); *geo = GeometryFactory::MakePyramid(1, 1, glm::vec4(0, 1, 0, 1));
m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, -std::rand() % 10))); m_nodesPool[i].SetMatrix(translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, -std::rand() % 10)));
m_drawablesPool[i].Init(&m_shader, geo, &m_mat, &m_uniBuffer); m_drawablesPool[i].Init(&m_shader, geo, &m_mat, &m_uniBuffer);
} }
m_scene.GetRoot()->AddChild(&m_nodesPool[i]); m_scene.GetRoot()->AddChild(&m_nodesPool[i]);
@@ -105,8 +104,8 @@ namespace OpenVulkano
m_camController.SetPosition({ 0, 0, 5 }); m_camController.SetPosition({ 0, 0, 5 });
m_camController.SetBoostFactor(5); m_camController.SetBoostFactor(5);
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo = std::shared_ptr<UI::PerformanceInfo> m_perfInfo =
std::make_shared<OpenVulkano::Scene::UI::PerformanceInfo>(); std::make_shared<UI::PerformanceInfo>();
m_ui.AddElement(m_perfInfo); m_ui.AddElement(m_perfInfo);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
} }
@@ -125,7 +124,7 @@ namespace OpenVulkano
BillboardControlBlock m_bbContolBlock; BillboardControlBlock m_bbContolBlock;
PerspectiveCamera m_cam; PerspectiveCamera m_cam;
UniformBuffer m_uniBuffer; UniformBuffer m_uniBuffer;
OpenVulkano::FreeCamCameraController m_camController; FreeCamCameraController m_camController;
Material m_mat; Material m_mat;
Material m_texturedMat; Material m_texturedMat;
Shader m_shader; Shader m_shader;
@@ -133,9 +132,9 @@ namespace OpenVulkano
std::vector<SimpleDrawable> m_drawablesPool; std::vector<SimpleDrawable> m_drawablesPool;
std::vector<Node> m_nodesPool; std::vector<Node> m_nodesPool;
Vector3f_SIMD m_position = { 0, 0, -10 }; Vector3f_SIMD m_position = { 0, 0, -10 };
OpenVulkano::Scene::UI::SimpleUi m_ui; UI::SimpleUi m_ui;
std::vector<Geometry> m_geo; std::vector<Geometry> m_geo;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo; std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
}; };
IGraphicsApp* BillboardExampleApp::Create() { return new BillboardExampleAppImpl(); } IGraphicsApp* BillboardExampleApp::Create() { return new BillboardExampleAppImpl(); }

View File

@@ -36,7 +36,7 @@ namespace OpenVulkano
{ {
OpenVulkano::Scene::Scene scene; OpenVulkano::Scene::Scene scene;
PerspectiveCamera cam; PerspectiveCamera cam;
OpenVulkano::FreeCamCameraController camController; FreeCamCameraController camController;
Material mat; Material mat;
Shader shader; Shader shader;
std::vector<SimpleDrawable> drawablesPool; std::vector<SimpleDrawable> drawablesPool;
@@ -44,13 +44,13 @@ namespace OpenVulkano
Vector3f_SIMD position = {0, 0, -10}; Vector3f_SIMD position = {0, 0, -10};
std::vector<Geometry> m_geos; std::vector<Geometry> m_geos;
OpenVulkano::Scene::UI::SimpleUi m_ui; UI::SimpleUi m_ui;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo; std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
public: public:
void Init() override void Init() override
{ {
auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); auto engineConfig = EngineConfiguration::GetEngineConfiguration();
//engineConfig->SetNumThreads(4); //engineConfig->SetNumThreads(4);
engineConfig->SetPreferFramebufferFormatSRGB(false); engineConfig->SetPreferFramebufferFormatSRGB(false);
@@ -58,9 +58,9 @@ namespace OpenVulkano
scene.Init(); scene.Init();
cam.Init(70, 16, 9, 0.1f, 100); cam.Init(70, 16, 9, 0.1f, 100);
scene.SetCamera(&cam); scene.SetCamera(&cam);
shader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/basic"); shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/basic");
shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basic"); shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basic");
shader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); shader.AddVertexInputDescription(Vertex::GetVertexInputDescription());
drawablesPool.resize(GEOS); drawablesPool.resize(GEOS);
m_geos.reserve(GEOS); m_geos.reserve(GEOS);
for (uint32_t i = 0; i < GEOS; i++) for (uint32_t i = 0; i < GEOS; i++)
@@ -78,7 +78,7 @@ namespace OpenVulkano
scene.GetRoot()->AddChild(&nodesPool[i]); scene.GetRoot()->AddChild(&nodesPool[i]);
if (i < DYNAMIC) nodesPool[i].SetUpdateFrequency(UpdateFrequency::Always); if (i < DYNAMIC) nodesPool[i].SetUpdateFrequency(UpdateFrequency::Always);
nodesPool[i].AddDrawable(&drawablesPool[std::rand() % GEOS]); nodesPool[i].AddDrawable(&drawablesPool[std::rand() % GEOS]);
nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1), Vector3f((std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5))); nodesPool[i].SetMatrix(translate(glm::mat4x4(1), Vector3f((std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5)));
} }
GetGraphicsAppManager()->GetRenderer()->SetScene(&scene); GetGraphicsAppManager()->GetRenderer()->SetScene(&scene);
@@ -87,7 +87,7 @@ namespace OpenVulkano
camController.SetDefaultKeybindings(); camController.SetDefaultKeybindings();
camController.SetPosition({0, 0, 10}); camController.SetPosition({0, 0, 10});
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo = std::make_shared<OpenVulkano::Scene::UI::PerformanceInfo>(); std::shared_ptr<UI::PerformanceInfo> m_perfInfo = std::make_shared<UI::PerformanceInfo>();
m_ui.AddElement(m_perfInfo); m_ui.AddElement(m_perfInfo);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
} }
@@ -96,7 +96,7 @@ namespace OpenVulkano
{ {
for (uint32_t i = 0; i < DYNAMIC; i++) for (uint32_t i = 0; i < DYNAMIC; i++)
{ {
nodesPool[i].SetMatrix(glm::translate(glm::mat4x4(1), glm::vec3((std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5))); nodesPool[i].SetMatrix(translate(glm::mat4x4(1), glm::vec3((std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5, (std::rand() % 10000) / 1000.0f - 5)));
} }
camController.Tick(); camController.Tick();

View File

@@ -7,14 +7,8 @@
#include "LabelDrawableExampleApp.hpp" #include "LabelDrawableExampleApp.hpp"
#include "Scene/Scene.hpp" #include "Scene/Scene.hpp"
#include "Scene/Shader/Shader.hpp" #include "Scene/Shader/Shader.hpp"
#include "Scene/Geometry.hpp"
#include "Scene/TextDrawable.hpp" #include "Scene/TextDrawable.hpp"
#include "Scene/GeometryFactory.hpp"
#include "Scene/Material.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/SimpleDrawable.hpp"
#include "Scene/UI/PerformanceInfo.hpp" #include "Scene/UI/PerformanceInfo.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Scene/Prefabs/LabelDrawable.hpp" #include "Scene/Prefabs/LabelDrawable.hpp"
#include "Input/InputManager.hpp" #include "Input/InputManager.hpp"
#include "Host/GraphicsAppManager.hpp" #include "Host/GraphicsAppManager.hpp"
@@ -23,9 +17,7 @@
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Base/EngineConfiguration.hpp" #include "Base/EngineConfiguration.hpp"
#include "Controller/FreeCamCameraController.hpp" #include "Controller/FreeCamCameraController.hpp"
#include "Image/ImageLoaderPng.hpp"
#include "Scene/SdfFontAtlasGenerator.hpp" #include "Scene/SdfFontAtlasGenerator.hpp"
#include "Scene/IFontAtlasGenerator.hpp"
#include <filesystem> #include <filesystem>
#ifdef _WIN32 #ifdef _WIN32
@@ -45,9 +37,7 @@ namespace OpenVulkano
void Init() override void Init() override
{ {
auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); EngineConfiguration::GetEngineConfiguration()->SetPreferFramebufferFormatSRGB(false);
engineConfig->SetNumThreads(1);
engineConfig->SetPreferFramebufferFormatSRGB(false);
std::srand(1); // Fix seed for random numbers std::srand(1); // Fix seed for random numbers
m_scene.Init(); m_scene.Init();
@@ -63,7 +53,6 @@ namespace OpenVulkano
m_nodesPool.resize(N); m_nodesPool.resize(N);
m_drawablesPool.reserve(N); m_drawablesPool.reserve(N);
BillboardControlBlock billboardSettings;
LabelDrawableSettings labelSettings; LabelDrawableSettings labelSettings;
for (int i = 0; i < N; i++) for (int i = 0; i < N; i++)
@@ -74,12 +63,11 @@ namespace OpenVulkano
} }
else else
{ {
labelSettings.hasRoundedCorners = (i % 2 == 0 ? 0 : 1); labelSettings.hasRoundedCorners = i & 1;
labelSettings.hasArrow = (i % 2 == 0 ? 1 : 0); labelSettings.hasArrow = i % 2 == 0;
} }
bool isBillboard = (i % 2 == 0 ? 1 : 0); labelSettings.isBillboard = i % 2 == 0;
LabelDrawable& label = m_drawablesPool.emplace_back(textDrawable.GetAtlasData(), labelSettings, isBillboard); LabelDrawable& label = m_drawablesPool.emplace_back(textDrawable.GetAtlasData(), labelSettings);
label.SetBillboardSettings(billboardSettings);
label.AddText(texts[i]); label.AddText(texts[i]);
if (i == 2) if (i == 2)
{ {
@@ -90,7 +78,7 @@ namespace OpenVulkano
} }
m_drawablesPool[i].SetIsHittable(true); m_drawablesPool[i].SetIsHittable(true);
m_scene.GetRoot()->AddChild(&m_nodesPool[i]); m_scene.GetRoot()->AddChild(&m_nodesPool[i]);
m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(-5 + std::rand() % 5, -5 + std::rand() % 5, -std::rand() % 10))); m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(5 - std::rand() % 10, 5 - std::rand() % 10, 5 - std::rand() % 10)));
m_nodesPool[i].AddDrawable(&m_drawablesPool[i]); m_nodesPool[i].AddDrawable(&m_drawablesPool[i]);
} }
@@ -100,8 +88,7 @@ namespace OpenVulkano
m_camController.SetPosition({ 0, 0, 10 }); m_camController.SetPosition({ 0, 0, 10 });
m_camController.SetBoostFactor(5); m_camController.SetBoostFactor(5);
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo = std::shared_ptr<UI::PerformanceInfo> m_perfInfo = std::make_shared<UI::PerformanceInfo>();
std::make_shared<OpenVulkano::Scene::UI::PerformanceInfo>();
m_ui.AddElement(m_perfInfo); m_ui.AddElement(m_perfInfo);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
} }
@@ -116,12 +103,12 @@ namespace OpenVulkano
private: private:
OpenVulkano::Scene::Scene m_scene; OpenVulkano::Scene::Scene m_scene;
PerspectiveCamera m_cam; PerspectiveCamera m_cam;
OpenVulkano::FreeCamCameraController m_camController; FreeCamCameraController m_camController;
std::vector<LabelDrawable> m_drawablesPool; std::vector<LabelDrawable> m_drawablesPool;
std::vector<Node> m_nodesPool; std::vector<Node> m_nodesPool;
Vector3f_SIMD m_position = { 0, 0, -10 }; Vector3f_SIMD m_position = { 0, 0, -10 };
OpenVulkano::Scene::UI::SimpleUi m_ui; UI::SimpleUi m_ui;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo; std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
}; };
IGraphicsApp* LabelDrawableExampleApp::Create() { return new LabelDrawableExampleAppImpl(); } IGraphicsApp* LabelDrawableExampleApp::Create() { return new LabelDrawableExampleAppImpl(); }

View File

@@ -17,16 +17,12 @@
#include "Scene/SimpleAnimationController.hpp" #include "Scene/SimpleAnimationController.hpp"
#include "Scene/SequenceAnimationController.hpp" #include "Scene/SequenceAnimationController.hpp"
#include "Scene/MorphableCameraController.hpp" #include "Scene/MorphableCameraController.hpp"
#include "Scene/PlaneCameraController.hpp"
#include "Scene/UI/PerformanceInfo.hpp" #include "Scene/UI/PerformanceInfo.hpp"
#include "Scene/SceneIntersectionTestController.hpp" #include "Scene/SceneIntersectionTestController.hpp"
#include "Input/InputManager.hpp"
#include "Host/GraphicsAppManager.hpp" #include "Host/GraphicsAppManager.hpp"
#include "Base/EngineConfiguration.hpp"
#include "Base/Logger.hpp" #include "Base/Logger.hpp"
#include "Controller/FreeCamCameraController.hpp" #include "Controller/FreeCamCameraController.hpp"
#include "Scene/Prefabs/LabelDrawable.hpp" #include "Scene/Prefabs/LabelDrawable.hpp"
#include "Scene/SimpleDrawable.hpp"
#include "Scene/Ray.hpp" #include "Scene/Ray.hpp"
#define USE_PLANE_CAM_CONTROL 0 #define USE_PLANE_CAM_CONTROL 0

View File

@@ -9,12 +9,8 @@
#include "Scene/Shader/Shader.hpp" #include "Scene/Shader/Shader.hpp"
#include "Scene/Geometry.hpp" #include "Scene/Geometry.hpp"
#include "Scene/TextDrawable.hpp" #include "Scene/TextDrawable.hpp"
#include "Scene/GeometryFactory.hpp"
#include "Scene/Material.hpp"
#include "Scene/Vertex.hpp" #include "Scene/Vertex.hpp"
#include "Scene/SimpleDrawable.hpp"
#include "Scene/UI/PerformanceInfo.hpp" #include "Scene/UI/PerformanceInfo.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Input/InputManager.hpp" #include "Input/InputManager.hpp"
#include "Host/GraphicsAppManager.hpp" #include "Host/GraphicsAppManager.hpp"
#include "Host/GLFW/WindowGLFW.hpp" #include "Host/GLFW/WindowGLFW.hpp"
@@ -22,9 +18,7 @@
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Base/EngineConfiguration.hpp" #include "Base/EngineConfiguration.hpp"
#include "Controller/FreeCamCameraController.hpp" #include "Controller/FreeCamCameraController.hpp"
#include "Image/ImageLoaderPng.hpp"
#include "Scene/SdfFontAtlasGenerator.hpp" #include "Scene/SdfFontAtlasGenerator.hpp"
#include "Scene/IFontAtlasGenerator.hpp"
#include "Scene/BitmapFontAtlasGenerator.hpp" #include "Scene/BitmapFontAtlasGenerator.hpp"
#include <filesystem> #include <filesystem>
@@ -45,11 +39,9 @@ namespace OpenVulkano
class TextExampleAppImpl final : public TextExampleApp class TextExampleAppImpl final : public TextExampleApp
{ {
public: public:
void Init() override void Init() override
{ {
auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration(); EngineConfiguration::GetEngineConfiguration()->SetPreferFramebufferFormatSRGB(false);
engineConfig->SetPreferFramebufferFormatSRGB(false);
std::srand(1); // Fix seed for random numbers std::srand(1); // Fix seed for random numbers
m_scene.Init(); m_scene.Init();
@@ -62,8 +54,7 @@ namespace OpenVulkano
texts.push_back(std::make_pair("\u0410\u0411\u0412\u041F", TextConfig())); texts.push_back(std::make_pair("\u0410\u0411\u0412\u041F", TextConfig()));
texts.push_back(std::make_pair("Unsupported glyphs \u1E30\u1E31 are coming", TextConfig())); texts.push_back(std::make_pair("Unsupported glyphs \u1E30\u1E31 are coming", TextConfig()));
texts.push_back(std::make_pair("This is first line\nSecond gg line\nThird G line", TextConfig())); texts.push_back(std::make_pair("This is first line\nSecond gg line\nThird G line", TextConfig()));
texts[0].second.applyBorder = true; texts[1].second.backgroundColor.a = 255;
texts[1].second.backgroundColor.a = 1;
const int N = texts.size(); const int N = texts.size();
auto& resourceLoader = ResourceLoader::GetInstance(); auto& resourceLoader = ResourceLoader::GetInstance();
@@ -73,6 +64,7 @@ namespace OpenVulkano
if constexpr (CREATE_BITMAP_ATLAS) if constexpr (CREATE_BITMAP_ATLAS)
{ {
// ReSharper disable once CppDFAUnreachableCode
std::set<uint32_t> s = BitmapFontAtlasGenerator::LoadAllGlyphs(fontPath); std::set<uint32_t> s = BitmapFontAtlasGenerator::LoadAllGlyphs(fontPath);
BitmapFontAtlasGenerator generator; BitmapFontAtlasGenerator generator;
generator.GenerateAtlas(fontPath, s); generator.GenerateAtlas(fontPath, s);
@@ -99,31 +91,26 @@ namespace OpenVulkano
if (i < texts.size()) if (i < texts.size())
{ {
t = new TextDrawable(m_atlasGenerator.GetAtlasData(), texts[textIdx].second); t = new TextDrawable(m_atlasGenerator.GetAtlasData(), texts[textIdx].second);
t->SetShader(&TextDrawable::GetSdfDefaultShader());
} }
else else
{ {
t = new TextDrawable(m_msdfAtlasGenerator.GetAtlasData(), texts[textIdx].second); t = new TextDrawable(m_msdfAtlasGenerator.GetAtlasData(), texts[textIdx].second);
t->SetShader(&TextDrawable::GetMsdfDefaultShader());
} }
#else #else
int xOffset = 0; int xOffset = 0;
if (i < N) if (i < N)
{ {
t = new TextDrawable(sdfMetadataInfo, texts[textIdx].second); t = new TextDrawable(sdfMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetSdfDefaultShader());
xOffset = -5; xOffset = -5;
} }
else if (i >= N && i < N * 2) else if (i >= N && i < N * 2)
{ {
t = new TextDrawable(msdfMetadataInfo, texts[textIdx].second); t = new TextDrawable(msdfMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetMsdfDefaultShader());
xOffset = 15; xOffset = 15;
} }
else else
{ {
t = new TextDrawable(bitmapMetadataInfo, texts[textIdx].second); t = new TextDrawable(bitmapMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetBitmapDefaultShader());
xOffset = 35; xOffset = 35;
} }
// OR use separate texture + metadata file // OR use separate texture + metadata file
@@ -139,10 +126,10 @@ namespace OpenVulkano
//TextDrawable* t = new TextDrawable(metadataInfo, &tex, texts[i].second); //TextDrawable* t = new TextDrawable(metadataInfo, &tex, texts[i].second);
#endif // MSDFGEN_AVAILABLE #endif // MSDFGEN_AVAILABLE
t->GenerateText(texts[textIdx].first); t->GenerateText(texts[textIdx].first);
m_drawablesPool[i] = t; m_drawablesPool[i].reset(t);
m_nodesPool[i].Init(); m_nodesPool[i].Init();
m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(xOffset, 2 - textIdx * 2, 0))); m_nodesPool[i].SetMatrix(Math::Utils::translate(glm::mat4x4(1.f), Vector3f(xOffset, 2 - textIdx * 2, 0)));
m_nodesPool[i].AddDrawable(m_drawablesPool[i]); m_nodesPool[i].AddDrawable(m_drawablesPool[i].get());
m_scene.GetRoot()->AddChild(&m_nodesPool[i]); m_scene.GetRoot()->AddChild(&m_nodesPool[i]);
} }
GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene); GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene);
@@ -151,8 +138,8 @@ namespace OpenVulkano
m_camController.SetPosition({ 10, 0, 15 }); m_camController.SetPosition({ 10, 0, 15 });
m_camController.SetBoostFactor(5); m_camController.SetBoostFactor(5);
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo = std::shared_ptr<UI::PerformanceInfo> m_perfInfo =
std::make_shared<OpenVulkano::Scene::UI::PerformanceInfo>(); std::make_shared<UI::PerformanceInfo>();
m_ui.AddElement(m_perfInfo); m_ui.AddElement(m_perfInfo);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
} }
@@ -164,26 +151,22 @@ namespace OpenVulkano
void Close() override void Close() override
{ {
for (SimpleDrawable* d: m_drawablesPool) m_drawablesPool.clear();
{
d->Close();
delete d;
}
} }
private: private:
OpenVulkano::Scene::Scene m_scene; OpenVulkano::Scene::Scene m_scene;
PerspectiveCamera m_cam; PerspectiveCamera m_cam;
OpenVulkano::FreeCamCameraController m_camController; FreeCamCameraController m_camController;
#ifdef MSDFGEN_AVAILABLE #ifdef MSDFGEN_AVAILABLE
SdfFontAtlasGenerator m_atlasGenerator; SdfFontAtlasGenerator m_atlasGenerator;
MsdfFontAtlasGenerator m_msdfAtlasGenerator; MsdfFontAtlasGenerator m_msdfAtlasGenerator;
#endif #endif
std::vector<SimpleDrawable*> m_drawablesPool; std::vector<std::unique_ptr<Drawable>> m_drawablesPool;
std::vector<Node> m_nodesPool; std::vector<Node> m_nodesPool;
Vector3f_SIMD m_position = { 0, 0, -10 }; Vector3f_SIMD m_position = { 0, 0, -10 };
OpenVulkano::Scene::UI::SimpleUi m_ui; UI::SimpleUi m_ui;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo; std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
}; };
IGraphicsApp* TextExampleApp::Create() { return new TextExampleAppImpl(); } IGraphicsApp* TextExampleApp::Create() { return new TextExampleAppImpl(); }

View File

@@ -16,7 +16,6 @@
#include "Input/InputManager.hpp" #include "Input/InputManager.hpp"
#include "Host/GraphicsAppManager.hpp" #include "Host/GraphicsAppManager.hpp"
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Base/EngineConfiguration.hpp"
#include "Controller/FreeCamCameraController.hpp" #include "Controller/FreeCamCameraController.hpp"
#include "Base/FrameMetadata.hpp" #include "Base/FrameMetadata.hpp"
@@ -30,14 +29,14 @@ namespace OpenVulkano
{ {
OpenVulkano::Scene::Scene scene; OpenVulkano::Scene::Scene scene;
PerspectiveCamera cam; PerspectiveCamera cam;
OpenVulkano::FreeCamCameraController camController; FreeCamCameraController camController;
Material mat; Material mat;
Shader shader; Shader shader;
SimpleDrawable drawable; SimpleDrawable drawable;
Node node; Node node;
OpenVulkano::Scene::UI::SimpleUi m_ui; UI::SimpleUi m_ui;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo; std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
public: public:
void Init() override void Init() override
@@ -45,9 +44,9 @@ namespace OpenVulkano
scene.Init(); scene.Init();
cam.Init(70, 16, 9, 0.1f, 100); cam.Init(70, 16, 9, 0.1f, 100);
scene.SetCamera(&cam); scene.SetCamera(&cam);
shader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/basic"); shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/basic");
shader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/basicTexture"); shader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/basicTexture");
shader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); shader.AddVertexInputDescription(Vertex::GetVertexInputDescription());
shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
static Geometry geo = GeometryFactory::MakeCube(); static Geometry geo = GeometryFactory::MakeCube();
mat.texture = &Texture::PLACEHOLDER; mat.texture = &Texture::PLACEHOLDER;
@@ -63,7 +62,7 @@ namespace OpenVulkano
//camController.SetDefaultKeybindings(); //camController.SetDefaultKeybindings();
camController.SetPosition({0, 0, 2}); camController.SetPosition({0, 0, 2});
m_perfInfo = std::make_shared<OpenVulkano::Scene::UI::PerformanceInfo>(); m_perfInfo = std::make_shared<UI::PerformanceInfo>();
m_ui.AddElement(m_perfInfo); m_ui.AddElement(m_perfInfo);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui); GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
} }
@@ -73,9 +72,9 @@ namespace OpenVulkano
{ {
t += CURRENT_FRAME.frameTime * 0.25; t += CURRENT_FRAME.frameTime * 0.25;
Math::Matrix4f rotation = Math::Utils::rotate(t, Math::Vector3f_SIMD{1.0f, 0.0f, 0.0f}); Matrix4f rotation = Math::Utils::rotate(t, Vector3f_SIMD{1.0f, 0.0f, 0.0f});
rotation *= Math::Utils::rotate(t, Math::Vector3f_SIMD{0.0f, 1.0f, 0.0f}); rotation *= Math::Utils::rotate(t, Vector3f_SIMD{0.0f, 1.0f, 0.0f});
rotation *= Math::Utils::rotate(t, Math::Vector3f_SIMD{0.0f, 0.0f, 1.0f}); rotation *= Math::Utils::rotate(t, Vector3f_SIMD{0.0f, 0.0f, 1.0f});
node.SetMatrix(rotation); node.SetMatrix(rotation);
camController.Tick(); camController.Tick();

View File

@@ -20,41 +20,33 @@ using namespace OpenVulkano;
int main(int argc, char** argv) int main(int argc, char** argv)
{ {
int selectedExample = -1;
if (argc == 2)
{
selectedExample = strtol(argv[1], nullptr, 10);
}
if (selectedExample < 0)
{
std::vector<std::string> examples; std::vector<std::string> examples;
for (const auto& e : EXAMPLE_APPS) for (const auto& e : EXAMPLE_APPS)
{ {
examples.emplace_back(e.first); examples.emplace_back(e.first);
} }
int selectedExample = 0;
ftxui::MenuOption option; ftxui::MenuOption option;
auto screen = ftxui::ScreenInteractive::TerminalOutput(); auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.ForceHandleCtrlC(true); bool shouldExit = true;
//screen.ForceHandleCtrlZ(true); option.on_enter = [&]() { shouldExit = false; screen.ExitLoopClosure()(); };
option.on_enter = screen.ExitLoopClosure();
auto menu = ftxui::Menu(&examples, &selectedExample, option); auto menu = ftxui::Menu(&examples, &selectedExample, option);
bool shouldExit = false;
menu |= ftxui::CatchEvent(
[&](ftxui::Event event)
{
if (event == ftxui::Event::CtrlC || event == ftxui::Event::CtrlZ)
{
screen.ExitLoopClosure()();
shouldExit = true;
}
return false;
});
screen.Loop(menu); screen.Loop(menu);
if (shouldExit) if (shouldExit) return 0;
{
return 0;
}
if (selectedExample >= examples.size()) if (selectedExample >= examples.size())
{ {
throw std::runtime_error("Invalid menu selection!"); throw std::runtime_error("Invalid menu selection!");
} }
}
std::unique_ptr<IGraphicsApp> app(EXAMPLE_APPS[selectedExample].second()); std::unique_ptr<IGraphicsApp> app(EXAMPLE_APPS[selectedExample].second());

View File

@@ -1,12 +0,0 @@
#pragma once
namespace OpenVulkano
{
class ICloseable
{
public:
virtual ~ICloseable() = default;
virtual void Close() = 0;
};
}

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#include "ITickable.hpp" #include "ITickable.hpp"
#include "ICloseable.hpp"
#include "Version.hpp" #include "Version.hpp"
#include <string> #include <string>
@@ -15,7 +14,7 @@ namespace OpenVulkano
{ {
class IGraphicsAppManager; class IGraphicsAppManager;
class IGraphicsApp : public ITickable, public ICloseable class IGraphicsApp : public ITickable
{ {
private: private:
IGraphicsAppManager* m_manager = nullptr; IGraphicsAppManager* m_manager = nullptr;
@@ -25,6 +24,7 @@ namespace OpenVulkano
virtual void Init() = 0; virtual void Init() = 0;
virtual void InitPostGraphics() {} virtual void InitPostGraphics() {}
virtual void Close() {}
virtual void CloseFinalize() {} virtual void CloseFinalize() {}
[[nodiscard]] IGraphicsAppManager* GetGraphicsAppManager() const { return m_manager; } [[nodiscard]] IGraphicsAppManager* GetGraphicsAppManager() const { return m_manager; }
void SetGraphicsAppManager(IGraphicsAppManager* manager) { m_manager = manager; } void SetGraphicsAppManager(IGraphicsAppManager* manager) { m_manager = manager; }

View File

@@ -1,7 +1,6 @@
#pragma once #pragma once
#include "ITickable.hpp" #include "ITickable.hpp"
#include "ICloseable.hpp"
#include "UI/IWindow.hpp" #include "UI/IWindow.hpp"
namespace OpenVulkano namespace OpenVulkano
@@ -12,11 +11,11 @@ namespace OpenVulkano
PlatformInitFailedException(char const* const message) : runtime_error(message) {} PlatformInitFailedException(char const* const message) : runtime_error(message) {}
}; };
class IPlatform : public ITickable, public ICloseable class IPlatform : public ITickable
{ {
public: public:
virtual void Init() = 0; virtual void Init() = 0;
virtual void Close() = 0;
virtual IWindow* MakeWindow() = 0; virtual IWindow* MakeWindow() = 0;
}; };
} }

View File

@@ -8,7 +8,6 @@
#include "IResourceManager.hpp" #include "IResourceManager.hpp"
#include "Base/ITickable.hpp" #include "Base/ITickable.hpp"
#include "Base/ICloseable.hpp"
#include "Scene/Scene.hpp" #include "Scene/Scene.hpp"
#include "Scene/UI/UI.hpp" #include "Scene/UI/UI.hpp"
#include <string> #include <string>
@@ -18,12 +17,13 @@ namespace OpenVulkano
class IWindow; class IWindow;
class IGraphicsAppManager; class IGraphicsAppManager;
class IRenderer : public ITickable, public ICloseable class IRenderer : public ITickable
{ {
public: public:
virtual ~IRenderer() = default; virtual ~IRenderer() = default;
virtual void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) = 0; virtual void Init(IGraphicsAppManager* graphicsAppManager, IWindow* window) = 0;
virtual void Close() = 0;
virtual std::string GetMainRenderDeviceName() = 0; virtual std::string GetMainRenderDeviceName() = 0;
virtual void Resize(uint32_t newWidth, uint32_t newHeight) = 0; virtual void Resize(uint32_t newWidth, uint32_t newHeight) = 0;

View File

@@ -8,7 +8,6 @@
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Base/PlatformEnums.hpp" #include "Base/PlatformEnums.hpp"
#include "Base/ICloseable.hpp"
#include <string> #include <string>
#include <stdexcept> #include <stdexcept>
@@ -36,12 +35,13 @@ namespace OpenVulkano
bool resizeable = true; bool resizeable = true;
}; };
class IWindow : public ICloseable class IWindow
{ {
public: public:
~IWindow() override = default; virtual ~IWindow() = default;
virtual void Init(RenderAPI::RenderApi renderApi) = 0; virtual void Init(RenderAPI::RenderApi renderApi) = 0;
virtual void Close() = 0;
virtual bool WindowHasBeenDestroyed() const = 0; virtual bool WindowHasBeenDestroyed() const = 0;
virtual void SetWindowHasBeenDestroyed() = 0; virtual void SetWindowHasBeenDestroyed() = 0;

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#include "Base/ITickable.hpp" #include "Base/ITickable.hpp"
#include "Base/ICloseable.hpp"
namespace OpenVulkano namespace OpenVulkano
{ {
@@ -16,7 +15,7 @@ namespace OpenVulkano
class Camera; class Camera;
} }
class CameraController : public ITickable, ICloseable class CameraController : public ITickable
{ {
Scene::Camera* m_camera; Scene::Camera* m_camera;
@@ -30,7 +29,7 @@ namespace OpenVulkano
virtual void Init(Scene::Camera* camera) { m_camera = camera; } virtual void Init(Scene::Camera* camera) { m_camera = camera; }
void Close() override { m_camera = nullptr; } virtual void Close() { m_camera = nullptr; }
void SetCamera(Scene::Camera* camera) { m_camera = camera; } void SetCamera(Scene::Camera* camera) { m_camera = camera; }

View File

@@ -105,7 +105,14 @@ namespace OpenVulkano
String& Trim() noexcept { return TrimBack().TrimFront(); } String& Trim() noexcept { return TrimBack().TrimFront(); }
[[nodiscard]] String Trim() const { return Trim(); } [[nodiscard]] String Trim() const
{
size_t start = m_string.find_first_not_of(" \t\n\r");
if (start == std::string::npos) start = 0;
size_t end = m_string.find_last_not_of(" \t\n\r");
if (end == std::string::npos) end = m_string.size();
return { m_string.substr(start, end - start + 1) };
}
String& TrimFront() noexcept String& TrimFront() noexcept
{ {

View File

@@ -7,7 +7,6 @@
#pragma once #pragma once
#include "Base/ITickable.hpp" #include "Base/ITickable.hpp"
#include "Base/ICloseable.hpp"
#include "Base/IPlatform.hpp" #include "Base/IPlatform.hpp"
#include "InputDeviceGLFW.hpp" #include "InputDeviceGLFW.hpp"
#include <array> #include <array>
@@ -18,7 +17,7 @@ namespace OpenVulkano
{ {
class WindowGLFW; class WindowGLFW;
class InputProviderGLFW final : public ITickable, public ICloseable class InputProviderGLFW final : public ITickable
{ {
friend WindowGLFW; friend WindowGLFW;
static InputProviderGLFW* INSTANCE; static InputProviderGLFW* INSTANCE;
@@ -32,7 +31,7 @@ namespace OpenVulkano
public: public:
void Init(); void Init();
void Close() override; virtual void Close();
void PreTick(); void PreTick();

View File

@@ -6,12 +6,11 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "InputKey.hpp" #include "InputKey.hpp"
namespace OpenVulkano::Input namespace OpenVulkano::Input
{ {
class InputDevice : public ICloseable class InputDevice
{ {
InputDeviceType deviceType = InputDeviceType::UNKNOWN; InputDeviceType deviceType = InputDeviceType::UNKNOWN;
int index = -1; int index = -1;
@@ -38,11 +37,11 @@ namespace OpenVulkano::Input
[[nodiscard]] virtual bool ReadButtonDown(int16_t key) const = 0; [[nodiscard]] virtual bool ReadButtonDown(int16_t key) const = 0;
public: public:
~InputDevice() override = default; virtual ~InputDevice() = default;
virtual void Tick() {} virtual void Tick() {}
void Close() override virtual void Close()
{ {
this->deviceType = InputDeviceType::UNKNOWN; this->deviceType = InputDeviceType::UNKNOWN;
this->index = -1; this->index = -1;

View File

@@ -14,101 +14,111 @@ namespace OpenVulkano::Math
/** /**
* \brief A class that represents an axis aligned bounding box * \brief A class that represents an axis aligned bounding box
*/ */
class AABB final : public Range<Math::Vector3f> template<typename T>
class AABB_T final : public Range<T>
{ {
public: public:
AABB() : Range(Math::Vector3f(INFINITY), Math::Vector3f(-INFINITY)) {} AABB_T() : Range<T>(T(INFINITY), T(-INFINITY)) {}
AABB(const Math::Vector3f& min, const Math::Vector3f& max) : Range(min, max) {} AABB_T(const T& min, const T& max) : Range<T>(min, max) {}
AABB(const Vector3f& point) : Range(point, point) AABB_T(const T& point) : Range<T>(point, point)
{} {}
AABB(const Vector3f& point, float radius) : Range(point - radius, point + radius) AABB_T(const T& point, float radius) : Range<T>(point - radius, point + radius)
{} {}
/** /**
* \brief Initiates the AABB to a single point (min=max=point) * \brief Initiates the AABB to a single point (min=max=point)
* \param point The point that should be used as min and max of the AABB * \param point The point that should be used as min and max of the AABB
*/ */
void Init(const Math::Vector3f& point) void Init(const T& point)
{ {
min = max = point; Range<T>::min = Range<T>::max = point;
} }
void Init(const Math::Vector3f& min, const Math::Vector3f& max) void Init(const T& min, const T& max)
{ {
this->min = min; this->min = min;
this->max = max; this->max = max;
} }
void Init(const Math::Vector3f& point, float radius) void Init(const T& point, float radius)
{ {
min = point - radius; Range<T>::min = point - radius;
max = point + radius; Range<T>::max = point + radius;
} }
/** /**
* \brief Initiates the AABB from some other AABB * \brief Initiates the AABB from some other AABB
* \param other The other AABB that should be copied * \param other The other AABB that should be copied
*/ */
void Init(const AABB& other) void Init(const AABB_T& other)
{ {
min = other.GetMin(); Range<T>::min = other.GetMin();
max = other.GetMax(); Range<T>::max = other.GetMax();
} }
void Grow(const Math::Vector3f& point) void Grow(const T& point)
{ {
min = Math::Utils::min(min, point); Range<T>::min = Math::Utils::min(Range<T>::min, point);
max = Math::Utils::max(max, point); Range<T>::max = Math::Utils::max(Range<T>::max, point);
} }
void Grow(const AABB& otherAABB) void Grow(const AABB_T& otherAABB)
{ {
min = Math::Utils::min(min, otherAABB.GetMin()); Range<T>::min = Math::Utils::min(Range<T>::min, otherAABB.GetMin());
max = Math::Utils::max(max, otherAABB.GetMax()); Range<T>::max = Math::Utils::max(Range<T>::max, otherAABB.GetMax());
} }
void Grow(const AABB& otherAABB, Math::Matrix4f transformation) void Grow(const AABB_T& otherAABB, Math::Matrix4f transformation)
{ {
//TODO //TODO
} }
[[nodiscard]] Math::Vector3f GetDiagonal() const [[nodiscard]] T GetDiagonal() const
{ {
return GetSize(); return Range<T>::GetSize();
} }
[[nodiscard]] Math::Vector3f GetCenter() const [[nodiscard]] T GetCenter() const
{ {
return min + (GetDiagonal() * 0.5f); return Range<T>::min + (GetDiagonal() * 0.5f);
}
[[nodiscard]] bool Covers(const AABB_T& other) const
{
return other.IsCovered(*this);
}
[[nodiscard]] bool IsCovered(const AABB_T& other) const
{
return Math::Utils::all(Math::Utils::greaterThanEqual(other.GetMax(), Range<T>::max)) && Math::Utils::all(Math::Utils::greaterThanEqual(Range<T>::min, other.GetMin()));
} }
/** /**
* \brief Checks if the AABB overlaps with an other AABB * \brief Checks if the AABB overlaps with another AABB
* \param other The other AABB that should be checked * \param other The other AABB that should be checked
* \return true if the AABB overlaps with the other, false if not * \return true if the AABB overlaps with the other, false if not
*/ */
[[nodiscard]] bool IsOverlapping(const AABB& other) const [[nodiscard]] bool IsOverlapping(const AABB_T& other) const
{ {
return !(other.min.x > max.x || other.max.x < min.x || other.min.y > max.y || return Math::Utils::all(Math::Utils::lessThanEqual(Range<T>::min, other.GetMax())) && Math::Utils::all(Math::Utils::greaterThanEqual(Range<T>::max, other.GetMin()));
other.max.y < min.y || other.min.z > max.z || other.max.z < min.z);
} }
[[nodiscard]] bool InBounds(const Math::Vector3f& position) const [[nodiscard]] bool InBounds(const T& position) const
{ {
return Math::Utils::all(Math::Utils::lessThanEqual(min, position)) && Math::Utils::all(Math::Utils::lessThanEqual(position, max)); return Math::Utils::all(Math::Utils::lessThanEqual(Range<T>::min, position)) && Math::Utils::all(Math::Utils::lessThanEqual(position, Range<T>::max));
} }
[[nodiscard]] bool Inside(const Math::Vector3f& position) const [[nodiscard]] bool Inside(const T& position) const
{ {
return Math::Utils::all(Math::Utils::lessThan(min, position)) && Math::Utils::all(Math::Utils::lessThan(position, max)); return Math::Utils::all(Math::Utils::lessThan(Range<T>::min, position)) && Math::Utils::all(Math::Utils::lessThan(position, Range<T>::max));
} }
[[nodiscard]] bool IsEmpty() const [[nodiscard]] bool IsEmpty() const
{ {
return min == Math::Vector3f(INFINITY) && max == Math::Vector3f(-INFINITY); return Range<T>::min == T(INFINITY) && Range<T>::max == T(-INFINITY);
} }
/** /**
@@ -116,8 +126,13 @@ namespace OpenVulkano::Math
*/ */
void Reset() void Reset()
{ {
min = Math::Vector3f(INFINITY); Range<T>::min = T(INFINITY);
max = Math::Vector3f(-INFINITY); Range<T>::max = T(-INFINITY);
} }
AABB_T& operator +=(const AABB_T& other) { Grow(other); return *this; }
}; };
typedef AABB_T<Vector3f> AABB;
typedef AABB_T<Vector2f> AABB2f;
} }

View File

@@ -52,6 +52,12 @@ namespace OpenVulkano::Math
} }
return angle; return angle;
} }
template<typename T>
constexpr void SortPair(T& e1, T& e2)
{
if (e1 > e2) std::swap(e1, e2);
}
} }
template<typename T> using Matrix2_SIMD = glm::tmat2x2<T, glm::aligned>; template<typename T> using Matrix2_SIMD = glm::tmat2x2<T, glm::aligned>;
@@ -177,3 +183,15 @@ glm::vec<L, float, Q> operator / (const float lhs, const glm::vec<L, T, Q>& rhs)
{ {
return lhs / glm::vec<L, float, Q>(rhs); return lhs / glm::vec<L, float, Q>(rhs);
} }
template<glm::length_t L, typename T, glm::qualifier Q, typename = std::enable_if_t<std::is_integral_v<T>>>
glm::vec<L, float, Q> operator * (const float lhs, const glm::vec<L, T, Q>& rhs)
{
return lhs * glm::vec<L, float, Q>(rhs);
}
template<glm::length_t L, typename T, glm::qualifier Q, typename = std::enable_if_t<std::is_integral_v<T>>>
glm::vec<L, float, Q> operator * (const glm::vec<L, float, Q>& lhs, const T rhs)
{
return lhs * static_cast<float>(rhs);
}

View File

@@ -12,6 +12,7 @@
#include "Scene/Texture.hpp" #include "Scene/Texture.hpp"
#include <string_view> #include <string_view>
#include <map> #include <map>
#include <magic_enum.hpp>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
@@ -34,15 +35,22 @@ namespace OpenVulkano::Scene
BITMAP, BITMAP,
UNKNOWN UNKNOWN
}; };
static constexpr std::string_view DEFAULT_FG_SHADERS[] = { "Shader/text", "Shader/msdfText" };
public: static constexpr std::string_view DEFAULT_FG_SHADERS[] = { "Shader/sdfText", "Shader/msdfText", "Shader/text" };
FontAtlasType(Type type) : m_type(type) {}
Type GetType() const { return m_type; } constexpr FontAtlasType(Type type) : m_type(type) {}
const std::string_view& GetDefaultFragmentShader() const
[[nodiscard]] constexpr Type GetType() const { return m_type; }
[[nodiscard]] constexpr auto GetName() const { return magic_enum::enum_name(m_type); }
[[nodiscard]] constexpr const std::string_view& GetDefaultFragmentShader() const
{ {
return DEFAULT_FG_SHADERS[static_cast<int>(m_type)]; return DEFAULT_FG_SHADERS[static_cast<int>(m_type)];
} }
[[nodiscard]] constexpr operator Type() const { return m_type; }
private: private:
Type m_type; Type m_type;
}; };
@@ -51,7 +59,7 @@ namespace OpenVulkano::Scene
{ {
// vertical difference between baselines // vertical difference between baselines
double lineHeight = 0; double lineHeight = 0;
int16_t atlasType = FontAtlasType::UNKNOWN; FontAtlasType atlasType = FontAtlasType::UNKNOWN;
}; };
struct AtlasData struct AtlasData
@@ -60,6 +68,8 @@ namespace OpenVulkano::Scene
AtlasMetadata meta; AtlasMetadata meta;
Unique<Image::Image> img; Unique<Image::Image> img;
Texture texture; Texture texture;
operator bool() const { return !glyphs.empty() && texture.textureBuffer; }
}; };
} }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Scene/IRayIntersectable.hpp" #include "Scene/IRayIntersectable.hpp"
#include "DrawEncoder.hpp" #include "DrawEncoder.hpp"
#include <memory> #include <memory>
@@ -27,7 +26,7 @@ namespace OpenVulkano::Scene
BACKGROUND = 0, MAIN, TRANSPARENT, POST BACKGROUND = 0, MAIN, TRANSPARENT, POST
}; };
class Drawable : public ICloseable, public IRayIntersectable class Drawable : public IRayIntersectable
{ {
std::vector<Node*> m_nodes; std::vector<Node*> m_nodes;
Scene* m_scene = nullptr; Scene* m_scene = nullptr;
@@ -43,7 +42,7 @@ namespace OpenVulkano::Scene
~Drawable() override {/* if (m_scene) Drawable::Close();*/ } ~Drawable() override {/* if (m_scene) Drawable::Close();*/ }
void Close() override; virtual void Close();
void SetShader(Shader* shader) { m_shader = shader; } void SetShader(Shader* shader) { m_shader = shader; }

View File

@@ -7,30 +7,31 @@
#pragma once #pragma once
#include "IFontAtlasGenerator.hpp" #include "IFontAtlasGenerator.hpp"
#include "AtlasData.hpp"
#include "Math/AABB.hpp" #include "Math/AABB.hpp"
#include "FreetypeHelper.hpp" #include "Extensions/FreetypeHelper.hpp"
#include <variant> #include <variant>
#include <set>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
class FontAtlasGeneratorBase : public IFontAtlasGenerator class FontAtlasGeneratorBase : public IFontAtlasGenerator
{ {
protected:
int m_channelsCount;
std::shared_ptr<AtlasData> m_atlasData;
public: public:
FontAtlasGeneratorBase(int channelsCount) : m_channelsCount(channelsCount) {} FontAtlasGeneratorBase(const int channelsCount) : m_channelsCount(channelsCount) {}
void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const override; void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const override;
std::shared_ptr<AtlasData> GetAtlasData() const { return m_atlasData; } [[nodiscard]] const std::shared_ptr<AtlasData>& GetAtlasData() const override { return m_atlasData; }
int GetAtlasChannelsCount() const { return m_channelsCount; } [[nodiscard]] int GetAtlasChannelsCount() const { return m_channelsCount; }
static std::set<uint32_t> LoadAllGlyphs(const std::variant<std::string, Array<char>>& data); [[nodiscard]] static std::set<uint32_t> LoadAllGlyphs(const std::variant<std::string, Array<char>>& data);
protected: protected:
void SavePng(std::string output) const; void SavePng(std::string output) const;
void SetupAtlasData(Math::Vector2ui textureResolution, double lineHeight, FontAtlasType::Type atlasType); void SetupAtlasData(Math::Vector2ui textureResolution, double lineHeight, FontAtlasType::Type atlasType);
void SetGlyphData(GlyphInfo& info, Math::Vector2d bearing, Math::Vector2d size, const Math::AABB& aabb, double advance); void SetGlyphData(GlyphInfo& info, Math::Vector2d bearing, Math::Vector2d size, const Math::AABB& aabb, double advance);
static std::string GetFreetypeErrorDescription(FT_Error error); [[nodiscard]] static std::string GetFreetypeErrorDescription(FT_Error error);
static std::pair<FtLibraryRecPtr, FtFaceRecPtr> InitFreetype(const std::variant<std::string, Array<char>>& source); [[nodiscard]] static std::pair<FtLibraryRecPtr, FtFaceRecPtr> InitFreetype(const std::variant<std::string, Array<char>>& source);
protected:
int m_channelsCount;
std::shared_ptr<AtlasData> m_atlasData;
}; };
} }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Base/Render/RenderResource.hpp" #include "Base/Render/RenderResource.hpp"
#include "Math/AABB.hpp" #include "Math/AABB.hpp"
#include "Base/Utils.hpp" #include "Base/Utils.hpp"
@@ -22,7 +21,7 @@ namespace OpenVulkano
UINT16 = sizeof(uint16_t), UINT32 = sizeof(uint32_t) UINT16 = sizeof(uint16_t), UINT32 = sizeof(uint32_t)
}; };
class Geometry : public RenderResourceHolder<Geometry>, public ICloseable class Geometry : public RenderResourceHolder<Geometry>
{ {
friend class MeshLoader; friend class MeshLoader;
public: public:
@@ -51,7 +50,7 @@ namespace OpenVulkano
void SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset = 0) const; void SetIndices(const uint32_t* data, uint32_t size, uint32_t dstOffset = 0) const;
void Close() override; virtual void Close();
void Free(); void Free();

View File

@@ -6,24 +6,25 @@
#pragma once #pragma once
#include "Scene/AtlasData.hpp" #include <Data/Containers/Array.hpp>
#include <string> #include <string>
#include <optional> #include <optional>
#include <map>
#include <variant>
#include <set> #include <set>
#include <memory> #include <memory>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
struct AtlasData;
class IFontAtlasGenerator class IFontAtlasGenerator
{ {
public: public:
virtual ~IFontAtlasGenerator() = default;
virtual void GenerateAtlas(const std::string& fontFile, const std::set<uint32_t>& charset, virtual void GenerateAtlas(const std::string& fontFile, const std::set<uint32_t>& charset,
const std::optional<std::string>& pngOutput = std::nullopt) = 0; const std::optional<std::string>& pngOutput = std::nullopt) = 0;
virtual void GenerateAtlas(const Array<char>& fontData, const std::set<uint32_t>& charset, virtual void GenerateAtlas(const Array<char>& fontData, const std::set<uint32_t>& charset,
const std::optional<std::string>& pngOutput = std::nullopt) = 0; const std::optional<std::string>& pngOutput = std::nullopt) = 0;
virtual void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const = 0; virtual void SaveAtlasMetadataInfo(const std::string& outputFile, bool packIntoSingleFile = true) const = 0;
virtual std::shared_ptr<AtlasData> GetAtlasData() const = 0; virtual const std::shared_ptr<AtlasData>& GetAtlasData() const = 0;
}; };
} }

View File

@@ -13,6 +13,7 @@ namespace OpenVulkano::Scene
class IRayIntersectable class IRayIntersectable
{ {
public: public:
virtual ~IRayIntersectable() = default;
virtual std::optional<RayHit> Intersect(const Ray& ray) const = 0; virtual std::optional<RayHit> Intersect(const Ray& ray) const = 0;
}; };
} }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Base/Render/RenderResource.hpp" #include "Base/Render/RenderResource.hpp"
#include "Math/Math.hpp" #include "Math/Math.hpp"
#include "Math/Pose.hpp" #include "Math/Pose.hpp"
@@ -20,7 +19,7 @@ namespace OpenVulkano::Scene
{ {
class Scene; class Scene;
class Node : public RenderResourceHolder<Node>, public ICloseable class Node : public RenderResourceHolder<Node>
{ {
friend Scene; friend Scene;
@@ -41,11 +40,11 @@ namespace OpenVulkano::Scene
Node(const Math::Matrix4f& pose); Node(const Math::Matrix4f& pose);
~Node() noexcept override; virtual ~Node() noexcept;
void Init(); void Init();
void Close() override; virtual void Close();
void AddChild(Node* node); void AddChild(Node* node);

View File

@@ -7,27 +7,77 @@
#include "LabelDrawable.hpp" #include "LabelDrawable.hpp"
#include "Scene/TextDrawable.hpp" #include "Scene/TextDrawable.hpp"
#include "Scene/DrawEncoder.hpp" #include "Scene/DrawEncoder.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Scene/IFontAtlasGenerator.hpp" #include "Scene/IFontAtlasGenerator.hpp"
#include "Base/Logger.hpp" #include "Base/Logger.hpp"
#include <optional> #include <optional>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
using namespace Math; namespace
{
Shader MakeLabelBgShader(const bool billboard)
{
Shader backgroundShader;
backgroundShader.AddShaderProgram(ShaderProgramType::VERTEX, billboard ? "Shader/labelBillboard" : "Shader/label");
backgroundShader.AddShaderProgram(ShaderProgramType::FRAGMENT, "Shader/label");
backgroundShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2);
backgroundShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 4);
backgroundShader.topology = Topology::TRIANGLE_STRIP;
backgroundShader.cullMode = CullMode::NONE;
return backgroundShader;
}
LabelDrawable::LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, const LabelDrawableSettings& settings, Shader MakeLabelTextShader(const FontAtlasType type, const bool billboard)
bool isBillboard) {
: Drawable(DrawEncoder::GetDrawEncoder<LabelDrawable>(), DrawPhase::MAIN) Shader shader = TextDrawable::MakeDefaultShader(type);
shader.depthCompareOp = CompareOp::LESS_OR_EQUAL;
shader.EnableDepthBias();
if (billboard)
{
for (auto& program : shader.shaderPrograms)
{
if (program.type == ShaderProgramType::VERTEX)
{
program.name = "Shader/textBillboard";
break;
}
}
DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
shader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4);
shader.depthBiasConstant = 0.01f;
}
return shader;
}
Shader BACKGROUND_SHADER = MakeLabelBgShader(false);
Shader BACKGROUND_BILLBOARD_SHADER = MakeLabelBgShader(true);
std::array TEXT_SHADERS = {
MakeLabelTextShader(FontAtlasType::SDF, false),
MakeLabelTextShader(FontAtlasType::SDF, true),
MakeLabelTextShader(FontAtlasType::MSDF, false),
MakeLabelTextShader(FontAtlasType::MSDF, true),
MakeLabelTextShader(FontAtlasType::BITMAP, false),
MakeLabelTextShader(FontAtlasType::BITMAP, true),
};
Shader* GetTextShader(const FontAtlasType type, const bool billboard)
{
return &TEXT_SHADERS[static_cast<int>(type) << 1 | billboard];
}
}
LabelDrawable::LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, const LabelDrawableSettings& settings)
: Drawable(DrawEncoder::GetDrawEncoder<LabelDrawable>(), DrawPhase::MAIN), m_atlasData(atlasData)
, m_labelBuffer(sizeof(LabelUniformData), &m_labelData, 4)
{ {
if (atlasData->glyphs.empty() || !atlasData->texture.size) if (atlasData->glyphs.empty() || !atlasData->texture.size)
{ {
throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty"); throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty");
} }
m_atlasData = atlasData;
m_isBillboard = isBillboard;
SetLabelSettings(settings); SetLabelSettings(settings);
SetupShaders(); SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER);
SetupBuffers();
} }
void LabelDrawable::SetLabelSettings(const LabelDrawableSettings& settings) void LabelDrawable::SetLabelSettings(const LabelDrawableSettings& settings)
@@ -43,124 +93,27 @@ namespace OpenVulkano::Scene
void LabelDrawable::AddText(const std::string& text, const TextConfig& config) void LabelDrawable::AddText(const std::string& text, const TextConfig& config)
{ {
if (text.empty()) if (text.empty()) return;
{
return;
}
TextDrawable& textDrawable = m_texts.emplace_back(m_atlasData, config); TextDrawable& textDrawable = m_texts.emplace_back(m_atlasData, config);
// do not render glyph's background textDrawable.GetConfig().backgroundColor.a = 0; // do not render glyph's background
textDrawable.GetConfig().backgroundColor.a = 0;
textDrawable.SetShader(&m_textShader);
double lineHeight = m_atlasData->meta.lineHeight; double lineHeight = m_atlasData->meta.lineHeight;
textDrawable.GenerateText(text, m_position); textDrawable.GenerateText(text, m_position);
RecalculateBbox(textDrawable.GetBoundingBox()); textDrawable.SetShader(GetTextShader(m_atlasData->meta.atlasType, IsBillboard()));
m_bbox.Grow(textDrawable.GetBoundingBox());
// update position for next text entry // update position for next text entry
m_position.y = m_bbox.GetMin().y - lineHeight; m_position.y = m_bbox.GetMin().y - lineHeight;
const auto& min = m_bbox.GetMin(); Math::Vector2f padding = m_settings.padding * 2;
const auto& max = m_bbox.GetMax(); if (m_settings.hasArrow) padding.y += m_settings.arrowLength;
Vertex v, v2, v3, v4;
const float offset = 0.001;
const float yOffset = m_settings.hasArrow ? m_settings.arrowLength : 0;
v.position = Vector3f(min.x - m_settings.horizontalOffset, min.y - m_settings.verticalOffset - yOffset, min.z - offset);
v2.position = Vector3f(max.x + m_settings.horizontalOffset, min.y - m_settings.verticalOffset - yOffset, min.z - offset);
v3.position = Vector3f(max.x + m_settings.horizontalOffset, max.y + m_settings.verticalOffset, min.z - offset);
v4.position = Vector3f(min.x - m_settings.horizontalOffset, max.y + m_settings.verticalOffset, min.z - offset);
m_labelData.textSize.x = v2.position.x - v.position.x; m_labelData.textSize = Math::Vector2f(m_bbox.GetSize()) + padding * 2;
m_labelData.textSize.y = v3.position.y - v.position.y; m_labelData.bboxCenter = { m_bbox.GetCenter() };
m_labelData.bboxCenter.x = (v2.position.x + v.position.x) / 2; if (m_settings.hasArrow) m_labelData.bboxCenter.y -= m_settings.arrowLength;
m_labelData.bboxCenter.y = (v3.position.y + v.position.y) / 2;
}
void LabelDrawable::SetBillboardSettings(const BillboardControlBlock& settings)
{
m_billboardSettings = settings;
} }
std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const
{ {
return ray.IntersectAABB(m_bbox); return ray.IntersectAABB(m_bbox);
} }
void LabelDrawable::RecalculateBbox(const Math::AABB& other)
{
if (m_bbox.IsEmpty())
{
m_bbox = other;
}
else
{
auto& currentMin = m_bbox.GetMin();
auto& currentMax = m_bbox.GetMax();
currentMin.x = std::min(currentMin.x, other.min.x);
currentMin.y = std::min(currentMin.y, other.min.y);
currentMax.x = std::max(currentMax.x, other.max.x);
currentMax.y = std::max(currentMax.y, other.max.y);
}
}
void LabelDrawable::SetupShaders()
{
if (!m_isBillboard)
{
m_backgroundShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/label");
}
else
{
m_backgroundShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/labelBillboard");
// binding for billboard's buffer
DescriptorSetLayoutBinding binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
binding.stageFlags = ShaderProgramType::Type::VERTEX;
m_backgroundShader.AddDescriptorSetLayoutBinding(binding, 4);
}
m_backgroundShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/label");
m_backgroundShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2);
m_backgroundShader.AddDescriptorSetLayoutBinding(UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING, 5);
m_backgroundShader.topology = Topology::TRIANGLE_STRIP;
m_backgroundShader.cullMode = CullMode::NONE;
SetShader(&m_backgroundShader);
FontAtlasType fontAtlasType(static_cast<FontAtlasType::Type>(m_atlasData->meta.atlasType));
if (!m_isBillboard)
{
m_textShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/text");
}
else
{
m_textShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/billboard");
DescriptorSetLayoutBinding billboardUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
billboardUniformBinding.stageFlags = ShaderProgramType::Type::VERTEX;
m_textShader.AddDescriptorSetLayoutBinding(billboardUniformBinding, 4);
}
DescriptorSetLayoutBinding textUniformBinding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
textUniformBinding.stageFlags = ShaderProgramType::FRAGMENT;
m_textShader.AddDescriptorSetLayoutBinding(textUniformBinding, 3);
m_textShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT,
std::string(fontAtlasType.GetDefaultFragmentShader()));
m_textShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription());
m_textShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING, 2);
m_textShader.alphaBlend = true;
m_textShader.cullMode = CullMode::NONE;
m_textShader.depthWrite = false;
m_textShader.depthCompareOp = CompareOp::LESS_OR_EQUAL;
}
void LabelDrawable::SetupBuffers()
{
m_billboardBuffer.size = sizeof(BillboardControlBlock);
m_billboardBuffer.data = &m_billboardSettings;
m_billboardBuffer.setId = 4;
DescriptorSetLayoutBinding binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
binding.stageFlags = ShaderProgramType::Type::VERTEX;
m_billboardBuffer.binding = binding;
m_labelBuffer.size = sizeof(LabelUniformData);
m_labelBuffer.data = &m_labelData;
m_labelBuffer.setId = 5;
m_labelBuffer.binding = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
}
} }

View File

@@ -6,79 +6,66 @@
#pragma once #pragma once
#include "Base/Wrapper.hpp"
#include "Scene/Drawable.hpp" #include "Scene/Drawable.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Scene/Texture.hpp"
#include "Scene/UniformBuffer.hpp" #include "Scene/UniformBuffer.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/BillboardControlBlock.hpp"
#include "Math/AABB.hpp" #include "Math/AABB.hpp"
#include "Scene/TextDrawable.hpp" #include "Scene/TextDrawable.hpp"
#include <list> #include <list>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
class Shader;
struct LabelDrawableSettings struct LabelDrawableSettings
{ {
Math::Vector4f backgroundColor = { 1, 0, 0, 1 }; Math::Vector4f backgroundColor = { 1, 0, 0, 1 };
float horizontalOffset = 0.05f; Math::Vector2f padding = { 0.2f, 0.2f };
float verticalOffset = 0.05f;
float cornerRadius = 0.05f; float cornerRadius = 0.05f;
float arrowLength = 0.5f; float arrowLength = 0.5f;
float arrowWidth = 0.2f; float arrowWidth = 0.2f;
int32_t hasRoundedCorners = false; bool hasRoundedCorners = false;
int32_t hasArrow = false; bool hasArrow = false;
bool isBillboard = false;
}; };
struct LabelUniformData struct LabelUniformData
{ {
Math::Vector4f textSize = { 0, 0, 0, 0 };
Math::Vector4f color = { 0, 0, 0, 0 }; Math::Vector4f color = { 0, 0, 0, 0 };
Math::Vector4f bboxCenter = { 0, 0, 0, 0 }; Math::Vector2f textSize = {};
Math::Vector2f bboxCenter = {};
float cornerRadius = 0.f; float cornerRadius = 0.f;
float arrowLength = 0.f; float arrowLength = 0.f;
float arrowWidth = 0.f; float arrowWidth = 0.f;
int32_t hasRoundedCorners = false; int32_t hasRoundedCorners = false;
int32_t hasArrow = false; int32_t hasArrow = false;
int32_t isBillboardFixedSize = false;
}; };
class LabelDrawable final : public Drawable class LabelDrawable final : public Drawable
{ {
public: public:
LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, const LabelDrawableSettings& settings = LabelDrawableSettings());
const LabelDrawableSettings& settings = LabelDrawableSettings(), bool isBillboard = false);
void AddText(const std::string& text, const TextConfig& config = TextConfig()); void AddText(const std::string& text, const TextConfig& config = TextConfig());
void SetLabelSettings(const LabelDrawableSettings& settings); void SetLabelSettings(const LabelDrawableSettings& settings);
void SetBillboardSettings(const BillboardControlBlock& settings); void SetPosition(const Math::Vector2f& pos) { m_position = pos; }
void SetPosition(const Math::Vector3f& pos) { m_position = pos; }
std::list<TextDrawable>& GetTexts() { return m_texts; } [[nodiscard]] std::list<TextDrawable>& GetTexts() { return m_texts; }
LabelDrawableSettings& GetSettings() { return m_settings; } [[nodiscard]] LabelDrawableSettings& GetSettings() { return m_settings; }
UniformBuffer* GetBillboardBuffer() { return &m_billboardBuffer; } [[nodiscard]] UniformBuffer* GetLabelBuffer() { return &m_labelBuffer; }
UniformBuffer* GetLabelBuffer() { return &m_labelBuffer; } [[nodiscard]] Math::Vector2f& GetPosition() { return m_position; }
BillboardControlBlock& GetBillboardSettings() { return m_billboardSettings; } [[nodiscard]] bool IsBillboard() const { return m_settings.isBillboard; }
Math::Vector3f& GetPosition() { return m_position; } [[nodiscard]] const Math::AABB2f& GetBoundingBox() const { return m_bbox; }
bool IsBillboard() const { return m_isBillboard; }
const Math::AABB& GetBoundingBox() const { return m_bbox; } [[nodiscard]] std::optional<RayHit> Intersect(const Ray& ray) const override;
std::optional<RayHit> Intersect(const Ray& ray) const override;
private: private:
void RecalculateBbox(const Math::AABB& other);
void SetupShaders();
void SetupBuffers();
private:
Shader m_backgroundShader;
UniformBuffer m_billboardBuffer;
UniformBuffer m_labelBuffer;
// list over vector to prevent memory reallocation and crash
std::list<TextDrawable> m_texts;
Shader m_textShader;
LabelDrawableSettings m_settings; LabelDrawableSettings m_settings;
LabelUniformData m_labelData;
std::shared_ptr<AtlasData> m_atlasData; std::shared_ptr<AtlasData> m_atlasData;
BillboardControlBlock m_billboardSettings; UniformBuffer m_labelBuffer;
Math::Vector3f m_position = { 0, 0, 0 }; LabelUniformData m_labelData;
Math::AABB m_bbox; std::list<TextDrawable> m_texts; // Using list instead of vector for stable iterators
bool m_isBillboard; Math::Vector2f m_position = { 0, 0 };
Math::AABB2f m_bbox;
}; };
} }

View File

@@ -11,11 +11,8 @@ namespace
{ {
int SolveQuadraticEquation(float a, float b, float c, float& x0, float& x1) int SolveQuadraticEquation(float a, float b, float c, float& x0, float& x1)
{ {
float discr = b * b - 4 * a * c; const float discr = b * b - 4 * a * c;
if (discr < 0) if (discr < 0) return 0;
{
return 0;
}
if (discr == 0) if (discr == 0)
{ {
x0 = x1 = (-b) / (2 * a); x0 = x1 = (-b) / (2 * a);
@@ -24,10 +21,7 @@ namespace
float q = (b > 0) ? -0.5 * (b + std::sqrt(discr)) : -0.5 * (b - std::sqrt(discr)); float q = (b > 0) ? -0.5 * (b + std::sqrt(discr)) : -0.5 * (b - std::sqrt(discr));
x0 = q / a; x0 = q / a;
x1 = c / q; x1 = c / q;
if (x0 > x1) OpenVulkano::Math::Utils::SortPair(x0, x1);
{
std::swap(x0, x1);
}
return 2; return 2;
} }
}; };
@@ -50,10 +44,10 @@ namespace OpenVulkano::Scene
std::optional<RayHit> Ray::IntersectTriangle(const Math::Vector3f& v0, const Math::Vector3f& v1, std::optional<RayHit> Ray::IntersectTriangle(const Math::Vector3f& v0, const Math::Vector3f& v1,
const Math::Vector3f& v2) const const Math::Vector3f& v2) const
{ {
RayHit hitRes;
float d; float d;
if (intersectRayTriangle(m_origin, m_dir, v0, v1, v2, m_baryPos, d) && d >= 0) if (intersectRayTriangle(m_origin, m_dir, v0, v1, v2, m_baryPos, d) && d >= 0)
{ {
RayHit hitRes;
hitRes.point = (1.f - m_baryPos.x - m_baryPos.y) * v0 + m_baryPos.x * v1 + m_baryPos.y * v2; hitRes.point = (1.f - m_baryPos.x - m_baryPos.y) * v0 + m_baryPos.x * v1 + m_baryPos.y * v2;
Math::Vector3f e = v1 - v0; Math::Vector3f e = v1 - v0;
Math::Vector3f e2 = v2 - v0; Math::Vector3f e2 = v2 - v0;
@@ -81,96 +75,73 @@ namespace OpenVulkano::Scene
std::optional<RayHit> Ray::IntersectQuad(const Math::Vector3f& v0, const Math::Vector3f& v1, std::optional<RayHit> Ray::IntersectQuad(const Math::Vector3f& v0, const Math::Vector3f& v1,
const Math::Vector3f& v2, const Math::Vector3f& v3) const const Math::Vector3f& v2, const Math::Vector3f& v3) const
{ {
if (auto hitRes = IntersectTriangle(v0, v1, v2)) if (const auto hitRes = IntersectTriangle(v0, v1, v2))
{ {
return hitRes; return hitRes;
} }
if (auto hitRes = IntersectTriangle(v0, v2, v3)) if (const auto hitRes = IntersectTriangle(v0, v2, v3))
{ {
return hitRes; return hitRes;
} }
return {}; return {};
} }
std::optional<RayHit> Ray::IntersectAABB(const Math::AABB2f& bbox) const
{
//TODO impl that skips z checks
return IntersectAABB(Math::AABB({bbox.GetMin(), 0}, {bbox.GetMax(), 0}));
}
std::optional<RayHit> Ray::IntersectAABB(const Math::AABB& bbox) const std::optional<RayHit> Ray::IntersectAABB(const Math::AABB& bbox) const
{ {
RayHit h1, h2; RayHit h1, h2;
const int intersections = this->IntersectAABB(bbox, h1, h2); const int intersections = this->IntersectAABB(bbox, h1, h2);
switch (intersections) if (intersections == 1) return h1;
{ if (intersections == 2) return (h1.distance2 < h2.distance2) ? h1 : h2;
case 1:
return h1;
case 2:
return (h1.distance2 < h2.distance2) ? h1 : h2;
}
return {}; return {};
} }
int Ray::IntersectAABB(const Math::AABB& bbox, RayHit& p1, RayHit& p2) const int Ray::IntersectAABB(const Math::AABB& bbox, RayHit& p1, RayHit& p2) const
{ {
const auto tmin = (bbox.min - m_origin) / m_dir; auto tmin = (bbox.min - m_origin) / m_dir;
const auto tmax = (bbox.max - m_origin) / m_dir; auto tmax = (bbox.max - m_origin) / m_dir;
float txmin = tmin.x;
float txmax = tmax.x;
float tymin = tmin.y;
float tymax = tmax.y;
float tzmin = tmin.z;
float tzmax = tmax.z;
if (txmin > txmax) SortPair(tmin.x, tmax.x);
SortPair(tmin.y, tmax.y);
SortPair(tmin.z, tmax.z);
if ((tmin.x > tmax.y) || (tmin.y > tmax.x)) return 0;
if (tmin.y > tmin.x)
{ {
std::swap(txmin, txmax); tmin.x = tmin.y;
} }
if (tymin > tymax) if (tmax.y < tmax.x)
{ {
std::swap(tymin, tymax); tmax.x = tmax.y;
}
if ((txmin > tymax) || (tymin > txmax))
{
return 0;
} }
if (tymin > txmin) if ((tmin.x > tmax.z) || (tmin.z > tmax.x)) return 0;
{
txmin = tymin;
}
if (tymax < txmax)
{
txmax = tymax;
}
if (tzmin > tzmax) if (tmin.z > tmin.x)
{ {
std::swap(tzmin, tzmax); tmin.x = tmin.z;
} }
if (tmax.z < tmax.x)
if ((txmin > tzmax) || (tzmin > txmax))
{ {
return 0; tmax.x = tmax.z;
}
if (tzmin > txmin)
{
txmin = tzmin;
}
if (tzmax < txmax)
{
txmax = tzmax;
} }
int intersections = 2; int intersections = 2;
if (txmin < 0) if (tmin.x < 0)
{ {
if (txmax < 0) if (tmax.x < 0) return 0;
{
return 0;
}
intersections--; intersections--;
txmin = txmax; tmin.x = tmax.x;
} }
p1.point = m_origin + txmin * m_dir; p1.point = m_origin + tmin.x * m_dir;
p2.point = m_origin + txmax * m_dir; p2.point = m_origin + tmax.x * m_dir;
p1.distance2 = distance2(m_origin, p1.point); p1.distance2 = distance2(m_origin, p1.point);
p2.distance2 = distance2(m_origin, p2.point); p2.distance2 = distance2(m_origin, p2.point);
p1.normal = p2.normal = Math::Vector3f(0); p1.normal = p2.normal = Math::Vector3f(0);
@@ -179,15 +150,11 @@ namespace OpenVulkano::Scene
std::optional<RayHit> Ray::IntersectPlane(const Math::Vector3f& pOrigin, const Math::Vector3f& pNorm) const std::optional<RayHit> Ray::IntersectPlane(const Math::Vector3f& pOrigin, const Math::Vector3f& pNorm) const
{ {
RayHit hit;
Math::Vector3f norm = normalize(pNorm); Math::Vector3f norm = normalize(pNorm);
float d; float d;
if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, d)) if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, d))
{ {
hit.SetDistance(d); return {{ m_origin + m_dir * d, norm, d, d * d }};
hit.point = m_origin + m_dir * d;
hit.normal = norm;
return hit;
} }
return {}; return {};
} }
@@ -201,56 +168,36 @@ namespace OpenVulkano::Scene
float x1, x2; float x1, x2;
int roots = ::SolveQuadraticEquation(a, b, c, x1, x2); int roots = ::SolveQuadraticEquation(a, b, c, x1, x2);
if (roots == 0) if (roots == 0) return 0;
{ SortPair(x1, x2);
return 0; bool calcP2 = false;
}
if (x1 > x2)
{
std::swap(x1, x2);
}
if (roots == 1) if (roots == 1)
{ {
// ray intersects sphere behind the origin if (x1 < 0) return 0; // ray intersects sphere behind the origin
if (x1 < 0)
{
return 0;
} }
p1.point = m_origin + x1 * m_dir; else
p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center);
p2 = p1;
}
else if (roots == 2)
{ {
// ray intersects sphere behind the origin if (x1 < 0 && x2 < 0) return 0; // ray intersects sphere behind the origin
if (x1 < 0 && x2 < 0)
{
return 0;
}
if (x1 >= 0 && x2 >= 0) if (x1 >= 0 && x2 >= 0)
{ {
p1.point = m_origin + x1 * m_dir; calcP2 = true;
p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center);
p2.point = m_origin + x2 * m_dir;
p2.distance2 = distance2(m_origin, p2.point);
p2.normal = normalize(p2.point - center);
} }
else else
{ {
--roots; --roots;
if (x1 < 0) if (x1 < 0) x1 = x2;
{ }
x1 = x2;
} }
p1.point = m_origin + x1 * m_dir; p1.point = m_origin + x1 * m_dir;
p1.distance2 = distance2(m_origin, p1.point); p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center); p1.normal = normalize(p1.point - center);
p2 = p1; if (calcP2)
} {
p2.point = m_origin + x2 * m_dir;
p2.distance2 = distance2(m_origin, p2.point);
p2.normal = normalize(p2.point - center);
} }
else p2 = p1;
return roots; return roots;
} }

View File

@@ -20,21 +20,32 @@ namespace OpenVulkano::Scene
Math::Vector3f point; Math::Vector3f point;
Math::Vector3f normal; Math::Vector3f normal;
float distance2; float distance2;
RayHit() : distance2(0), distance(-1) {}
RayHit(Math::Vector3f point, Math::Vector3f normal, float distance2)
: point(point), normal(normal), distance2(distance2)
{}
RayHit(Math::Vector3f point, Math::Vector3f normal, float distance, float distance2)
: point(point), normal(normal), distance2(distance2), distance(distance)
{}
[[nodiscard]] float GetDistance() const [[nodiscard]] float GetDistance() const
{ {
if (distance == -1) if (distance == -1) distance = std::sqrt(distance2);
{
distance = std::sqrt(distance2);
}
return distance; return distance;
} }
void SetDistance(float d) void SetDistance(float d)
{ {
this->distance = d; this->distance = d;
this->distance2 = d * d; this->distance2 = d * d;
} }
bool operator==(const RayHit& other) const; bool operator==(const RayHit& other) const;
bool operator!=(const RayHit& other) const; bool operator!=(const RayHit& other) const;
private: private:
mutable float distance = -1; mutable float distance = -1;
}; };
@@ -66,6 +77,7 @@ namespace OpenVulkano::Scene
const Math::Vector3f& n1, const Math::Vector3f& n2) const; const Math::Vector3f& n1, const Math::Vector3f& n2) const;
[[nodiscard]] std::optional<RayHit> IntersectQuad(const Math::Vector3f& v0, const Math::Vector3f& v1, [[nodiscard]] std::optional<RayHit> IntersectQuad(const Math::Vector3f& v0, const Math::Vector3f& v1,
const Math::Vector3f& v2, const Math::Vector3f& v3) const; const Math::Vector3f& v2, const Math::Vector3f& v3) const;
[[nodiscard]] std::optional<RayHit> IntersectAABB(const Math::AABB2f& bbox) const;
[[nodiscard]] std::optional<RayHit> IntersectAABB(const Math::AABB& bbox) const; [[nodiscard]] std::optional<RayHit> IntersectAABB(const Math::AABB& bbox) const;
int IntersectAABB(const Math::AABB& bbox, RayHit& p1, RayHit& p2) const; int IntersectAABB(const Math::AABB& bbox, RayHit& p1, RayHit& p2) const;
[[nodiscard]] std::optional<RayHit> IntersectPlane(const Math::Vector3f& pOrigin, [[nodiscard]] std::optional<RayHit> IntersectPlane(const Math::Vector3f& pOrigin,

View File

@@ -15,7 +15,7 @@ namespace OpenVulkano
{ {
namespace Scene namespace Scene
{ {
class Scene : public ICloseable class Scene
{ {
public: public:
Node* root; Node* root;
@@ -46,7 +46,7 @@ namespace OpenVulkano
this->root = root; this->root = root;
} }
void Close() override virtual void Close()
{ {
//TODO //TODO
} }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Base/Utils.hpp" #include "Base/Utils.hpp"
#include "Base/Render/RenderResource.hpp" #include "Base/Render/RenderResource.hpp"
#include "VertexInputDescription.hpp" #include "VertexInputDescription.hpp"
@@ -81,8 +80,7 @@ namespace OpenVulkano::Scene
}; };
class Shader final : public RenderResourceHolder<Shader>
class Shader final : public RenderResourceHolder<Shader>, public ICloseable
{ {
public: public:
std::vector<ShaderProgram> shaderPrograms{}; std::vector<ShaderProgram> shaderPrograms{};
@@ -96,9 +94,11 @@ namespace OpenVulkano::Scene
bool depthTest = true; bool depthTest = true;
bool depthWrite = true; bool depthWrite = true;
bool dynamicViewport = true; // If disabled the swapchains fullscreen viewport will always be used, regardless of framebuffer or viewport bool dynamicViewport = true; // If disabled the swapchains fullscreen viewport will always be used, regardless of framebuffer or viewport
bool depthBias = false;
float depthBiasClamp = 0.0f, depthBiasSlope = 0.0f, depthBiasConstant = 0.0f;
Shader() = default; Shader() = default;
~Shader() override { Shader::Close(); } ~Shader() { Shader::Close(); }
Shader& AddShaderProgram(const ShaderProgram& shaderProgram) Shader& AddShaderProgram(const ShaderProgram& shaderProgram)
{ {
@@ -128,6 +128,7 @@ namespace OpenVulkano::Scene
{ {
CheckShaderInitState(); CheckShaderInitState();
if (bindingId < 0) bindingId = static_cast<int>(vertexInputDescriptions.size()); if (bindingId < 0) bindingId = static_cast<int>(vertexInputDescriptions.size());
// ReSharper disable once CppDFALoopConditionNotUpdated
while (bindingId > static_cast<int>(vertexInputDescriptions.size())) while (bindingId > static_cast<int>(vertexInputDescriptions.size()))
{ {
vertexInputDescriptions.emplace_back(0, 0); vertexInputDescriptions.emplace_back(0, 0);
@@ -149,6 +150,7 @@ namespace OpenVulkano::Scene
if (setId < 0) setId = static_cast<int>(descriptorSets.size() + 2); if (setId < 0) setId = static_cast<int>(descriptorSets.size() + 2);
if (setId < 2) throw std::runtime_error("Cant bind set id 0 or 1! They are used for node and camera!"); if (setId < 2) throw std::runtime_error("Cant bind set id 0 or 1! They are used for node and camera!");
setId -= 2; setId -= 2;
// ReSharper disable once CppDFALoopConditionNotUpdated
while (setId >= static_cast<int>(descriptorSets.size())) while (setId >= static_cast<int>(descriptorSets.size()))
{ {
descriptorSets.emplace_back(); descriptorSets.emplace_back();
@@ -163,7 +165,14 @@ namespace OpenVulkano::Scene
pushConstantRanges.push_back(pushConstantRange); pushConstantRanges.push_back(pushConstantRange);
} }
void Close() override void EnableDepthBias(const float slope = -1.0, const float constant = 0.001f)
{
depthBias = true;
depthBiasSlope = slope;
depthBiasConstant = constant;
}
void Close()
{ {
if (HasRenderResource()) if (HasRenderResource())
GetRenderResource().Release(); GetRenderResource().Release();

View File

@@ -12,6 +12,8 @@
namespace OpenVulkano namespace OpenVulkano
{ {
enum class VertexStepMode : uint32_t { VERTEX = 0, INSTANCE };
struct VertexInputParameter struct VertexInputParameter
{ {
uint32_t location; uint32_t location;
@@ -32,13 +34,16 @@ namespace OpenVulkano
{ {
uint32_t bindingId; uint32_t bindingId;
uint32_t vertexSize; uint32_t vertexSize;
VertexStepMode stepMode = VertexStepMode::VERTEX;
std::vector<VertexInputParameter> inputParameters; std::vector<VertexInputParameter> inputParameters;
VertexInputDescription(uint32_t bindingId, uint32_t vertexSize) : bindingId(bindingId), vertexSize(vertexSize) VertexInputDescription(uint32_t bindingId, uint32_t vertexSize) : bindingId(bindingId), vertexSize(vertexSize)
{} {}
VertexInputDescription(uint32_t bindingId, const VertexInputDescription& vertexDescription) VertexInputDescription(uint32_t bindingId, const VertexInputDescription& vertexDescription)
: bindingId(bindingId), vertexSize(vertexDescription.vertexSize), inputParameters(vertexDescription.inputParameters) : bindingId(bindingId), vertexSize(vertexDescription.vertexSize)
, stepMode(vertexDescription.stepMode)
, inputParameters(vertexDescription.inputParameters)
{ {
for (auto& param : inputParameters) for (auto& param : inputParameters)
{ {

View File

@@ -6,9 +6,7 @@
#include "TextDrawable.hpp" #include "TextDrawable.hpp"
#include "Scene/Geometry.hpp" #include "Scene/Geometry.hpp"
#include "Scene/Material.hpp" #include "Shader/Shader.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Scene/IFontAtlasGenerator.hpp" #include "Scene/IFontAtlasGenerator.hpp"
#include "Base/Logger.hpp" #include "Base/Logger.hpp"
#include "Host/ResourceLoader.hpp" #include "Host/ResourceLoader.hpp"
@@ -20,89 +18,58 @@
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
Shader& TextDrawable::GetSdfDefaultShader() namespace
{ {
static bool once = true; constexpr uint32_t MISSING_GLYPH_SYMBOL = '?';
static Shader sdfDefaultShader;
if (once) Shader DEFAULT_SHADER_BITMAP = TextDrawable::MakeDefaultShader(FontAtlasType::BITMAP);
{ Shader DEFAULT_SHADER_SDF = TextDrawable::MakeDefaultShader(FontAtlasType::SDF);
sdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/sdfText"); Shader DEFAULT_SHADER_MSDF = TextDrawable::MakeDefaultShader(FontAtlasType::MSDF);
sdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/sdfText");
sdfDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription());
sdfDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
desc.stageFlags = ShaderProgramType::FRAGMENT;
sdfDefaultShader.AddDescriptorSetLayoutBinding(desc);
sdfDefaultShader.alphaBlend = true;
sdfDefaultShader.cullMode = CullMode::NONE;
once = false;
}
return sdfDefaultShader;
} }
Shader& TextDrawable::GetMsdfDefaultShader() Shader TextDrawable::MakeDefaultShader(const FontAtlasType type)
{ {
static bool once = true; Shader shader;
static Shader msdfDefaultShader; shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/text");
if (once) shader.AddShaderProgram(ShaderProgramType::FRAGMENT, std::string(type.GetDefaultFragmentShader()));
{ VertexInputDescription inputDesc(0, sizeof(TextGlyphVertex));
msdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/sdfText"); inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position));
msdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/msdfText"); inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+8);
msdfDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription()); inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+16);
msdfDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING); inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+24);
DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING; inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv));
desc.stageFlags = ShaderProgramType::FRAGMENT; inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+8);
msdfDefaultShader.AddDescriptorSetLayoutBinding(desc); inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+16);
msdfDefaultShader.alphaBlend = true; inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+24);
msdfDefaultShader.cullMode = CullMode::NONE; inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, color));
once = false; inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, background));
} inputDesc.stepMode = VertexStepMode::INSTANCE;
return msdfDefaultShader; shader.AddVertexInputDescription(inputDesc);
} shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
shader.alphaBlend = true;
Shader& TextDrawable::GetBitmapDefaultShader() shader.cullMode = CullMode::NONE;
{ shader.topology = Topology::TRIANGLE_FAN;
static bool once = true; return shader;
static Shader bitmapDefaultShader;
if (once)
{
bitmapDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/text");
bitmapDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/text");
bitmapDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription());
bitmapDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
desc.stageFlags = ShaderProgramType::FRAGMENT;
bitmapDefaultShader.AddDescriptorSetLayoutBinding(desc);
bitmapDefaultShader.alphaBlend = true;
bitmapDefaultShader.cullMode = CullMode::NONE;
once = false;
}
return bitmapDefaultShader;
} }
TextDrawable::TextDrawable(const TextConfig& config) TextDrawable::TextDrawable(const TextConfig& config)
{ : Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_cfg(config)
m_cfg = config; {}
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT;
}
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config) TextDrawable::TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config)
: TextDrawable(atlasMetadata, nullptr, config) : TextDrawable(atlasMetadata, nullptr, config)
{ {}
}
TextDrawable::TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config) TextDrawable::TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config)
: TextDrawable(OpenVulkano::Utils::ReadFile(atlasMetadataFile), nullptr, config) : TextDrawable(Utils::ReadFile(atlasMetadataFile), nullptr, config)
{ {}
}
TextDrawable::TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config) TextDrawable::TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config)
: TextDrawable(OpenVulkano::Utils::ReadFile(atlasMetadataFile), atlasTex, config) : TextDrawable(Utils::ReadFile(atlasMetadataFile), atlasTex, config)
{ {}
}
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config) TextDrawable::TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config)
: Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_cfg(config)
{ {
uint32_t isPacked; uint32_t isPacked;
std::memcpy(&isPacked, atlasMetadata.Data() + (atlasMetadata.Size() - sizeof(uint32_t)), sizeof(uint32_t)); std::memcpy(&isPacked, atlasMetadata.Data() + (atlasMetadata.Size() - sizeof(uint32_t)), sizeof(uint32_t));
@@ -113,19 +80,17 @@ namespace OpenVulkano::Scene
m_atlasData = std::make_shared<AtlasData>(); m_atlasData = std::make_shared<AtlasData>();
if (isPacked) if (isPacked)
{ {
m_material.texture = &m_atlasData->texture; Texture* texture = &m_atlasData->texture;
m_atlasData->img = Image::IImageLoader::loadData((const uint8_t*) atlasMetadata.Data(), m_atlasData->img = Image::IImageLoader::loadData(reinterpret_cast<const uint8_t*>(atlasMetadata.Data()), offsetToMetadata);
offsetToMetadata); texture->format = m_atlasData->img->dataFormat;
m_material.texture->format = m_atlasData->img->dataFormat; texture->resolution = m_atlasData->img->resolution;
m_material.texture->resolution = m_atlasData->img->resolution; texture->size = m_atlasData->img->data.Size();
m_material.texture->size = m_atlasData->img->data.Size(); texture->textureBuffer = m_atlasData->img->data.Data();
m_material.texture->textureBuffer = m_atlasData->img->data.Data();
} }
else else
{ {
if (atlasTex == nullptr) { throw std::runtime_error("Atlas texture cannot be null with non-packed atlas metadata"); } if (atlasTex == nullptr) { throw std::runtime_error("Atlas texture cannot be null with non-packed atlas metadata"); }
m_atlasData->texture = *atlasTex; m_atlasData->texture = *atlasTex;
m_material.texture = atlasTex;
} }
// metadata info // metadata info
@@ -146,67 +111,47 @@ namespace OpenVulkano::Scene
read_bytes += sizeof(GlyphInfo); read_bytes += sizeof(GlyphInfo);
readMetadataBytes += sizeof(GlyphInfo); readMetadataBytes += sizeof(GlyphInfo);
} }
m_cfg = config;
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT;
if (m_atlasData->meta.atlasType == FontAtlasType::BITMAP) if (m_atlasData->meta.atlasType == FontAtlasType::BITMAP)
{ {
m_material.texture->m_samplerConfig = &SamplerConfig::NEAREST; m_atlasData->texture.m_samplerConfig = &SamplerConfig::NEAREST;
} }
} }
TextDrawable::TextDrawable(const std::shared_ptr<AtlasData>& atlasData, const TextConfig& config) TextDrawable::TextDrawable(const std::shared_ptr<AtlasData>& atlasData, const TextConfig& config)
: Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_atlasData(atlasData), m_cfg(config)
{ {
if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer) if (!atlasData || !*atlasData) throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
{
throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
}
m_atlasData = atlasData;
m_cfg = config;
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT;
} }
void TextDrawable::GenerateText(const std::string& text, const Math::Vector3f& pos) uint32_t TextDrawable::GetFallbackGlyph() const
{ {
if (text.empty()) if (m_atlasData->glyphs.find(MISSING_GLYPH_SYMBOL) != m_atlasData->glyphs.end())
{ {
return; return MISSING_GLYPH_SYMBOL;
} }
Logger::RENDER->warn("Could not find glyph for character ? to use as fallback. Using first glyph instead");
return m_atlasData->glyphs.begin()->first;
}
void TextDrawable::GenerateText(const std::string& text, const Math::Vector2f& pos)
{
if (text.empty()) return;
if (m_vertexBuffer.data) throw std::runtime_error("Text has already been initialized");
const uint32_t fallbackGlyph = GetFallbackGlyph();
m_text = text; m_text = text;
auto GetActualLength = [&]() m_symbolCount = 0;
{ const size_t len = utf8::distance(text.begin(), text.end());
auto begin = text.begin(); m_vertexBuffer.Close();
auto end = text.end(); TextGlyphVertex* vertices = m_vertexBuffer.Init<TextGlyphVertex>(len);
size_t len = 0; std::map<uint32_t, GlyphInfo>* symbols = &m_atlasData->glyphs;
while (begin != end) AtlasMetadata* meta = &m_atlasData->meta;
{
uint32_t c = utf8::next(begin, end);
if (c == '\n') continue;
++len;
}
return len;
};
size_t len = GetActualLength();
m_geometry.Close();
m_geometry.Init(len * 4, len * 6);
AtlasMetadata* meta;
std::map<uint32_t, GlyphInfo>* symbols;
m_material.texture = &m_atlasData->texture;
symbols = &m_atlasData->glyphs;
meta = &m_atlasData->meta;
double cursorX = pos.x; double cursorX = pos.x;
auto begin = text.begin();
auto end = text.end();
const double lineHeight = meta->lineHeight; const double lineHeight = meta->lineHeight;
double posY = pos.y; double posY = pos.y;
int i = 0; Math::Vector3f bmin(pos, 0), bmax(pos, 0);
Math::Vector3f bmin(pos), bmax(pos); for (auto begin = text.begin(), end = text.end(); begin != end;)
bool firstGlyph = true;
while (begin != end)
{ {
uint32_t c = utf8::next(begin, end); uint32_t c = utf8::next(begin, end);
if (c == '\n') if (c == '\n')
@@ -215,72 +160,56 @@ namespace OpenVulkano::Scene
cursorX = pos.x; cursorX = pos.x;
continue; continue;
} }
// TODO handle special chars
if (symbols->find(c) == symbols->end()) if (!symbols->contains(c))
{ {
Logger::RENDER->error("Could not find glyph for character {}", c); Logger::RENDER->warn("Could not find glyph for character {}, using fallback", c);
if (symbols->find(static_cast<uint32_t>('?')) != symbols->end()) c = fallbackGlyph;
{
c = static_cast<uint32_t>('?');
}
else
{
Logger::RENDER->error("Could not find glyph for character ? to replace glyph {}", c);
continue;
}
} }
uint32_t vIdx = i * 4;
uint32_t indices[] = { 1 + vIdx, 2 + vIdx, 3 + vIdx, 1 + vIdx, 3 + vIdx, 0 + vIdx };
GlyphInfo& info = symbols->at(c); GlyphInfo& info = symbols->at(c);
// left bottom for (int i = 0; i < 4; i++)
m_geometry.vertices[vIdx].position.x = info.xyz[0].x + cursorX; {
m_geometry.vertices[vIdx].position.y = posY - info.xyz[0].y; vertices->position[i].x = info.xyz[i].x + cursorX;
m_geometry.vertices[vIdx].position.z = info.xyz[0].z; vertices->uv[i] = info.uv[i];
m_geometry.vertices[vIdx].textureCoordinates = Math::Vector3f(info.uv[0], 0); if (i < 2) vertices->position[i].y = posY - info.xyz[i].y;
else vertices->position[i].y = posY + info.xyz[i].y;
vertices->color = m_cfg.textColor;
vertices->background = m_cfg.backgroundColor;
}
// right bottom
m_geometry.vertices[vIdx + 1].position.x = info.xyz[1].x + cursorX;
m_geometry.vertices[vIdx + 1].position.y = posY - info.xyz[1].y;
m_geometry.vertices[vIdx + 1].position.z = info.xyz[1].z;
m_geometry.vertices[vIdx + 1].textureCoordinates = Math::Vector3f(info.uv[1], 0);
// top right
m_geometry.vertices[vIdx + 2].position.x = info.xyz[2].x + cursorX;
m_geometry.vertices[vIdx + 2].position.y = posY + info.xyz[2].y;
m_geometry.vertices[vIdx + 2].position.z = info.xyz[2].z;
m_geometry.vertices[vIdx + 2].textureCoordinates = Math::Vector3f(info.uv[2], 0);
// top left
m_geometry.vertices[vIdx + 3].position.x = info.xyz[3].x + cursorX;
m_geometry.vertices[vIdx + 3].position.y = posY + info.xyz[3].y;
m_geometry.vertices[vIdx + 3].position.z = info.xyz[3].z;
m_geometry.vertices[vIdx + 3].textureCoordinates = Math::Vector3f(info.uv[3], 0);
m_geometry.SetIndices(indices, 6, 6 * i);
// TODO: change to lower value(or ideally remove completely) to avoid overlapping and make less space between symbols // TODO: change to lower value(or ideally remove completely) to avoid overlapping and make less space between symbols
// when setting for depth comparison operator will be available( <= ) // when setting for depth comparison operator will be available( <= )
cursorX += info.advance + 0.08; cursorX += info.advance + 0.08;
if (firstGlyph)
{ bmax.x = std::max(bmax.x, vertices->position[1].x);
bmin.x = m_geometry.vertices[vIdx].position.x; bmax.y = std::max(bmax.y, vertices->position[2].y);
firstGlyph = false; bmin.y = std::min(bmin.y, vertices->position[1].y);
} vertices++;
bmax.x = std::max(bmax.x, m_geometry.vertices[vIdx + 1].position.x); m_symbolCount++;
bmax.y = std::max(bmax.y, m_geometry.vertices[vIdx + 2].position.y);
bmin.y = std::min(bmin.y, m_geometry.vertices[vIdx + 1].position.y);
++i;
} }
bmin.x = vertices->position[0].x;
m_bbox.Init(bmin, bmax); m_bbox.Init(bmin, bmax);
SimpleDrawable::Init(m_shader, &m_geometry, &m_material, &m_uniBuffer);
if (!GetShader()) SetShader(GetDefaultShader(m_atlasData->meta.atlasType));
} }
void TextDrawable::SetAtlasData(const std::shared_ptr<AtlasData>& atlasData) void TextDrawable::SetAtlasData(const std::shared_ptr<AtlasData>& atlasData)
{ {
if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer) if (!atlasData || !*atlasData) throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
{
throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
}
m_atlasData = atlasData; m_atlasData = atlasData;
} }
Shader* TextDrawable::GetDefaultShader(const FontAtlasType type)
{
switch (type)
{
case FontAtlasType::SDF: return &DEFAULT_SHADER_SDF;
case FontAtlasType::MSDF: return &DEFAULT_SHADER_MSDF;
default: Logger::RENDER->warn("No default shader for atlas type: {}", type.GetName());
case FontAtlasType::BITMAP: return &DEFAULT_SHADER_BITMAP;
}
}
} }

View File

@@ -6,62 +6,63 @@
#pragma once #pragma once
#include "SimpleDrawable.hpp" #include "Drawable.hpp"
#include "Texture.hpp" #include "Texture.hpp"
#include "Material.hpp" #include "VertexBuffer.hpp"
#include "Geometry.hpp"
#include "UniformBuffer.hpp"
#include "AtlasData.hpp" #include "AtlasData.hpp"
#include "Image/Image.hpp" #include "Image/Image.hpp"
#include <map>
#include <optional>
namespace OpenVulkano::Scene namespace OpenVulkano::Scene
{ {
class IFontAtlasGenerator; class IFontAtlasGenerator;
struct TextConfig struct TextConfig
{ {
Math::Vector4f textColor = { 1, 1, 1, 1 }; Math::Vector4uc textColor = { 255, 255, 255, 255 };
Math::Vector4f borderColor = { 1, 0, 0, 1 }; Math::Vector4uc backgroundColor = { 0, 255, 0, 0 };
Math::Vector4f backgroundColor = { 0, 1, 0, 0 };
float threshold = 0.4f;
float borderSize = 0.05f;
float smoothing = 1.f/32.f;
uint32_t applyBorder = false;
//bool sdfMultiChannel = false;
}; };
class TextDrawable : public SimpleDrawable struct TextGlyphVertex
{ {
std::array<Math::Vector2f, 4> position;
std::array<Math::Vector2f, 4> uv;
Math::Vector4uc color = { 255, 255, 255, 255 };
Math::Vector4uc background = {};
};
class TextDrawable : public Drawable
{
VertexBuffer m_vertexBuffer;
std::shared_ptr<AtlasData> m_atlasData;
Math::AABB2f m_bbox;
std::string m_text;
size_t m_symbolCount = 0;
TextConfig m_cfg;
uint32_t GetFallbackGlyph() const;
public: public:
static Shader& GetSdfDefaultShader();
static Shader& GetMsdfDefaultShader();
static Shader& GetBitmapDefaultShader();
TextDrawable(const TextConfig& config = TextConfig()); TextDrawable(const TextConfig& config = TextConfig());
TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config = TextConfig()); TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config = TextConfig());
TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config = TextConfig()); TextDrawable(const std::string& atlasMetadataFile, const TextConfig& config = TextConfig());
TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config = TextConfig()); TextDrawable(const std::string& atlasMetadataFile, Texture* atlasTex, const TextConfig& config = TextConfig());
TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config = TextConfig()); TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config = TextConfig());
TextDrawable(const std::shared_ptr<AtlasData>& atlasData, const TextConfig& config = TextConfig()); TextDrawable(const std::shared_ptr<AtlasData>& atlasData, const TextConfig& config = TextConfig());
void GenerateText(const std::string& text, const Math::Vector3f& pos = Math::Vector3f(0.f));
void GenerateText(const std::string& text, const Math::Vector2f& pos = Math::Vector2f(0.f));
void SetConfig(const TextConfig& cfg) { m_cfg = cfg; } void SetConfig(const TextConfig& cfg) { m_cfg = cfg; }
void SetShader(Shader* shader) { m_shader = shader; }
void SetAtlasData(const std::shared_ptr<AtlasData>& atlasData); void SetAtlasData(const std::shared_ptr<AtlasData>& atlasData);
Math::AABB& GetBoundingBox() { return m_bbox; }
TextConfig& GetConfig() { return m_cfg; } [[nodiscard]] Math::AABB2f& GetBoundingBox() { return m_bbox; }
Shader* GetShader() { return m_shader; } [[nodiscard]] TextConfig& GetConfig() { return m_cfg; }
[[nodiscard]] const std::string& GetText() const { return m_text; } [[nodiscard]] const std::string& GetText() const { return m_text; }
std::shared_ptr<AtlasData> GetAtlasData() { return m_atlasData; } [[nodiscard]] const std::shared_ptr<AtlasData>& GetAtlasData() { return m_atlasData; }
private:
Geometry m_geometry; [[nodiscard]] VertexBuffer* GetVertexBuffer() { return &m_vertexBuffer; }
Material m_material; [[nodiscard]] Texture* GetTexture() { return &m_atlasData->texture; }
UniformBuffer m_uniBuffer; [[nodiscard]] size_t GetSymbolCount() const { return m_symbolCount; }
std::shared_ptr<AtlasData> m_atlasData;
Math::AABB m_bbox; [[nodiscard]] static Shader MakeDefaultShader(FontAtlasType type);
Shader* m_shader = nullptr; [[nodiscard]] static Shader* GetDefaultShader(FontAtlasType type);
std::string m_text;
TextConfig m_cfg;
}; };
} }

View File

@@ -19,11 +19,15 @@ namespace OpenVulkano::Scene
DescriptorSetLayoutBinding binding; DescriptorSetLayoutBinding binding;
uint32_t setId; uint32_t setId;
size_t size = 0; size_t size;
const void* data = nullptr; const void* data;
UpdateFrequency updateFrequency = UpdateFrequency::Never; UpdateFrequency updateFrequency = UpdateFrequency::Never;
bool updated = true; bool updated = true;
UniformBuffer(size_t size = 0, const void* data = nullptr, uint32_t setId = 2, const DescriptorSetLayoutBinding& binding = DESCRIPTOR_SET_LAYOUT_BINDING)
: binding(binding), setId(setId), size(size), data(data)
{}
void Init(size_t size, const void* data, uint32_t setId = 2, const DescriptorSetLayoutBinding& binding = DESCRIPTOR_SET_LAYOUT_BINDING) void Init(size_t size, const void* data, uint32_t setId = 2, const DescriptorSetLayoutBinding& binding = DESCRIPTOR_SET_LAYOUT_BINDING)
{ {
this->size = size; this->size = size;

View File

@@ -0,0 +1,54 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "Base/Render/RenderResource.hpp"
#include "Scene/UpdateFrequency.hpp"
namespace OpenVulkano::Scene
{
class VertexBuffer final : public RenderResourceHolder<VertexBuffer>
{
public:
size_t size = 0;
const void* data = nullptr;
UpdateFrequency updateFrequency = UpdateFrequency::Never;
bool updated = true;
bool ownsMemory = true;
~VertexBuffer() { Close(); }
void Init(size_t size, const void* data)
{
this->size = size;
this->data = data;
this->ownsMemory = false;
}
void Init(size_t size)
{
this->size = size;
this->data = malloc(size);
this->ownsMemory = true;
}
template<typename T>
T* Init(size_t count)
{
Init(count * sizeof(T));
return static_cast<T*>(const_cast<void*>(data));
}
void Close()
{
if (ownsMemory && data) free(const_cast<void*>(data));
data = nullptr;
}
UpdateFrequency GetUpdateFrequency() const { return updateFrequency; }
};
}

View File

@@ -3,11 +3,11 @@
layout(location = 1) in vec2 texCoord; layout(location = 1) in vec2 texCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(set = 5, binding = 0) uniform LabelData layout(set = 4, binding = 0) uniform LabelData
{ {
vec4 textSize;
vec4 color; vec4 color;
vec4 bboxCenter; vec2 textSize;
vec2 bboxCenter;
float radius; float radius;
float arrowLength; float arrowLength;
float arrowWidth; float arrowWidth;

View File

@@ -11,13 +11,14 @@ layout(set = 1, binding = 0) uniform CameraData
mat4 viewProjection; mat4 viewProjection;
} cam; } cam;
layout(set = 5, binding = 0) uniform LabelData layout(set = 4, binding = 0) uniform LabelData
{ {
vec4 textSize;
vec4 color; vec4 color;
vec4 bboxCenter; vec2 textSize;
vec2 bboxCenter;
float radius; float radius;
float arrowLength; float arrowLength;
float arrowWidth;
bool hasRoundedCorners; bool hasRoundedCorners;
bool hasArrow; bool hasArrow;
} labelInfo; } labelInfo;
@@ -28,18 +29,18 @@ layout(location = 1) out vec2 textureCoordinates;
// Background plane positions are in clipped space // Background plane positions are in clipped space
const vec4 PLANE[4] = vec4[]( const vec4 PLANE[4] = vec4[](
vec4(-0.5, -0.5, 0, 1), vec4(0.5, -0.5, 0, 1), vec4(-0.5, 0.5, 0, 1), vec4(0.5, 0.5, 0, 1) vec4(-0.5, -0.5, 0, 1), vec4(0.5, -0.5, 0, 1), vec4(-0.5, 0.5, 0, 1), vec4(0.5, 0.5, 0, 1)
); );
const vec2 TEX_COORDS[4] = vec2[]( const vec2 TEX_COORDS[4] = vec2[](
vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1) vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1)
); );
void main() { void main()
{
vec4 position = PLANE[gl_VertexIndex]; vec4 position = PLANE[gl_VertexIndex];
vec2 bbox = labelInfo.textSize.xy; position.xy *= labelInfo.textSize;
position.xy *= bbox; position.xy += labelInfo.bboxCenter;
position.xy += vec2(labelInfo.bboxCenter); //position.z = -0.001;
position.z = -0.001;
gl_Position = cam.viewProjection * node.world * position; gl_Position = cam.viewProjection * node.world * position;
textureCoordinates = TEX_COORDS[gl_VertexIndex] * bbox; textureCoordinates = TEX_COORDS[gl_VertexIndex] * labelInfo.textSize;
} }

View File

@@ -22,21 +22,17 @@ layout(set = 1, binding = 0) uniform CameraData
float pixelScaleFactor; float pixelScaleFactor;
} cam; } cam;
layout(set = 4, binding = 0) uniform BillboardData layout(set = 4, binding = 0) uniform LabelData
{ {
vec2 size;
bool isFixedSize;
} billboardInfo;
layout(set = 5, binding = 0) uniform LabelData
{
vec4 textSize;
vec4 color; vec4 color;
vec4 bboxCenter; vec2 textSize;
vec2 bboxCenter;
float radius; float radius;
float arrowLength; float arrowLength;
float arrowWidth;
bool hasRoundedCorners; bool hasRoundedCorners;
bool hasArrow; bool hasArrow;
bool isBillboardFixedSize;
} labelInfo; } labelInfo;
layout(location = 0) out vec4 color; layout(location = 0) out vec4 color;
@@ -45,21 +41,19 @@ layout(location = 1) out vec2 textureCoordinates;
// Background plane positions are in clipped space // Background plane positions are in clipped space
const vec4 PLANE[4] = vec4[]( const vec4 PLANE[4] = vec4[](
vec4(-0.5, -0.5, 0, 1), vec4(0.5, -0.5, 0, 1), vec4(-0.5, 0.5, 0, 1), vec4(0.5, 0.5, 0, 1) vec4(-0.5, -0.5, 0, 1), vec4(0.5, -0.5, 0, 1), vec4(-0.5, 0.5, 0, 1), vec4(0.5, 0.5, 0, 1)
);
const vec2 TEX_COORDS[4] = vec2[](
vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1)
); );
void main() { const vec2 TEX_COORDS[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1));
void main()
{
vec4 position = PLANE[gl_VertexIndex]; vec4 position = PLANE[gl_VertexIndex];
vec2 bbox = labelInfo.textSize.xy; position.xy *= labelInfo.textSize;
position.xy *= bbox; position.xy += labelInfo.bboxCenter;
position.xy += vec2(labelInfo.bboxCenter); position.z = - 0.001;
position.z = -0.001; textureCoordinates = TEX_COORDS[gl_VertexIndex] * labelInfo.textSize;
textureCoordinates = TEX_COORDS[gl_VertexIndex] * bbox;
if (!billboardInfo.isFixedSize) if (!labelInfo.isBillboardFixedSize)
{ {
mat4 mv = cam.view * node.world; mat4 mv = cam.view * node.world;
@@ -79,9 +73,9 @@ void main() {
} }
else else
{ {
vec4 billboardPos = vec4(0.5, 0.5, 0.5, 1); vec4 billboardPos = vec4(0.5, 0.5, 0, 1);
vec4 viewPos = cam.view * node.world * billboardPos; vec4 viewPos = cam.view * node.world * billboardPos;
float dist = -viewPos.z; float dist = - viewPos.z;
gl_Position = cam.projection * (viewPos + vec4(position.xy*dist*0.2,0,0)); gl_Position = cam.projection * (viewPos + vec4(position.xy *dist * 0.2, 0, 0));
} }
} }

View File

@@ -1,47 +1,40 @@
#version 450 #version 450
layout(location = 1) in vec2 texCoord; layout(location = 0) in vec4 color;
layout(location = 1) in vec4 bgColor;
layout(location = 2) in vec2 texCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(set = 2, binding = 0) uniform sampler2D texSampler; layout(set = 2, binding = 0) uniform sampler2D texSampler;
layout(set = 3, binding = 0) uniform TextConfig float median(float r, float g, float b)
{ {
vec4 textColor;
vec4 borderColor;
vec4 backgroundColor;
float threshold;
float borderSize;
float smoothing;
bool applyBorder;
} textConfig;
float median(float r, float g, float b) {
return max(min(r, g), min(max(r, g), b)); return max(min(r, g), min(max(r, g), b));
} }
// this parameter should be same as FontAtlasGeneratorConfig::pixelRange // this parameter should be same as FontAtlasGeneratorConfig::pixelRange
const float pxRange = 3; const float pxRange = 3;
float screenPxRange() { float screenPxRange()
vec2 unitRange = vec2(pxRange)/vec2(textureSize(texSampler, 0)); {
vec2 screenTexSize = vec2(1.0)/fwidth(texCoord); vec2 unitRange = vec2(pxRange) / vec2(textureSize(texSampler, 0));
return max(0.5*dot(unitRange, screenTexSize), 1.0); vec2 screenTexSize = vec2(1.0) / fwidth(texCoord);
return max(0.5 * dot(unitRange, screenTexSize), 1.0);
} }
void main() void main()
{ {
vec3 msd = texture(texSampler, texCoord).rgb; vec3 msd = texture(texSampler, texCoord).rgb;
float sd = median(msd.r, msd.g, msd.b); float sd = median(msd.r, msd.g, msd.b);
float screenPxDistance = screenPxRange()*(sd - 0.5); float screenPxDistance = screenPxRange() * (sd - 0.5);
float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0); float opacity = clamp(screenPxDistance + 0.5, 0.0, 1.0);
if (textConfig.backgroundColor.a != 0) if (bgColor.a != 0)
{ {
outColor = mix(textConfig.backgroundColor, textConfig.textColor, opacity); outColor = mix(bgColor, color, opacity);
} }
else else
{ {
outColor = vec4(vec3(textConfig.textColor), opacity); outColor = vec4(vec3(color), opacity);
} }
} }

View File

@@ -1,39 +1,24 @@
#version 450 #version 450
layout(location = 1) in vec2 texCoord; layout(location = 0) in vec4 color;
layout(location = 1) in vec4 bgColor;
layout(location = 2) in vec2 texCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(set = 2, binding = 0) uniform sampler2D texSampler; layout(set = 2, binding = 0) uniform sampler2D texSampler;
layout(set = 3, binding = 0) uniform TextConfig const float threshold = 0.4f;
{ const float smoothing = 1.f/32.f;
vec4 textColor;
vec4 borderColor;
vec4 backgroundColor;
float threshold;
float borderSize;
float smoothing;
bool applyBorder;
} textConfig;
void main() void main()
{ {
float distance = texture(texSampler, texCoord).r; float distance = texture(texSampler, texCoord).r;
float alpha = smoothstep(textConfig.threshold - textConfig.smoothing, textConfig.threshold + textConfig.smoothing, distance); float alpha = smoothstep(threshold - smoothing, threshold + smoothing, distance);
if (textConfig.applyBorder) outColor = vec4(color) * alpha;
{
float border = smoothstep(textConfig.threshold + textConfig.borderSize - textConfig.smoothing,
textConfig.threshold + textConfig.borderSize + textConfig.smoothing, distance);
outColor = mix(textConfig.borderColor, textConfig.textColor, border) * alpha;
}
else
{
outColor = vec4(textConfig.textColor) * alpha;
}
if (textConfig.backgroundColor.a != 0) if (bgColor.a != 0)
{ {
outColor = mix(textConfig.backgroundColor, outColor, alpha); outColor = mix(bgColor, outColor, alpha);
} }
} }

View File

@@ -1,26 +0,0 @@
#version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal;
layout(location = 2) in vec3 tangent;
layout(location = 3) in vec3 biTangent;
layout(location = 4) in vec3 textureCoordinates;
layout(location = 5) in vec4 color;
layout(location = 1) out vec2 fragTextureCoordinates;
layout(set = 0, binding = 0) uniform NodeData
{
mat4 world;
} node;
layout(set = 1, binding = 0) uniform CameraData
{
mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
} cam;
void main() {
gl_Position = cam.viewProjection * node.world * vec4(position, 1.0);
fragTextureCoordinates.xy = textureCoordinates.xy;
}

View File

@@ -0,0 +1,32 @@
#version 450
layout(location = 1) in vec2 texCoord;
layout(location = 0) out vec4 outColor;
layout(set = 2, binding = 0) uniform sampler2D texSampler;
layout(set = 3, binding = 0) uniform TextConfig
{
vec4 textColor;
vec4 borderColor;
vec4 backgroundColor;
float threshold;
float borderSize;
float smoothing;
} textConfig;
void main()
{
float distance = texture(texSampler, texCoord).r;
float alpha = smoothstep(textConfig.threshold - textConfig.smoothing, textConfig.threshold + textConfig.smoothing, distance);
float border = smoothstep(textConfig.threshold + textConfig.borderSize - textConfig.smoothing,
textConfig.threshold + textConfig.borderSize + textConfig.smoothing, distance);
outColor = mix(textConfig.borderColor, textConfig.textColor, border) * alpha;
if (textConfig.backgroundColor.a != 0)
{
outColor = mix(textConfig.backgroundColor, outColor, alpha);
}
}

View File

@@ -1,25 +1,15 @@
#version 450 #version 450
layout(location = 0) in vec4 color; layout(location = 0) in vec4 color;
layout(location = 1) in vec2 texCoord; layout(location = 1) in vec4 bgColor;
layout(location = 2) in vec2 texCoord;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(set = 2, binding = 0) uniform sampler2D texSampler; layout(set = 2, binding = 0) uniform sampler2D texSampler;
layout(set = 3, binding = 0) uniform TextConfig
{
vec4 textColor;
vec4 borderColor;
vec4 backgroundColor;
float threshold;
float borderSize;
float smoothing;
bool applyBorder;
} textConfig;
void main() void main()
{ {
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(texSampler, texCoord).r); vec4 sampled = vec4(1.0, 1.0, 1.0, texture(texSampler, texCoord).r);
outColor = vec4(textConfig.textColor) * sampled; outColor = vec4(color) * sampled;
} }

View File

@@ -1,13 +1,13 @@
#version 450 #version 450
layout(location = 0) in vec3 position;
layout(location = 1) in vec3 normal; layout(location = 0) in vec2 position[4];
layout(location = 2) in vec3 tangent; layout(location = 4) in vec2 textureCoordinates[4];
layout(location = 3) in vec3 biTangent; layout(location = 8) in vec4 color;
layout(location = 4) in vec3 textureCoordinates; layout(location = 9) in vec4 bgColor;
layout(location = 5) in vec4 color;
layout(location = 0) out vec4 outColor; layout(location = 0) out vec4 outColor;
layout(location = 1) out vec2 fragTextureCoordinates; layout(location = 1) out vec4 outBgColor;
layout(location = 2) out vec2 fragTextureCoordinates;
layout(set = 0, binding = 0) uniform NodeData layout(set = 0, binding = 0) uniform NodeData
{ {
@@ -17,13 +17,11 @@ layout(set = 0, binding = 0) uniform NodeData
layout(set = 1, binding = 0) uniform CameraData layout(set = 1, binding = 0) uniform CameraData
{ {
mat4 viewProjection; mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
} cam; } cam;
void main() { void main() {
gl_Position = cam.viewProjection * node.world * vec4(position, 1.0); gl_Position = cam.viewProjection * node.world * vec4(position[gl_VertexIndex], 0.0, 1.0);
fragTextureCoordinates.xy = textureCoordinates.xy; fragTextureCoordinates = textureCoordinates[gl_VertexIndex];
outColor = color; outColor = color;
outBgColor = bgColor;
} }

View File

@@ -0,0 +1,71 @@
#version 450
#extension GL_ARB_separate_shader_objects : enable
layout(location = 0) in vec2 position[4];
layout(location = 4) in vec2 textureCoordinates[4];
layout(location = 8) in vec4 color;
layout(location = 9) in vec4 bgColor;
layout(location = 0) out vec4 outColor;
layout(location = 1) out vec4 outBgColor;
layout(location = 2) out vec2 outTexture;
layout(set = 0, binding = 0) uniform NodeData
{
mat4 world;
} node;
layout(set = 1, binding = 0) uniform CameraData
{
mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
} cam;
layout(set = 4, binding = 0) uniform BillboardData
{
vec4 color;
vec2 textSize;
vec2 bboxCenter;
float radius;
float arrowLength;
float arrowWidth;
bool hasRoundedCorners;
bool hasArrow;
bool isBillboardFixedSize;
} billboardInfo;
void main()
{
vec4 pos = vec4(position[gl_VertexIndex], 0, 1);
if (!billboardInfo.isBillboardFixedSize)
{
mat4 mv = cam.view * node.world;
mv[0][0] = 1;
mv[0][1] = 0;
mv[0][2] = 0;
mv[1][0] = 0;
mv[1][1] = 1;
mv[1][2] = 0;
mv[2][0] = 0;
mv[2][1] = 0;
mv[2][2] = 1;
gl_Position = cam.projection * mv * pos;
}
else
{
vec4 billboardPos = vec4(0.5, 0.5, 0, 1);
vec4 viewPos = cam.view * node.world * billboardPos;
float dist = -viewPos.z;
gl_Position = cam.projection * (viewPos + vec4(pos.xy * dist * 0.2, 0, 0));
}
outTexture = textureCoordinates[gl_VertexIndex];
outColor = color;
outBgColor = bgColor;
}

View File

@@ -1,5 +1,5 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Device.hpp" #include "Device.hpp"
namespace OpenVulkano namespace OpenVulkano
@@ -9,7 +9,7 @@ namespace OpenVulkano
/** /**
* \brief A not managed buffer. This should be used rarely. * \brief A not managed buffer. This should be used rarely.
*/ */
struct Buffer : public ICloseable struct Buffer
{ {
vk::Device device; vk::Device device;
vk::DeviceMemory memory; vk::DeviceMemory memory;
@@ -94,7 +94,7 @@ namespace OpenVulkano
device.invalidateMappedMemoryRanges(vk::MappedMemoryRange(memory, offset, size)); device.invalidateMappedMemoryRanges(vk::MappedMemoryRange(memory, offset, size));
} }
void Close() override void Close()
{ {
if (mapped) UnMap(); if (mapped) UnMap();
if(memory) if(memory)

View File

@@ -6,14 +6,13 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
namespace OpenVulkano namespace OpenVulkano
{ {
namespace Vulkan namespace Vulkan
{ {
struct CommandHelper : virtual ICloseable struct CommandHelper final
{ {
vk::Device device; vk::Device device;
vk::CommandPool cmdPool; vk::CommandPool cmdPool;
@@ -42,7 +41,7 @@ namespace OpenVulkano
return level; return level;
} }
void Close() override void Close()
{ {
device.freeCommandBuffers(cmdPool, 1, &cmdBuffer); device.freeCommandBuffers(cmdPool, 1, &cmdBuffer);
device.destroyCommandPool(cmdPool); device.destroyCommandPool(cmdPool);

View File

@@ -21,7 +21,7 @@ namespace OpenVulkano
{ {
class Device; class Device;
class Context final : public ICloseable class Context final
{ {
bool enableValidationLayer, initialized; bool enableValidationLayer, initialized;
std::set<std::string> requiredExtensions; std::set<std::string> requiredExtensions;
@@ -45,14 +45,14 @@ namespace OpenVulkano
#endif #endif
} }
~Context() override ~Context()
{ {
if (initialized) Close(); if (initialized) Close();
} }
void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window); void Init(IGraphicsAppManager* graphicsAppManager, IVulkanWindow* window);
void Close() override; void Close();
void Resize(uint32_t newWidth, uint32_t newHeight); void Resize(uint32_t newWidth, uint32_t newHeight);

View File

@@ -10,13 +10,12 @@
#include <set> #include <set>
#include <functional> #include <functional>
#include <fstream> #include <fstream>
#include "Base/ICloseable.hpp"
namespace OpenVulkano namespace OpenVulkano
{ {
namespace Vulkan namespace Vulkan
{ {
class Device : public ICloseable class Device final
{ {
public: public:
vk::PhysicalDevice physicalDevice; vk::PhysicalDevice physicalDevice;
@@ -106,7 +105,7 @@ namespace OpenVulkano
return memoryProperties.memoryTypes[memoryType].propertyFlags; return memoryProperties.memoryTypes[memoryType].propertyFlags;
} }
void Close() override; void Close();
}; };
} }
} }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Image.hpp" #include "Image.hpp"
#include "Device.hpp" #include "Device.hpp"
#include <cstdint> #include <cstdint>
@@ -17,7 +16,7 @@ namespace OpenVulkano::Vulkan
{ {
class RenderPass; class RenderPass;
class FrameBuffer : ICloseable class FrameBuffer
{ {
Image depthBuffer; Image depthBuffer;
std::vector<vk::Framebuffer> frameBuffers; std::vector<vk::Framebuffer> frameBuffers;
@@ -50,7 +49,7 @@ namespace OpenVulkano::Vulkan
protected: protected:
void Resize(vk::Extent3D size); void Resize(vk::Extent3D size);
void Close() override virtual void Close()
{ {
DestroyFrameBuffer(); DestroyFrameBuffer();
if(depthBuffer) depthBuffer.Close(); if(depthBuffer) depthBuffer.Close();

View File

@@ -47,7 +47,7 @@ namespace OpenVulkano::Vulkan
SetLayout(cmdBuffer, vk::ImageSubresourceRange(aspectMask, 0, 1, 0, 1), newLayout, oldLayout); SetLayout(cmdBuffer, vk::ImageSubresourceRange(aspectMask, 0, 1, 0, 1), newLayout, oldLayout);
} }
void Close() override; virtual void Close();
operator bool() const { return image.operator bool(); } operator bool() const { return image.operator bool(); }

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "MetalBackedTexture.h" #include "MetalBackedTexture.h"
#import <CoreVideo/CVPixelBuffer.h> #import <CoreVideo/CVPixelBuffer.h>
@@ -16,19 +15,20 @@ namespace OpenVulkano::Vulkan
{ {
class Renderer; class Renderer;
class MetalTextureCache : public ICloseable class MetalTextureCache final
{ {
CVMetalTextureCacheRef m_textureCache = nullptr; CVMetalTextureCacheRef m_textureCache = nullptr;
Vulkan::ResourceManager* m_resourceManager = nullptr; Vulkan::ResourceManager* m_resourceManager = nullptr;
std::map<void*, MetalBackedTexture> m_mtlToVkTextureMap; std::map<void*, MetalBackedTexture> m_mtlToVkTextureMap;
Renderer* m_renderer; Renderer* m_renderer;
IEventHandler* m_eventHandler = nullptr;
public: public:
~MetalTextureCache() { if (m_resourceManager) Close(); } ~MetalTextureCache() { if (m_resourceManager) Close(); }
void Init(IRenderer* renderer); void Init(IRenderer* renderer);
void Close() override; void Close();
Scene::Texture* Get(CVPixelBufferRef pixelBuffer, MTLPixelFormat pixelFormat); Scene::Texture* Get(CVPixelBufferRef pixelBuffer, MTLPixelFormat pixelFormat);

View File

@@ -28,7 +28,7 @@ namespace OpenVulkano::Vulkan
Logger::AR->error("Failed to create metal texture cache! Status code: {}", result); Logger::AR->error("Failed to create metal texture cache! Status code: {}", result);
} }
m_resourceManager = &m_renderer->GetResourceManager(); m_resourceManager = &m_renderer->GetResourceManager();
m_renderer->RegisterCloseable(this); m_renderer->OnClose += EventHandler(this, &MetalTextureCache::Close);
} }
Scene::Texture* MetalTextureCache::Get(CVPixelBufferRef pixelBuffer, MTLPixelFormat pixelFormat) Scene::Texture* MetalTextureCache::Get(CVPixelBufferRef pixelBuffer, MTLPixelFormat pixelFormat)
@@ -57,7 +57,7 @@ namespace OpenVulkano::Vulkan
void MetalTextureCache::Close() void MetalTextureCache::Close()
{ {
m_mtlToVkTextureMap.clear(); m_mtlToVkTextureMap.clear();
m_renderer->UnregisterCloseable(this); m_eventHandler->SetInvalid();
m_renderer = nullptr; m_renderer = nullptr;
m_resourceManager = nullptr; m_resourceManager = nullptr;
//TODO delete the texture cache object? //TODO delete the texture cache object?

View File

@@ -13,7 +13,7 @@ namespace OpenVulkano::Vulkan
{ {
class FrameBuffer; class FrameBuffer;
class RenderPass : public ICloseable class RenderPass
{ //TODO allow to control the render rect size { //TODO allow to control the render rect size
protected: protected:
vk::Device m_device; vk::Device m_device;
@@ -27,14 +27,14 @@ namespace OpenVulkano::Vulkan
RenderPass() = default; RenderPass() = default;
~RenderPass() override virtual ~RenderPass()
{ {
if (m_frameBuffer) RenderPass::Close(); if (m_frameBuffer) RenderPass::Close();
} }
void Init(Device* device, FrameBuffer* frameBuffer, bool clearColor = false, bool clearDepth = false); void Init(Device* device, FrameBuffer* frameBuffer, bool clearColor = false, bool clearDepth = false);
void Close() override; virtual void Close();
void SetClearColor(vk::ClearColorValue clearColor = vk::ClearColorValue(std::array<float, 4>{ 0.39f, 0.58f, 0.93f, 1.0f })) void SetClearColor(vk::ClearColorValue clearColor = vk::ClearColorValue(std::array<float, 4>{ 0.39f, 0.58f, 0.93f, 1.0f }))
{ {

View File

@@ -89,12 +89,7 @@ namespace OpenVulkano::Vulkan
{ {
context.device->device.destroySemaphore(sema); context.device->device.destroySemaphore(sema);
} }
while (!closeables.empty()) OnClose();
{
ICloseable* closeable = closeables.back();
closeables.pop_back();
closeable->Close();
}
depthBufferQuery.Close(); depthBufferQuery.Close();
uiRenderer.Close(); uiRenderer.Close();
resourceManager.Close(); resourceManager.Close();

View File

@@ -40,7 +40,6 @@ namespace OpenVulkano::Vulkan
std::vector<std::vector<CommandHelper>> commands; std::vector<std::vector<CommandHelper>> commands;
std::vector<std::vector<vk::CommandBuffer>> submitBuffers; std::vector<std::vector<vk::CommandBuffer>> submitBuffers;
UiRenderer uiRenderer; UiRenderer uiRenderer;
std::vector<ICloseable*> closeables;
DepthBufferQuery depthBufferQuery; DepthBufferQuery depthBufferQuery;
public: public:
@@ -83,14 +82,12 @@ namespace OpenVulkano::Vulkan
Context& GetContext() { return context; } Context& GetContext() { return context; }
void RegisterCloseable(ICloseable* closeable) { closeables.push_back(closeable); }
void UnregisterCloseable(ICloseable* closeable) { Utils::Remove(closeables, closeable); }
IResourceManager* GetIResourceManager() override { return &resourceManager; } IResourceManager* GetIResourceManager() override { return &resourceManager; }
float GetLastQueriedDepthValue() override { return depthBufferQuery.GetQueriedValue(); } float GetLastQueriedDepthValue() override { return depthBufferQuery.GetQueriedValue(); }
void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) override { depthBufferQuery.SetQueryCoordinates(depthCoordinates); } void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) override { depthBufferQuery.SetQueryCoordinates(depthCoordinates); }
Event<> OnClose;
}; };
} }

View File

@@ -5,6 +5,9 @@
*/ */
#include "ResourceManager.hpp" #include "ResourceManager.hpp"
#include <Scene/VertexBuffer.hpp>
#include "ManagedBuffer.hpp" #include "ManagedBuffer.hpp"
#include "MemoryAllocation.hpp" #include "MemoryAllocation.hpp"
#include "Scene/Vertex.hpp" #include "Scene/Vertex.hpp"
@@ -21,6 +24,7 @@
#include "Vulkan/Scene/VulkanTexture.hpp" #include "Vulkan/Scene/VulkanTexture.hpp"
#include "Vulkan/Scene/VulkanCamera.hpp" #include "Vulkan/Scene/VulkanCamera.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp" #include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"
namespace OpenVulkano::Vulkan namespace OpenVulkano::Vulkan
{ {
@@ -173,6 +177,21 @@ namespace OpenVulkano::Vulkan
return geometry->GetRenderResource(); return geometry->GetRenderResource();
} }
VulkanVertexBuffer* ResourceManager::PrepareVertexBuffer(Scene::VertexBuffer* vbo)
{
const std::unique_lock lock(mutex);
if(!vbo->HasRenderResource())
{
ManagedBuffer::Ptr vertexBuffer =
CreateDeviceOnlyBufferWithData(vbo->size, vk::BufferUsageFlagBits::eVertexBuffer, vbo->data);
ManagedBuffer::Ptr indexBuffer;
VulkanVertexBuffer* vkVbo = new VulkanVertexBuffer(vbo, vertexBuffer);
vertexBuffers.emplace_back(vkVbo);
return vkVbo;
}
return vbo->GetRenderResource();
}
void ResourceManager::PrepareMaterial(Scene::Material* material) void ResourceManager::PrepareMaterial(Scene::Material* material)
{ {
if (material->texture && !material->texture->HasRenderResource()) if (material->texture && !material->texture->HasRenderResource())

View File

@@ -34,6 +34,7 @@ namespace OpenVulkano
class Shader; class Shader;
class Camera; class Camera;
class UniformBuffer; class UniformBuffer;
class VertexBuffer;
} }
namespace Vulkan namespace Vulkan
@@ -45,11 +46,12 @@ namespace OpenVulkano
class VulkanNode; class VulkanNode;
class VulkanShader; class VulkanShader;
class VulkanUniformBuffer; class VulkanUniformBuffer;
class VulkanVertexBuffer;
class UniformBuffer; class UniformBuffer;
class ManagedBuffer; class ManagedBuffer;
class MemoryAllocation; class MemoryAllocation;
class ResourceManager : public IShaderOwner, public IResourceManager class ResourceManager final : public IShaderOwner, public IResourceManager
{ {
friend UniformBuffer; friend UniformBuffer;
friend VulkanTexture; friend VulkanTexture;
@@ -63,6 +65,7 @@ namespace OpenVulkano
MemoryPool memPool; MemoryPool memPool;
std::vector<Unique<VulkanShader>> shaders; std::vector<Unique<VulkanShader>> shaders;
std::vector<Unique<VulkanGeometry>> geometries; std::vector<Unique<VulkanGeometry>> geometries;
std::vector<Unique<VulkanVertexBuffer>> vertexBuffers;
std::vector<Unique<VulkanNode>> nodes; std::vector<Unique<VulkanNode>> nodes;
std::vector<Unique<VulkanTexture>> textures; std::vector<Unique<VulkanTexture>> textures;
std::vector<Unique<VulkanCamera>> cameras; std::vector<Unique<VulkanCamera>> cameras;
@@ -100,6 +103,8 @@ namespace OpenVulkano
VulkanUniformBuffer* PrepareUniformBuffer(Scene::UniformBuffer* buffer); VulkanUniformBuffer* PrepareUniformBuffer(Scene::UniformBuffer* buffer);
VulkanVertexBuffer* PrepareVertexBuffer(Scene::VertexBuffer* vbo);
VulkanNode* PrepareNode(Scene::Node* node); VulkanNode* PrepareNode(Scene::Node* node);
VulkanTexture* PrepareTexture(Scene::Texture* texture); VulkanTexture* PrepareTexture(Scene::Texture* texture);

View File

@@ -6,7 +6,6 @@
#pragma once #pragma once
#include "Base/ICloseable.hpp"
#include "Vulkan/Resources/ManagedBuffer.hpp" #include "Vulkan/Resources/ManagedBuffer.hpp"
#include "Vulkan/Scene/IRecordable.hpp" #include "Vulkan/Scene/IRecordable.hpp"
@@ -14,7 +13,7 @@ namespace OpenVulkano::Vulkan
{ {
class ManagedBuffer; class ManagedBuffer;
class UniformBuffer final : public IRecordable, public ICloseable class UniformBuffer final : public IRecordable
{ {
ManagedBuffer::Ptr m_buffer = nullptr; ManagedBuffer::Ptr m_buffer = nullptr;
vk::DescriptorSet m_descriptorSet; vk::DescriptorSet m_descriptorSet;
@@ -30,7 +29,7 @@ namespace OpenVulkano::Vulkan
void Init(ManagedBuffer::Ptr buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId); void Init(ManagedBuffer::Ptr buffer, uint32_t frameOffset, uint32_t frameSize, vk::DescriptorSetLayout* descriptorSetLayout, const DescriptorSetLayoutBinding& binding, uint32_t setId);
void Close() override; virtual void Close();
void Record(VulkanDrawContext* drawContext) override; void Record(VulkanDrawContext* drawContext) override;

View File

@@ -12,107 +12,61 @@
#include "Vulkan/VulkanDrawContext.hpp" #include "Vulkan/VulkanDrawContext.hpp"
#include "Vulkan/Scene/VulkanTexture.hpp" #include "Vulkan/Scene/VulkanTexture.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp" #include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"
using namespace OpenVulkano::Scene; using namespace OpenVulkano::Scene;
namespace OpenVulkano::Vulkan namespace OpenVulkano::Vulkan
{ {
void EncodeBackground(LabelDrawable* labelDrawable, Vulkan::VulkanDrawContext* drawContext) void EncodeBackground(LabelDrawable* labelDrawable, VulkanDrawContext* drawContext)
{ {
if (labelDrawable->IsBillboard()) VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
{ if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
OpenVulkano::Scene::UniformBuffer* buffer = labelDrawable->GetBillboardBuffer();
VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource();
if (!vkBuffer)
{
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer);
}
vkBuffer->Record(drawContext);
}
OpenVulkano::Scene::UniformBuffer* labelBuffer = labelDrawable->GetLabelBuffer();
VulkanUniformBuffer* vkBuffer = labelBuffer->GetRenderResource();
if (!vkBuffer)
{
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelBuffer);
}
vkBuffer->Record(drawContext); vkBuffer->Record(drawContext);
for (Node* node: labelDrawable->GetNodes()) for (Node* node: labelDrawable->GetNodes())
{ {
if (!node->IsEnabled()) [[unlikely]] if (!node->IsEnabled()) [[unlikely]] continue;
{
continue;
}
drawContext->EncodeNode(node); drawContext->EncodeNode(node);
} }
drawContext->commandBuffer.draw(4, 1, 0, 0); drawContext->commandBuffer.draw(4, 1, 0, 0);
} }
void EncodeTextDrawable(LabelDrawable* labelDrawable, Vulkan::VulkanDrawContext* drawContext) void EncodeTextDrawable(LabelDrawable* labelDrawable, VulkanDrawContext* drawContext)
{ {
for (TextDrawable& entry : labelDrawable->GetTexts()) for (TextDrawable& entry : labelDrawable->GetTexts())
{ {
OpenVulkano::Scene::Shader* shader = entry.GetShader(); drawContext->EncodeShader(entry.GetShader());
drawContext->EncodeShader(shader); VertexBuffer* vbo = entry.GetVertexBuffer();
Geometry* mesh = entry.GetMesh(); VulkanVertexBuffer* renderVbo = vbo->GetRenderResource();
VulkanGeometry* renderGeo = mesh->GetRenderResource(); if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo);
if (!renderGeo) renderVbo->RecordBind(drawContext->commandBuffer);
{
renderGeo = drawContext->renderer->GetResourceManager().PrepareGeometry(mesh);
}
renderGeo->RecordBind(drawContext->commandBuffer);
std::array<OpenVulkano::Scene::UniformBuffer*, 2> uniforms = { nullptr, nullptr };
// fragment shader buffer
uniforms[0] = entry.GetBuffer();
if (labelDrawable->IsBillboard()) if (labelDrawable->IsBillboard())
{ {
// vertex shader buffer VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
uniforms[1] = labelDrawable->GetBillboardBuffer(); if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
}
for (OpenVulkano::Scene::UniformBuffer* buffer : uniforms)
{
if (buffer)
{
VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource();
if (!vkBuffer)
{
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer);
}
vkBuffer->Record(drawContext); vkBuffer->Record(drawContext);
} }
}
if (Material* material = entry.GetMaterial()) VulkanTexture* renderTexture = entry.GetTexture()->GetRenderResource();
{
if (Texture* texture = material->texture)
{
VulkanTexture* renderTexture = texture->GetRenderResource();
if (!renderTexture) if (!renderTexture)
{ {
drawContext->renderer->GetResourceManager().PrepareMaterial(entry.GetMaterial()); renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(entry.GetTexture());
renderTexture = texture->GetRenderResource();
} }
renderTexture->Record(drawContext); renderTexture->Record(drawContext);
}
}
for (Node* node: labelDrawable->GetNodes()) for (Node* node: labelDrawable->GetNodes())
{ {
if (!node->IsEnabled()) [[unlikely]] if (!node->IsEnabled()) [[unlikely]] continue;
{
continue;
}
drawContext->EncodeNode(node); drawContext->EncodeNode(node);
renderGeo->RecordDraw(drawContext->commandBuffer); drawContext->commandBuffer.draw(4, entry.GetSymbolCount(), 0, 0);
} }
} }
} }
void EncodeLabelDrawable(Drawable* instance, Vulkan::VulkanDrawContext* drawContext) void EncodeLabelDrawable(Drawable* instance, VulkanDrawContext* drawContext)
{ {
LabelDrawable* labelDrawable = static_cast<LabelDrawable*>(instance); LabelDrawable* labelDrawable = static_cast<LabelDrawable*>(instance);
EncodeBackground(labelDrawable, drawContext); EncodeBackground(labelDrawable, drawContext);
@@ -122,5 +76,5 @@ namespace OpenVulkano::Vulkan
namespace namespace
{ {
void* labelDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction<LabelDrawable>(&OpenVulkano::Vulkan::EncodeLabelDrawable); [[maybe_unused]] void* labelDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction<LabelDrawable>(&OpenVulkano::Vulkan::EncodeLabelDrawable);
} }

View File

@@ -0,0 +1,45 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include "Scene/TextDrawable.hpp"
#include "VulkanNode.hpp"
#include "Vulkan/VulkanDrawContext.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"
#include "VulkanTexture.hpp"
using namespace OpenVulkano::Scene;
namespace OpenVulkano::Vulkan
{
void EncodeTextDrawable(Drawable* instance, VulkanDrawContext* drawContext)
{
TextDrawable* drawable = static_cast<TextDrawable*>(instance);
VertexBuffer* vbo = drawable->GetVertexBuffer();
VulkanVertexBuffer* renderVbo = vbo->GetRenderResource();
if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo);
renderVbo->RecordBind(drawContext->commandBuffer);
VulkanTexture* renderTexture = drawable->GetTexture()->GetRenderResource();
if (!renderTexture)
{
renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(drawable->GetTexture());
}
renderTexture->Record(drawContext);
for(Node* node : instance->GetNodes())
{
if (!node->IsEnabled()) [[unlikely]] continue;
drawContext->EncodeNode(node);
drawContext->commandBuffer.draw(4, drawable->GetSymbolCount(), 0, 0);
}
}
}
namespace
{
[[maybe_unused]] void* textDrawableVulkanEncoderReg = DrawEncoder::RegisterVulkanEncodeFunction<TextDrawable>(&OpenVulkano::Vulkan::EncodeTextDrawable);
}

View File

@@ -54,7 +54,7 @@ namespace OpenVulkano::Vulkan
for(const auto& description : shader->vertexInputDescriptions) for(const auto& description : shader->vertexInputDescriptions)
{ {
vertexBindDesc.emplace_back(description.bindingId, description.vertexSize, vk::VertexInputRate::eVertex); vertexBindDesc.emplace_back(description.bindingId, description.vertexSize, static_cast<vk::VertexInputRate>(description.stepMode));
if (shader->vertexInputDescriptions.size() > 1) if (shader->vertexInputDescriptions.size() > 1)
{ {
for(const auto& param : description.inputParameters) for(const auto& param : description.inputParameters)
@@ -84,6 +84,13 @@ namespace OpenVulkano::Vulkan
vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast<vk::PrimitiveTopology>(shader->topology), 0 }; vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast<vk::PrimitiveTopology>(shader->topology), 0 };
vk::PipelineRasterizationStateCreateInfo rasterizer = {}; vk::PipelineRasterizationStateCreateInfo rasterizer = {};
rasterizer.cullMode = static_cast<vk::CullModeFlagBits>(shader->cullMode); rasterizer.cullMode = static_cast<vk::CullModeFlagBits>(shader->cullMode);
if (shader->depthBias)
{
rasterizer.depthBiasEnable = VK_TRUE;
rasterizer.depthBiasClamp = shader->depthBiasClamp;
rasterizer.depthBiasConstantFactor = shader->depthBiasConstant;
rasterizer.depthBiasSlopeFactor = shader->depthBiasSlope;
}
vk::PipelineMultisampleStateCreateInfo msaa = {}; vk::PipelineMultisampleStateCreateInfo msaa = {};
vk::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, static_cast<vk::CompareOp>(shader->depthCompareOp) }; vk::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, static_cast<vk::CompareOp>(shader->depthCompareOp) };
depth.maxDepthBounds = 1; depth.maxDepthBounds = 1;

View File

@@ -11,10 +11,8 @@
#include <vulkan/vulkan.hpp> #include <vulkan/vulkan.hpp>
#include <vector> #include <vector>
namespace OpenVulkano namespace OpenVulkano::Vulkan
{ {
namespace Vulkan
{
class Context; class Context;
class IShaderOwner; class IShaderOwner;
@@ -45,5 +43,4 @@ namespace OpenVulkano
void CreatePipelineLayout(); void CreatePipelineLayout();
}; };
}
} }

View File

@@ -0,0 +1,43 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "IRecordable.hpp"
#include "Scene/Scene.hpp"
#include "Scene/VertexBuffer.hpp"
#include "Vulkan/Resources/ManagedBuffer.hpp"
namespace OpenVulkano::Vulkan
{
class VulkanVertexBuffer final : public IRenderResource<Scene::VertexBuffer>
{
ManagedBuffer::Ptr m_vertexBuffer;
public:
VulkanVertexBuffer(Scene::VertexBuffer* vbo, ManagedBuffer::Ptr& vertexBuffer)
: IRenderResource<Scene::VertexBuffer>(vbo) , m_vertexBuffer(std::move(vertexBuffer))
{}
~VulkanVertexBuffer() override = default;
void RecordBind(vk::CommandBuffer& cmdBuffer)
{
const vk::DeviceSize m_offsets = 0;
cmdBuffer.bindVertexBuffers(0, 1, &m_vertexBuffer->buffer, &m_offsets);
}
void RecordDraw(vk::CommandBuffer& cmdBuffer, uint32_t vertexCount, uint32_t instanceCount, uint32_t firstVertex = 0, uint32_t firstInstance = 0)
{
cmdBuffer.draw(vertexCount, instanceCount, firstVertex, firstInstance);
}
void Release() override
{
//TODO
}
};
}