Skip to content

Commit

Permalink
Improved: Rendering API & Added: FontBatchRenderer
Browse files Browse the repository at this point in the history
  • Loading branch information
WillisMedwell committed Feb 29, 2024
1 parent 17b3cf5 commit bf98ea1
Show file tree
Hide file tree
Showing 26 changed files with 925 additions and 258 deletions.
131 changes: 64 additions & 67 deletions code/Demos/src/Main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
#include <string_view>

#include <Engine.hpp>
#include <Renderer/Renderer.hpp>
#include <Utily/Utily.hpp>

using namespace std::literals;
Expand Down Expand Up @@ -338,37 +339,14 @@ struct SpinningTeapotLogic {

struct FontData {
std::chrono::steady_clock::time_point start_time;
glm::vec4 background_colour = { 0, 0, 0, 1.0f };
Media::Font font;
Cameras::StationaryPerspective camera { glm::vec3(0, 0, -10), glm::normalize(glm::vec3(0, 0, 1)) };
glm::vec4 background_colour = { 1.0f, 0, 1.0f, 1.0f };

AppRenderer::ShaderId s_id;
AppRenderer::IndexBufferId ib_id;
AppRenderer::VertexBufferId vb_id;
AppRenderer::VertexArrayId va_id;
AppRenderer::TextureId t_id;

constexpr static std::string_view VERT =
"precision highp float; "
"uniform mat4 u_mvp;"
"layout(location = 0) in vec2 l_pos;"
"layout(location = 1) in vec2 l_uv;"
"out vec2 uv;"
"void main() {"
" gl_Position = u_mvp * vec4(l_pos, -1.0, 1.0);"
" uv = l_uv;"
"}"sv;
constexpr static std::string_view FRAG =
"precision highp float; "
"uniform sampler2D u_texture;"
"out vec4 FragColor;"
"in vec2 uv;"
"void main() {"
" vec2 uv_flipped = vec2(uv.x, 1 - uv.y);"
" FragColor = vec4(texture(u_texture, uv_flipped).rrr, 1);"
"}"sv;
Media::Font font {};
Media::FontAtlas font_atlas {};

Media::FontAtlas font_atlas = {};
Renderer::ResourceManager resource_manager {};
Renderer::FontRenderer font_renderer {};
Renderer::FontBatchRenderer font_batch_renderer {};
};
struct FontLogic {
void init(AppRenderer& renderer, entt::registry& ecs, FontData& data) {
Expand All @@ -379,53 +357,72 @@ struct FontLogic {

data.font_atlas.init(data.font, 100).on_error(print_then_quit);
data.font_atlas.image.save_to_disk("FontAtlasGeneration.png").on_error(print_then_quit);

data.s_id = renderer.add_shader(data.VERT, data.FRAG).on_error(print_then_quit).value();
data.ib_id = renderer.add_index_buffer().on_error(print_then_quit).value();
data.vb_id = renderer.add_vertex_buffer().on_error(print_then_quit).value();
data.va_id = renderer.add_vertex_array(Model::Vertex2D::VBL {}, data.vb_id).on_error(print_then_quit).value();
data.t_id = renderer.add_texture(data.font_atlas.image).on_error(print_then_quit).value();
//data.font_renderer.init(data.resource_manager, data.font_atlas);
data.font_batch_renderer.init(data.resource_manager, data.font_atlas);
}
void update(float dt, const Core::InputManager& input, AppState& state, entt::registry& ecs, FontData& data) {

auto duration = std::chrono::duration_cast<std::chrono::milliseconds>(std::chrono::high_resolution_clock::now() - data.start_time);
if (duration > std::chrono::seconds(1)) {
state.should_close = true;
}
}
void draw(AppRenderer& renderer, entt::registry& ecs, FontData& data) {
renderer.screen_frame_buffer.clear(data.background_colour);

// auto pm = data.camera.projection_matrix(renderer.window_width, renderer.window_height);
auto pm = Cameras::Orthographic::projection_matrix(renderer.window_width, renderer.window_height);

renderer.screen_frame_buffer.bind();
renderer.screen_frame_buffer.clear();
renderer.screen_frame_buffer.clear(data.background_colour);
renderer.screen_frame_buffer.resize(renderer.window_width, renderer.window_height);

Core::IndexBuffer& ib = renderer.index_buffers[data.ib_id.id];
Core::VertexBuffer& vb = renderer.vertex_buffers[data.vb_id.id];
Core::VertexArray& va = renderer.vertex_arrays[data.va_id.id];
Core::Shader& s = renderer.shaders[data.s_id.id];
Core::Texture& t = renderer.textures[data.t_id.id];

const static auto [verts, indis] = Media::FontMeshGenerator::generate_static_mesh("hello there", 100, { 50, 50 }, data.font_atlas);

s.bind();

s.set_uniform("u_mvp", pm).on_error(print_then_quit);
s.set_uniform("u_texture", static_cast<int>(t.bind().value())).on_error(print_then_quit);

va.bind();
ib.bind();
vb.bind();
ib.load_indices(indis);
vb.load_vertices(verts);

glDrawElements(GL_TRIANGLES, ib.get_count(), GL_UNSIGNED_INT, (void*)0);
data.font_batch_renderer.begin_batch({
.resource_manager = data.resource_manager,
.screen_dimensions = glm::vec2 { renderer.window_width, renderer.window_height },
.font_colour = { 0, 0, 0, 1 },
});

data.font_batch_renderer.push_to_batch("hi there", { 0, 0 }, 50);

data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. lah blah blah", { 0, 25 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blh blah blah", { 0, 50 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. bah blah blah", { 0, 75 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah bah blah", { 0, 100 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah blah", { 0, 125 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah bah", { 0, 150 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah bla", { 0, 175 }, 25);
// Note that the last four calls are similar to the first four but with slightly different y-positions.
// Ensure this is intentional and not a duplication error. If they are indeed different messages or required duplications, convert them similarly:
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. lah blah blah", { 0, 40 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blh blah blah", { 0, 60 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. bah blah blah", { 0, 80 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah bah blah", { 0, 110 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah blah", { 0, 130 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah bah", { 0, 160 }, 25);
data.font_batch_renderer.push_to_batch("this is a lot of freaking text on the screen. blah blah bla", { 0, 180 }, 25);

data.font_batch_renderer.end_batch();

// data.font_renderer.add_to_draw_list("some text", pos);
// data.font_renderer.add_to_draw_list("some other text", pos2);
// data.font_renderer.draw("some other text", pos2);

// data.font_renderer.begin_batch();
//
// data.font_renderer.push();
// data.font_renderer.push();
// data.font_renderer.push();
// data.font_renderer.push();

// data.font_renderer.end_batch();

// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. lah blah blah", 25, { 0, 25 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blh blah blah", 25, { 0, 50 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. bah blah blah", 25, { 0, 75 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah bah blah", 25, { 0, 100 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah blah", 25, { 0, 125 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah bah", 25, { 0, 150 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah bla", 25, { 0, 175 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. lah blah blah", 25, { 0, 40 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blh blah blah", 25, { 0, 60 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. bah blah blah", 25, { 0, 80 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah bah blah", 25, { 0, 110 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah blah", 25, { 0, 130 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah bah", 25, { 0, 160 }, { 0, 0, 0, 1 });
// data.font_renderer.draw(data.resource_manager, glm::vec2 { renderer.window_width, renderer.window_height }, "this is a lot of freaking text on the screen. blah blah bla", 25, { 0, 180 }, { 0, 0, 0, 1 });
}
void stop() {

}
};

Expand Down
7 changes: 5 additions & 2 deletions code/Engine/include/App/App.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,11 @@

#include "Cameras/Cameras.hpp"
#include "Profiler/Profiler.hpp"
#include "Core/Renderer.hpp"
#include "Core/Core.hpp"

#include "Core/Input.hpp"
#include "AppRenderer.hpp"

#include "App/AppRenderer.hpp"

#include <chrono>
#include <thread>
Expand All @@ -23,6 +24,8 @@ struct AppState {
bool should_close = false;
};



template <typename T, typename AppData>
concept HasValidAppLogic = requires(T t, double dt, AppState& state, AppData& data, AppRenderer& renderer, const Core::InputManager& input, entt::registry& ecs) {
{
Expand Down
34 changes: 8 additions & 26 deletions code/Engine/include/App/AppRenderer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ class AppRenderer
Utily::StaticVector<Core::IndexBuffer, 20> index_buffers;
Utily::StaticVector<Core::VertexArray, 20> vertex_arrays;
Utily::StaticVector<Core::Texture, 100> textures;

Core::ScreenFrameBuffer screen_frame_buffer;

float window_width;
Expand All @@ -40,40 +40,22 @@ class AppRenderer
[[nodiscard]] auto add_index_buffer() noexcept -> Utily::Result<IndexBufferId, Utily::Error>;

template <typename... Args>
[[nodiscard]] auto add_vertex_array(Core::VertexBufferLayout<Args...> vertex_buffer_layout, VertexBufferId vb_id) -> Utily::Result<VertexArrayId, Utily::Error> {
[[nodiscard]] auto add_vertex_array(Core::VertexBufferLayout<Args...> vertex_buffer_layout, VertexBufferId vb_id, IndexBufferId ib_id) -> Utily::Result<VertexArrayId, Utily::Error> {
auto id = vertex_arrays.size();
vertex_arrays.emplace_back();

Core::VertexArray& va = vertex_arrays[id];
auto result = va.init();
Core::VertexBuffer& vb = vertex_buffers[vb_id.id];
Core::IndexBuffer& ib = index_buffers[ib_id.id];

auto result = va.init(vertex_buffer_layout, vb, ib);
if constexpr (Config::DEBUG_LEVEL != Config::DebugInfo::none) {
if (result.has_error()) {
return result.error();
}
}

va.bind();
vertex_buffers[vb_id.id].bind();

constexpr static auto layout = vertex_buffer_layout.get_layout();
/*constexpr static*/ auto stride = vertex_buffer_layout.get_stride();

uint32_t offset = 0;
for (size_t i = 0; i < layout.size(); i++) {
const auto& element = layout[i];

#if defined(CONFIG_TARGET_NATIVE)
glEnableVertexArrayAttrib(va.get_id().value(), i);
glVertexAttribPointer(i, element.count, element.type, element.normalised, stride, reinterpret_cast<const void*>(offset));
#elif defined(CONFIG_TARGET_WEB)
glEnableVertexAttribArray(i);
glVertexAttribPointer(i, element.count, element.type, element.normalised, stride, reinterpret_cast<const void*>(offset));
#endif

offset += element.type_size;
}
return 0;
}
return { static_cast<int>(id) };
}

[[nodiscard]] auto add_texture(Media::Image& image) noexcept -> Utily::Result<TextureId, Utily::Error>;

Expand Down
3 changes: 2 additions & 1 deletion code/Engine/include/Config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,9 @@ namespace Config {
// false == ensure the gpu texture is reading valid cpu image data. Enables fencing as default.
constexpr static bool SKIP_IMAGE_TEXTURE_FENCING = false;


constexpr static bool SKIP_PROFILE = false;

constexpr static bool ENABLE_VSYNC = false;
}

#if defined(EMSCRIPTEN)
Expand Down
53 changes: 53 additions & 0 deletions code/Engine/include/Core/DebugOpRecorder.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
#pragma once

#include "Config.hpp"
#include <string_view>
#include <tuple>
#include <vector>

namespace Core {
class DebugOpRecorder
{
public:
static inline auto instance() -> DebugOpRecorder& {
static DebugOpRecorder dor {};
return dor;
}

inline void clear() {
if constexpr (Config::DEBUG_LEVEL == Config::DebugInfo::all) {
_ops.clear();
}
}

inline void push(std::string_view type [[maybe_unused]], std::string_view details [[maybe_unused]]) {
if constexpr (Config::DEBUG_LEVEL == Config::DebugInfo::all) {
try {
_ops.emplace_back(type, details);
} catch (const std::exception& e) {
std::cerr << e.what() << '\n';
}
}
}

inline auto get_formatted_ops() {
std::string res {};
if constexpr (Config::DEBUG_LEVEL == Config::DebugInfo::all) {
for (auto [core_type, details] : _ops) {
res += " - ";
res += core_type;
res += ": \t";
res += details;
res += "\n";
}
}
return res;
}

private:
using Ops = std::vector<std::tuple<std::string_view, std::string_view>>;

Ops _ops;
DebugOpRecorder() = default;
};
}
13 changes: 6 additions & 7 deletions code/Engine/include/Core/IndexBuffer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@
#include <Utily/Utily.hpp>

#include "Config.hpp"
#include "Model/Types.hpp"
#include "Profiler/Profiler.hpp"
#include "Core/DebugOpRecorder.hpp"


namespace Core {
class IndexBuffer
Expand All @@ -25,16 +28,12 @@ namespace Core {
&& std::same_as<std::ranges::range_value_t<Range>, uint32_t>
&& std::ranges::sized_range<Range>
void load_indices(const Range& indices) noexcept {
Profiler::Timer timer("Core::IndexBuffer::load_indices", {"rendering"});
Core::DebugOpRecorder::instance().push("Core::IndexBuffer", "load_indices()");
Profiler::Timer timer("Core::IndexBuffer::load_indices", { "rendering" });

this->bind();
size_t size_in_bytes = indices.size() * sizeof(uint32_t);
#if defined(CONFIG_TARGET_NATIVE)
size_t size_in_bytes = indices.size() * sizeof(Model::Index);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_in_bytes, &(*indices.begin()), GL_DYNAMIC_DRAW);
#elif defined(CONFIG_TARGET_WEB)
// for some reason, GL_DYNAMIC_DRAW has a very small buffer capacity.
glBufferData(GL_ELEMENT_ARRAY_BUFFER, size_in_bytes, &(*indices.begin()), GL_STATIC_DRAW);
#endif
_count = indices.size();
}

Expand Down
3 changes: 3 additions & 0 deletions code/Engine/include/Core/OpenglContext.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@

#include <Utily/Utily.hpp>

#include "Core/DebugOpRecorder.hpp"


namespace Core {
class OpenglContext
{
Expand Down
14 changes: 0 additions & 14 deletions code/Engine/include/Core/Renderer.hpp

This file was deleted.

2 changes: 2 additions & 0 deletions code/Engine/include/Core/Shader.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@ namespace Core {
auto set_uniform(std::string_view uniform, int32_t value) noexcept -> Utily::Result<void, Utily::Error>;
auto set_uniform(std::string_view uniform, float value) noexcept -> Utily::Result<void, Utily::Error>;
auto set_uniform(std::string_view uniform, const glm::vec3& value) noexcept -> Utily::Result<void, Utily::Error>;
auto set_uniform(std::string_view uniform, const glm::vec4& value) noexcept -> Utily::Result<void, Utily::Error>;
auto set_uniform(std::string_view uniform, const glm::mat4& value) noexcept -> Utily::Result<void, Utily::Error>;


~Shader();

private:
Expand Down
Loading

0 comments on commit bf98ea1

Please sign in to comment.