#include #include #include #include #include #include #include #include #include #include #include #include #include namespace lt { Renderer *Renderer::s_context = nullptr; Renderer::Renderer( GLFWwindow *window_handle, const Ref &shared_context, CreateInfo create_info ) : m_quad_renderer( create_scope( LT_MAX_QUAD_RENDERER_VERTICES, shared_context, std::move(create_info.quad_renderer_shader) ) ) , m_texture_renderer( create_scope( LT_MAX_TEXTURE_RENDERER_VERTICES, shared_context, std::move(create_info.texture_renderer_shader) ) ) , m_tinted_texture_renderer( create_scope( LT_MAX_TINTED_TEXTURE_RENDERER_VERTICES, shared_context, std::move(create_info.tinted_texture_renderer_shader) ) ) , m_view_projection_buffer(nullptr) , m_render_command(nullptr) , m_blender(nullptr) , m_target_framebuffer(nullptr) { ensure(!s_context, "An instance of 'renderer' already exists, do not construct this class!"); s_context = this; m_view_projection_buffer = ConstantBuffer::create( ConstantBufferIndex::ViewProjection, sizeof(math::mat4), shared_context ); m_render_command = RenderCommand::create(window_handle, shared_context); m_blender = Blender::create(shared_context); m_blender->enable(BlendFactor::SRC_ALPHA, BlendFactor::INVERSE_SRC_ALPHA); } Renderer::~Renderer() // NOLINT { } auto Renderer::create( GLFWwindow *windowHandle, Ref sharedContext, CreateInfo create_info ) -> Scope { return make_scope( new Renderer(windowHandle, std::move(sharedContext), std::move(create_info)) ); } void Renderer::on_window_resize(const WindowResizedEvent &event) { m_render_command->set_viewport(0u, 0u, event.get_size().x, event.get_size().y); } //======================================== DRAW_QUAD ========================================// /* tinted textures */ void Renderer::draw_quad_impl( const math::vec3 &position, const math::vec2 &size, const math::vec4 &tint, Ref texture ) { draw_quad( math::translate(position) * math::scale(math::vec3 { size.x, size.y, 1.0f }), tint, texture ); } /* tint */ void Renderer::draw_quad_impl( const math::vec3 &position, const math::vec2 &size, const math::vec4 &tint ) { draw_quad(math::translate(position) * math::scale(math::vec3 { size.x, size.y, 1.0f }), tint); } /* texture */ void Renderer::draw_quad_impl( const math::vec3 &position, const math::vec2 &size, Ref texture ) { draw_quad( math::translate(position) * math::scale(math::vec3 { size.x, size.y, 1.0f }), texture ); } //======================================== DRAW_QUAD ========================================// //==================== DRAW_QUAD_TINT ====================// void Renderer::draw_quad_impl(const math::mat4 &transform, const math::vec4 &tint) { auto map = std::span { m_quad_renderer->get_map_current(), 4 }; // top left map[0].position = transform * math::vec4(-0.5f, -0.5f, 0.0f, 1.0f); map[0].tint = tint; // top right map[1].position = transform * math::vec4(0.5f, -0.5f, 0.0f, 1.0f); map[1].tint = tint; // bottom right map[2].position = transform * math::vec4(0.5f, 0.5f, 0.0f, 1.0f); map[2].tint = tint; // bottom left map[3].position = transform * math::vec4(-0.5f, 0.5f, 0.0f, 1.0f); map[3].tint = tint; // advance if (!m_quad_renderer->advance()) { log_wrn("Exceeded LT_MAX_QUAD_RENDERER_VERTICES: {}", LT_MAX_QUAD_RENDERER_VERTICES); flush_scene(); } } void Renderer::draw_quad_impl(const math::mat4 &transform, const Ref &texture) { ensure(texture, "Texture passed to renderer::draw_quad_impl"); texture->bind(); auto map = std::span { m_texture_renderer->get_map_current(), 4 }; // top left map[0].position = transform * math::vec4(-0.5f, -0.5f, 0.0f, 1.0f); map[0].texcoord = { 0.0f, 0.0f }; // top right map[1].position = transform * math::vec4(0.5f, -0.5f, 0.0f, 1.0f); map[1].texcoord = { 1.0f, 0.0f }; // bottom right map[2].position = transform * math::vec4(0.5f, 0.5f, 0.0f, 1.0f); map[2].texcoord = { 1.0f, 1.0f }; // bottom left map[3].position = transform * math::vec4(-0.5f, 0.5f, 0.0f, 1.0f); map[3].texcoord = { 0.0f, 1.0f }; // advance if (!m_texture_renderer->advance()) { log_wrn("Exceeded LT_MAX_TEXTURE_RENDERER_VERTICES: {}", LT_MAX_TEXTURE_RENDERER_VERTICES); flush_scene(); } } void Renderer::draw_quad_impl( const math::mat4 &transform, const math::vec4 &tint, const Ref &texture ) { ensure(texture, "Texture passed to renderer::draw_quad_impl"); texture->bind(); auto map = std::span { m_tinted_texture_renderer->get_map_current(), 4 }; // top left map[0].position = transform * math::vec4(-0.5f, -0.5f, 0.0f, 1.0f); map[0].tint = tint; map[0].texcoord = { 0.0f, 0.0f }; // top right map[1].position = transform * math::vec4(0.5f, -0.5f, 0.0f, 1.0f); map[1].tint = tint; map[1].texcoord = { 1.0f, 0.0f }; // bottom right map[2].position = transform * math::vec4(0.5f, 0.5f, 0.0f, 1.0f); map[2].tint = tint; map[2].texcoord = { 1.0f, 1.0f }; // bottom left map[3].position = transform * math::vec4(-0.5f, 0.5f, 0.0f, 1.0f); map[3].tint = tint; map[3].texcoord = { 0.0f, 1.0f }; if (!m_tinted_texture_renderer->advance()) { log_wrn("Exceeded LT_MAX_TEXTURE_RENDERER_VERTICES: {}", LT_MAX_TEXTURE_RENDERER_VERTICES); flush_scene(); } } void Renderer::begin_frame() { } void Renderer::end_frame() { m_render_command->swap_buffers(); m_render_command->clear_back_buffer( m_default_framebuffer_camera ? m_default_framebuffer_camera->get_background_color() : math::vec4(0.0f) ); m_default_framebuffer_camera = nullptr; } void Renderer::begin_scene_impl( Camera *camera, const math::mat4 &cameraTransform, const Ref &targetFrameBuffer /* = nullptr */ ) { // determine the target frame buffer m_target_framebuffer = targetFrameBuffer; if (targetFrameBuffer) { targetFrameBuffer->bind_as_target(camera->get_background_color()); } else { m_default_framebuffer_camera = camera; m_render_command->default_target_framebuffer(); } // update view projection buffer auto *map = (math::mat4 *)m_view_projection_buffer->map(); map[0] = camera->get_projection() * math::inverse(cameraTransform); m_view_projection_buffer->un_map(); // map renderers m_quad_renderer->map(); m_texture_renderer->map(); m_tinted_texture_renderer->map(); } void Renderer::flush_scene() { /* 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); } /* 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); } /* 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(); } void Renderer::end_scene_impl() { /* 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); } /* 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); } /* 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); } // reset frame buffer if (m_target_framebuffer) { m_target_framebuffer = nullptr; m_render_command->default_target_framebuffer(); } } } // namespace lt