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

View File

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

View File

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

View File

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

View File

@@ -9,12 +9,8 @@
#include "Scene/Shader/Shader.hpp"
#include "Scene/Geometry.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/UniformBuffer.hpp"
#include "Input/InputManager.hpp"
#include "Host/GraphicsAppManager.hpp"
#include "Host/GLFW/WindowGLFW.hpp"
@@ -22,9 +18,7 @@
#include "Math/Math.hpp"
#include "Base/EngineConfiguration.hpp"
#include "Controller/FreeCamCameraController.hpp"
#include "Image/ImageLoaderPng.hpp"
#include "Scene/SdfFontAtlasGenerator.hpp"
#include "Scene/IFontAtlasGenerator.hpp"
#include "Scene/BitmapFontAtlasGenerator.hpp"
#include <filesystem>
@@ -45,11 +39,9 @@ namespace OpenVulkano
class TextExampleAppImpl final : public TextExampleApp
{
public:
void Init() override
{
auto engineConfig = OpenVulkano::EngineConfiguration::GetEngineConfiguration();
engineConfig->SetPreferFramebufferFormatSRGB(false);
EngineConfiguration::GetEngineConfiguration()->SetPreferFramebufferFormatSRGB(false);
std::srand(1); // Fix seed for random numbers
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("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[0].second.applyBorder = true;
texts[1].second.backgroundColor.a = 1;
texts[1].second.backgroundColor.a = 255;
const int N = texts.size();
auto& resourceLoader = ResourceLoader::GetInstance();
@@ -73,6 +64,7 @@ namespace OpenVulkano
if constexpr (CREATE_BITMAP_ATLAS)
{
// ReSharper disable once CppDFAUnreachableCode
std::set<uint32_t> s = BitmapFontAtlasGenerator::LoadAllGlyphs(fontPath);
BitmapFontAtlasGenerator generator;
generator.GenerateAtlas(fontPath, s);
@@ -98,32 +90,27 @@ namespace OpenVulkano
#if defined(MSDFGEN_AVAILABLE) && CREATE_NEW_ATLAS
if (i < texts.size())
{
t = new TextDrawable(m_atlasGenerator.GetAtlasData(), texts[textIdx].second);
t->SetShader(&TextDrawable::GetSdfDefaultShader());
t = new TextDrawable(m_atlasGenerator.GetAtlasData(), texts[textIdx].second);
}
else
{
t = new TextDrawable(m_msdfAtlasGenerator.GetAtlasData(), texts[textIdx].second);
t->SetShader(&TextDrawable::GetMsdfDefaultShader());
t = new TextDrawable(m_msdfAtlasGenerator.GetAtlasData(), texts[textIdx].second);
}
#else
int xOffset = 0;
if (i < N)
{
t = new TextDrawable(sdfMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetSdfDefaultShader());
t = new TextDrawable(sdfMetadataInfo, texts[textIdx].second);
xOffset = -5;
}
else if (i >= N && i < N * 2)
{
t = new TextDrawable(msdfMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetMsdfDefaultShader());
t = new TextDrawable(msdfMetadataInfo, texts[textIdx].second);
xOffset = 15;
}
else
{
t = new TextDrawable(bitmapMetadataInfo, texts[textIdx].second);
t->SetShader(&TextDrawable::GetBitmapDefaultShader());
t = new TextDrawable(bitmapMetadataInfo, texts[textIdx].second);
xOffset = 35;
}
// OR use separate texture + metadata file
@@ -139,10 +126,10 @@ namespace OpenVulkano
//TextDrawable* t = new TextDrawable(metadataInfo, &tex, texts[i].second);
#endif // MSDFGEN_AVAILABLE
t->GenerateText(texts[textIdx].first);
m_drawablesPool[i] = t;
m_drawablesPool[i].reset(t);
m_nodesPool[i].Init();
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]);
}
GetGraphicsAppManager()->GetRenderer()->SetScene(&m_scene);
@@ -151,8 +138,8 @@ namespace OpenVulkano
m_camController.SetPosition({ 10, 0, 15 });
m_camController.SetBoostFactor(5);
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);
GetGraphicsAppManager()->GetRenderer()->SetActiveUi(&m_ui);
}
@@ -164,26 +151,22 @@ namespace OpenVulkano
void Close() override
{
for (SimpleDrawable* d: m_drawablesPool)
{
d->Close();
delete d;
}
m_drawablesPool.clear();
}
private:
OpenVulkano::Scene::Scene m_scene;
PerspectiveCamera m_cam;
OpenVulkano::FreeCamCameraController m_camController;
FreeCamCameraController m_camController;
#ifdef MSDFGEN_AVAILABLE
SdfFontAtlasGenerator m_atlasGenerator;
MsdfFontAtlasGenerator m_msdfAtlasGenerator;
#endif
std::vector<SimpleDrawable*> m_drawablesPool;
std::vector<std::unique_ptr<Drawable>> m_drawablesPool;
std::vector<Node> m_nodesPool;
Vector3f_SIMD m_position = { 0, 0, -10 };
OpenVulkano::Scene::UI::SimpleUi m_ui;
std::shared_ptr<OpenVulkano::Scene::UI::PerformanceInfo> m_perfInfo;
UI::SimpleUi m_ui;
std::shared_ptr<UI::PerformanceInfo> m_perfInfo;
};
IGraphicsApp* TextExampleApp::Create() { return new TextExampleAppImpl(); }

View File

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

View File

@@ -20,40 +20,32 @@ using namespace OpenVulkano;
int main(int argc, char** argv)
{
std::vector<std::string> examples;
for (const auto& e : EXAMPLE_APPS)
int selectedExample = -1;
if (argc == 2)
{
examples.emplace_back(e.first);
selectedExample = strtol(argv[1], nullptr, 10);
}
int selectedExample = 0;
ftxui::MenuOption option;
auto screen = ftxui::ScreenInteractive::TerminalOutput();
screen.ForceHandleCtrlC(true);
//screen.ForceHandleCtrlZ(true);
option.on_enter = screen.ExitLoopClosure();
auto menu = ftxui::Menu(&examples, &selectedExample, option);
bool shouldExit = false;
menu |= ftxui::CatchEvent(
[&](ftxui::Event event)
if (selectedExample < 0)
{
if (event == ftxui::Event::CtrlC || event == ftxui::Event::CtrlZ)
std::vector<std::string> examples;
for (const auto& e : EXAMPLE_APPS)
{
screen.ExitLoopClosure()();
shouldExit = true;
examples.emplace_back(e.first);
}
return false;
});
screen.Loop(menu);
if (shouldExit)
{
return 0;
}
ftxui::MenuOption option;
auto screen = ftxui::ScreenInteractive::TerminalOutput();
bool shouldExit = true;
option.on_enter = [&]() { shouldExit = false; screen.ExitLoopClosure()(); };
auto menu = ftxui::Menu(&examples, &selectedExample, option);
screen.Loop(menu);
if (selectedExample >= examples.size())
{
throw std::runtime_error("Invalid menu selection!");
if (shouldExit) return 0;
if (selectedExample >= examples.size())
{
throw std::runtime_error("Invalid menu selection!");
}
}
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
#include "ITickable.hpp"
#include "ICloseable.hpp"
#include "Version.hpp"
#include <string>
@@ -15,7 +14,7 @@ namespace OpenVulkano
{
class IGraphicsAppManager;
class IGraphicsApp : public ITickable, public ICloseable
class IGraphicsApp : public ITickable
{
private:
IGraphicsAppManager* m_manager = nullptr;
@@ -25,6 +24,7 @@ namespace OpenVulkano
virtual void Init() = 0;
virtual void InitPostGraphics() {}
virtual void Close() {}
virtual void CloseFinalize() {}
[[nodiscard]] IGraphicsAppManager* GetGraphicsAppManager() const { return m_manager; }
void SetGraphicsAppManager(IGraphicsAppManager* manager) { m_manager = manager; }

View File

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

View File

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

View File

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

View File

@@ -7,7 +7,6 @@
#pragma once
#include "Base/ITickable.hpp"
#include "Base/ICloseable.hpp"
namespace OpenVulkano
{
@@ -16,7 +15,7 @@ namespace OpenVulkano
class Camera;
}
class CameraController : public ITickable, ICloseable
class CameraController : public ITickable
{
Scene::Camera* m_camera;
@@ -30,7 +29,7 @@ namespace OpenVulkano
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; }

View File

@@ -105,7 +105,14 @@ namespace OpenVulkano
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
{

View File

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

View File

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

View File

@@ -14,101 +14,111 @@ namespace OpenVulkano::Math
/**
* \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:
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)
* \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->max = max;
}
void Init(const Math::Vector3f& point, float radius)
void Init(const T& point, float radius)
{
min = point - radius;
max = point + radius;
Range<T>::min = point - radius;
Range<T>::max = point + radius;
}
/**
* \brief Initiates the AABB from some other AABB
* \param other The other AABB that should be copied
*/
void Init(const AABB& other)
void Init(const AABB_T& other)
{
min = other.GetMin();
max = other.GetMax();
Range<T>::min = other.GetMin();
Range<T>::max = other.GetMax();
}
void Grow(const Math::Vector3f& point)
void Grow(const T& point)
{
min = Math::Utils::min(min, point);
max = Math::Utils::max(max, point);
Range<T>::min = Math::Utils::min(Range<T>::min, 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());
max = Math::Utils::max(max, otherAABB.GetMax());
Range<T>::min = Math::Utils::min(Range<T>::min, otherAABB.GetMin());
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
}
[[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
* \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 ||
other.max.y < min.y || other.min.z > max.z || other.max.z < min.z);
return Math::Utils::all(Math::Utils::lessThanEqual(Range<T>::min, other.GetMax())) && Math::Utils::all(Math::Utils::greaterThanEqual(Range<T>::max, other.GetMin()));
}
[[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
{
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()
{
min = Math::Vector3f(INFINITY);
max = Math::Vector3f(-INFINITY);
Range<T>::min = T(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;
}
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>;
@@ -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);
}
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 <string_view>
#include <map>
#include <magic_enum.hpp>
namespace OpenVulkano::Scene
{
@@ -34,15 +35,22 @@ namespace OpenVulkano::Scene
BITMAP,
UNKNOWN
};
static constexpr std::string_view DEFAULT_FG_SHADERS[] = { "Shader/text", "Shader/msdfText" };
public:
FontAtlasType(Type type) : m_type(type) {}
Type GetType() const { return m_type; }
const std::string_view& GetDefaultFragmentShader() const
static constexpr std::string_view DEFAULT_FG_SHADERS[] = { "Shader/sdfText", "Shader/msdfText", "Shader/text" };
constexpr FontAtlasType(Type type) : m_type(type) {}
[[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)];
}
[[nodiscard]] constexpr operator Type() const { return m_type; }
private:
Type m_type;
};
@@ -51,7 +59,7 @@ namespace OpenVulkano::Scene
{
// vertical difference between baselines
double lineHeight = 0;
int16_t atlasType = FontAtlasType::UNKNOWN;
FontAtlasType atlasType = FontAtlasType::UNKNOWN;
};
struct AtlasData
@@ -60,6 +68,8 @@ namespace OpenVulkano::Scene
AtlasMetadata meta;
Unique<Image::Image> img;
Texture texture;
operator bool() const { return !glyphs.empty() && texture.textureBuffer; }
};
}

View File

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

View File

@@ -7,30 +7,31 @@
#pragma once
#include "IFontAtlasGenerator.hpp"
#include "AtlasData.hpp"
#include "Math/AABB.hpp"
#include "FreetypeHelper.hpp"
#include "Extensions/FreetypeHelper.hpp"
#include <variant>
#include <set>
namespace OpenVulkano::Scene
{
class FontAtlasGeneratorBase : public IFontAtlasGenerator
{
protected:
int m_channelsCount;
std::shared_ptr<AtlasData> m_atlasData;
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;
std::shared_ptr<AtlasData> GetAtlasData() const { return m_atlasData; }
int GetAtlasChannelsCount() const { return m_channelsCount; }
static std::set<uint32_t> LoadAllGlyphs(const std::variant<std::string, Array<char>>& data);
[[nodiscard]] const std::shared_ptr<AtlasData>& GetAtlasData() const override { return m_atlasData; }
[[nodiscard]] int GetAtlasChannelsCount() const { return m_channelsCount; }
[[nodiscard]] static std::set<uint32_t> LoadAllGlyphs(const std::variant<std::string, Array<char>>& data);
protected:
void SavePng(std::string output) const;
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);
static std::string GetFreetypeErrorDescription(FT_Error error);
static std::pair<FtLibraryRecPtr, FtFaceRecPtr> InitFreetype(const std::variant<std::string, Array<char>>& source);
protected:
int m_channelsCount;
std::shared_ptr<AtlasData> m_atlasData;
[[nodiscard]] static std::string GetFreetypeErrorDescription(FT_Error error);
[[nodiscard]] static std::pair<FtLibraryRecPtr, FtFaceRecPtr> InitFreetype(const std::variant<std::string, Array<char>>& source);
};
}

View File

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

View File

@@ -6,24 +6,25 @@
#pragma once
#include "Scene/AtlasData.hpp"
#include <Data/Containers/Array.hpp>
#include <string>
#include <optional>
#include <map>
#include <variant>
#include <set>
#include <memory>
namespace OpenVulkano::Scene
{
struct AtlasData;
class IFontAtlasGenerator
{
public:
virtual ~IFontAtlasGenerator() = default;
virtual void GenerateAtlas(const std::string& fontFile, const std::set<uint32_t>& charset,
const std::optional<std::string>& pngOutput = std::nullopt) = 0;
virtual void GenerateAtlas(const Array<char>& fontData, const std::set<uint32_t>& charset,
const std::optional<std::string>& pngOutput = std::nullopt) = 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
{
public:
virtual ~IRayIntersectable() = default;
virtual std::optional<RayHit> Intersect(const Ray& ray) const = 0;
};
}

View File

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

View File

@@ -7,27 +7,77 @@
#include "LabelDrawable.hpp"
#include "Scene/TextDrawable.hpp"
#include "Scene/DrawEncoder.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Scene/IFontAtlasGenerator.hpp"
#include "Base/Logger.hpp"
#include <optional>
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,
bool isBillboard)
: Drawable(DrawEncoder::GetDrawEncoder<LabelDrawable>(), DrawPhase::MAIN)
Shader MakeLabelTextShader(const FontAtlasType type, const bool billboard)
{
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)
{
throw std::runtime_error("Can't create label drawable. Either glyphs or texture is empty");
}
m_atlasData = atlasData;
m_isBillboard = isBillboard;
SetLabelSettings(settings);
SetupShaders();
SetupBuffers();
SetShader(IsBillboard() ? &BACKGROUND_BILLBOARD_SHADER : &BACKGROUND_SHADER);
}
void LabelDrawable::SetLabelSettings(const LabelDrawableSettings& settings)
@@ -43,124 +93,27 @@ namespace OpenVulkano::Scene
void LabelDrawable::AddText(const std::string& text, const TextConfig& config)
{
if (text.empty())
{
return;
}
if (text.empty()) return;
TextDrawable& textDrawable = m_texts.emplace_back(m_atlasData, config);
// do not render glyph's background
textDrawable.GetConfig().backgroundColor.a = 0;
textDrawable.SetShader(&m_textShader);
textDrawable.GetConfig().backgroundColor.a = 0; // do not render glyph's background
double lineHeight = m_atlasData->meta.lineHeight;
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
m_position.y = m_bbox.GetMin().y - lineHeight;
const auto& min = m_bbox.GetMin();
const auto& max = m_bbox.GetMax();
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);
Math::Vector2f padding = m_settings.padding * 2;
if (m_settings.hasArrow) padding.y += m_settings.arrowLength;
m_labelData.textSize.x = v2.position.x - v.position.x;
m_labelData.textSize.y = v3.position.y - v.position.y;
m_labelData.bboxCenter.x = (v2.position.x + v.position.x) / 2;
m_labelData.bboxCenter.y = (v3.position.y + v.position.y) / 2;
}
void LabelDrawable::SetBillboardSettings(const BillboardControlBlock& settings)
{
m_billboardSettings = settings;
m_labelData.textSize = Math::Vector2f(m_bbox.GetSize()) + padding * 2;
m_labelData.bboxCenter = { m_bbox.GetCenter() };
if (m_settings.hasArrow) m_labelData.bboxCenter.y -= m_settings.arrowLength;
}
std::optional<RayHit> LabelDrawable::Intersect(const Ray& ray) const
{
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
#include "Base/Wrapper.hpp"
#include "Scene/Drawable.hpp"
#include "Scene/Shader/Shader.hpp"
#include "Scene/Texture.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/BillboardControlBlock.hpp"
#include "Math/AABB.hpp"
#include "Scene/TextDrawable.hpp"
#include <list>
namespace OpenVulkano::Scene
{
class Shader;
struct LabelDrawableSettings
{
Math::Vector4f backgroundColor = { 1, 0, 0, 1 };
float horizontalOffset = 0.05f;
float verticalOffset = 0.05f;
Math::Vector2f padding = { 0.2f, 0.2f };
float cornerRadius = 0.05f;
float arrowLength = 0.5f;
float arrowWidth = 0.2f;
int32_t hasRoundedCorners = false;
int32_t hasArrow = false;
bool hasRoundedCorners = false;
bool hasArrow = false;
bool isBillboard = false;
};
struct LabelUniformData
{
Math::Vector4f textSize = { 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 arrowLength = 0.f;
float arrowWidth = 0.f;
int32_t hasRoundedCorners = false;
int32_t hasArrow = false;
int32_t isBillboardFixedSize = false;
};
class LabelDrawable final : public Drawable
{
public:
LabelDrawable(const std::shared_ptr<AtlasData>& atlasData,
const LabelDrawableSettings& settings = LabelDrawableSettings(), bool isBillboard = false);
LabelDrawable(const std::shared_ptr<AtlasData>& atlasData, const LabelDrawableSettings& settings = LabelDrawableSettings());
void AddText(const std::string& text, const TextConfig& config = TextConfig());
void SetLabelSettings(const LabelDrawableSettings& settings);
void SetBillboardSettings(const BillboardControlBlock& settings);
void SetPosition(const Math::Vector3f& pos) { m_position = pos; }
std::list<TextDrawable>& GetTexts() { return m_texts; }
LabelDrawableSettings& GetSettings() { return m_settings; }
UniformBuffer* GetBillboardBuffer() { return &m_billboardBuffer; }
UniformBuffer* GetLabelBuffer() { return &m_labelBuffer; }
BillboardControlBlock& GetBillboardSettings() { return m_billboardSettings; }
Math::Vector3f& GetPosition() { return m_position; }
bool IsBillboard() const { return m_isBillboard; }
const Math::AABB& GetBoundingBox() const { return m_bbox; }
std::optional<RayHit> Intersect(const Ray& ray) const override;
void SetPosition(const Math::Vector2f& pos) { m_position = pos; }
[[nodiscard]] std::list<TextDrawable>& GetTexts() { return m_texts; }
[[nodiscard]] LabelDrawableSettings& GetSettings() { return m_settings; }
[[nodiscard]] UniformBuffer* GetLabelBuffer() { return &m_labelBuffer; }
[[nodiscard]] Math::Vector2f& GetPosition() { return m_position; }
[[nodiscard]] bool IsBillboard() const { return m_settings.isBillboard; }
[[nodiscard]] const Math::AABB2f& GetBoundingBox() const { return m_bbox; }
[[nodiscard]] std::optional<RayHit> Intersect(const Ray& ray) const override;
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;
LabelUniformData m_labelData;
std::shared_ptr<AtlasData> m_atlasData;
BillboardControlBlock m_billboardSettings;
Math::Vector3f m_position = { 0, 0, 0 };
Math::AABB m_bbox;
bool m_isBillboard;
UniformBuffer m_labelBuffer;
LabelUniformData m_labelData;
std::list<TextDrawable> m_texts; // Using list instead of vector for stable iterators
Math::Vector2f m_position = { 0, 0 };
Math::AABB2f m_bbox;
};
}

View File

@@ -10,12 +10,9 @@
namespace
{
int SolveQuadraticEquation(float a, float b, float c, float& x0, float& x1)
{
float discr = b * b - 4 * a * c;
if (discr < 0)
{
return 0;
}
{
const float discr = b * b - 4 * a * c;
if (discr < 0) return 0;
if (discr == 0)
{
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));
x0 = q / a;
x1 = c / q;
if (x0 > x1)
{
std::swap(x0, x1);
}
OpenVulkano::Math::Utils::SortPair(x0, x1);
return 2;
}
};
@@ -50,10 +44,10 @@ namespace OpenVulkano::Scene
std::optional<RayHit> Ray::IntersectTriangle(const Math::Vector3f& v0, const Math::Vector3f& v1,
const Math::Vector3f& v2) const
{
RayHit hitRes;
float d;
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;
Math::Vector3f e = v1 - 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,
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;
}
if (auto hitRes = IntersectTriangle(v0, v2, v3))
if (const auto hitRes = IntersectTriangle(v0, v2, v3))
{
return hitRes;
}
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
{
RayHit h1, h2;
const int intersections = this->IntersectAABB(bbox, h1, h2);
switch (intersections)
{
case 1:
return h1;
case 2:
return (h1.distance2 < h2.distance2) ? h1 : h2;
}
if (intersections == 1) return h1;
if (intersections == 2) return (h1.distance2 < h2.distance2) ? h1 : h2;
return {};
}
int Ray::IntersectAABB(const Math::AABB& bbox, RayHit& p1, RayHit& p2) const
{
const auto tmin = (bbox.min - m_origin) / m_dir;
const 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;
auto tmin = (bbox.min - m_origin) / m_dir;
auto tmax = (bbox.max - m_origin) / m_dir;
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);
}
if ((txmin > tymax) || (tymin > txmax))
{
return 0;
tmax.x = tmax.y;
}
if (tymin > txmin)
{
txmin = tymin;
}
if (tymax < txmax)
{
txmax = tymax;
}
if (tzmin > tzmax)
{
std::swap(tzmin, tzmax);
}
if ((tmin.x > tmax.z) || (tmin.z > tmax.x)) return 0;
if ((txmin > tzmax) || (tzmin > txmax))
if (tmin.z > tmin.x)
{
return 0;
tmin.x = tmin.z;
}
if (tzmin > txmin)
if (tmax.z < tmax.x)
{
txmin = tzmin;
}
if (tzmax < txmax)
{
txmax = tzmax;
tmax.x = tmax.z;
}
int intersections = 2;
if (txmin < 0)
if (tmin.x < 0)
{
if (txmax < 0)
{
return 0;
}
if (tmax.x < 0) return 0;
intersections--;
txmin = txmax;
tmin.x = tmax.x;
}
p1.point = m_origin + txmin * m_dir;
p2.point = m_origin + txmax * m_dir;
p1.point = m_origin + tmin.x * m_dir;
p2.point = m_origin + tmax.x * m_dir;
p1.distance2 = distance2(m_origin, p1.point);
p2.distance2 = distance2(m_origin, p2.point);
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
{
RayHit hit;
Math::Vector3f norm = normalize(pNorm);
float d;
if (intersectRayPlane(m_origin, m_dir, pOrigin, pNorm, d))
{
hit.SetDistance(d);
hit.point = m_origin + m_dir * d;
hit.normal = norm;
return hit;
return {{ m_origin + m_dir * d, norm, d, d * d }};
}
return {};
}
@@ -201,56 +168,36 @@ namespace OpenVulkano::Scene
float x1, x2;
int roots = ::SolveQuadraticEquation(a, b, c, x1, x2);
if (roots == 0)
{
return 0;
}
if (x1 > x2)
{
std::swap(x1, x2);
}
if (roots == 0) return 0;
SortPair(x1, x2);
bool calcP2 = false;
if (roots == 1)
{
// ray intersects sphere behind the origin
if (x1 < 0)
{
return 0;
}
p1.point = m_origin + x1 * m_dir;
p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center);
p2 = p1;
if (x1 < 0) return 0; // ray intersects sphere behind the origin
}
else if (roots == 2)
else
{
// ray intersects sphere behind the origin
if (x1 < 0 && x2 < 0)
{
return 0;
}
if (x1 < 0 && x2 < 0) return 0; // ray intersects sphere behind the origin
if (x1 >= 0 && x2 >= 0)
{
p1.point = m_origin + x1 * m_dir;
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);
calcP2 = true;
}
else
{
--roots;
if (x1 < 0)
{
x1 = x2;
}
p1.point = m_origin + x1 * m_dir;
p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center);
p2 = p1;
if (x1 < 0) x1 = x2;
}
}
p1.point = m_origin + x1 * m_dir;
p1.distance2 = distance2(m_origin, p1.point);
p1.normal = normalize(p1.point - center);
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;
}

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
#pragma once
#include "Base/ICloseable.hpp"
#include "Base/Utils.hpp"
#include "Base/Render/RenderResource.hpp"
#include "VertexInputDescription.hpp"
@@ -81,8 +80,7 @@ namespace OpenVulkano::Scene
};
class Shader final : public RenderResourceHolder<Shader>, public ICloseable
class Shader final : public RenderResourceHolder<Shader>
{
public:
std::vector<ShaderProgram> shaderPrograms{};
@@ -96,9 +94,11 @@ namespace OpenVulkano::Scene
bool depthTest = true;
bool depthWrite = true;
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() override { Shader::Close(); }
~Shader() { Shader::Close(); }
Shader& AddShaderProgram(const ShaderProgram& shaderProgram)
{
@@ -128,6 +128,7 @@ namespace OpenVulkano::Scene
{
CheckShaderInitState();
if (bindingId < 0) bindingId = static_cast<int>(vertexInputDescriptions.size());
// ReSharper disable once CppDFALoopConditionNotUpdated
while (bindingId > static_cast<int>(vertexInputDescriptions.size()))
{
vertexInputDescriptions.emplace_back(0, 0);
@@ -149,6 +150,7 @@ namespace OpenVulkano::Scene
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!");
setId -= 2;
// ReSharper disable once CppDFALoopConditionNotUpdated
while (setId >= static_cast<int>(descriptorSets.size()))
{
descriptorSets.emplace_back();
@@ -163,7 +165,14 @@ namespace OpenVulkano::Scene
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())
GetRenderResource().Release();

View File

@@ -12,6 +12,8 @@
namespace OpenVulkano
{
enum class VertexStepMode : uint32_t { VERTEX = 0, INSTANCE };
struct VertexInputParameter
{
uint32_t location;
@@ -32,13 +34,16 @@ namespace OpenVulkano
{
uint32_t bindingId;
uint32_t vertexSize;
VertexStepMode stepMode = VertexStepMode::VERTEX;
std::vector<VertexInputParameter> inputParameters;
VertexInputDescription(uint32_t bindingId, uint32_t vertexSize) : bindingId(bindingId), vertexSize(vertexSize)
{}
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)
{

View File

@@ -6,9 +6,7 @@
#include "TextDrawable.hpp"
#include "Scene/Geometry.hpp"
#include "Scene/Material.hpp"
#include "Scene/Vertex.hpp"
#include "Scene/UniformBuffer.hpp"
#include "Shader/Shader.hpp"
#include "Scene/IFontAtlasGenerator.hpp"
#include "Base/Logger.hpp"
#include "Host/ResourceLoader.hpp"
@@ -20,89 +18,58 @@
namespace OpenVulkano::Scene
{
Shader& TextDrawable::GetSdfDefaultShader()
namespace
{
static bool once = true;
static Shader sdfDefaultShader;
if (once)
{
sdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/sdfText");
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;
constexpr uint32_t MISSING_GLYPH_SYMBOL = '?';
Shader DEFAULT_SHADER_BITMAP = TextDrawable::MakeDefaultShader(FontAtlasType::BITMAP);
Shader DEFAULT_SHADER_SDF = TextDrawable::MakeDefaultShader(FontAtlasType::SDF);
Shader DEFAULT_SHADER_MSDF = TextDrawable::MakeDefaultShader(FontAtlasType::MSDF);
}
Shader& TextDrawable::GetMsdfDefaultShader()
Shader TextDrawable::MakeDefaultShader(const FontAtlasType type)
{
static bool once = true;
static Shader msdfDefaultShader;
if (once)
{
msdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::VERTEX, "Shader/sdfText");
msdfDefaultShader.AddShaderProgram(OpenVulkano::ShaderProgramType::FRAGMENT, "Shader/msdfText");
msdfDefaultShader.AddVertexInputDescription(OpenVulkano::Vertex::GetVertexInputDescription());
msdfDefaultShader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
DescriptorSetLayoutBinding desc = UniformBuffer::DESCRIPTOR_SET_LAYOUT_BINDING;
desc.stageFlags = ShaderProgramType::FRAGMENT;
msdfDefaultShader.AddDescriptorSetLayoutBinding(desc);
msdfDefaultShader.alphaBlend = true;
msdfDefaultShader.cullMode = CullMode::NONE;
once = false;
}
return msdfDefaultShader;
}
Shader& TextDrawable::GetBitmapDefaultShader()
{
static bool once = true;
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;
Shader shader;
shader.AddShaderProgram(ShaderProgramType::VERTEX, "Shader/text");
shader.AddShaderProgram(ShaderProgramType::FRAGMENT, std::string(type.GetDefaultFragmentShader()));
VertexInputDescription inputDesc(0, sizeof(TextGlyphVertex));
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position));
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+8);
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+16);
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, position)+24);
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv));
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+8);
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+16);
inputDesc.AddInputParameter(DataFormat::R32G32_SFLOAT, offsetof(TextGlyphVertex, uv)+24);
inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, color));
inputDesc.AddInputParameter(DataFormat::R8G8B8A8_UNORM, offsetof(TextGlyphVertex, background));
inputDesc.stepMode = VertexStepMode::INSTANCE;
shader.AddVertexInputDescription(inputDesc);
shader.AddDescriptorSetLayoutBinding(Texture::DESCRIPTOR_SET_LAYOUT_BINDING);
shader.alphaBlend = true;
shader.cullMode = CullMode::NONE;
shader.topology = Topology::TRIANGLE_FAN;
return shader;
}
TextDrawable::TextDrawable(const TextConfig& config)
{
m_cfg = config;
m_uniBuffer.Init(sizeof(TextConfig), &m_cfg, 3);
m_uniBuffer.binding.stageFlags = ShaderProgramType::FRAGMENT;
}
: Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_cfg(config)
{}
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, const TextConfig& config)
: TextDrawable(atlasMetadata, nullptr, 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(OpenVulkano::Utils::ReadFile(atlasMetadataFile), atlasTex, config)
{
}
: TextDrawable(Utils::ReadFile(atlasMetadataFile), atlasTex, config)
{}
TextDrawable::TextDrawable(const Array<char>& atlasMetadata, Texture* atlasTex, const TextConfig& config)
: Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_cfg(config)
{
uint32_t isPacked;
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>();
if (isPacked)
{
m_material.texture = &m_atlasData->texture;
m_atlasData->img = Image::IImageLoader::loadData((const uint8_t*) atlasMetadata.Data(),
offsetToMetadata);
m_material.texture->format = m_atlasData->img->dataFormat;
m_material.texture->resolution = m_atlasData->img->resolution;
m_material.texture->size = m_atlasData->img->data.Size();
m_material.texture->textureBuffer = m_atlasData->img->data.Data();
Texture* texture = &m_atlasData->texture;
m_atlasData->img = Image::IImageLoader::loadData(reinterpret_cast<const uint8_t*>(atlasMetadata.Data()), offsetToMetadata);
texture->format = m_atlasData->img->dataFormat;
texture->resolution = m_atlasData->img->resolution;
texture->size = m_atlasData->img->data.Size();
texture->textureBuffer = m_atlasData->img->data.Data();
}
else
{
if (atlasTex == nullptr) { throw std::runtime_error("Atlas texture cannot be null with non-packed atlas metadata"); }
m_atlasData->texture = *atlasTex;
m_material.texture = atlasTex;
}
// metadata info
@@ -146,67 +111,47 @@ namespace OpenVulkano::Scene
read_bytes += 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)
{
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)
: Drawable(DrawEncoder::GetDrawEncoder<TextDrawable>()), m_atlasData(atlasData), m_cfg(config)
{
if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer)
{
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;
if (!atlasData || !*atlasData) throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
}
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;
auto GetActualLength = [&]()
{
auto begin = text.begin();
auto end = text.end();
size_t len = 0;
while (begin != end)
{
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;
m_symbolCount = 0;
const size_t len = utf8::distance(text.begin(), text.end());
m_vertexBuffer.Close();
TextGlyphVertex* vertices = m_vertexBuffer.Init<TextGlyphVertex>(len);
std::map<uint32_t, GlyphInfo>* symbols = &m_atlasData->glyphs;
AtlasMetadata* meta = &m_atlasData->meta;
double cursorX = pos.x;
auto begin = text.begin();
auto end = text.end();
const double lineHeight = meta->lineHeight;
double posY = pos.y;
int i = 0;
Math::Vector3f bmin(pos), bmax(pos);
bool firstGlyph = true;
while (begin != end)
Math::Vector3f bmin(pos, 0), bmax(pos, 0);
for (auto begin = text.begin(), end = text.end(); begin != end;)
{
uint32_t c = utf8::next(begin, end);
if (c == '\n')
@@ -215,72 +160,56 @@ namespace OpenVulkano::Scene
cursorX = pos.x;
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);
if (symbols->find(static_cast<uint32_t>('?')) != symbols->end())
{
c = static_cast<uint32_t>('?');
}
else
{
Logger::RENDER->error("Could not find glyph for character ? to replace glyph {}", c);
continue;
}
Logger::RENDER->warn("Could not find glyph for character {}, using fallback", c);
c = fallbackGlyph;
}
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);
// left bottom
m_geometry.vertices[vIdx].position.x = info.xyz[0].x + cursorX;
m_geometry.vertices[vIdx].position.y = posY - info.xyz[0].y;
m_geometry.vertices[vIdx].position.z = info.xyz[0].z;
m_geometry.vertices[vIdx].textureCoordinates = Math::Vector3f(info.uv[0], 0);
for (int i = 0; i < 4; i++)
{
vertices->position[i].x = info.xyz[i].x + cursorX;
vertices->uv[i] = info.uv[i];
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
// when setting for depth comparison operator will be available( <= )
cursorX += info.advance + 0.08;
if (firstGlyph)
{
bmin.x = m_geometry.vertices[vIdx].position.x;
firstGlyph = false;
}
bmax.x = std::max(bmax.x, m_geometry.vertices[vIdx + 1].position.x);
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;
bmax.x = std::max(bmax.x, vertices->position[1].x);
bmax.y = std::max(bmax.y, vertices->position[2].y);
bmin.y = std::min(bmin.y, vertices->position[1].y);
vertices++;
m_symbolCount++;
}
bmin.x = vertices->position[0].x;
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)
{
if (!atlasData || atlasData->glyphs.empty() || !atlasData->texture.textureBuffer)
{
throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
}
if (!atlasData || !*atlasData) throw std::runtime_error("Cannot initialize text drawable with empty atlas data");
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
#include "SimpleDrawable.hpp"
#include "Drawable.hpp"
#include "Texture.hpp"
#include "Material.hpp"
#include "Geometry.hpp"
#include "UniformBuffer.hpp"
#include "VertexBuffer.hpp"
#include "AtlasData.hpp"
#include "Image/Image.hpp"
#include <map>
#include <optional>
namespace OpenVulkano::Scene
{
class IFontAtlasGenerator;
struct TextConfig
{
Math::Vector4f textColor = { 1, 1, 1, 1 };
Math::Vector4f borderColor = { 1, 0, 0, 1 };
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;
Math::Vector4uc textColor = { 255, 255, 255, 255 };
Math::Vector4uc backgroundColor = { 0, 255, 0, 0 };
};
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:
static Shader& GetSdfDefaultShader();
static Shader& GetMsdfDefaultShader();
static Shader& GetBitmapDefaultShader();
TextDrawable(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, 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());
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 SetShader(Shader* shader) { m_shader = shader; }
void SetAtlasData(const std::shared_ptr<AtlasData>& atlasData);
Math::AABB& GetBoundingBox() { return m_bbox; }
TextConfig& GetConfig() { return m_cfg; }
Shader* GetShader() { return m_shader; }
[[nodiscard]] Math::AABB2f& GetBoundingBox() { return m_bbox; }
[[nodiscard]] TextConfig& GetConfig() { return m_cfg; }
[[nodiscard]] const std::string& GetText() const { return m_text; }
std::shared_ptr<AtlasData> GetAtlasData() { return m_atlasData; }
private:
Geometry m_geometry;
Material m_material;
UniformBuffer m_uniBuffer;
std::shared_ptr<AtlasData> m_atlasData;
Math::AABB m_bbox;
Shader* m_shader = nullptr;
std::string m_text;
TextConfig m_cfg;
[[nodiscard]] const std::shared_ptr<AtlasData>& GetAtlasData() { return m_atlasData; }
[[nodiscard]] VertexBuffer* GetVertexBuffer() { return &m_vertexBuffer; }
[[nodiscard]] Texture* GetTexture() { return &m_atlasData->texture; }
[[nodiscard]] size_t GetSymbolCount() const { return m_symbolCount; }
[[nodiscard]] static Shader MakeDefaultShader(FontAtlasType type);
[[nodiscard]] static Shader* GetDefaultShader(FontAtlasType type);
};
}

View File

@@ -19,11 +19,15 @@ namespace OpenVulkano::Scene
DescriptorSetLayoutBinding binding;
uint32_t setId;
size_t size = 0;
const void* data = nullptr;
size_t size;
const void* data;
UpdateFrequency updateFrequency = UpdateFrequency::Never;
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)
{
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,71 +3,71 @@
layout(location = 1) in vec2 texCoord;
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 bboxCenter;
float radius;
float arrowLength;
float arrowWidth;
bool hasRoundedCorners;
bool hasArrow;
vec4 color;
vec2 textSize;
vec2 bboxCenter;
float radius;
float arrowLength;
float arrowWidth;
bool hasRoundedCorners;
bool hasArrow;
} labelInfo;
void main()
{
if (labelInfo.hasRoundedCorners || labelInfo.hasArrow)
{
vec2 bbox = vec2(labelInfo.textSize);
const float arrowLength = int(labelInfo.hasArrow) * labelInfo.arrowLength;
float arrowWidth = labelInfo.arrowWidth;
vec2 uvScaled = texCoord;
{
if (labelInfo.hasRoundedCorners || labelInfo.hasArrow)
{
vec2 bbox = vec2(labelInfo.textSize);
const float arrowLength = int(labelInfo.hasArrow) * labelInfo.arrowLength;
float arrowWidth = labelInfo.arrowWidth;
vec2 uvScaled = texCoord;
float distX = min(uvScaled.x, bbox.x - uvScaled.x);
float distY = min(uvScaled.y - arrowLength, bbox.y - uvScaled.y);
float distanceFromCorner = distX * distY;
float distX = min(uvScaled.x, bbox.x - uvScaled.x);
float distY = min(uvScaled.y - arrowLength, bbox.y - uvScaled.y);
float distanceFromCorner = distX * distY;
if (distanceFromCorner < labelInfo.radius)
{
// plain arrow
if (labelInfo.hasArrow && !labelInfo.hasRoundedCorners)
{
// Some bias to prevent line between arrow and label +
// check that we are dealing with lower parts of the label where arrow should be drawn,
// to prevent discarding fragments from upper corners
if (distY <= 0.01 && uvScaled.y < (bbox.y - arrowWidth) && arrowLength != 0.0f)
{
arrowWidth = arrowWidth * ((arrowLength + distY) / arrowLength);
if (distX < (bbox.x - arrowWidth) * 0.5)
{
discard;
}
}
}
// TODO: rounded corners + rounded arrow.
// now renders rounded corners and sharp arrow
else if (labelInfo.hasArrow && labelInfo.hasRoundedCorners)
{
if (distY <= 0.05 && uvScaled.y < (bbox.y - arrowWidth) && arrowLength != 0.0f)
{
arrowWidth = arrowWidth * ((arrowLength + distY) / arrowLength);
if (distX < (bbox.x - arrowWidth) * 0.5)
{
discard;
}
}
else
{
discard;
}
}
// no arrow, rounded corners
else
{
discard;
}
}
}
outColor = labelInfo.color;
if (distanceFromCorner < labelInfo.radius)
{
// plain arrow
if (labelInfo.hasArrow && !labelInfo.hasRoundedCorners)
{
// Some bias to prevent line between arrow and label +
// check that we are dealing with lower parts of the label where arrow should be drawn,
// to prevent discarding fragments from upper corners
if (distY <= 0.01 && uvScaled.y < (bbox.y - arrowWidth) && arrowLength != 0.0f)
{
arrowWidth = arrowWidth * ((arrowLength + distY) / arrowLength);
if (distX < (bbox.x - arrowWidth) * 0.5)
{
discard;
}
}
}
// TODO: rounded corners + rounded arrow.
// now renders rounded corners and sharp arrow
else if (labelInfo.hasArrow && labelInfo.hasRoundedCorners)
{
if (distY <= 0.05 && uvScaled.y < (bbox.y - arrowWidth) && arrowLength != 0.0f)
{
arrowWidth = arrowWidth * ((arrowLength + distY) / arrowLength);
if (distX < (bbox.x - arrowWidth) * 0.5)
{
discard;
}
}
else
{
discard;
}
}
// no arrow, rounded corners
else
{
discard;
}
}
}
outColor = labelInfo.color;
}

View File

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

View File

@@ -8,35 +8,31 @@ layout(set = 0, binding = 0) uniform NodeData
layout(set = 1, binding = 0) uniform CameraData
{
mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
float nearPlane;
float farPlane;
float width;
float height;
float fov;
float aspect;
float scaleFactor;
float pixelScaleFactor;
mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
float nearPlane;
float farPlane;
float width;
float height;
float fov;
float aspect;
float scaleFactor;
float pixelScaleFactor;
} 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 bboxCenter;
float radius;
float arrowLength;
bool hasRoundedCorners;
bool hasArrow;
vec4 color;
vec2 textSize;
vec2 bboxCenter;
float radius;
float arrowLength;
float arrowWidth;
bool hasRoundedCorners;
bool hasArrow;
bool isBillboardFixedSize;
} labelInfo;
layout(location = 0) out vec4 color;
@@ -45,43 +41,41 @@ layout(location = 1) out vec2 textureCoordinates;
// Background plane positions are in clipped space
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)
);
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];
vec2 bbox = labelInfo.textSize.xy;
position.xy *= bbox;
position.xy += vec2(labelInfo.bboxCenter);
position.z = -0.001;
textureCoordinates = TEX_COORDS[gl_VertexIndex] * bbox;
const vec2 TEX_COORDS[4] = vec2[](vec2(0, 0), vec2(1, 0), vec2(0, 1), vec2(1, 1));
if (!billboardInfo.isFixedSize)
{
mat4 mv = cam.view * node.world;
void main()
{
vec4 position = PLANE[gl_VertexIndex];
position.xy *= labelInfo.textSize;
position.xy += labelInfo.bboxCenter;
position.z = - 0.001;
textureCoordinates = TEX_COORDS[gl_VertexIndex] * labelInfo.textSize;
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 * vec4(position.xyz, 1);
}
else
{
vec4 billboardPos = vec4(0.5, 0.5, 0.5, 1);
vec4 viewPos = cam.view * node.world * billboardPos;
float dist = -viewPos.z;
gl_Position = cam.projection * (viewPos + vec4(position.xy*dist*0.2,0,0));
}
if (!labelInfo.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 * vec4(position.xyz, 1);
}
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(position.xy *dist * 0.2, 0, 0));
}
}

View File

@@ -1,47 +1,40 @@
#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(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));
}
// this parameter should be same as FontAtlasGeneratorConfig::pixelRange
const float pxRange = 3;
float screenPxRange() {
vec2 unitRange = vec2(pxRange)/vec2(textureSize(texSampler, 0));
vec2 screenTexSize = vec2(1.0)/fwidth(texCoord);
return max(0.5*dot(unitRange, screenTexSize), 1.0);
float screenPxRange()
{
vec2 unitRange = vec2(pxRange) / vec2(textureSize(texSampler, 0));
vec2 screenTexSize = vec2(1.0) / fwidth(texCoord);
return max(0.5 * dot(unitRange, screenTexSize), 1.0);
}
void main()
{
vec3 msd = texture(texSampler, texCoord).rgb;
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);
if (textConfig.backgroundColor.a != 0)
if (bgColor.a != 0)
{
outColor = mix(textConfig.backgroundColor, textConfig.textColor, opacity);
outColor = mix(bgColor, color, opacity);
}
else
{
outColor = vec4(vec3(textConfig.textColor), opacity);
outColor = vec4(vec3(color), opacity);
}
}

View File

@@ -1,39 +1,24 @@
#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(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;
const float threshold = 0.4f;
const float smoothing = 1.f/32.f;
void main()
{
float distance = texture(texSampler, texCoord).r;
float alpha = smoothstep(textConfig.threshold - textConfig.smoothing, textConfig.threshold + textConfig.smoothing, distance);
if (textConfig.applyBorder)
{
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;
}
float alpha = smoothstep(threshold - smoothing, threshold + smoothing, distance);
outColor = vec4(color) * 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
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(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()
{
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
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 = 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 vec2 fragTextureCoordinates;
layout(location = 1) out vec4 outBgColor;
layout(location = 2) out vec2 fragTextureCoordinates;
layout(set = 0, binding = 0) uniform NodeData
{
@@ -16,14 +16,12 @@ layout(set = 0, binding = 0) uniform NodeData
layout(set = 1, binding = 0) uniform CameraData
{
mat4 viewProjection;
mat4 view;
mat4 projection;
vec4 camPos;
mat4 viewProjection;
} cam;
void main() {
gl_Position = cam.viewProjection * node.world * vec4(position, 1.0);
fragTextureCoordinates.xy = textureCoordinates.xy;
outColor = color;
gl_Position = cam.viewProjection * node.world * vec4(position[gl_VertexIndex], 0.0, 1.0);
fragTextureCoordinates = textureCoordinates[gl_VertexIndex];
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
#include "Base/ICloseable.hpp"
#include "Device.hpp"
namespace OpenVulkano
@@ -9,7 +9,7 @@ namespace OpenVulkano
/**
* \brief A not managed buffer. This should be used rarely.
*/
struct Buffer : public ICloseable
struct Buffer
{
vk::Device device;
vk::DeviceMemory memory;
@@ -94,7 +94,7 @@ namespace OpenVulkano
device.invalidateMappedMemoryRanges(vk::MappedMemoryRange(memory, offset, size));
}
void Close() override
void Close()
{
if (mapped) UnMap();
if(memory)

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@@ -6,7 +6,6 @@
#pragma once
#include "Base/ICloseable.hpp"
#include "MetalBackedTexture.h"
#import <CoreVideo/CVPixelBuffer.h>
@@ -16,19 +15,20 @@ namespace OpenVulkano::Vulkan
{
class Renderer;
class MetalTextureCache : public ICloseable
class MetalTextureCache final
{
CVMetalTextureCacheRef m_textureCache = nullptr;
Vulkan::ResourceManager* m_resourceManager = nullptr;
std::map<void*, MetalBackedTexture> m_mtlToVkTextureMap;
Renderer* m_renderer;
IEventHandler* m_eventHandler = nullptr;
public:
~MetalTextureCache() { if (m_resourceManager) Close(); }
void Init(IRenderer* renderer);
void Close() override;
void Close();
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);
}
m_resourceManager = &m_renderer->GetResourceManager();
m_renderer->RegisterCloseable(this);
m_renderer->OnClose += EventHandler(this, &MetalTextureCache::Close);
}
Scene::Texture* MetalTextureCache::Get(CVPixelBufferRef pixelBuffer, MTLPixelFormat pixelFormat)
@@ -57,7 +57,7 @@ namespace OpenVulkano::Vulkan
void MetalTextureCache::Close()
{
m_mtlToVkTextureMap.clear();
m_renderer->UnregisterCloseable(this);
m_eventHandler->SetInvalid();
m_renderer = nullptr;
m_resourceManager = nullptr;
//TODO delete the texture cache object?

View File

@@ -13,7 +13,7 @@ namespace OpenVulkano::Vulkan
{
class FrameBuffer;
class RenderPass : public ICloseable
class RenderPass
{ //TODO allow to control the render rect size
protected:
vk::Device m_device;
@@ -27,14 +27,14 @@ namespace OpenVulkano::Vulkan
RenderPass() = default;
~RenderPass() override
virtual ~RenderPass()
{
if (m_frameBuffer) RenderPass::Close();
}
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 }))
{

View File

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

View File

@@ -40,7 +40,6 @@ namespace OpenVulkano::Vulkan
std::vector<std::vector<CommandHelper>> commands;
std::vector<std::vector<vk::CommandBuffer>> submitBuffers;
UiRenderer uiRenderer;
std::vector<ICloseable*> closeables;
DepthBufferQuery depthBufferQuery;
public:
@@ -83,14 +82,12 @@ namespace OpenVulkano::Vulkan
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; }
float GetLastQueriedDepthValue() override { return depthBufferQuery.GetQueriedValue(); }
void SetQueryDepthValue(const Math::Vector2f& depthCoordinates) override { depthBufferQuery.SetQueryCoordinates(depthCoordinates); }
Event<> OnClose;
};
}

View File

@@ -5,6 +5,9 @@
*/
#include "ResourceManager.hpp"
#include <Scene/VertexBuffer.hpp>
#include "ManagedBuffer.hpp"
#include "MemoryAllocation.hpp"
#include "Scene/Vertex.hpp"
@@ -21,6 +24,7 @@
#include "Vulkan/Scene/VulkanTexture.hpp"
#include "Vulkan/Scene/VulkanCamera.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"
namespace OpenVulkano::Vulkan
{
@@ -173,6 +177,21 @@ namespace OpenVulkano::Vulkan
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)
{
if (material->texture && !material->texture->HasRenderResource())

View File

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

View File

@@ -6,7 +6,6 @@
#pragma once
#include "Base/ICloseable.hpp"
#include "Vulkan/Resources/ManagedBuffer.hpp"
#include "Vulkan/Scene/IRecordable.hpp"
@@ -14,7 +13,7 @@ namespace OpenVulkano::Vulkan
{
class ManagedBuffer;
class UniformBuffer final : public IRecordable, public ICloseable
class UniformBuffer final : public IRecordable
{
ManagedBuffer::Ptr m_buffer = nullptr;
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 Close() override;
virtual void Close();
void Record(VulkanDrawContext* drawContext) override;

View File

@@ -12,107 +12,61 @@
#include "Vulkan/VulkanDrawContext.hpp"
#include "Vulkan/Scene/VulkanTexture.hpp"
#include "Vulkan/Scene/VulkanUniformBuffer.hpp"
#include "Vulkan/Scene/VulkanVertexBuffer.hpp"
using namespace OpenVulkano::Scene;
namespace OpenVulkano::Vulkan
{
void EncodeBackground(LabelDrawable* labelDrawable, Vulkan::VulkanDrawContext* drawContext)
void EncodeBackground(LabelDrawable* labelDrawable, VulkanDrawContext* drawContext)
{
if (labelDrawable->IsBillboard())
{
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);
}
VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
vkBuffer->Record(drawContext);
for (Node* node: labelDrawable->GetNodes())
{
if (!node->IsEnabled()) [[unlikely]]
{
continue;
}
if (!node->IsEnabled()) [[unlikely]] continue;
drawContext->EncodeNode(node);
}
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())
{
OpenVulkano::Scene::Shader* shader = entry.GetShader();
drawContext->EncodeShader(shader);
Geometry* mesh = entry.GetMesh();
VulkanGeometry* renderGeo = mesh->GetRenderResource();
if (!renderGeo)
{
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();
drawContext->EncodeShader(entry.GetShader());
VertexBuffer* vbo = entry.GetVertexBuffer();
VulkanVertexBuffer* renderVbo = vbo->GetRenderResource();
if (!renderVbo) renderVbo = drawContext->renderer->GetResourceManager().PrepareVertexBuffer(vbo);
renderVbo->RecordBind(drawContext->commandBuffer);
if (labelDrawable->IsBillboard())
{
// vertex shader buffer
uniforms[1] = labelDrawable->GetBillboardBuffer();
VulkanUniformBuffer* vkBuffer = labelDrawable->GetLabelBuffer()->GetRenderResource();
if (!vkBuffer) vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(labelDrawable->GetLabelBuffer());
vkBuffer->Record(drawContext);
}
for (OpenVulkano::Scene::UniformBuffer* buffer : uniforms)
VulkanTexture* renderTexture = entry.GetTexture()->GetRenderResource();
if (!renderTexture)
{
if (buffer)
{
VulkanUniformBuffer* vkBuffer = buffer->GetRenderResource();
if (!vkBuffer)
{
vkBuffer = drawContext->renderer->GetResourceManager().PrepareUniformBuffer(buffer);
}
vkBuffer->Record(drawContext);
}
}
if (Material* material = entry.GetMaterial())
{
if (Texture* texture = material->texture)
{
VulkanTexture* renderTexture = texture->GetRenderResource();
if (!renderTexture)
{
drawContext->renderer->GetResourceManager().PrepareMaterial(entry.GetMaterial());
renderTexture = texture->GetRenderResource();
}
renderTexture->Record(drawContext);
}
renderTexture = drawContext->renderer->GetResourceManager().PrepareTexture(entry.GetTexture());
}
renderTexture->Record(drawContext);
for (Node* node: labelDrawable->GetNodes())
{
if (!node->IsEnabled()) [[unlikely]]
{
continue;
}
if (!node->IsEnabled()) [[unlikely]] continue;
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);
EncodeBackground(labelDrawable, drawContext);
@@ -122,5 +76,5 @@ namespace OpenVulkano::Vulkan
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)
{
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)
{
for(const auto& param : description.inputParameters)
@@ -84,6 +84,13 @@ namespace OpenVulkano::Vulkan
vk::PipelineInputAssemblyStateCreateInfo inputAssembly = { {}, static_cast<vk::PrimitiveTopology>(shader->topology), 0 };
vk::PipelineRasterizationStateCreateInfo rasterizer = {};
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::PipelineDepthStencilStateCreateInfo depth = { {}, shader->depthTest, shader->depthWrite, static_cast<vk::CompareOp>(shader->depthCompareOp) };
depth.maxDepthBounds = 1;

View File

@@ -11,39 +11,36 @@
#include <vulkan/vulkan.hpp>
#include <vector>
namespace OpenVulkano
namespace OpenVulkano::Vulkan
{
namespace Vulkan
{
class Context;
class IShaderOwner;
class Context;
class IShaderOwner;
class VulkanShader final : public IRenderResource<Scene::Shader>, public IRecordable
{
public:
vk::Device device;
std::vector<vk::ShaderModule> shaderModules; // TODO manage live time somewhere else to allow sharing of shader programs
std::vector<vk::PipelineShaderStageCreateInfo> shaderStageCreateInfo;
vk::Pipeline pipeline; // TODO pipeline and shader config should be split
std::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
vk::PipelineLayout pipelineLayout;
IShaderOwner* owner = nullptr;
Context* context = nullptr;
{
public:
vk::Device device;
std::vector<vk::ShaderModule> shaderModules; // TODO manage live time somewhere else to allow sharing of shader programs
std::vector<vk::PipelineShaderStageCreateInfo> shaderStageCreateInfo;
vk::Pipeline pipeline; // TODO pipeline and shader config should be split
std::vector<vk::DescriptorSetLayout> descriptorSetLayouts;
vk::PipelineLayout pipelineLayout;
IShaderOwner* owner = nullptr;
Context* context = nullptr;
VulkanShader(Context* context, Scene::Shader* shader, IShaderOwner* owner);
VulkanShader(Context* context, Scene::Shader* shader, IShaderOwner* owner);
~VulkanShader() override;
~VulkanShader() override;
void Resize();
void Resize();
void Record(VulkanDrawContext* context) override;
void Record(VulkanDrawContext* context) override;
void Release() override;
void Release() override;
private:
void BuildPipeline();
private:
void BuildPipeline();
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
}
};
}