diff --git a/assets/shaders/glsl/ui.frag b/assets/shaders/glsl/ui.frag new file mode 100644 index 0000000..9938c76 --- /dev/null +++ b/assets/shaders/glsl/ui.frag @@ -0,0 +1,24 @@ +#version 460 + +layout(set = 2, binding = 0) +uniform sampler2D u_texture; + +layout(set = 3, binding = 0) +uniform Parameters +{ + vec4 u_color; +}; + +layout(location = 0) +in vec2 i_texCoord; + +layout(location = 1) +in vec4 i_color; + +layout(location = 0) +out vec4 o_color; + +void main() +{ + o_color = texture(u_texture, i_texCoord) * i_color * u_color; +} diff --git a/assets/shaders/glsl/ui.vert b/assets/shaders/glsl/ui.vert index 805cb7c..013abd8 100644 --- a/assets/shaders/glsl/ui.vert +++ b/assets/shaders/glsl/ui.vert @@ -12,13 +12,20 @@ in vec2 i_position; layout(location = 1) in vec2 i_texCoord; +layout(location = 2) +in vec4 i_color; + layout(location = 0) out vec2 o_texCoord; +layout(location = 1) +out vec4 o_color; + void main() { vec2 relativePos = 2.0 * (i_position / u_windowSize) - vec2(1.0); relativePos.y *= -1.0; gl_Position = vec4(relativePos, 0.0, 1.0); o_texCoord = i_texCoord; + o_color = i_color; } diff --git a/private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp b/private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp index ee3a4bb..3316a81 100644 --- a/private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp +++ b/private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp @@ -1,8 +1,6 @@ #include "./ui_renderer.hpp" -#include - namespace sdl_gpu_test::inline app6 { namespace @@ -25,7 +23,7 @@ void UIRenderer::init(Application& application) .stage = sdlpp::GPUShaderStage::VERTEX, .numUniformBuffers = 1 }); - const sdlpp::GPUShader fragmentShader = application.loadShader("shaders/glsl/color_from_texture.frag.spv", { + const sdlpp::GPUShader fragmentShader = application.loadShader("shaders/glsl/ui.frag.spv", { .format = sdlpp::GPUShaderFormat::SPIRV, .stage = sdlpp::GPUShaderStage::FRAGMENT, .numSamplers = 1, @@ -64,6 +62,12 @@ void UIRenderer::init(Application& application) .bindingIndex = 0, .format = sdlpp::GPUVertexElementFormat::FLOAT2, .offset = offsetof(UIVertex, texcoord) + }, + sdlpp::GPUVertexAttribute{ + .location = 2, + .bindingIndex = 0, + .format = sdlpp::GPUVertexElementFormat::FLOAT4, + .offset = offsetof(UIVertex, color) } }; mUIPipeline.create(device, { @@ -78,45 +82,20 @@ void UIRenderer::init(Application& application) } }); - + // load the font map for rendering text const FontMap fontMap = loadFontMap(application.getFileSystem().getPath("fonts/symtext.fnt")); - const UVFontMap uvFontMap = makeUVFontMap({ + mFontMap = makeUVFontMap({ .original = &fontMap, .textureWidth = 256, .textureHeight = 256 }); - unsigned posX = 100; - const unsigned posY = 100; - for (const char chr : std::string_view("Dies ist ein Test-Text!")) - { - const UVFontMapEntry& entry = uvFontMap.entries[chr < 0 ? '_' : chr]; - const UIVertex topLeft = { - .pos = {posX + entry.xOffset, posY + entry.yOffset}, - .texcoord = {entry.uvX, entry.uvY} - }; - const UIVertex bottomRight = { - .pos = {topLeft.pos.x + static_cast(entry.width), topLeft.pos.y + static_cast(entry.height)}, - .texcoord = {entry.uvX + entry.uvWidth, entry.uvY + entry.uvHeight} - }; - const UIVertex bottomLeft = { - .pos = {topLeft.pos.x, bottomRight.pos.y}, - .texcoord = {topLeft.texcoord.x, bottomRight.texcoord.y} - }; - const UIVertex topRight = { - .pos = {bottomRight.pos.x, topLeft.pos.y}, - .texcoord = {bottomRight.texcoord.x, topLeft.texcoord.y} - }; - - mUIVertices.push_back(topLeft); - mUIVertices.push_back(bottomLeft); - mUIVertices.push_back(topRight); - mUIVertices.push_back(bottomRight); - mUIVertices.push_back(topRight); - mUIVertices.push_back(bottomLeft); - - posX += entry.xAdvance; - } + // render some test text + drawText({ + .x = 100, + .y = 100, + .text = "Test-Text!\nSecond line?" + }); // create UI vertex buffer mUIVertexBuffer.create(device, { @@ -164,4 +143,67 @@ void UIRenderer::render(const UIRendererRenderArgs& args) } } +void UIRenderer::drawText(const DrawTextArgs& args) +{ + unsigned posX = args.x; + unsigned posY = args.y; + for (const char chr : args.text) + { + switch (chr) + { + case '\n': + posX = args.x; + posY += mFontMap.lineHeight; + break; + default: + posX += drawChar({ + .x = posX, + .y = posY, + .chr = chr + }); + break; + } + } +} + +unsigned UIRenderer::drawChar(const DrawCharArgs& args) +{ + const UVFontMapEntry& entry = mFontMap.entries[args.chr < 0 ? '_' : args.chr]; // TODO: more chars + const glm::vec2 topLeft = {args.x + entry.xOffset, args.y + entry.yOffset}; + drawQuadInternal({ + .topLeft = topLeft, + .bottomRight = {topLeft.x + static_cast(entry.width), topLeft.y + static_cast(entry.height)}, + .uvTopLeft = {entry.uvX, entry.uvY}, + .uvBottomRight = {entry.uvX + entry.uvWidth, entry.uvY + entry.uvHeight} + }); + + return entry.xAdvance; +} + +void UIRenderer::drawQuadInternal(const DrawQuadInternalArgs& args) +{ + const UIVertex topLeft = { + .pos = args.topLeft, + .texcoord = args.uvTopLeft + }; + const UIVertex bottomRight = { + .pos = args.bottomRight, + .texcoord = args.uvBottomRight + }; + const UIVertex bottomLeft = { + .pos = {topLeft.pos.x, bottomRight.pos.y}, + .texcoord = {topLeft.texcoord.x, bottomRight.texcoord.y} + }; + const UIVertex topRight = { + .pos = {bottomRight.pos.x, topLeft.pos.y}, + .texcoord = {bottomRight.texcoord.x, topLeft.texcoord.y} + }; + + mUIVertices.push_back(topLeft); + mUIVertices.push_back(bottomLeft); + mUIVertices.push_back(topRight); + mUIVertices.push_back(bottomRight); + mUIVertices.push_back(topRight); + mUIVertices.push_back(bottomLeft); +} } diff --git a/private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp b/private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp index d304b8f..57a2458 100644 --- a/private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp +++ b/private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp @@ -5,6 +5,7 @@ #define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_UI_UI_RENDERER_HPP_INCLUDED 1 #include +#include #include "../../application.hpp" #include "../../sdlpp/gpu.hpp" #include "../../util/font_map.hpp" @@ -15,6 +16,21 @@ struct UIVertex { glm::vec2 pos; glm::vec2 texcoord; + glm::vec4 color = glm::vec4(1.f); +}; + +struct DrawTextArgs +{ + unsigned x = 0; + unsigned y = 0; + std::string_view text; +}; + +struct DrawCharArgs +{ + unsigned x = 0; + unsigned y = 0; + char chr; }; struct UIRendererRenderArgs @@ -38,6 +54,18 @@ private: public: void init(Application& application); void render(const UIRendererRenderArgs& args); + + void drawText(const DrawTextArgs& args); + unsigned drawChar(const DrawCharArgs& args); +private: + struct DrawQuadInternalArgs + { + glm::vec2 topLeft; + glm::vec2 bottomRight; + glm::vec2 uvTopLeft; + glm::vec2 uvBottomRight; + }; + void drawQuadInternal(const DrawQuadInternalArgs& args); }; } // namespace sdl_gpu_test::inline app6