Added quad rendering and a (WIP) button type.
This commit is contained in:
parent
c469772afa
commit
eb47d92099
BIN
assets/bitmaps/button.png
Normal file
BIN
assets/bitmaps/button.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 849 B |
@ -1,2 +1,2 @@
|
|||||||
symtex_glyphs ../fonts/symtex.png
|
symtex_glyphs ../fonts/symtex.png
|
||||||
sdl_logo sdl.png
|
button button.png
|
@ -78,6 +78,11 @@ void UIApp::init(const AppInitArgs& args)
|
|||||||
.posX = 100,
|
.posX = 100,
|
||||||
.posY = 100
|
.posY = 100
|
||||||
});
|
});
|
||||||
|
mButton = mWidgetTree.getRootWidget().emplaceChild<Button>({
|
||||||
|
.text = "Click Me!",
|
||||||
|
.posX = 100,
|
||||||
|
.posY = 500
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIApp::update(const AppUpdateArgs& args)
|
void UIApp::update(const AppUpdateArgs& args)
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED)
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED)
|
||||||
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED 1
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_APP_HPP_INCLUDED 1
|
||||||
|
|
||||||
#include <glm/vec2.hpp>
|
|
||||||
|
|
||||||
#include "../application.hpp"
|
#include "../application.hpp"
|
||||||
|
#include "../gui/button.hpp"
|
||||||
#include "../gui/label.hpp"
|
#include "../gui/label.hpp"
|
||||||
#include "../gui/widget.hpp"
|
#include "../gui/widget.hpp"
|
||||||
#include "../gui/ui_renderer.hpp"
|
#include "../gui/ui_renderer.hpp"
|
||||||
@ -27,6 +26,7 @@ private:
|
|||||||
WidgetTree mWidgetTree;
|
WidgetTree mWidgetTree;
|
||||||
|
|
||||||
Label* mLabel;
|
Label* mLabel;
|
||||||
|
Button* mButton;
|
||||||
|
|
||||||
sdlpp::Gamepad mGamepad;
|
sdlpp::Gamepad mGamepad;
|
||||||
Uint32 mNumVertices = 0;
|
Uint32 mNumVertices = 0;
|
||||||
|
@ -5,6 +5,7 @@ src_files = Split("""
|
|||||||
main.cpp
|
main.cpp
|
||||||
|
|
||||||
application.cpp
|
application.cpp
|
||||||
|
gui/button.cpp
|
||||||
gui/label.cpp
|
gui/label.cpp
|
||||||
gui/ui_renderer.cpp
|
gui/ui_renderer.cpp
|
||||||
gui/widget.cpp
|
gui/widget.cpp
|
||||||
|
93
private/sdl_gpu_test/gui/button.cpp
Normal file
93
private/sdl_gpu_test/gui/button.cpp
Normal file
@ -0,0 +1,93 @@
|
|||||||
|
|
||||||
|
#include "./button.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
Button::Button(ButtonCreateArgs args) : mText(std::move(args.text)), mTextColor(args.textColor),
|
||||||
|
mBackgroundColor(args.backgroundColor), mPosX(args.posX), mPosY(args.posY), mWidth(args.width), mHeight(args.height)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setText(std::string text)
|
||||||
|
{
|
||||||
|
if (text != mText)
|
||||||
|
{
|
||||||
|
mText = std::move(text);
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setTextColor(const glm::vec4& color)
|
||||||
|
{
|
||||||
|
if (color != mTextColor)
|
||||||
|
{
|
||||||
|
mTextColor = color;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setBackgroundColor(const glm::vec4& color)
|
||||||
|
{
|
||||||
|
if (color != mBackgroundColor)
|
||||||
|
{
|
||||||
|
mBackgroundColor = color;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setPosX(int posX)
|
||||||
|
{
|
||||||
|
if (posX != mPosX)
|
||||||
|
{
|
||||||
|
mPosX = posX;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::setPosY(int posY)
|
||||||
|
{
|
||||||
|
if (posY != mPosY)
|
||||||
|
{
|
||||||
|
mPosY = posY;
|
||||||
|
invalidate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::handleEnteredTree()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::revalidate()
|
||||||
|
{
|
||||||
|
update();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Button::update()
|
||||||
|
{
|
||||||
|
if (mTree == nullptr)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mPrimitiveID != UIRenderer::UNSET_PRIMITIVE_ID)
|
||||||
|
{
|
||||||
|
mTree->getRenderer().removePrimitive(mPrimitiveID);
|
||||||
|
}
|
||||||
|
mTree->getRenderer().drawQuad({
|
||||||
|
.texture = "button",
|
||||||
|
.x = mPosX,
|
||||||
|
.y = mPosY,
|
||||||
|
.width = mWidth,
|
||||||
|
.height = mHeight,
|
||||||
|
.color = mBackgroundColor
|
||||||
|
}, &mPrimitiveID);
|
||||||
|
mTree->getRenderer().drawTextCentered({
|
||||||
|
.x = mPosX + (mWidth / 2),
|
||||||
|
.y = mPosY + (mHeight / 2),
|
||||||
|
.text = mText,
|
||||||
|
.color = mTextColor
|
||||||
|
}, &mPrimitiveID);
|
||||||
|
}
|
||||||
|
}
|
68
private/sdl_gpu_test/gui/button.hpp
Normal file
68
private/sdl_gpu_test/gui/button.hpp
Normal file
@ -0,0 +1,68 @@
|
|||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_GUI_BUTTON_HPP_INCLUDED)
|
||||||
|
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_GUI_BUTTON_HPP_INCLUDED 1
|
||||||
|
|
||||||
|
#include <glm/vec4.hpp>
|
||||||
|
|
||||||
|
#include "./widget.hpp"
|
||||||
|
|
||||||
|
namespace sdl_gpu_test
|
||||||
|
{
|
||||||
|
struct ButtonCreateArgs
|
||||||
|
{
|
||||||
|
std::string text;
|
||||||
|
glm::vec4 textColor = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
glm::vec4 backgroundColor = {1.f, 0.f, 0.f, 1.f};
|
||||||
|
int posX = 0;
|
||||||
|
int posY = 0;
|
||||||
|
int width = 256;
|
||||||
|
int height = 84;
|
||||||
|
};
|
||||||
|
|
||||||
|
class Button : public Widget
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
using create_args_t = ButtonCreateArgs;
|
||||||
|
private:
|
||||||
|
std::string mText;
|
||||||
|
glm::vec4 mTextColor = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
glm::vec4 mBackgroundColor = {1.f, 1.f, 1.f, 1.f};
|
||||||
|
int mPosX = 0;
|
||||||
|
int mPosY = 0;
|
||||||
|
int mWidth = 0;
|
||||||
|
int mHeight = 0;
|
||||||
|
UIRenderer::primitive_id_t mPrimitiveID = UIRenderer::UNSET_PRIMITIVE_ID;
|
||||||
|
public:
|
||||||
|
explicit Button(ButtonCreateArgs args);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const std::string& getText() const noexcept { return mText; }
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const glm::vec4& getTextColor() const noexcept { return mTextColor; }
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
const glm::vec4& getBackgroundTextColor() const noexcept { return mBackgroundColor; }
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int getPosX() const noexcept { return mPosX; }
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
int getPosY() const noexcept { return mPosY; }
|
||||||
|
|
||||||
|
void setText(std::string text);
|
||||||
|
void setTextColor(const glm::vec4& color);
|
||||||
|
void setBackgroundColor(const glm::vec4& color);
|
||||||
|
void setPosX(int posX);
|
||||||
|
void setPosY(int posY);
|
||||||
|
|
||||||
|
void handleEnteredTree() override;
|
||||||
|
void revalidate() override;
|
||||||
|
private:
|
||||||
|
void update();
|
||||||
|
};
|
||||||
|
} // namespace sdl_gpu_test
|
||||||
|
|
||||||
|
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_GUI_BUTTON_HPP_INCLUDED)
|
@ -3,6 +3,8 @@
|
|||||||
|
|
||||||
#include <mijin/util/string.hpp>
|
#include <mijin/util/string.hpp>
|
||||||
|
|
||||||
|
#include "../util/spdlog_wrapper.hpp"
|
||||||
|
|
||||||
namespace sdl_gpu_test::inline app6
|
namespace sdl_gpu_test::inline app6
|
||||||
{
|
{
|
||||||
namespace
|
namespace
|
||||||
@ -151,6 +153,69 @@ void UIRenderer::render(const UIRendererRenderArgs& args)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::pair<unsigned, unsigned> UIRenderer::measureText(const MeasureTextArgs& args) const
|
||||||
|
{
|
||||||
|
unsigned width = 0;
|
||||||
|
unsigned height = mFontMap.lineHeight;
|
||||||
|
unsigned lineWidth = 0;
|
||||||
|
|
||||||
|
for (std::size_t pos = 0; pos < args.text.size(); ++pos)
|
||||||
|
{
|
||||||
|
char chr = args.text[pos];
|
||||||
|
switch (chr)
|
||||||
|
{
|
||||||
|
case '\n':
|
||||||
|
width = std::max(lineWidth, width);
|
||||||
|
lineWidth = 0;
|
||||||
|
height += mFontMap.lineHeight;
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
++pos;
|
||||||
|
if (pos >= args.text.size())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chr = args.text[pos];
|
||||||
|
switch (chr)
|
||||||
|
{
|
||||||
|
case 'r':
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
if (pos < args.text.size() - 2
|
||||||
|
&& mijin::isHexadecimalChar(chr)
|
||||||
|
&& mijin::isHexadecimalChar(args.text[pos + 1])
|
||||||
|
&& mijin::isHexadecimalChar(args.text[pos + 2]))
|
||||||
|
{
|
||||||
|
pos += 2;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// what?
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case '\\':
|
||||||
|
++pos;
|
||||||
|
if (pos >= args.text.size())
|
||||||
|
{
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
chr = args.text[pos];
|
||||||
|
[[fallthrough]];
|
||||||
|
default:
|
||||||
|
{
|
||||||
|
const UVFontMapEntry& entry = mFontMap.entries[chr < 0 ? '_' : chr]; // TODO: more chars
|
||||||
|
lineWidth += entry.xAdvance;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return {std::max(width, lineWidth), height};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void UIRenderer::drawText(const DrawTextArgs& args, primitive_id_t* outPrimitiveId)
|
void UIRenderer::drawText(const DrawTextArgs& args, primitive_id_t* outPrimitiveId)
|
||||||
{
|
{
|
||||||
glm::vec4 color = args.color;
|
glm::vec4 color = args.color;
|
||||||
@ -169,7 +234,7 @@ void UIRenderer::drawText(const DrawTextArgs& args, primitive_id_t* outPrimitive
|
|||||||
{
|
{
|
||||||
case '\n':
|
case '\n':
|
||||||
posX = args.x;
|
posX = args.x;
|
||||||
posY += mFontMap.lineHeight;
|
posY += static_cast<int>(mFontMap.lineHeight);
|
||||||
break;
|
break;
|
||||||
case '$':
|
case '$':
|
||||||
++pos;
|
++pos;
|
||||||
@ -215,17 +280,28 @@ void UIRenderer::drawText(const DrawTextArgs& args, primitive_id_t* outPrimitive
|
|||||||
chr = args.text[pos];
|
chr = args.text[pos];
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
default:
|
default:
|
||||||
posX += drawChar({
|
posX += static_cast<int>(drawChar({
|
||||||
.x = posX,
|
.x = posX,
|
||||||
.y = posY,
|
.y = posY,
|
||||||
.chr = chr,
|
.chr = chr,
|
||||||
.color = color
|
.color = color
|
||||||
}, outPrimitiveId);
|
}, outPrimitiveId));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIRenderer::drawTextCentered(DrawTextArgs args, primitive_id_t* outPrimitiveId)
|
||||||
|
{
|
||||||
|
const auto [width, height] = measureText({
|
||||||
|
.text = args.text
|
||||||
|
});
|
||||||
|
args.x -= static_cast<int>(width / 2);
|
||||||
|
args.y -= static_cast<int>(height + mFontMap.lineHeight - mFontMap.base) / 2;
|
||||||
|
drawText(args, outPrimitiveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
unsigned UIRenderer::drawChar(const DrawCharArgs& args, primitive_id_t* outPrimitiveId)
|
unsigned UIRenderer::drawChar(const DrawCharArgs& args, primitive_id_t* outPrimitiveId)
|
||||||
{
|
{
|
||||||
if (outPrimitiveId != nullptr && *outPrimitiveId == UNSET_PRIMITIVE_ID)
|
if (outPrimitiveId != nullptr && *outPrimitiveId == UNSET_PRIMITIVE_ID)
|
||||||
@ -246,6 +322,31 @@ unsigned UIRenderer::drawChar(const DrawCharArgs& args, primitive_id_t* outPrimi
|
|||||||
return entry.xAdvance;
|
return entry.xAdvance;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void UIRenderer::drawQuad(const DrawQuadArgs& args, primitive_id_t* outPrimitiveId)
|
||||||
|
{
|
||||||
|
auto itEntry = mTextureAtlas.entries.find(args.texture);
|
||||||
|
if (itEntry == mTextureAtlas.entries.end())
|
||||||
|
{
|
||||||
|
spdlog::warn("Attempt to draw quad with unknown texture: {}.", args.texture);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const UVTextureAtlasEntry& entry = itEntry->second;
|
||||||
|
|
||||||
|
if (outPrimitiveId != nullptr && *outPrimitiveId == UNSET_PRIMITIVE_ID)
|
||||||
|
{
|
||||||
|
*outPrimitiveId = mNextOwner++;
|
||||||
|
}
|
||||||
|
|
||||||
|
drawQuadInternal({
|
||||||
|
.topLeft = {args.x, args.y},
|
||||||
|
.bottomRight = {args.x + args.width, args.y + args.height},
|
||||||
|
.uvTopLeft = {entry.uvX, entry.uvY},
|
||||||
|
.uvBottomRight = {entry.uvX + entry.uvWidth, entry.uvY + entry.uvHeight},
|
||||||
|
.color = args.color
|
||||||
|
}, outPrimitiveId == nullptr ? UNSET_PRIMITIVE_ID : *outPrimitiveId);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool UIRenderer::removePrimitive(primitive_id_t primitiveId)
|
bool UIRenderer::removePrimitive(primitive_id_t primitiveId)
|
||||||
{
|
{
|
||||||
bool didRemove = false;
|
bool didRemove = false;
|
||||||
@ -254,7 +355,8 @@ bool UIRenderer::removePrimitive(primitive_id_t primitiveId)
|
|||||||
if (mTriangleOwners[triangleIdx] == primitiveId)
|
if (mTriangleOwners[triangleIdx] == primitiveId)
|
||||||
{
|
{
|
||||||
mTriangleOwners.erase(mTriangleOwners.begin() + triangleIdx);
|
mTriangleOwners.erase(mTriangleOwners.begin() + triangleIdx);
|
||||||
mVertices.erase(mVertices.begin() + 3 * triangleIdx, mVertices.begin() + 3 * (triangleIdx + 1));
|
mVertices.erase(mVertices.begin() + static_cast<std::ptrdiff_t>(3) * triangleIdx,
|
||||||
|
mVertices.begin() + static_cast<std::ptrdiff_t>(3) * (triangleIdx + 1));
|
||||||
didRemove = true;
|
didRemove = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -294,11 +396,11 @@ void UIRenderer::drawQuadInternal(const DrawQuadInternalArgs& args, primitive_id
|
|||||||
mVerticesDirty = true;
|
mVerticesDirty = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UIRenderer::addTriangleInternal(const UIVertex& v0, const UIVertex& v1, const UIVertex& v2, UIRenderer::primitive_id_t primitiveId)
|
void UIRenderer::addTriangleInternal(const UIVertex& vtx0, const UIVertex& vtx1, const UIVertex& vtx2, primitive_id_t primitiveId)
|
||||||
{
|
{
|
||||||
mVertices.push_back(v0);
|
mVertices.push_back(vtx0);
|
||||||
mVertices.push_back(v1);
|
mVertices.push_back(vtx1);
|
||||||
mVertices.push_back(v2);
|
mVertices.push_back(vtx2);
|
||||||
mTriangleOwners.push_back(primitiveId);
|
mTriangleOwners.push_back(primitiveId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -20,6 +20,11 @@ struct UIVertex
|
|||||||
glm::vec4 color = glm::vec4(1.f);
|
glm::vec4 color = glm::vec4(1.f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MeasureTextArgs
|
||||||
|
{
|
||||||
|
std::string_view text;
|
||||||
|
};
|
||||||
|
|
||||||
struct DrawTextArgs
|
struct DrawTextArgs
|
||||||
{
|
{
|
||||||
int x = 0;
|
int x = 0;
|
||||||
@ -36,6 +41,16 @@ struct DrawCharArgs
|
|||||||
glm::vec4 color = glm::vec4(1.f);
|
glm::vec4 color = glm::vec4(1.f);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct DrawQuadArgs
|
||||||
|
{
|
||||||
|
std::string texture;
|
||||||
|
int x = 0;
|
||||||
|
int y = 0;
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
glm::vec4 color = glm::vec4(1.f);
|
||||||
|
};
|
||||||
|
|
||||||
struct UIRendererRenderArgs
|
struct UIRendererRenderArgs
|
||||||
{
|
{
|
||||||
const sdlpp::GPUCommandBuffer* cmdBuffer;
|
const sdlpp::GPUCommandBuffer* cmdBuffer;
|
||||||
@ -67,8 +82,12 @@ public:
|
|||||||
void init(Application& application);
|
void init(Application& application);
|
||||||
void render(const UIRendererRenderArgs& args);
|
void render(const UIRendererRenderArgs& args);
|
||||||
|
|
||||||
|
[[nodiscard]]
|
||||||
|
std::pair<unsigned, unsigned> measureText(const MeasureTextArgs& args) const;
|
||||||
void drawText(const DrawTextArgs& args, primitive_id_t* outPrimitiveId = nullptr);
|
void drawText(const DrawTextArgs& args, primitive_id_t* outPrimitiveId = nullptr);
|
||||||
|
void drawTextCentered(DrawTextArgs args, primitive_id_t* outPrimitiveId = nullptr);
|
||||||
unsigned drawChar(const DrawCharArgs& args, primitive_id_t* outPrimitiveId = nullptr);
|
unsigned drawChar(const DrawCharArgs& args, primitive_id_t* outPrimitiveId = nullptr);
|
||||||
|
void drawQuad(const DrawQuadArgs& args, primitive_id_t* outPrimitiveId = nullptr);
|
||||||
bool removePrimitive(primitive_id_t primitiveId);
|
bool removePrimitive(primitive_id_t primitiveId);
|
||||||
private:
|
private:
|
||||||
struct DrawQuadInternalArgs
|
struct DrawQuadInternalArgs
|
||||||
@ -80,7 +99,7 @@ private:
|
|||||||
glm::vec4 color = glm::vec4(1.f);
|
glm::vec4 color = glm::vec4(1.f);
|
||||||
};
|
};
|
||||||
void drawQuadInternal(const DrawQuadInternalArgs& args, primitive_id_t primitiveId);
|
void drawQuadInternal(const DrawQuadInternalArgs& args, primitive_id_t primitiveId);
|
||||||
void addTriangleInternal(const UIVertex& v0, const UIVertex& v1, const UIVertex& v2, primitive_id_t primitiveId);
|
void addTriangleInternal(const UIVertex& vtx0, const UIVertex& vtx1, const UIVertex& vtx2, primitive_id_t primitiveId);
|
||||||
void uploadVertices();
|
void uploadVertices();
|
||||||
};
|
};
|
||||||
} // namespace sdl_gpu_test::inline app6
|
} // namespace sdl_gpu_test::inline app6
|
||||||
|
Loading…
x
Reference in New Issue
Block a user