mirror of
https://github.com/johndoe6345789/SDL3CPlusPlus.git
synced 2026-04-25 14:15:02 +00:00
refactor: Restructure GUI renderer implementation and update service dependencies
This commit is contained in:
@@ -152,7 +152,7 @@ if(BUILD_SDL3_APP)
|
||||
src/services/impl/scene_service.cpp
|
||||
src/services/impl/graphics_service.cpp
|
||||
src/app/service_based_app.cpp
|
||||
src/gui/gui_renderer.cpp
|
||||
src/services/impl/gui_renderer.cpp
|
||||
)
|
||||
target_include_directories(sdl3_app PRIVATE "${CMAKE_CURRENT_SOURCE_DIR}/src")
|
||||
target_link_libraries(sdl3_app PRIVATE ${SDL_TARGET} Vulkan::Vulkan lua::lua CLI11::CLI11 rapidjson assimp::assimp Bullet::Bullet glm::glm Vorbis::vorbisfile Vorbis::vorbis)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
#include "gui/gui_renderer.hpp"
|
||||
#include "gui_renderer.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
@@ -14,14 +14,9 @@
|
||||
|
||||
#include "../../third_party/font8x8_basic.h"
|
||||
|
||||
namespace services = sdl3cpp::services;
|
||||
|
||||
namespace sdl3cpp::gui {
|
||||
namespace sdl3cpp::services::impl {
|
||||
namespace {
|
||||
|
||||
using ParsedSvg = sdl3cpp::gui::ParsedSvg;
|
||||
using SvgCircle = sdl3cpp::gui::SvgCircle;
|
||||
|
||||
bool ExtractAttribute(const std::string& source, const char* name, std::string& outValue) {
|
||||
std::string key = name;
|
||||
size_t pos = source.find(key);
|
||||
@@ -61,7 +56,7 @@ float ParseFloatValue(const std::string& text) {
|
||||
}
|
||||
}
|
||||
|
||||
services::GuiColor ParseColorString(const std::string& text, const services::GuiColor& fallback) {
|
||||
GuiColor ParseColorString(const std::string& text, const GuiColor& fallback) {
|
||||
if (text.empty() || text[0] != '#') {
|
||||
return fallback;
|
||||
}
|
||||
@@ -141,9 +136,9 @@ ParsedSvg ParseSvgFile(const std::filesystem::path& path) {
|
||||
return result;
|
||||
}
|
||||
|
||||
services::GuiCommand::RectData IntersectRect(const services::GuiCommand::RectData& a,
|
||||
const services::GuiCommand::RectData& b) {
|
||||
services::GuiCommand::RectData result;
|
||||
GuiCommand::RectData IntersectRect(const GuiCommand::RectData& a,
|
||||
const GuiCommand::RectData& b) {
|
||||
GuiCommand::RectData result;
|
||||
result.x = std::max(a.x, b.x);
|
||||
result.y = std::max(a.y, b.y);
|
||||
float right = std::min(a.x + a.width, b.x + b.width);
|
||||
@@ -161,7 +156,7 @@ int ClampToRange(int value, int minimum, int maximum) {
|
||||
|
||||
class GuiRenderer::Canvas {
|
||||
public:
|
||||
using RectData = services::GuiCommand::RectData;
|
||||
using RectData = GuiCommand::RectData;
|
||||
|
||||
void Resize(uint32_t width, uint32_t height) {
|
||||
width_ = width;
|
||||
@@ -187,8 +182,8 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void FillRect(const RectData& rect, const services::GuiColor& fillColor,
|
||||
const services::GuiColor& borderColor, float borderWidth) {
|
||||
void FillRect(const RectData& rect, const GuiColor& fillColor,
|
||||
const GuiColor& borderColor, float borderWidth) {
|
||||
DrawFilledRect(rect, fillColor);
|
||||
if (borderWidth > 0.0f && borderColor.a > 0.0f) {
|
||||
DrawFilledRect({rect.x, rect.y, rect.width, borderWidth}, borderColor);
|
||||
@@ -199,7 +194,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DrawText(const std::string& text, const services::GuiColor& color, const RectData& bounds,
|
||||
void DrawText(const std::string& text, const GuiColor& color, const RectData& bounds,
|
||||
const std::string& alignX, const std::string& alignY, float fontSize) {
|
||||
if (text.empty() || width_ == 0 || height_ == 0) {
|
||||
return;
|
||||
@@ -244,7 +239,7 @@ public:
|
||||
}
|
||||
}
|
||||
|
||||
void DrawSvg(const ParsedSvg& svg, const RectData& target, const services::GuiColor& tint) {
|
||||
void DrawSvg(const ParsedSvg& svg, const RectData& target, const GuiColor& tint) {
|
||||
if (svg.circles.empty() || svg.viewWidth <= 0.0f || svg.viewHeight <= 0.0f || width_ == 0 ||
|
||||
height_ == 0) {
|
||||
return;
|
||||
@@ -260,7 +255,7 @@ public:
|
||||
float cx = clipped.x + circle.cx * scaleX;
|
||||
float cy = clipped.y + circle.cy * scaleY;
|
||||
float radius = circle.r * scale;
|
||||
services::GuiColor color = circle.color;
|
||||
GuiColor color = circle.color;
|
||||
if (tint.a > 0.0f) {
|
||||
color.r *= tint.r;
|
||||
color.g *= tint.g;
|
||||
@@ -300,7 +295,7 @@ private:
|
||||
return clipped;
|
||||
}
|
||||
|
||||
void DrawFilledRect(const RectData& rect, const services::GuiColor& color) {
|
||||
void DrawFilledRect(const RectData& rect, const GuiColor& color) {
|
||||
if (rect.width <= 0.0f || rect.height <= 0.0f) {
|
||||
return;
|
||||
}
|
||||
@@ -319,7 +314,7 @@ private:
|
||||
}
|
||||
}
|
||||
|
||||
void BlendPixel(int x, int y, const services::GuiColor& color) {
|
||||
void BlendPixel(int x, int y, const GuiColor& color) {
|
||||
size_t index = (static_cast<size_t>(y) * width_ + static_cast<size_t>(x)) * 4;
|
||||
auto clampByte = [](float value) -> uint8_t {
|
||||
return static_cast<uint8_t>(std::clamp(value, 0.0f, 1.0f) * 255.0f);
|
||||
@@ -348,7 +343,7 @@ private:
|
||||
|
||||
GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat,
|
||||
const std::filesystem::path& scriptDirectory,
|
||||
std::shared_ptr<services::IBufferService> bufferService)
|
||||
std::shared_ptr<IBufferService> bufferService)
|
||||
: device_(device),
|
||||
physicalDevice_(physicalDevice),
|
||||
swapchainFormat_(swapchainFormat),
|
||||
@@ -365,7 +360,7 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
return canvasWidth_ > 0 && canvasHeight_ > 0 && stagingBuffer_ != VK_NULL_HANDLE;
|
||||
}
|
||||
|
||||
void GuiRenderer::Prepare(const std::vector<services::GuiCommand>& commands, uint32_t width,
|
||||
void GuiRenderer::Prepare(const std::vector<GuiCommand>& commands, uint32_t width,
|
||||
uint32_t height) {
|
||||
if (width == 0 || height == 0 || !canvas_) {
|
||||
return;
|
||||
@@ -374,10 +369,10 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
canvas_->Clear();
|
||||
for (const auto& command : commands) {
|
||||
switch (command.type) {
|
||||
case services::GuiCommand::Type::Rect:
|
||||
case GuiCommand::Type::Rect:
|
||||
canvas_->FillRect(command.rect, command.color, command.borderColor, command.borderWidth);
|
||||
break;
|
||||
case services::GuiCommand::Type::Text: {
|
||||
case GuiCommand::Type::Text: {
|
||||
if (command.hasClipRect) {
|
||||
canvas_->PushClip(command.clipRect);
|
||||
}
|
||||
@@ -385,7 +380,7 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
canvas_->DrawText(command.text, command.color, command.bounds, command.alignX,
|
||||
command.alignY, command.fontSize);
|
||||
} else {
|
||||
services::GuiCommand::RectData fallback{
|
||||
GuiCommand::RectData fallback{
|
||||
command.rect.x, command.rect.y,
|
||||
command.fontSize * static_cast<float>(std::max<size_t>(1, command.text.size())), command.fontSize};
|
||||
canvas_->DrawText(command.text, command.color, fallback, command.alignX,
|
||||
@@ -396,13 +391,13 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
}
|
||||
break;
|
||||
}
|
||||
case services::GuiCommand::Type::ClipPush:
|
||||
case GuiCommand::Type::ClipPush:
|
||||
canvas_->PushClip(command.rect);
|
||||
break;
|
||||
case services::GuiCommand::Type::ClipPop:
|
||||
case GuiCommand::Type::ClipPop:
|
||||
canvas_->PopClip();
|
||||
break;
|
||||
case services::GuiCommand::Type::Svg:
|
||||
case GuiCommand::Type::Svg:
|
||||
if (command.svgPath.empty()) {
|
||||
break;
|
||||
}
|
||||
@@ -569,4 +564,4 @@ GuiRenderer::GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFor
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace sdl3cpp::gui
|
||||
} // namespace sdl3cpp::services::impl
|
||||
@@ -1,5 +1,5 @@
|
||||
#ifndef SDL3CPP_GUI_GUI_RENDERER_HPP
|
||||
#define SDL3CPP_GUI_GUI_RENDERER_HPP
|
||||
#ifndef SDL3CPP_SERVICES_GUI_RENDERER_HPP
|
||||
#define SDL3CPP_SERVICES_GUI_RENDERER_HPP
|
||||
|
||||
#include <filesystem>
|
||||
#include <memory>
|
||||
@@ -11,13 +11,13 @@
|
||||
#include "services/interfaces/gui_types.hpp"
|
||||
#include "services/interfaces/i_buffer_service.hpp"
|
||||
|
||||
namespace sdl3cpp::gui {
|
||||
namespace sdl3cpp::services::impl {
|
||||
|
||||
struct SvgCircle {
|
||||
float cx = 0.0f;
|
||||
float cy = 0.0f;
|
||||
float r = 0.0f;
|
||||
services::GuiColor color{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
GuiColor color{1.0f, 1.0f, 1.0f, 1.0f};
|
||||
};
|
||||
|
||||
struct ParsedSvg {
|
||||
@@ -30,13 +30,13 @@ class GuiRenderer {
|
||||
public:
|
||||
GuiRenderer(VkDevice device, VkPhysicalDevice physicalDevice, VkFormat swapchainFormat,
|
||||
const std::filesystem::path& scriptDirectory,
|
||||
std::shared_ptr<services::IBufferService> bufferService);
|
||||
std::shared_ptr<IBufferService> bufferService);
|
||||
~GuiRenderer();
|
||||
|
||||
GuiRenderer(const GuiRenderer&) = delete;
|
||||
GuiRenderer& operator=(const GuiRenderer&) = delete;
|
||||
|
||||
void Prepare(const std::vector<services::GuiCommand>& commands, uint32_t width,
|
||||
void Prepare(const std::vector<GuiCommand>& commands, uint32_t width,
|
||||
uint32_t height);
|
||||
void BlitToSwapchain(VkCommandBuffer commandBuffer, VkImage image);
|
||||
void Resize(uint32_t width, uint32_t height, VkFormat format);
|
||||
@@ -65,9 +65,9 @@ private:
|
||||
uint32_t canvasHeight_ = 0;
|
||||
std::unique_ptr<Canvas> canvas_;
|
||||
std::unordered_map<std::string, ParsedSvg> svgCache_;
|
||||
std::shared_ptr<services::IBufferService> bufferService_;
|
||||
std::shared_ptr<IBufferService> bufferService_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::gui
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
#endif // SDL3CPP_GUI_GUI_RENDERER_HPP
|
||||
#endif // SDL3CPP_SERVICES_GUI_RENDERER_HPP
|
||||
@@ -18,7 +18,7 @@ void GuiRendererService::Initialize(VkDevice device,
|
||||
if (logger_) {
|
||||
logger_->TraceFunction(__func__);
|
||||
}
|
||||
renderer_ = std::make_unique<sdl3cpp::gui::GuiRenderer>(
|
||||
renderer_ = std::make_unique<GuiRenderer>(
|
||||
device, physicalDevice, format, resourcePath, bufferService_);
|
||||
}
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include "../interfaces/i_gui_renderer_service.hpp"
|
||||
#include "../interfaces/i_logger.hpp"
|
||||
#include "../../di/lifecycle.hpp"
|
||||
#include "../../gui/gui_renderer.hpp"
|
||||
#include "gui_renderer.hpp"
|
||||
#include <memory>
|
||||
|
||||
namespace sdl3cpp::services::impl {
|
||||
@@ -35,7 +35,7 @@ public:
|
||||
private:
|
||||
std::shared_ptr<ILogger> logger_;
|
||||
std::shared_ptr<IBufferService> bufferService_;
|
||||
std::unique_ptr<sdl3cpp::gui::GuiRenderer> renderer_;
|
||||
std::unique_ptr<GuiRenderer> renderer_;
|
||||
};
|
||||
|
||||
} // namespace sdl3cpp::services::impl
|
||||
|
||||
@@ -11,7 +11,7 @@ namespace sdl3cpp::services::impl {
|
||||
/**
|
||||
* @brief Vulkan GUI service implementation.
|
||||
*
|
||||
* Small wrapper service (~60 lines) around GuiRenderer.
|
||||
* Small wrapper service (~60 lines) around the GUI renderer service.
|
||||
* Provides 2D GUI overlay rendering for SVG, text, and shapes.
|
||||
*/
|
||||
class VulkanGuiService : public IGuiService,
|
||||
|
||||
@@ -14,7 +14,7 @@ struct GuiCommand;
|
||||
* @brief GUI rendering service interface.
|
||||
*
|
||||
* Handles 2D GUI overlay rendering using Vulkan.
|
||||
* Wraps the GuiRenderer class with support for SVG, text, and shapes.
|
||||
* Delegates low-level draw work to the GUI renderer service.
|
||||
*/
|
||||
class IGuiService {
|
||||
public:
|
||||
|
||||
Reference in New Issue
Block a user