diff --git a/res/scripts/hud.lua b/res/scripts/hud.lua
index 322f03db5..a0e363b99 100644
--- a/res/scripts/hud.lua
+++ b/res/scripts/hud.lua
@@ -126,6 +126,8 @@ function on_hud_open()
configure_SSAO()
hud.default_hand_controller = update_hand
+
+ gui.root.root:add("")
end
function on_hud_render()
diff --git a/src/graphics/core/Framebuffer.cpp b/src/graphics/core/Framebuffer.cpp
index bb360b54e..5d6be967d 100644
--- a/src/graphics/core/Framebuffer.cpp
+++ b/src/graphics/core/Framebuffer.cpp
@@ -89,6 +89,10 @@ Texture* Framebuffer::getTexture() const {
return texture.get();
}
+std::shared_ptr Framebuffer::getSharedTexture() const {
+ return texture;
+}
+
uint Framebuffer::getWidth() const {
return width;
}
diff --git a/src/graphics/core/Framebuffer.hpp b/src/graphics/core/Framebuffer.hpp
index e48e97df4..4d21449c5 100644
--- a/src/graphics/core/Framebuffer.hpp
+++ b/src/graphics/core/Framebuffer.hpp
@@ -13,7 +13,7 @@ class Framebuffer : public Bindable {
uint width;
uint height;
uint format;
- std::unique_ptr texture;
+ std::shared_ptr texture;
public:
Framebuffer(uint fbo, uint depth, std::unique_ptr texture);
Framebuffer(uint width, uint height, bool alpha=false);
@@ -33,6 +33,8 @@ public:
/// @brief Get framebuffer color attachment
Texture* getTexture() const;
+ std::shared_ptr getSharedTexture() const;
+
/// @brief Get framebuffer width
uint getWidth() const;
/// @brief Get framebuffer height
diff --git a/src/graphics/ui/elements/Frame.cpp b/src/graphics/ui/elements/Frame.cpp
new file mode 100644
index 000000000..2a7af926b
--- /dev/null
+++ b/src/graphics/ui/elements/Frame.cpp
@@ -0,0 +1,42 @@
+#include "Frame.hpp"
+
+#include "assets/Assets.hpp"
+#include "graphics/core/Batch2D.hpp"
+#include "graphics/core/Framebuffer.hpp"
+#include "graphics/core/DrawContext.hpp"
+#include "graphics/core/Texture.hpp"
+#include "window/Window.hpp"
+#include "../GUI.hpp"
+
+using namespace gui;
+
+static inline constexpr int MAX_TEXTURE_SIZE = 2048;
+
+gui::Frame::Frame(GUI& gui) : Container(gui, {}), fbo(nullptr) {}
+
+gui::Frame::~Frame() = default;
+
+void gui::Frame::draw(const DrawContext& pctx, const Assets& assets) {
+ glm::ivec2 size = getSize();
+ if (size.x <= 0 || size.y <= 0 ||
+ size.x > MAX_TEXTURE_SIZE || size.y > MAX_TEXTURE_SIZE) {
+ return;
+ }
+ auto& nonConstASsets = const_cast(assets);
+ if (fbo && (fbo->getWidth() != size.x || fbo->getHeight() != size.y)) {
+ fbo->resize(size.x, size.y);
+ nonConstASsets.store(fbo->getSharedTexture(), texture);
+ } else if (fbo == nullptr) {
+ fbo = std::make_unique(size.x, size.y, true);
+ nonConstASsets.store(fbo->getSharedTexture(), texture);
+ }
+
+ // ui uses flipped camera with matrix based on main viewport
+ setPos({0, pctx.getViewport().y - size.y});
+
+ auto ctx = pctx.sub();
+ ctx.setFramebuffer(fbo.get());
+ display::clear();
+ Container::draw(ctx, assets);
+ ctx.getBatch2D()->flush();
+}
diff --git a/src/graphics/ui/elements/Frame.hpp b/src/graphics/ui/elements/Frame.hpp
new file mode 100644
index 000000000..1f4a10c86
--- /dev/null
+++ b/src/graphics/ui/elements/Frame.hpp
@@ -0,0 +1,18 @@
+#pragma once
+
+#include "Container.hpp"
+
+class Framebuffer;
+
+namespace gui {
+ class Frame final : public Container {
+ public:
+ explicit Frame(GUI& gui);
+ virtual ~Frame();
+
+ void draw(const DrawContext& pctx, const Assets& assets) override;
+ private:
+ std::unique_ptr fbo;
+ std::string texture = "gui/no_icon";
+ };
+}
diff --git a/src/graphics/ui/gui_xml.cpp b/src/graphics/ui/gui_xml.cpp
index 0020c28d1..f34bd9247 100644
--- a/src/graphics/ui/gui_xml.cpp
+++ b/src/graphics/ui/gui_xml.cpp
@@ -8,6 +8,7 @@
#include "elements/Button.hpp"
#include "elements/Canvas.hpp"
#include "elements/CheckBox.hpp"
+#include "elements/Frame.hpp"
#include "elements/Image.hpp"
#include "elements/InlineFrame.hpp"
#include "elements/InputBindBox.hpp"
@@ -850,6 +851,15 @@ static std::shared_ptr read_page_box(
return menu;
}
+static std::shared_ptr read_frame(
+ UiXmlReader& reader, const xml::xmlelement& element
+) {
+ auto& gui = reader.getGUI();
+ auto frame = std::make_shared(gui);
+ read_container_impl(reader, element, *frame, true);
+ return frame;
+}
+
static std::shared_ptr read_iframe(
UiXmlReader& reader, const xml::xmlelement& element
) {
@@ -867,6 +877,7 @@ UiXmlReader::UiXmlReader(gui::GUI& gui, scriptenv&& env)
contextStack.emplace("");
add("image", read_image);
add("canvas", read_canvas);
+ add("frame", read_frame);
add("iframe", read_iframe);
add("label", read_label);
add("panel", read_panel);