Moved UI rendering to a separate class/file.
This commit is contained in:
parent
773d86ffd3
commit
0168ade08c
@ -9,9 +9,7 @@
|
||||
|
||||
#include "../sdlpp/keyboard.hpp"
|
||||
#include "../util/bitmap.hpp"
|
||||
#include "../util/font_map.hpp"
|
||||
#include "../util/mesh.hpp"
|
||||
#include "../util/texture_atlas.hpp"
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
@ -26,11 +24,6 @@ struct VertexShaderParameters
|
||||
glm::mat4 worldToView;
|
||||
glm::mat4 viewToClip;
|
||||
};
|
||||
|
||||
struct UIVertexShaderParameters
|
||||
{
|
||||
glm::vec2 windowSize;
|
||||
};
|
||||
}
|
||||
|
||||
void UIApp::init(const AppInitArgs& args)
|
||||
@ -49,7 +42,7 @@ void UIApp::init(const AppInitArgs& args)
|
||||
createMeshPipeline();
|
||||
|
||||
// create UI pipeline
|
||||
createUIPipeline();
|
||||
mUIRenderer.init(*this);
|
||||
|
||||
// load the mesh
|
||||
const Mesh mesh = loadMesh(mFileSystem.getPath("meshes/cube.obj"));
|
||||
@ -70,57 +63,6 @@ void UIApp::init(const AppInitArgs& args)
|
||||
mTexture = loadTexture("bitmaps/cube.png", textureArgs);
|
||||
mSampler.create(mDevice, {});
|
||||
|
||||
const FontMap fontMap = loadFontMap(mFileSystem.getPath("fonts/symtext.fnt"));
|
||||
const UVFontMap uvFontMap = 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<float>(entry.width), topLeft.pos.y + static_cast<float>(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;
|
||||
}
|
||||
|
||||
// create UI vertex buffer
|
||||
mUIVertexBuffer.create(mDevice, {
|
||||
.usage = {.vertex = true},
|
||||
.size = static_cast<Uint32>(mUIVertices.size() * sizeof(UIVertex))
|
||||
});
|
||||
uploadVertexData(mUIVertexBuffer, std::span(mUIVertices));
|
||||
|
||||
// and UI texture
|
||||
mUITexture = loadTexture("bitmaps/ui.png", textureArgs);
|
||||
|
||||
mUISampler.create(mDevice, {});
|
||||
|
||||
// open gamepad
|
||||
const std::vector<SDL_JoystickID> gamepads = sdlpp::getGamepads();
|
||||
if (!gamepads.empty())
|
||||
@ -188,25 +130,12 @@ void UIApp::update(const AppUpdateArgs& args)
|
||||
renderPass.end();
|
||||
|
||||
// render the "UI"
|
||||
if (!mUIVertices.empty())
|
||||
{
|
||||
const UIVertexShaderParameters uiVertexShaderParameters = {
|
||||
.windowSize = {
|
||||
static_cast<float>(swapchainWidth), static_cast<float>(swapchainHeight)
|
||||
}
|
||||
};
|
||||
colorTargets[0].loadOp = sdlpp::GPULoadOp::LOAD; // don't clear again
|
||||
renderPass = cmdBuffer.beginRenderPass({
|
||||
.colorTargetInfos = colorTargets
|
||||
mUIRenderer.render({
|
||||
.cmdBuffer = &cmdBuffer,
|
||||
.targetTexture = &swapchainTexture,
|
||||
.targetTextureWidth = swapchainWidth,
|
||||
.targetTextureHeight = swapchainHeight
|
||||
});
|
||||
cmdBuffer.pushFragmentUniformData(0, std::span(&WHITE, 1));
|
||||
cmdBuffer.pushVertexUniformData(0, std::span(&uiVertexShaderParameters, 1));
|
||||
renderPass.bindFragmentSampler({.texture = mUITexture, .sampler = mUISampler});
|
||||
renderPass.bindGraphicsPipeline(mUIPipeline);
|
||||
renderPass.bindVertexBuffer({.buffer = mUIVertexBuffer});
|
||||
renderPass.drawPrimitives({.numVertices = static_cast<Uint32>(mUIVertices.size())});
|
||||
renderPass.end();
|
||||
}
|
||||
|
||||
// finalize
|
||||
cmdBuffer.submit();
|
||||
@ -300,67 +229,6 @@ void UIApp::createMeshPipeline()
|
||||
});
|
||||
}
|
||||
|
||||
void UIApp::createUIPipeline()
|
||||
{
|
||||
// create shaders
|
||||
const sdlpp::GPUShader vertexShader = loadShader("shaders/glsl/ui.vert.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::VERTEX,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
const sdlpp::GPUShader fragmentShader = loadShader("shaders/glsl/color_from_texture.frag.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::FRAGMENT,
|
||||
.numSamplers = 1,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
std::array colorTargetsDescs = {
|
||||
sdlpp::GPUColorTargetDescription{
|
||||
.format = mDevice.getSwapchainTextureFormat(mWindow),
|
||||
.blendState = {
|
||||
.enableBlend = true,
|
||||
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
||||
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
|
||||
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
|
||||
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
|
||||
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
|
||||
}
|
||||
}
|
||||
};
|
||||
std::array vertexBindings = {
|
||||
sdlpp::GPUVertexBinding{
|
||||
.index = 0,
|
||||
.pitch = sizeof(UIVertex)
|
||||
}
|
||||
};
|
||||
std::array vertexAttributes = {
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 0,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||
.offset = offsetof(UIVertex, pos)
|
||||
},
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 1,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||
.offset = offsetof(UIVertex, texcoord)
|
||||
}
|
||||
};
|
||||
mUIPipeline.create(mDevice, {
|
||||
.vertexShader = vertexShader,
|
||||
.fragmentShader = fragmentShader,
|
||||
.vertexInputState = {
|
||||
.vertexBindings = vertexBindings,
|
||||
.vertexAttributes = vertexAttributes
|
||||
},
|
||||
.targetInfo = {
|
||||
.colorTargetDescriptions = colorTargetsDescs
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void UIApp::processInput(const AppUpdateArgs& args)
|
||||
{
|
||||
const std::span<const SDL_bool> keystates = sdlpp::getKeyboardState();
|
||||
|
@ -6,17 +6,12 @@
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
|
||||
#include "./ui/ui_renderer.hpp"
|
||||
#include "../application.hpp"
|
||||
#include "../sdlpp/gamepad.hpp"
|
||||
|
||||
namespace sdl_gpu_test
|
||||
{
|
||||
struct UIVertex
|
||||
{
|
||||
glm::vec2 pos;
|
||||
glm::vec2 texcoord;
|
||||
};
|
||||
|
||||
class UIApp : public Application
|
||||
{
|
||||
private:
|
||||
@ -26,11 +21,7 @@ private:
|
||||
sdlpp::GPUTexture mTexture;
|
||||
sdlpp::GPUSampler mSampler;
|
||||
|
||||
sdlpp::GPUBuffer mUIVertexBuffer;
|
||||
sdlpp::GPUGraphicsPipeline mUIPipeline;
|
||||
std::vector<UIVertex> mUIVertices;
|
||||
sdlpp::GPUTexture mUITexture;
|
||||
sdlpp::GPUSampler mUISampler;
|
||||
UIRenderer mUIRenderer;
|
||||
|
||||
sdlpp::Gamepad mGamepad;
|
||||
Uint32 mNumVertices = 0;
|
||||
@ -45,7 +36,6 @@ public:
|
||||
void handleMouseMotionEvent(const sdlpp::MouseMotionEvent& event) override;
|
||||
private:
|
||||
void createMeshPipeline();
|
||||
void createUIPipeline();
|
||||
void processInput(const AppUpdateArgs& args);
|
||||
};
|
||||
} // namespace sdl_gpu_test
|
||||
|
167
private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp
Normal file
167
private/sdl_gpu_test/6_ui/ui/ui_renderer.cpp
Normal file
@ -0,0 +1,167 @@
|
||||
|
||||
#include "./ui_renderer.hpp"
|
||||
|
||||
#include <glm/vec4.hpp>
|
||||
|
||||
namespace sdl_gpu_test::inline app6
|
||||
{
|
||||
namespace
|
||||
{
|
||||
struct UIVertexShaderParameters
|
||||
{
|
||||
glm::vec2 windowSize;
|
||||
};
|
||||
}
|
||||
|
||||
void UIRenderer::init(Application& application)
|
||||
{
|
||||
// for convenience
|
||||
mApplication = &application;
|
||||
const sdlpp::GPUDevice& device = application.getDevice();
|
||||
|
||||
// create shaders
|
||||
const sdlpp::GPUShader vertexShader = application.loadShader("shaders/glsl/ui.vert.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::VERTEX,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
const sdlpp::GPUShader fragmentShader = application.loadShader("shaders/glsl/color_from_texture.frag.spv", {
|
||||
.format = sdlpp::GPUShaderFormat::SPIRV,
|
||||
.stage = sdlpp::GPUShaderStage::FRAGMENT,
|
||||
.numSamplers = 1,
|
||||
.numUniformBuffers = 1
|
||||
});
|
||||
|
||||
std::array colorTargetsDescs = {
|
||||
sdlpp::GPUColorTargetDescription{
|
||||
.format = device.getSwapchainTextureFormat(application.getWindow()),
|
||||
.blendState = {
|
||||
.enableBlend = true,
|
||||
.srcColorBlendfactor = sdlpp::GPUBlendFactor::SRC_ALPHA,
|
||||
.dstColorBlendfactor = sdlpp::GPUBlendFactor::ONE_MINUS_SRC_ALPHA,
|
||||
.colorBlendOp = sdlpp::GPUBlendOp::ADD,
|
||||
.srcAlphaBlendfactor = sdlpp::GPUBlendFactor::ONE,
|
||||
.dstAlphaBlendfactor = sdlpp::GPUBlendFactor::ZERO,
|
||||
.alphaBlendOp = sdlpp::GPUBlendOp::ADD
|
||||
}
|
||||
}
|
||||
};
|
||||
std::array vertexBindings = {
|
||||
sdlpp::GPUVertexBinding{
|
||||
.index = 0,
|
||||
.pitch = sizeof(UIVertex)
|
||||
}
|
||||
};
|
||||
std::array vertexAttributes = {
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 0,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||
.offset = offsetof(UIVertex, pos)
|
||||
},
|
||||
sdlpp::GPUVertexAttribute{
|
||||
.location = 1,
|
||||
.bindingIndex = 0,
|
||||
.format = sdlpp::GPUVertexElementFormat::FLOAT2,
|
||||
.offset = offsetof(UIVertex, texcoord)
|
||||
}
|
||||
};
|
||||
mUIPipeline.create(device, {
|
||||
.vertexShader = vertexShader,
|
||||
.fragmentShader = fragmentShader,
|
||||
.vertexInputState = {
|
||||
.vertexBindings = vertexBindings,
|
||||
.vertexAttributes = vertexAttributes
|
||||
},
|
||||
.targetInfo = {
|
||||
.colorTargetDescriptions = colorTargetsDescs
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
const FontMap fontMap = loadFontMap(application.getFileSystem().getPath("fonts/symtext.fnt"));
|
||||
const UVFontMap uvFontMap = 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<float>(entry.width), topLeft.pos.y + static_cast<float>(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;
|
||||
}
|
||||
|
||||
// create UI vertex buffer
|
||||
mUIVertexBuffer.create(device, {
|
||||
.usage = {.vertex = true},
|
||||
.size = static_cast<Uint32>(mUIVertices.size() * sizeof(UIVertex))
|
||||
});
|
||||
application.uploadVertexData(mUIVertexBuffer, std::span(mUIVertices));
|
||||
|
||||
// create texture and sampler
|
||||
sdlpp::GPUTextureCreateArgs textureArgs = {
|
||||
.format = sdlpp::GPUTextureFormat::R8G8B8A8_UNORM_SRGB,
|
||||
.usage = {.sampler = true}
|
||||
};
|
||||
mUITexture = application.loadTexture("bitmaps/ui.png", textureArgs);
|
||||
|
||||
mUISampler.create(device, {});
|
||||
}
|
||||
|
||||
void UIRenderer::render(const UIRendererRenderArgs& args)
|
||||
{
|
||||
if (!mUIVertices.empty())
|
||||
{
|
||||
const UIVertexShaderParameters uiVertexShaderParameters = {
|
||||
.windowSize = {
|
||||
static_cast<float>(args.targetTextureWidth), static_cast<float>(args.targetTextureHeight)
|
||||
}
|
||||
};
|
||||
std::array colorTargets = {sdlpp::GPUColorTargetInfo{
|
||||
.texture = *args.targetTexture,
|
||||
.clearColor = {.r = 0.f, .g = 0.f, .b = 0.f, .a = 1.f},
|
||||
.loadOp = sdlpp::GPULoadOp::LOAD,
|
||||
}};
|
||||
colorTargets[0].loadOp = sdlpp::GPULoadOp::LOAD; // don't clear again
|
||||
sdlpp::GPURenderPass renderPass = args.cmdBuffer->beginRenderPass({
|
||||
.colorTargetInfos = colorTargets
|
||||
});
|
||||
static const glm::vec4 WHITE(1.f, 1.f, 1.f, 1.f);
|
||||
args.cmdBuffer->pushFragmentUniformData(0, std::span(&WHITE, 1));
|
||||
args.cmdBuffer->pushVertexUniformData(0, std::span(&uiVertexShaderParameters, 1));
|
||||
renderPass.bindFragmentSampler({.texture = mUITexture, .sampler = mUISampler});
|
||||
renderPass.bindGraphicsPipeline(mUIPipeline);
|
||||
renderPass.bindVertexBuffer({.buffer = mUIVertexBuffer});
|
||||
renderPass.drawPrimitives({.numVertices = static_cast<Uint32>(mUIVertices.size())});
|
||||
renderPass.end();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
44
private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp
Normal file
44
private/sdl_gpu_test/6_ui/ui/ui_renderer.hpp
Normal file
@ -0,0 +1,44 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#if !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_UI_UI_RENDERER_HPP_INCLUDED)
|
||||
#define SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_UI_UI_RENDERER_HPP_INCLUDED 1
|
||||
|
||||
#include <glm/vec2.hpp>
|
||||
#include "../../application.hpp"
|
||||
#include "../../sdlpp/gpu.hpp"
|
||||
#include "../../util/font_map.hpp"
|
||||
|
||||
namespace sdl_gpu_test::inline app6
|
||||
{
|
||||
struct UIVertex
|
||||
{
|
||||
glm::vec2 pos;
|
||||
glm::vec2 texcoord;
|
||||
};
|
||||
|
||||
struct UIRendererRenderArgs
|
||||
{
|
||||
const sdlpp::GPUCommandBuffer* cmdBuffer;
|
||||
const sdlpp::GPUTexture* targetTexture;
|
||||
unsigned targetTextureWidth;
|
||||
unsigned targetTextureHeight;
|
||||
};
|
||||
|
||||
class UIRenderer
|
||||
{
|
||||
private:
|
||||
Application* mApplication = nullptr;
|
||||
sdlpp::GPUBuffer mUIVertexBuffer;
|
||||
sdlpp::GPUGraphicsPipeline mUIPipeline;
|
||||
std::vector<UIVertex> mUIVertices;
|
||||
sdlpp::GPUTexture mUITexture;
|
||||
sdlpp::GPUSampler mUISampler;
|
||||
UVFontMap mFontMap;
|
||||
public:
|
||||
void init(Application& application);
|
||||
void render(const UIRendererRenderArgs& args);
|
||||
};
|
||||
} // namespace sdl_gpu_test::inline app6
|
||||
|
||||
#endif // !defined(SDL_GPU_TEST_PRIVATE_SDL_GPU_TEST_6_UI_UI_UI_RENDERER_HPP_INCLUDED)
|
@ -16,6 +16,7 @@ src_files = Split("""
|
||||
4_textured_cube/app.cpp
|
||||
5_input/app.cpp
|
||||
6_ui/app.cpp
|
||||
6_ui/ui/ui_renderer.cpp
|
||||
""")
|
||||
|
||||
shader_files = env.Glob("#assets/shaders/glsl/*.frag") \
|
||||
|
@ -40,6 +40,15 @@ protected:
|
||||
public:
|
||||
virtual ~Application() noexcept = default;
|
||||
|
||||
[[nodiscard]]
|
||||
const sdlpp::Window& getWindow() const noexcept { return mWindow; }
|
||||
|
||||
[[nodiscard]]
|
||||
const sdlpp::GPUDevice& getDevice() const noexcept { return mDevice; }
|
||||
|
||||
[[nodiscard]]
|
||||
mijin::StackedFileSystemAdapter& getFileSystem() noexcept { return mFileSystem; }
|
||||
|
||||
virtual void init(const AppInitArgs& args);
|
||||
virtual void cleanup(const AppCleanupArgs& args);
|
||||
virtual void update(const AppUpdateArgs& args);
|
||||
|
Loading…
x
Reference in New Issue
Block a user