light/modules/engine/src/graphics/renderer.cpp

318 lines
8.6 KiB
C++
Raw Normal View History

2025-07-05 13:28:41 +03:30
#include <engine/camera/scene.hpp>
#include <engine/events/window.hpp>
#include <engine/graphics/blender.hpp>
#include <engine/graphics/buffers.hpp>
#include <engine/graphics/framebuffer.hpp>
#include <engine/graphics/render_command.hpp>
#include <engine/graphics/renderer.hpp>
#include <engine/graphics/texture.hpp>
#include <glm/glm.hpp>
#include <glm/gtc/matrix_transform.hpp>
2022-03-04 22:40:20 +03:30
#include <glm/matrix.hpp>
2025-07-06 16:52:50 +03:30
#include <utility>
2021-05-30 16:45:54 +04:30
namespace Light {
2025-07-06 14:02:50 +03:30
Renderer *Renderer::s_context = nullptr;
2025-07-05 13:28:41 +03:30
2025-07-06 16:52:50 +03:30
Renderer::Renderer(GLFWwindow *windowHandle, const Ref<SharedContext> &sharedContext)
: m_quad_renderer(LT_MAX_QUAD_RENDERER_VERTICES, sharedContext)
, m_texture_renderer(LT_MAX_TEXTURE_RENDERER_VERTICES, sharedContext)
, m_tinted_texture_renderer(LT_MAX_TINTED_TEXTURE_RENDERER_VERTICES, sharedContext)
, m_view_projection_buffer(nullptr)
, m_render_command(nullptr)
, m_blender(nullptr)
, m_target_framebuffer(nullptr)
2025-07-06 16:52:50 +03:30
2022-03-04 22:40:20 +03:30
{
2025-07-05 16:07:51 +03:30
lt_assert(!s_context, "An instance of 'renderer' already exists, do not construct this class!");
s_context = this;
2022-03-04 22:40:20 +03:30
m_view_projection_buffer = ConstantBuffer::create(
2025-07-05 13:28:41 +03:30
ConstantBufferIndex::ViewProjection,
sizeof(glm::mat4),
sharedContext
);
2022-03-04 22:40:20 +03:30
m_render_command = RenderCommand::create(windowHandle, sharedContext);
m_blender = Blender::create(sharedContext);
m_blender->enable(BlendFactor::SRC_ALPHA, BlendFactor::INVERSE_SRC_ALPHA);
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
auto Renderer::create(GLFWwindow *windowHandle, Ref<SharedContext> sharedContext) -> Scope<Renderer>
2022-03-04 22:40:20 +03:30
{
2025-07-06 16:52:50 +03:30
return make_scope<Renderer>(new Renderer(windowHandle, std::move(sharedContext)));
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
void Renderer::on_window_resize(const WindowResizedEvent &event)
2022-03-04 22:40:20 +03:30
{
m_render_command->set_viewport(0u, 0u, event.get_size().x, event.get_size().y);
2022-03-04 22:40:20 +03:30
}
//======================================== DRAW_QUAD ========================================//
/* tinted textures */
2025-07-06 14:02:50 +03:30
void Renderer::draw_quad_impl(
2025-07-05 13:28:41 +03:30
const glm::vec3 &position,
const glm::vec2 &size,
const glm::vec4 &tint,
Ref<Texture> texture
)
2022-03-04 22:40:20 +03:30
{
draw_quad(
2025-07-05 13:28:41 +03:30
glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }),
tint,
2025-07-06 16:52:50 +03:30
std::move(texture)
2025-07-05 13:28:41 +03:30
);
2022-03-04 22:40:20 +03:30
}
/* tint */
2025-07-06 14:02:50 +03:30
void Renderer::draw_quad_impl(
2025-07-05 16:07:51 +03:30
const glm::vec3 &position,
const glm::vec2 &size,
const glm::vec4 &tint
)
2022-03-04 22:40:20 +03:30
{
draw_quad(
2025-07-05 13:28:41 +03:30
glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }),
tint
);
2022-03-04 22:40:20 +03:30
}
/* texture */
2025-07-06 14:02:50 +03:30
void Renderer::draw_quad_impl(
2025-07-05 16:07:51 +03:30
const glm::vec3 &position,
const glm::vec2 &size,
Ref<Texture> texture
)
2022-03-04 22:40:20 +03:30
{
draw_quad(
2025-07-05 13:28:41 +03:30
glm::translate(glm::mat4(1.0f), position)
* glm::scale(glm::mat4(1.0f), { size.x, size.y, 1.0f }),
2025-07-06 16:52:50 +03:30
std::move(texture)
2025-07-05 13:28:41 +03:30
);
2022-03-04 22:40:20 +03:30
}
//======================================== DRAW_QUAD ========================================//
//==================== DRAW_QUAD_TINT ====================//
2025-07-06 14:02:50 +03:30
void Renderer::draw_quad_impl(const glm::mat4 &transform, const glm::vec4 &tint)
2022-03-04 22:40:20 +03:30
{
// locals
2025-07-06 14:02:50 +03:30
QuadRendererProgram::QuadVertexData *bufferMap = m_quad_renderer.get_map_current();
2022-03-04 22:40:20 +03:30
// top left
bufferMap[0].position = transform * glm::vec4(-0.5f, -0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[0].tint = tint;
2022-03-04 22:40:20 +03:30
// top right
bufferMap[1].position = transform * glm::vec4(0.5f, -0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[1].tint = tint;
2022-03-04 22:40:20 +03:30
// bottom right
bufferMap[2].position = transform * glm::vec4(0.5f, 0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[2].tint = tint;
2022-03-04 22:40:20 +03:30
// bottom left
bufferMap[3].position = transform * glm::vec4(-0.5f, 0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[3].tint = tint;
2022-03-04 22:40:20 +03:30
// advance
if (!m_quad_renderer.advance())
2021-05-30 16:45:54 +04:30
{
2025-07-06 16:30:38 +03:30
log_wrn("Exceeded LT_MAX_QUAD_RENDERER_VERTICES: {}", LT_MAX_QUAD_RENDERER_VERTICES);
flush_scene();
2022-03-04 22:40:20 +03:30
}
}
//==================== DRAW_QUAD_TINT ====================//
2021-05-30 16:45:54 +04:30
2022-03-04 22:40:20 +03:30
//==================== DRAW_QUAD_TEXTURE ====================//
2025-07-06 16:52:50 +03:30
void Renderer::draw_quad_impl(const glm::mat4 &transform, const Ref<Texture> &texture)
2022-03-04 22:40:20 +03:30
{
// #todo: implement a proper binding
lt_assert(texture, "Texture passed to renderer::draw_quad_impl");
texture->bind();
2021-07-09 11:56:31 +04:30
2022-03-04 22:40:20 +03:30
// locals
2025-07-06 14:02:50 +03:30
TextureRendererProgram::TextureVertexData *bufferMap = m_texture_renderer.get_map_current();
2021-05-30 16:45:54 +04:30
2022-03-04 22:40:20 +03:30
// top left
bufferMap[0].position = transform * glm::vec4(-0.5f, -0.5f, 0.0f, 1.0f);
bufferMap[0].texcoord = { 0.0f, 0.0f };
2021-05-30 16:45:54 +04:30
2022-03-04 22:40:20 +03:30
// top right
bufferMap[1].position = transform * glm::vec4(0.5f, -0.5f, 0.0f, 1.0f);
bufferMap[1].texcoord = { 1.0f, 0.0f };
// bottom right
bufferMap[2].position = transform * glm::vec4(0.5f, 0.5f, 0.0f, 1.0f);
bufferMap[2].texcoord = { 1.0f, 1.0f };
// bottom left
bufferMap[3].position = transform * glm::vec4(-0.5f, 0.5f, 0.0f, 1.0f);
bufferMap[3].texcoord = { 0.0f, 1.0f };
2022-03-04 22:40:20 +03:30
// advance
if (!m_texture_renderer.advance())
{
2025-07-06 16:30:38 +03:30
log_wrn("Exceeded LT_MAX_TEXTURE_RENDERER_VERTICES: {}", LT_MAX_TEXTURE_RENDERER_VERTICES);
flush_scene();
}
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
void Renderer::draw_quad_impl(
2025-07-05 16:07:51 +03:30
const glm::mat4 &transform,
const glm::vec4 &tint,
2025-07-06 16:52:50 +03:30
const Ref<Texture> &texture
2025-07-05 16:07:51 +03:30
)
2022-03-04 22:40:20 +03:30
{
// #todo: implement a proper binding
lt_assert(texture, "Texture passed to renderer::draw_quad_impl");
texture->bind();
2022-03-04 22:40:20 +03:30
// locals
TintedTextureRendererProgram::TintedTextureVertexData *bufferMap = m_tinted_texture_renderer
2025-07-06 14:02:50 +03:30
.get_map_current();
2022-03-04 22:40:20 +03:30
// top left
bufferMap[0].position = transform * glm::vec4(-0.5f, -0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[0].tint = tint;
2022-03-04 22:40:20 +03:30
bufferMap[0].texcoord = { 0.0f, 0.0f };
// top right
bufferMap[1].position = transform * glm::vec4(0.5f, -0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[1].tint = tint;
2022-03-04 22:40:20 +03:30
bufferMap[1].texcoord = { 1.0f, 0.0f };
// bottom right
bufferMap[2].position = transform * glm::vec4(0.5f, 0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[2].tint = tint;
2022-03-04 22:40:20 +03:30
bufferMap[2].texcoord = { 1.0f, 1.0f };
// bottom left
bufferMap[3].position = transform * glm::vec4(-0.5f, 0.5f, 0.0f, 1.0f);
2025-07-05 13:28:41 +03:30
bufferMap[3].tint = tint;
2022-03-04 22:40:20 +03:30
bufferMap[3].texcoord = { 0.0f, 1.0f };
// advance
if (!m_tinted_texture_renderer.advance())
{
2025-07-06 16:30:38 +03:30
log_wrn("Exceeded LT_MAX_TEXTURE_RENDERER_VERTICES: {}", LT_MAX_TEXTURE_RENDERER_VERTICES);
flush_scene();
}
2022-03-04 22:40:20 +03:30
}
2022-03-04 22:40:20 +03:30
//==================== DRAW_QUAD_TEXTURE ====================//
2025-07-06 14:02:50 +03:30
void Renderer::begin_frame()
2022-03-04 22:40:20 +03:30
{
}
2025-07-06 14:02:50 +03:30
void Renderer::end_frame()
2022-03-04 22:40:20 +03:30
{
m_render_command->swap_buffers();
m_render_command->clear_back_buffer(
2025-07-06 14:02:50 +03:30
m_default_framebuffer_camera ? m_default_framebuffer_camera->get_background_color() :
2025-07-05 16:07:51 +03:30
glm::vec4(0.0f)
2025-07-05 13:28:41 +03:30
);
2022-03-04 22:40:20 +03:30
m_default_framebuffer_camera = nullptr;
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
void Renderer::begin_scene_impl(
2025-07-05 13:28:41 +03:30
Camera *camera,
const glm::mat4 &cameraTransform,
const Ref<Framebuffer> &targetFrameBuffer /* = nullptr */
)
2022-03-04 22:40:20 +03:30
{
// determine the target frame buffer
m_target_framebuffer = targetFrameBuffer;
2022-03-04 22:40:20 +03:30
if (targetFrameBuffer)
2025-07-06 16:52:50 +03:30
{
2025-07-06 14:02:50 +03:30
targetFrameBuffer->bind_as_target(camera->get_background_color());
2025-07-06 16:52:50 +03:30
}
2022-03-04 22:40:20 +03:30
else
2021-05-30 16:45:54 +04:30
{
m_default_framebuffer_camera = camera;
m_render_command->default_target_framebuffer();
}
2022-03-04 22:40:20 +03:30
// update view projection buffer
2025-07-06 16:52:50 +03:30
auto *map = (glm::mat4 *)m_view_projection_buffer->map();
2025-07-06 14:02:50 +03:30
map[0] = camera->get_projection() * glm::inverse(cameraTransform);
m_view_projection_buffer->un_map();
2022-03-04 22:40:20 +03:30
// map renderers
m_quad_renderer.map();
m_texture_renderer.map();
m_tinted_texture_renderer.map();
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
void Renderer::flush_scene()
2022-03-04 22:40:20 +03:30
{
/* tinted texture renderer */
m_tinted_texture_renderer.un_map();
if (m_tinted_texture_renderer.get_quad_count())
{
m_tinted_texture_renderer.bind();
m_render_command->draw_indexed(m_tinted_texture_renderer.get_quad_count() * 6u);
}
2022-03-04 22:40:20 +03:30
/* quad renderer */
m_quad_renderer.un_map();
if (m_quad_renderer.get_quad_count())
{
m_quad_renderer.bind();
m_render_command->draw_indexed(m_quad_renderer.get_quad_count() * 6u);
}
2022-03-04 22:40:20 +03:30
/* texture renderer */
m_texture_renderer.un_map();
if (m_texture_renderer.get_quad_count())
{
m_texture_renderer.bind();
m_render_command->draw_indexed(m_texture_renderer.get_quad_count() * 6u);
}
m_quad_renderer.map();
m_texture_renderer.map();
m_tinted_texture_renderer.map();
2022-03-04 22:40:20 +03:30
}
2025-07-06 14:02:50 +03:30
void Renderer::end_scene_impl()
2022-03-04 22:40:20 +03:30
{
/* tinted texture renderer */
m_tinted_texture_renderer.un_map();
if (m_tinted_texture_renderer.get_quad_count())
2022-03-04 22:40:20 +03:30
{
m_tinted_texture_renderer.bind();
m_render_command->draw_indexed(m_tinted_texture_renderer.get_quad_count() * 6u);
}
2022-03-04 22:40:20 +03:30
/* quad renderer */
m_quad_renderer.un_map();
if (m_quad_renderer.get_quad_count())
{
m_quad_renderer.bind();
m_render_command->draw_indexed(m_quad_renderer.get_quad_count() * 6u);
}
2022-03-04 22:40:20 +03:30
/* texture renderer */
m_texture_renderer.un_map();
if (m_texture_renderer.get_quad_count())
{
m_texture_renderer.bind();
m_render_command->draw_indexed(m_texture_renderer.get_quad_count() * 6u);
}
2022-03-04 22:40:20 +03:30
// reset frame buffer
if (m_target_framebuffer)
{
m_target_framebuffer = nullptr;
m_render_command->default_target_framebuffer();
}
2022-03-04 22:40:20 +03:30
}
2022-03-04 22:40:20 +03:30
} // namespace Light