VEX Engine
Retro looking game engine made in vulkan mostly because i wanted to understand it better.
Loading...
Searching...
No Matches
VexUI.hpp
Go to the documentation of this file.
1
6
7#pragma once
8
9#ifndef VK_NO_PROTOTYPES
10 #define VK_NO_PROTOTYPES 1
11#endif
12#define VMA_STATIC_VULKAN_FUNCTIONS 0
13#define VMA_DYNAMIC_VULKAN_FUNCTIONS 1
14#include <vk_mem_alloc.h>
15#include <vector>
16#include <string>
17#include <unordered_map>
18#include <functional>
19#include <glm/glm.hpp>
20#include <nlohmann/json.hpp>
21#include "Layout.hpp"
23#include <SDL3/SDL.h>
24#include <volk.h>
25
30
31#include "../../../thirdparty/stb/stb_truetype.h"
32
33namespace vex {
34
35class VexUI;
36
38enum class UIUnitType { Auto, Px, Psp, Vw, Vh, Percent };
39
41struct UIUnitValue {
42 float value = 0.f;
43 UIUnitType type = UIUnitType::Psp;
44
45 UIUnitValue() = default;
46 UIUnitValue(float v) : value(v), type(UIUnitType::Psp) {}
47 UIUnitValue(float v, UIUnitType t) : value(v), type(t) {}
48
49 // Allows backward compatibility.
50 UIUnitValue& operator=(float v) {
51 value = v;
52 return *this;
53 }
54
56 void parse(const nlohmann::json& jval);
57
58 static UIUnitValue parseJson(const nlohmann::json& jval) {
59 UIUnitValue v; v.parse(jval); return v;
60 }
61
63 nlohmann::json toJson() const;
64
66 float getPixels(const VexUI* ui) const;
67};
68
70struct UIUnitVec2 {
71 UIUnitValue x{0.f, UIUnitType::Auto};
72 UIUnitValue y{0.f, UIUnitType::Auto};
73};
74
76struct FontAtlas {
77 stbtt_fontinfo info{};
78 std::vector<stbtt_bakedchar> cdata;
79 VkImage image = VK_NULL_HANDLE;
80 VmaAllocation alloc = VK_NULL_HANDLE;
81 VkImageView view = VK_NULL_HANDLE;
82 uint32_t texIdx = 0;
83 int width = 0, height = 0;
84 float ascent = 0.f;
85 float descent = 0.f;
86 float scale = 0.f;
87 float bakedSize = 0.f;
88};
89
91struct UIStyle {
92 glm::vec4 color{1,1,1,1};
93 glm::vec4 bgColor{-1,-1,-1,-1};
94 glm::vec4 borderColor = {0,0,0,0};
95 std::string font;
96 UIUnitValue fontSize{16.f, UIUnitType::Psp};
97 UIUnitValue borderWidth{0.f, UIUnitType::Psp};
98};
99
101enum class TextAlign { Left, Center, Right };
102
104struct UIQuad {
105 uint32_t vertexOffset;
106 float texIndex; // -1 = solid color
107};
108
110enum class WidgetType { Container, Label, Image, Button };
111
113struct Widget {
114 WidgetType type = WidgetType::Container;
115 std::string id;
116 std::string text;
117 std::string image;
118
119 UIUnitVec2 size;
120 float rotation = 0.f;
121 UIStyle style;
122
123 nlohmann::json nodeJson;
124
125 LayoutNode* layoutNode = nullptr;
126 std::vector<Widget*> children;
127 Widget* parent = nullptr;
128 std::function<void()> onClick = nullptr;
129 std::function<void()> onFocusEnter = nullptr;
130 std::function<void()> onFocusLost = nullptr;
131 VexUI* ui = nullptr;
132 TextAlign textAlign = TextAlign::Left;
133
134 ~Widget();
135 void applyLayout(VexUI* uiManager);
136};
137
139class VexUI {
140public:
147 ~VexUI();
148
150 bool init();
153 void load(const std::string& path);
159 void render(VkCommandBuffer cmd, VkPipeline pipeline, VkPipelineLayout pipelineLayout, int currentFrame);
162 void processEvent(const SDL_Event& ev);
163
166 Widget* getFocusedWidget() const { return m_focusedWidget; }
167
171 void setText(const std::string& id, const std::string& txt);
172
176 void setOnClick(const std::string& id, std::function<void()> cb);
177
181 Widget* getWidget(const std::string& id) {
182 if (Widget* w = findById(m_root, id)) return w;
183 log("Widget not found");
184 return nullptr;
185 }
186
190 UIStyle* getStyle(const std::string& id) {
191 if (Widget* w = findById(m_root, id)) return &w->style;
192 log("Widget not found");
193 return nullptr;
194 }
195
199 void setStyle(const std::string& id, const UIStyle& style) {
200 if (initialized) {
201 if (Widget* w = findById(m_root, id)) w->style = style;
202 } else {
203 pendingSetters.push_back([this, id, style]() {
204 if (Widget* w = findById(m_root, id)) w->style = style;
205 });
206 }
207 }
208
212 void setRotation(const std::string& id, float degrees);
213
218 void setPosition(const std::string& id, UIUnitValue x, UIUnitValue y);
219
224 void setSize(const std::string& id, UIUnitValue w, UIUnitValue h);
225
229 void setImage(const std::string& id, const std::string& path);
230
235 void setFont(const std::string& id, const std::string& fontPath, UIUnitValue fontSize);
236
240 void setColor(const std::string& id, glm::vec4 color);
241
245 void setBackgroundColor(const std::string& id, glm::vec4 color);
246
251 void setBorder(const std::string& id, UIUnitValue width, glm::vec4 color);
252
255 bool isInitialized() { return initialized; }
256
259 int getZIndex() { return zIndex; }
260
263 void setZIndex(int zIndex) {
264 if(initialized) { this->zIndex = zIndex; }
265 else { pendingSetters.push_back([this, zIndex]() { this->zIndex = zIndex; }); }
266 }
267
270 void update(float deltaTime = 0.016f) {
271 if (initialized) {
272 if (m_gamepadNavigationCooldown > 0.0f) m_gamepadNavigationCooldown -= deltaTime;
273 if (loadPending) {
274 loadPending = false;
275 load(loadPath);
276 }
277 for (auto& setter : pendingSetters) setter();
278 pendingSetters.clear();
279 }
280 }
281
282 float getPspMultiplier() const;
283 glm::uvec2 getRenderResolution() const { return m_ctx.currentRenderResolution; }
284
285private:
286 VulkanContext& m_ctx;
287 VirtualFileSystem* m_vfs;
288 VulkanResources* m_res;
289 ResolutionManager* m_resMgr;
290
291 Widget* m_root = nullptr;
292 bool initialized = false;
293 int zIndex = 0;
294
295 glm::uvec2 m_lastRenderRes{0, 0};
296 float m_lastPspMult = 0.f;
297
298 std::vector<std::function<void()>> pendingSetters;
299
300 bool loadPending = false;
301 std::string loadPath = "";
302
303 std::unordered_map<std::string, FontAtlas> m_fontAtlases;
304
305 VkBuffer m_vb = VK_NULL_HANDLE;
306 VmaAllocation m_vbAlloc = VK_NULL_HANDLE;
307 size_t m_vbSize = 0;
308 VkSampler m_uiSampler = VK_NULL_HANDLE;
309
310 Widget* m_focusedWidget = nullptr;
311 float m_gamepadAxisX = 0.0f;
312 float m_gamepadAxisY = 0.0f;
313 Widget* m_previousFocusedWidget = nullptr;
314 float m_gamepadNavigationCooldown = 0.0f;
315 static constexpr float GAMEPAD_NAV_COOLDOWN = 0.2f;
316 static constexpr float GAMEPAD_AXIS_THRESHOLD = 0.5f;
317
320 void loadFonts(Widget* w);
321
324 void loadImages(Widget* w);
325
328 void layout(glm::uvec2 res);
329
334 void batch(Widget* w, std::vector<float>& verts, glm::vec2 parentOffset = {0.f, 0.f});
335
338 void uploadVerts(const std::vector<float>& verts);
339
343 Widget* parseNode(const nlohmann::json& j);
344
347 void freeTree(Widget* w);
348
354 Widget* findWidgetAt(Widget* w, glm::vec2 pos, glm::vec2 parentOffset = {0.f, 0.f});
355
360 Widget* findById(Widget* w, const std::string& id);
361
367 std::vector<std::string> wrapText(const std::string& text, const FontAtlas& a, float maxWidth);
368
373 glm::vec2 calculateTextSize(Widget* w, float maxWidth = FLT_MAX);
374
379 static void measureTextNode(LayoutNode* node, float width, float height);
380
384 void safeUpdate(const std::string& id, std::function<void(Widget*)> action);
385
389 void navigateToWidget(float dirX, float dirY);
390
392 void getNavigableWidgets(std::vector<Widget*>& out);
393
395 void collectNavigableWidgets(Widget* w, std::vector<Widget*>& out);
396
398 bool isWidgetNavigable(Widget* w) const;
399
401 glm::vec2 getWidgetCenter(Widget* w);
402
404 Widget* findClosestNavigableWidget(const glm::vec2& fromPos, const glm::vec2& direction, const std::vector<Widget*>& candidates);
405
408 void setFocusedWidget(Widget* w);
409};
410
411} // namespace vex
Main header for the Entity Component System (ECS) framework.
This file defines ResolutionManager class and ResolutionMode struct.
This file defines VulkanResources Class.
This file defines VirtualFileSystem and VPKStream classes.
Class responsible for managing resolution settings, calculating render resolution based on selected m...
Class defining VexUI, it initializes the UI system, loads, renders, converts ui data,...
Definition VexUI.hpp:139
void setStyle(const std::string &id, const UIStyle &style)
Set a UI element's style.
Definition VexUI.hpp:199
VexUI(VulkanContext &ctx, VirtualFileSystem *vfs, VulkanResources *res, ResolutionManager *resMgr)
Constructor for VexUI.
Definition VexUI.cpp:462
void setColor(const std::string &id, glm::vec4 color)
Set text/tint color.
Definition VexUI.cpp:1074
void setSize(const std::string &id, UIUnitValue w, UIUnitValue h)
Resize a widget.
Definition VexUI.cpp:1050
void setRotation(const std::string &id, float degrees)
Set rotation of a widget in degrees.
Definition VexUI.cpp:1034
void loadImages(Widget *w)
Loads images for the UI.
Definition VexUI.cpp:567
bool isWidgetNavigable(Widget *w) const
Check if widget is navigable (button type).
Definition VexUI.cpp:760
void batch(Widget *w, std::vector< float > &verts, glm::vec2 parentOffset={0.f, 0.f})
Batches the UI for rendering.
Definition VexUI.cpp:851
void setZIndex(int zIndex)
Set the z-index of the UI system.
Definition VexUI.hpp:263
glm::vec2 calculateTextSize(Widget *w, float maxWidth=FLT_MAX)
Calculates the size of the text.
Definition VexUI.cpp:816
int getZIndex()
Get the current z-index of the UI system.
Definition VexUI.hpp:259
void setText(const std::string &id, const std::string &txt)
Set text of a UI element.
Definition VexUI.cpp:680
bool init()
Initialize the UI system, components needed later on.
Definition VexUI.cpp:475
void getNavigableWidgets(std::vector< Widget * > &out)
Get all navigable widgets (buttons).
Definition VexUI.cpp:752
void setPosition(const std::string &id, UIUnitValue x, UIUnitValue y)
Move a widget (sets Left/Top yoga properties). Works best with position: absolute,...
Definition VexUI.cpp:1041
static void measureTextNode(LayoutNode *node, float width, float height)
Measures a text node.
Definition VexUI.cpp:840
Widget * findById(Widget *w, const std::string &id)
Finds a widget by its id.
Definition VexUI.cpp:673
void loadFonts(Widget *w)
Loads fonts for the UI.
Definition VexUI.cpp:514
void processEvent(const SDL_Event &ev)
Process mouse and keyboard events.
Definition VexUI.cpp:695
Widget * getFocusedWidget() const
Get the currently focused widget.
Definition VexUI.hpp:166
bool isInitialized()
Check if the UI system is initialized.
Definition VexUI.hpp:255
void safeUpdate(const std::string &id, std::function< void(Widget *)> action)
Updates a widget safely.
Definition VexUI.cpp:500
void update(float deltaTime=0.016f)
Update the UI system.
Definition VexUI.hpp:270
void setFont(const std::string &id, const std::string &fontPath, UIUnitValue fontSize)
Change font properties.
Definition VexUI.cpp:1065
Widget * findClosestNavigableWidget(const glm::vec2 &fromPos, const glm::vec2 &direction, const std::vector< Widget * > &candidates)
Find closest navigable widget in a direction.
Definition VexUI.cpp:782
void setBorder(const std::string &id, UIUnitValue width, glm::vec4 color)
Set border properties.
Definition VexUI.cpp:1088
void navigateToWidget(float dirX, float dirY)
Navigate to widget in a given direction.
Definition VexUI.cpp:732
void freeTree(Widget *w)
Frees the widget tree.
Definition VexUI.cpp:1028
void setOnClick(const std::string &id, std::function< void()> cb)
Set on-click callback of a UI element.
Definition VexUI.cpp:689
UIStyle * getStyle(const std::string &id)
Get a UI element's style.
Definition VexUI.hpp:190
Widget * parseNode(const nlohmann::json &j)
Parses a node from json to widgets.
Definition VexUI.cpp:578
void layout(glm::uvec2 res)
Layouts the UI using yoga.
Definition VexUI.cpp:643
void uploadVerts(const std::vector< float > &verts)
Uploads the vertex buffer to the GPU.
Definition VexUI.cpp:1020
glm::vec2 getWidgetCenter(Widget *w)
Get widget center position in screen space.
Definition VexUI.cpp:765
std::vector< std::string > wrapText(const std::string &text, const FontAtlas &a, float maxWidth)
Wraps text to fit within a given width.
Definition VexUI.cpp:209
void setImage(const std::string &id, const std::string &path)
Change the image of an image widget.
Definition VexUI.cpp:1057
void load(const std::string &path)
Load UI data from a JSON file.
Definition VexUI.cpp:608
Widget * findWidgetAt(Widget *w, glm::vec2 pos, glm::vec2 parentOffset={0.f, 0.f})
Finds a widget at a position.
Definition VexUI.cpp:647
Widget * getWidget(const std::string &id)
Get a UI element.
Definition VexUI.hpp:181
void setBackgroundColor(const std::string &id, glm::vec4 color)
Set background color.
Definition VexUI.cpp:1081
void render(VkCommandBuffer cmd, VkPipeline pipeline, VkPipelineLayout pipelineLayout, int currentFrame)
Render the UI. It is called by main rendering function.
Definition VexUI.cpp:954
void collectNavigableWidgets(Widget *w, std::vector< Widget * > &out)
Recursively collect navigable widgets.
Definition VexUI.cpp:754
void setFocusedWidget(Widget *w)
Set focus to a widget and trigger focus callbacks.
Definition VexUI.cpp:808
This class provides abstraction of file system needed for loading packed and unpacked assets.
This class manages resources like textures, descriptor sets, and uniform buffers.
Definition Resources.hpp:23
This file defines struct holding all vulkan data, like device, surface, swapchain,...
UIUnitType
Supported responsive UI unit types.
Definition VexUI.hpp:38
WidgetType
Enum specifying possible types of widgets.
Definition VexUI.hpp:110
void VEX_EXPORT log(const char *fmt,...)
Logs a formatted message.
TextAlign
Allows for text aligment.
Definition VexUI.hpp:101
Font atlas structure.
Definition VexUI.hpp:76
Layout node representing a single UI element in the layout tree.
Definition Layout.hpp:41
Quad component needed for rendering.
Definition VexUI.hpp:104
Basic UI styling component.
Definition VexUI.hpp:91
Struct storing unit value logic natively.
Definition VexUI.hpp:41
void parse(const nlohmann::json &jval)
Parses a json value into the unit struct.
Definition VexUI.cpp:284
nlohmann::json toJson() const
Converts the unit back to a json-compatible format (preserves strings like "px", "%").
Definition VexUI.cpp:306
float getPixels(const VexUI *ui) const
Dynamically calculates the raw pixel representation required for rendering.
Definition VexUI.cpp:320
2D representation of UIUnitValue to replace glm::vec2 size safely.
Definition VexUI.hpp:70
Struct holding all vulkan data, like device, surface, swapchain, images, views, and more.
Definition context.hpp:26
Struct defining widget component, it has a lot of redundancy and probably will need cleanup before ex...
Definition VexUI.hpp:113