Begin full text rendering support

This commit is contained in:
Bailey Harrison 2023-05-15 00:27:31 +01:00
parent f9099e9ddf
commit 5ddcb90ad2
14 changed files with 284 additions and 338 deletions

View File

@ -26,9 +26,7 @@ set(SRC_FILES
"src/scene_manager.cpp" "src/scene_manager.cpp"
"src/systems/collisions.cpp" "src/systems/collisions.cpp"
"src/systems/render.cpp" "src/systems/render.cpp"
"src/systems/render2d.cpp"
"src/systems/transform.cpp" "src/systems/transform.cpp"
"src/systems/ui.cpp"
"src/util/files.cpp" "src/util/files.cpp"
"src/util/model_loader.cpp" "src/util/model_loader.cpp"
"src/vulkan/device.cpp" "src/vulkan/device.cpp"
@ -45,10 +43,8 @@ set(SRC_FILES
set(INCLUDE_FILES set(INCLUDE_FILES
"include/application.h" "include/application.h"
"include/components/collider.h" "include/components/collider.h"
"include/components/renderable_text.h"
"include/components/renderable.h" "include/components/renderable.h"
"include/components/transform.h" "include/components/transform.h"
"include/components/ui_element.h"
"include/ecs_system.h" "include/ecs_system.h"
"include/engine_api.h" "include/engine_api.h"
"include/event_system.h" "include/event_system.h"
@ -69,9 +65,7 @@ set(INCLUDE_FILES
"include/scene_manager.h" "include/scene_manager.h"
"include/systems/collisions.h" "include/systems/collisions.h"
"include/systems/render.h" "include/systems/render.h"
"include/systems/render2d.h"
"include/systems/transform.h" "include/systems/transform.h"
"include/systems/ui.h"
"include/util.h" "include/util.h"
"include/util/files.h" "include/util/files.h"
"include/util/model_loader.h" "include/util/model_loader.h"

View File

@ -1,26 +0,0 @@
#ifndef ENGINE_INCLUDE_COMPONENTS_RENDERABLE_TEXT_H_
#define ENGINE_INCLUDE_COMPONENTS_RENDERABLE_TEXT_H_
#include <memory>
#include <string>
#include "resources/texture.h"
namespace engine {
struct RenderableTextComponent {
void SetText(const std::string& text) {
text_ = text;
invalidated_ = true;
}
private:
std::string text_{"hello world"};
bool invalidated_ =
true; // text has been changed, texture must be regenerated
std::unique_ptr<resources::Texture> texture_{};
};
} // namespace engine
#endif

View File

@ -1,12 +0,0 @@
#ifndef ENGINE_INCLUDE_COMPONENTS_UI_ELEMENT_H_
#define ENGINE_INCLUDE_COMPONENTS_UI_ELEMENT_H_
namespace engine {
struct UIElementComponent {
int n;
};
} // namespace engine
#endif

View File

@ -1,20 +0,0 @@
#ifndef ENGINE_INCLUDE_SYSTEMS_RENDER2D_H_
#define ENGINE_INCLUDE_SYSTEMS_RENDER2D_H_
#include "ecs_system.h"
namespace engine {
class Render2DSystem : public System {
public:
Render2DSystem(Scene* scene);
~Render2DSystem();
void OnUpdate(float ts) override;
private:
};
} // namespace engine
#endif

View File

@ -1,19 +0,0 @@
#ifndef ENGINE_INCLUDE_SYSTEMS_UI_H_
#define ENGINE_INCLUDE_SYSTEMS_UI_H_
#include "ecs_system.h"
namespace engine {
class UISystem : public System {
public:
UISystem(Scene* scene);
void OnUpdate(float ts) override;
private:
};
} // namespace engine
#endif

View File

@ -1,12 +0,0 @@
#version 450
layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
layout(set = 1, binding = 0) uniform sampler2D texSampler;
void main() {
outColor = texture(texSampler, fragUV);
}

View File

@ -1,22 +0,0 @@
#version 450
layout( push_constant ) uniform Constants {
mat4 model;
vec2 atlas_top_left;
vec2 atlas_bottom_right;
vec2 offset;
vec2 size;
} constants;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNorm;
layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
void main() {
vec2 position = inPosition.xy * constants.size + constants.offset;
position *= 0.001;
gl_Position = constants.model * vec4(position, 0.0, 1.0);
fragUV = constants.atlas_top_left + (inUV * (constants.atlas_bottom_right - constants.atlas_top_left));
}

View File

@ -0,0 +1,13 @@
#version 450
layout(set = 2, binding = 0) uniform sampler2D materialSetSampler;
layout(location = 0) in vec2 fragUV;
layout(location = 0) out vec4 outColor;
void main() {
outColor = texture(materialSetSampler, fragUV);
}

View File

@ -0,0 +1,42 @@
#version 450
layout(set = 0, binding = 0) uniform GlobalSetUniformBuffer {
mat4 proj;
} globalSetUniformBuffer;
layout(set = 1, binding = 0) uniform FrameSetUniformBuffer {
mat4 view;
} frameSetUniformBuffer;
layout( push_constant ) uniform Constants {
mat4 model;
} constants;
layout(location = 0) in vec3 inPosition;
layout(location = 1) in vec3 inNorm;
layout(location = 2) in vec2 inUV;
layout(location = 0) out vec2 fragUV;
vec2 positions[6] = vec2[](
vec2( 1.0, 1.0),
vec2(-1.0, 1.0),
vec2(-1.0, -1.0),
vec2( 1.0, 1.0),
vec2(-1.0, -1.0),
vec2( 1.0, -1.0)
);
vec2 uvs[6] = vec2[](
vec2(1.0, 0.0),
vec2(0.0, 0.0),
vec2(0.0, 1.0),
vec2(1.0, 0.0),
vec2(0.0, 1.0),
vec2(1.0, 1.0)
);
void main() {
gl_Position = constants.model * vec4(positions[gl_VertexIndex], 0.0, 1.0);
fragUV = uvs[gl_VertexIndex];
}

View File

@ -29,8 +29,7 @@
namespace engine { namespace engine {
static std::filesystem::path getResourcesPath() static std::filesystem::path getResourcesPath() {
{
std::filesystem::path resourcesPath{}; std::filesystem::path resourcesPath{};
#ifdef _MSC_VER #ifdef _MSC_VER
@ -44,8 +43,7 @@ namespace engine {
if (std::filesystem::is_directory(cwd / "res")) { if (std::filesystem::is_directory(cwd / "res")) {
resourcesPath = cwd / "res"; resourcesPath = cwd / "res";
} } else {
else {
resourcesPath = cwd.parent_path() / "share" / "sdltest"; resourcesPath = cwd.parent_path() / "share" / "sdltest";
} }
@ -54,14 +52,15 @@ namespace engine {
} }
if (std::filesystem::is_directory(resourcesPath) == false) { if (std::filesystem::is_directory(resourcesPath) == false) {
throw std::runtime_error("Unable to determine resources location. CWD: " + cwd.string()); throw std::runtime_error("Unable to determine resources location. CWD: " +
cwd.string());
} }
return resourcesPath; return resourcesPath;
} }
Application::Application(const char* appName, const char* appVersion, gfx::GraphicsSettings graphicsSettings) Application::Application(const char* appName, const char* appVersion,
{ gfx::GraphicsSettings graphicsSettings) {
window_ = std::make_unique<Window>(appName, true, false); window_ = std::make_unique<Window>(appName, true, false);
input_manager_ = std::make_unique<InputManager>(window_.get()); input_manager_ = std::make_unique<InputManager>(window_.get());
scene_manager_ = std::make_unique<SceneManager>(this); scene_manager_ = std::make_unique<SceneManager>(this);
@ -77,7 +76,8 @@ namespace engine {
RegisterResourceManager<resources::Mesh>(); RegisterResourceManager<resources::Mesh>();
// initialise the render data // initialise the render data
render_data_.gfxdev = std::make_unique<GFXDevice>(appName, appVersion, window_->GetHandle(), graphicsSettings); render_data_.gfxdev = std::make_unique<GFXDevice>(
appName, appVersion, window_->GetHandle(), graphicsSettings);
std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings; std::vector<gfx::DescriptorSetLayoutBinding> globalSetBindings;
{ {
@ -85,13 +85,18 @@ namespace engine {
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
binding0.stage_flags = gfx::ShaderStageFlags::kVertex; binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
} }
render_data_.global_set_layout = gfxdev()->CreateDescriptorSetLayout(globalSetBindings); render_data_.global_set_layout =
render_data_.global_set = gfxdev()->AllocateDescriptorSet(render_data_.global_set_layout); gfxdev()->CreateDescriptorSetLayout(globalSetBindings);
render_data_.global_set =
gfxdev()->AllocateDescriptorSet(render_data_.global_set_layout);
RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{ RenderData::GlobalSetUniformBuffer globalSetUniformBufferData{
.proj = glm::mat4{ 1.0f }, .proj = glm::mat4{1.0f},
}; };
render_data_.global_set_uniform_buffer = gfxdev()->CreateUniformBuffer(sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData); render_data_.global_set_uniform_buffer = gfxdev()->CreateUniformBuffer(
gfxdev()->UpdateDescriptorUniformBuffer(render_data_.global_set, 0, render_data_.global_set_uniform_buffer, 0, sizeof(RenderData::GlobalSetUniformBuffer)); sizeof(RenderData::GlobalSetUniformBuffer), &globalSetUniformBufferData);
gfxdev()->UpdateDescriptorUniformBuffer(
render_data_.global_set, 0, render_data_.global_set_uniform_buffer, 0,
sizeof(RenderData::GlobalSetUniformBuffer));
std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings; std::vector<gfx::DescriptorSetLayoutBinding> frameSetBindings;
{ {
@ -99,13 +104,18 @@ namespace engine {
binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer; binding0.descriptor_type = gfx::DescriptorType::kUniformBuffer;
binding0.stage_flags = gfx::ShaderStageFlags::kVertex; binding0.stage_flags = gfx::ShaderStageFlags::kVertex;
} }
render_data_.frame_set_layout = gfxdev()->CreateDescriptorSetLayout(frameSetBindings); render_data_.frame_set_layout =
render_data_.frame_set = gfxdev()->AllocateDescriptorSet(render_data_.frame_set_layout); gfxdev()->CreateDescriptorSetLayout(frameSetBindings);
render_data_.frame_set =
gfxdev()->AllocateDescriptorSet(render_data_.frame_set_layout);
RenderData::FrameSetUniformBuffer initialSetOneData{ RenderData::FrameSetUniformBuffer initialSetOneData{
.view = glm::mat4{ 1.0f }, .view = glm::mat4{1.0f},
}; };
render_data_.frame_set_uniform_buffer = gfxdev()->CreateUniformBuffer(sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData); render_data_.frame_set_uniform_buffer = gfxdev()->CreateUniformBuffer(
gfxdev()->UpdateDescriptorUniformBuffer(render_data_.frame_set, 0, render_data_.frame_set_uniform_buffer, 0, sizeof(RenderData::FrameSetUniformBuffer)); sizeof(RenderData::FrameSetUniformBuffer), &initialSetOneData);
gfxdev()->UpdateDescriptorUniformBuffer(
render_data_.frame_set, 0, render_data_.frame_set_uniform_buffer, 0,
sizeof(RenderData::FrameSetUniformBuffer));
std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings; std::vector<gfx::DescriptorSetLayoutBinding> materialSetBindings;
{ {
@ -113,55 +123,64 @@ namespace engine {
binding0.descriptor_type = gfx::DescriptorType::kCombinedImageSampler; binding0.descriptor_type = gfx::DescriptorType::kCombinedImageSampler;
binding0.stage_flags = gfx::ShaderStageFlags::kFragment; binding0.stage_flags = gfx::ShaderStageFlags::kFragment;
} }
render_data_.material_set_layout = gfxdev()->CreateDescriptorSetLayout(materialSetBindings); render_data_.material_set_layout =
gfxdev()->CreateDescriptorSetLayout(materialSetBindings);
// default resources /* default fonts */
{ {
auto monoFont = std::make_unique<resources::Font>( auto monoFont = std::make_unique<resources::Font>(
GetResourcePath("engine/fonts/mono.ttf") GetResourcePath("engine/fonts/mono.ttf"));
); GetResourceManager<resources::Font>()->AddPersistent("builtin.mono",
GetResourceManager<resources::Font>()->AddPersistent("builtin.mono", std::move(monoFont)); std::move(monoFont));
} }
/* default shaders */
{ {
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.has_normal = true; vertParams.has_normal = true;
vertParams.has_uv0 = true; vertParams.has_uv0 = true;
auto texturedShader = std::make_unique<resources::Shader>( auto texturedShader = std::make_unique<resources::Shader>(
&render_data_, &render_data_, GetResourcePath("engine/shaders/standard.vert").c_str(),
GetResourcePath("engine/shaders/standard.vert").c_str(), GetResourcePath("engine/shaders/standard.frag").c_str(), vertParams,
GetResourcePath("engine/shaders/standard.frag").c_str(), false, true);
vertParams, GetResourceManager<resources::Shader>()->AddPersistent(
false, "builtin.standard", std::move(texturedShader));
true
);
GetResourceManager<resources::Shader>()->AddPersistent("builtin.standard", std::move(texturedShader));
} }
{ {
resources::Shader::VertexParams vertParams{}; resources::Shader::VertexParams vertParams{};
vertParams.has_normal = true; vertParams.has_normal = true;
vertParams.has_uv0 = true; vertParams.has_uv0 = true;
auto skyboxShader = std::make_unique<resources::Shader>( auto skyboxShader = std::make_unique<resources::Shader>(
&render_data_, &render_data_, GetResourcePath("engine/shaders/skybox.vert").c_str(),
GetResourcePath("engine/shaders/skybox.vert").c_str(), GetResourcePath("engine/shaders/skybox.frag").c_str(), vertParams,
GetResourcePath("engine/shaders/skybox.frag").c_str(), false, true);
vertParams, GetResourceManager<resources::Shader>()->AddPersistent(
false, "builtin.skybox", std::move(skyboxShader));
true
);
GetResourceManager<resources::Shader>()->AddPersistent("builtin.skybox", std::move(skyboxShader));
} }
{ {
auto whiteTexture = std::make_unique<resources::Texture>( resources::Shader::VertexParams vertParams{};
&render_data_, vertParams.has_normal = true;
GetResourcePath("engine/textures/white.png"), vertParams.has_uv0 = true;
resources::Texture::Filtering::kOff auto quadShader = std::make_unique<resources::Shader>(
); &render_data_, GetResourcePath("engine/shaders/quad.vert").c_str(),
GetResourceManager<resources::Texture>()->AddPersistent("builtin.white", std::move(whiteTexture)); GetResourcePath("engine/shaders/quad.frag").c_str(), vertParams,
} true, true);
GetResourceManager<resources::Shader>()->AddPersistent(
"builtin.quad", std::move(quadShader));
} }
Application::~Application()
/* default textures */
{ {
auto whiteTexture = std::make_unique<resources::Texture>(
&render_data_, GetResourcePath("engine/textures/white.png"),
resources::Texture::Filtering::kOff);
GetResourceManager<resources::Texture>()->AddPersistent(
"builtin.white", std::move(whiteTexture));
}
}
Application::~Application() {
for (const auto& [info, sampler] : render_data_.samplers) { for (const auto& [info, sampler] : render_data_.samplers) {
gfxdev()->DestroySampler(sampler); gfxdev()->DestroySampler(sampler);
} }
@ -172,14 +191,14 @@ namespace engine {
gfxdev()->DestroyUniformBuffer(render_data_.global_set_uniform_buffer); gfxdev()->DestroyUniformBuffer(render_data_.global_set_uniform_buffer);
gfxdev()->DestroyDescriptorSetLayout(render_data_.global_set_layout); gfxdev()->DestroyDescriptorSetLayout(render_data_.global_set_layout);
} }
void Application::GameLoop() void Application::GameLoop() {
{
LOG_TRACE("Begin game loop..."); LOG_TRACE("Begin game loop...");
constexpr int FPS_LIMIT = 240; constexpr int FPS_LIMIT = 240;
constexpr auto FRAMETIME_LIMIT = std::chrono::nanoseconds(1000000000 / FPS_LIMIT); constexpr auto FRAMETIME_LIMIT =
std::chrono::nanoseconds(1000000000 / FPS_LIMIT);
auto beginFrame = std::chrono::steady_clock::now(); auto beginFrame = std::chrono::steady_clock::now();
auto endFrame = beginFrame + FRAMETIME_LIMIT; auto endFrame = beginFrame + FRAMETIME_LIMIT;
@ -187,12 +206,13 @@ namespace engine {
// single-threaded game loop // single-threaded game loop
while (window_->IsRunning()) { while (window_->IsRunning()) {
/* logic */ /* logic */
scene_manager_->UpdateActiveScene(window_->dt()); scene_manager_->UpdateActiveScene(window_->dt());
if(window_->GetKeyPress(inputs::Key::K_F)) [[unlikely]] { if (window_->GetKeyPress(inputs::Key::K_F)) [[unlikely]] {
window_->InfoBox("fps", std::to_string(window_->GetFPS()) + " fps " + std::to_string(window_->dt() * 1000.0f) + " ms"); window_->InfoBox("fps", std::to_string(window_->GetFPS()) + " fps " +
std::to_string(window_->dt() * 1000.0f) +
" ms");
} }
uint64_t now = window_->GetNanos(); uint64_t now = window_->GetNanos();
@ -212,10 +232,9 @@ namespace engine {
} }
beginFrame = endFrame; beginFrame = endFrame;
endFrame = beginFrame + FRAMETIME_LIMIT; endFrame = beginFrame + FRAMETIME_LIMIT;
} }
gfxdev()->WaitIdle(); gfxdev()->WaitIdle();
}
} }
} // namespace engine

View File

@ -78,6 +78,13 @@ std::unique_ptr<std::vector<uint8_t>> Font::GetTextBitmap(
auto bitmap = auto bitmap =
std::make_unique<std::vector<uint8_t>>(bitmap_width * bitmap_height * 4); std::make_unique<std::vector<uint8_t>>(bitmap_width * bitmap_height * 4);
for (size_t i = 0; i < bitmap->size() / 4; i++) {
bitmap->at(i * 4 + 0) = 0x00;
bitmap->at(i * 4 + 1) = 0x00;
bitmap->at(i * 4 + 2) = 0x00;
bitmap->at(i * 4 + 3) = 0xFF;
}
int top_left_x = 0; int top_left_x = 0;
for (const auto& renderInfo : characterRenderInfos) { for (const auto& renderInfo : characterRenderInfos) {
if (renderInfo.isEmpty == false) { if (renderInfo.isEmpty == false) {

View File

@ -1,16 +0,0 @@
#include "systems/render2d.h"
#include <typeinfo>
#include "components/transform.h"
namespace engine {
Render2DSystem::Render2DSystem(Scene* scene)
: System(scene, {typeid(TransformComponent).hash_code()}) {}
Render2DSystem::~Render2DSystem() {}
void Render2DSystem::OnUpdate(float ts) { (void)ts; }
} // namespace engine

View File

@ -1,21 +0,0 @@
#include "systems/ui.h"
#include "components/ui_element.h"
#include <typeinfo>
namespace engine {
UISystem::UISystem(Scene* scene)
: System(scene, { typeid(UIElementComponent).hash_code() })
{
}
void UISystem::OnUpdate(float ts)
{
(void)ts;
}
}

View File

@ -102,7 +102,7 @@ void PlayGame(GameSettings settings) {
cube_renderable->material = std::make_shared<engine::resources::Material>( cube_renderable->material = std::make_shared<engine::resources::Material>(
app.GetResource<engine::resources::Shader>("builtin.standard")); app.GetResource<engine::resources::Shader>("builtin.standard"));
cube_renderable->material->texture_ = grass_texture; cube_renderable->material->texture_ = grass_texture;
// app.GetResource<engine::resources::Texture>("builtin.white"); // app.GetResource<engine::resources::Texture>("builtin.white");
cube_renderable->mesh = GenCuboidMesh(app.gfxdev(), 1.0f, 1.0f, 1.0f, 1); cube_renderable->mesh = GenCuboidMesh(app.gfxdev(), 1.0f, 1.0f, 1.0f, 1);
auto cube_collider = auto cube_collider =
my_scene->AddComponent<engine::ColliderComponent>(cube); my_scene->AddComponent<engine::ColliderComponent>(cube);
@ -129,7 +129,7 @@ void PlayGame(GameSettings settings) {
floor_collider->aabb = {{0.0f, 0.0f, 0.0f}, {10000.0f, 1.0f, 10000.0f}}; floor_collider->aabb = {{0.0f, 0.0f, 0.0f}, {10000.0f, 1.0f, 10000.0f}};
} }
//engine::util::LoadMeshFromFile( // engine::util::LoadMeshFromFile(
// my_scene, app.GetResourcePath("models/astronaut/astronaut.dae")); // my_scene, app.GetResourcePath("models/astronaut/astronaut.dae"));
/* skybox */ /* skybox */
@ -146,5 +146,24 @@ void PlayGame(GameSettings settings) {
-5.0f, -5.0f, -5.0f}; -5.0f, -5.0f, -5.0f};
} }
/* some text */
{
int width, height;
auto bitmap = app.GetResource<engine::resources::Font>("builtin.mono")
->GetTextBitmap("The", 768.0f, width, height);
uint32_t textbox = my_scene->CreateEntity("textbox");
auto textbox_renderable =
my_scene->AddComponent<engine::RenderableComponent>(textbox);
textbox_renderable->material =
std::make_unique<engine::resources::Material>(
app.GetResource<engine::resources::Shader>("builtin.quad"));
textbox_renderable->material->texture_ =
std::make_unique<engine::resources::Texture>(
&app.render_data_, bitmap->data(), width, height,
engine::resources::Texture::Filtering::kOff);
textbox_renderable->mesh = GenSphereMesh(app.gfxdev(), 1.0f, 8);
}
app.GameLoop(); app.GameLoop();
} }