From 0ee2712029f53175552d459f908b163ad61de197 Mon Sep 17 00:00:00 2001 From: hachem Date: Sun, 23 Aug 2026 16:19:19 +0200 Subject: feat: RHI interface with shared scene and black hole renderers --- src/rendering/black_hole_renderer.cpp | 134 +++++++++++++++++++ src/rendering/black_hole_renderer.h | 46 +++++++ src/rendering/framebuffer.cpp | 244 ---------------------------------- src/rendering/framebuffer.h | 80 ----------- src/rendering/index_buffer.cpp | 34 ----- src/rendering/index_buffer.h | 23 ---- src/rendering/render_api.h | 21 +++ src/rendering/renderer.cpp | 167 ----------------------- src/rendering/renderer.h | 153 --------------------- src/rendering/renderer_backend.h | 32 ----- src/rendering/rhi.h | 107 +++++++++++++++ src/rendering/rhi/rhi.h | 108 --------------- src/rendering/scene_renderer.cpp | 202 ++++++++++++++++++++++++++++ src/rendering/scene_renderer.h | 48 +++++++ src/rendering/texture_manager.cpp | 34 ----- src/rendering/texture_manager.h | 19 --- src/rendering/uniform_buffer.cpp | 36 ----- src/rendering/uniform_buffer.h | 24 ---- src/rendering/vertex_array.cpp | 59 -------- src/rendering/vertex_array.h | 35 ----- src/rendering/vertex_buffer.cpp | 50 ------- src/rendering/vertex_buffer.h | 78 ----------- 22 files changed, 558 insertions(+), 1176 deletions(-) create mode 100644 src/rendering/black_hole_renderer.cpp create mode 100644 src/rendering/black_hole_renderer.h delete mode 100644 src/rendering/framebuffer.cpp delete mode 100644 src/rendering/framebuffer.h delete mode 100644 src/rendering/index_buffer.cpp delete mode 100644 src/rendering/index_buffer.h create mode 100644 src/rendering/render_api.h delete mode 100644 src/rendering/renderer.cpp delete mode 100644 src/rendering/renderer.h create mode 100644 src/rendering/rhi.h delete mode 100644 src/rendering/rhi/rhi.h create mode 100644 src/rendering/scene_renderer.cpp create mode 100644 src/rendering/scene_renderer.h delete mode 100644 src/rendering/texture_manager.cpp delete mode 100644 src/rendering/texture_manager.h delete mode 100644 src/rendering/uniform_buffer.cpp delete mode 100644 src/rendering/uniform_buffer.h delete mode 100644 src/rendering/vertex_array.cpp delete mode 100644 src/rendering/vertex_array.h delete mode 100644 src/rendering/vertex_buffer.cpp delete mode 100644 src/rendering/vertex_buffer.h (limited to 'src/rendering') diff --git a/src/rendering/black_hole_renderer.cpp b/src/rendering/black_hole_renderer.cpp new file mode 100644 index 0000000..2534b1d --- /dev/null +++ b/src/rendering/black_hole_renderer.cpp @@ -0,0 +1,134 @@ +#include "black_hole_renderer.h" + +#include "core/log.h" +#include "core/settings_manager.h" + +#include +#include +#include + +namespace Donut +{ + using namespace RHI; + + namespace + { + constexpr float SagA_rs = 1.269e10f; + + struct CamUBO { + glm::vec3 pos; float p0; glm::vec3 right; float p1; + glm::vec3 up; float p2; glm::vec3 fwd; float p3; + float tan_half_fov; float aspect; uint32_t moving; int p4; + }; + struct SimUBO { int steps_moving; int steps_static; float early_exit; float time; }; + } + + auto BlackHoleRenderer::init(RHI::Device& device) -> bool + { + m_device = &device; + + m_geo_lo = device.create_render_target(GEO_LO_W, GEO_LO_H, Format::RGBA8, false, Filter::Linear); + m_geo_hi = device.create_render_target(GEO_HI_W, GEO_HI_H, Format::RGBA8, false, Filter::Linear); + + const float quad[] = { + -1.f, 1.f, 0.f, 1.f, -1.f, -1.f, 0.f, 0.f, 1.f, -1.f, 1.f, 0.f, + -1.f, 1.f, 0.f, 1.f, 1.f, -1.f, 1.f, 0.f, 1.f, 1.f, 1.f, 1.f, + }; + m_quad_vb = device.create_buffer(BufferType::Vertex, sizeof(quad), quad); + + m_cam_ubo = device.create_buffer(BufferType::Uniform, 128); + m_disk_ubo = device.create_buffer(BufferType::Uniform, 32); + m_obj_ubo = device.create_buffer(BufferType::Uniform, 800); + m_sim_ubo = device.create_buffer(BufferType::Uniform, 16); + + std::vector obj(800, 0); + int num_objects = 1; std::memcpy(obj.data() + 0, &num_objects, 4); + float pos_radius[4] = { 0, 0, 0, SagA_rs }; std::memcpy(obj.data() + 16, pos_radius, 16); + float color[4] = { 0, 0, 0, 1 }; std::memcpy(obj.data() + 272, color, 16); + m_obj_ubo->update(obj.data(), obj.size()); + + { + PipelineDesc d; + d.shader = "geodesic"; + d.vertex_layout = { 16, { { 0, 2, 0 }, { 1, 2, 8 } } }; + d.resources = { + { ResourceKind::UniformBuffer, 0, "Camera" }, + { ResourceKind::UniformBuffer, 1, "Disk" }, + { ResourceKind::UniformBuffer, 2, "Objects" }, + { ResourceKind::UniformBuffer, 3, "Simulation" }, + { ResourceKind::Texture, 4, "u_HDRIEnvironment" }, + }; + d.topology = Topology::Triangles; + d.has_depth = false; + m_geo_pipeline = device.create_pipeline(d); + } + { + PipelineDesc d; + d.shader = "textured_quad"; + d.vertex_layout = { 16, { { 0, 2, 0 }, { 1, 2, 8 } } }; + d.resources = { { ResourceKind::Texture, 0, "u_ScreenTexture" } }; + d.topology = Topology::Triangles; + d.has_depth = true; + m_present_pipeline = device.create_pipeline(d); + } + + DONUT_INFO("BlackHoleRenderer ready ({}x{} moving / {}x{} settled)", + GEO_LO_W, GEO_LO_H, GEO_HI_W, GEO_HI_H); + return true; + } + + auto BlackHoleRenderer::render_geodesic(RHI::CommandList& cmd, const GeodesicView& view, + const BlackHoleParams& params, RHI::Texture* cubemap) -> void + { + CamUBO cam{}; + cam.pos = view.position; cam.right = view.right; cam.up = view.up; cam.fwd = view.forward; + cam.tan_half_fov = view.tan_half_fov; + cam.aspect = view.aspect; + cam.moving = view.moving ? 1u : 0u; + m_cam_ubo->update(&cam, sizeof(cam)); + + constexpr int kStepCeil = 15000; + SimUBO sim{}; + sim.steps_static = std::clamp(params.quality_steps, 1000, kStepCeil); + sim.steps_moving = sim.steps_static; + sim.early_exit = SettingsManager::get_early_exit_distance(); + sim.time = view.time; + m_sim_ubo->update(&sim, sizeof(sim)); + + float disk[8] = { + std::max(params.disk_inner_rs, 3.0f) * SagA_rs, + std::max(params.disk_outer_rs, params.disk_inner_rs + 0.5f) * SagA_rs, + std::max(params.turbulence, 0.0f), + SagA_rs * 0.1f, + std::max(params.brightness, 0.0f), + std::max(params.temperature, 1000.0f), + 0.0f, 0.0f, + }; + m_disk_ubo->update(disk, sizeof(disk)); + + RenderTarget* target = view.moving ? m_geo_lo.get() : m_geo_hi.get(); + m_last_target = target; + + cmd.begin_render_pass(target, glm::vec4(0, 0, 0, 1)); + cmd.set_viewport(0, 0, target->width(), target->height(), false); + cmd.bind_pipeline(m_geo_pipeline.get()); + cmd.bind_uniform(0, m_cam_ubo.get()); + cmd.bind_uniform(1, m_disk_ubo.get()); + cmd.bind_uniform(2, m_obj_ubo.get()); + cmd.bind_uniform(3, m_sim_ubo.get()); + cmd.bind_texture(4, cubemap); + cmd.bind_vertex_buffer(m_quad_vb.get()); + cmd.draw(6); + cmd.end_render_pass(); + } + + auto BlackHoleRenderer::blit(RHI::CommandList& cmd, int fb_width, int fb_height) -> void + { + if (!m_last_target) return; + cmd.set_viewport(0, 0, fb_width, fb_height, true); + cmd.bind_pipeline(m_present_pipeline.get()); + cmd.bind_texture(0, m_last_target->color_texture()); + cmd.bind_vertex_buffer(m_quad_vb.get()); + cmd.draw(6); + } +} diff --git a/src/rendering/black_hole_renderer.h b/src/rendering/black_hole_renderer.h new file mode 100644 index 0000000..563fa9b --- /dev/null +++ b/src/rendering/black_hole_renderer.h @@ -0,0 +1,46 @@ +#pragma once + +#include "rhi.h" +#include "renderer_backend.h" +#include + +namespace Donut +{ + struct GeodesicView + { + glm::vec3 position, right, up, forward; + float tan_half_fov = 1.0f; + float aspect = 16.0f / 9.0f; + bool moving = false; + float time = 0.0f; + }; + + class BlackHoleRenderer + { + public: + static constexpr int GEO_LO_W = 480, GEO_LO_H = 270; + static constexpr int GEO_HI_W = 960, GEO_HI_H = 540; + + auto init(RHI::Device& device) -> bool; + + auto render_geodesic(RHI::CommandList& cmd, const GeodesicView& view, + const BlackHoleParams& params, RHI::Texture* cubemap) -> void; + + auto blit(RHI::CommandList& cmd, int fb_width, int fb_height) -> void; + + private: + RHI::Device* m_device = nullptr; + + Ref m_geo_pipeline; + Ref m_geo_lo; + Ref m_geo_hi; + Ref m_quad_vb; + Ref m_cam_ubo; + Ref m_disk_ubo; + Ref m_obj_ubo; + Ref m_sim_ubo; + + Ref m_present_pipeline; + RHI::RenderTarget* m_last_target = nullptr; + }; +} diff --git a/src/rendering/framebuffer.cpp b/src/rendering/framebuffer.cpp deleted file mode 100644 index cad3919..0000000 --- a/src/rendering/framebuffer.cpp +++ /dev/null @@ -1,244 +0,0 @@ -#include "framebuffer.h" -#include "core/log.h" - -#include - -namespace Donut -{ - namespace Utils - { - static GLenum texture_target(bool multisampled) - { - return multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D; - } - - static void bind_texture(bool multisampled, uint32_t id) - { - glBindTexture(texture_target(multisampled), id); - } - - static void create_textures(bool multisampled, uint32_t* out_id, uint32_t count) - { - glGenTextures(count, out_id); - } - - static void attach_color_texture(uint32_t id, int samples, GLenum internal_format, GLenum format, uint32_t width, uint32_t height, int index) - { - bool multisampled = samples > 1; - if (multisampled) - { - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, internal_format, width, height, GL_FALSE); - } - else - { - GLenum type = (format == GL_RED_INTEGER) ? GL_INT : GL_UNSIGNED_BYTE; - glTexImage2D(GL_TEXTURE_2D, 0, internal_format, width, height, 0, format, type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0 + index, texture_target(multisampled), id, 0); - } - - static void attach_depth_texture(uint32_t id, int samples, GLenum format, GLenum attachment_type, uint32_t width, uint32_t height) - { - bool multisampled = samples > 1; - if (multisampled) - { - glTexImage2DMultisample(GL_TEXTURE_2D_MULTISAMPLE, samples, format, width, height, GL_FALSE); - } - else - { - GLenum depth_format = (format == GL_DEPTH24_STENCIL8) ? GL_DEPTH_STENCIL : GL_DEPTH_COMPONENT; - GLenum depth_type = (format == GL_DEPTH24_STENCIL8) ? GL_UNSIGNED_INT_24_8 : GL_FLOAT; - glTexImage2D(GL_TEXTURE_2D, 0, format, width, height, 0, depth_format, depth_type, nullptr); - - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_R, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } - - glFramebufferTexture2D(GL_FRAMEBUFFER, attachment_type, texture_target(multisampled), id, 0); - } - - static bool is_depth_format(FramebufferTextureFormat format) - { - switch (format) - { - case FramebufferTextureFormat::DEPTH24STENCIL8: return true; - } - return false; - } - - static GLenum donut_fb_texture_format_to_gl(FramebufferTextureFormat format) - { - switch (format) - { - case FramebufferTextureFormat::RGBA8: return GL_RGBA8; - case FramebufferTextureFormat::RED_INTEGER: return GL_RED_INTEGER; - } - - return 0; - } - } - - Framebuffer::Framebuffer(const FramebufferSpecification& spec) - : m_specification(spec) - { - for (auto spec : m_specification.attachments.attachments) - { - if (!Utils::is_depth_format(spec.texture_format)) - m_color_attachment_specifications.emplace_back(spec); - else - m_depth_attachment_specification = spec; - } - - invalidate(); - } - - Framebuffer::~Framebuffer() - { - glDeleteFramebuffers(1, &m_renderer_id); - glDeleteTextures(static_cast(m_color_attachments.size()), m_color_attachments.data()); - glDeleteTextures(1, &m_depth_attachment); - } - - auto Framebuffer::invalidate() -> void - { - if (m_renderer_id) - { - glDeleteFramebuffers(1, &m_renderer_id); - glDeleteTextures(static_cast(m_color_attachments.size()), m_color_attachments.data()); - glDeleteTextures(1, &m_depth_attachment); - - m_color_attachments.clear(); - m_depth_attachment = 0; - } - - glGenFramebuffers(1, &m_renderer_id); - glBindFramebuffer(GL_FRAMEBUFFER, m_renderer_id); - - bool multisample = m_specification.Samples > 1; - - if (m_color_attachment_specifications.size()) - { - m_color_attachments.resize(m_color_attachment_specifications.size()); - Utils::create_textures(multisample, m_color_attachments.data(), static_cast(m_color_attachments.size())); - - for (size_t i = 0; i < m_color_attachments.size(); i++) - { - Utils::bind_texture(multisample, m_color_attachments[i]); - switch (m_color_attachment_specifications[i].texture_format) - { - case FramebufferTextureFormat::RGBA8: - Utils::attach_color_texture(m_color_attachments[i], m_specification.Samples, GL_RGBA8, GL_RGBA, m_specification.Width, m_specification.Height, static_cast(i)); - break; - case FramebufferTextureFormat::RED_INTEGER: - Utils::attach_color_texture(m_color_attachments[i], m_specification.Samples, GL_R32I, GL_RED_INTEGER, m_specification.Width, m_specification.Height, static_cast(i)); - break; - } - } - } - - if (m_depth_attachment_specification.texture_format != FramebufferTextureFormat::None) - { - Utils::create_textures(multisample, &m_depth_attachment, 1); - Utils::bind_texture(multisample, m_depth_attachment); - switch (m_depth_attachment_specification.texture_format) - { - case FramebufferTextureFormat::DEPTH24STENCIL8: - Utils::attach_depth_texture(m_depth_attachment, m_specification.Samples, GL_DEPTH24_STENCIL8, GL_DEPTH_STENCIL_ATTACHMENT, m_specification.Width, m_specification.Height); - break; - } - } - - if (m_color_attachments.size() > 1) - { - GLenum buffers[4] = { GL_COLOR_ATTACHMENT0, GL_COLOR_ATTACHMENT1, GL_COLOR_ATTACHMENT2, GL_COLOR_ATTACHMENT3 }; - glDrawBuffers(static_cast(m_color_attachments.size()), buffers); - } - else if (m_color_attachments.empty()) - glDrawBuffer(GL_NONE); - - if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) - { - GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER); - switch (status) - { - case GL_FRAMEBUFFER_UNDEFINED: - DONUT_ERROR("Framebuffer is undefined"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT: - DONUT_ERROR("Framebuffer has incomplete attachment"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: - DONUT_ERROR("Framebuffer is missing attachment"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_DRAW_BUFFER: - DONUT_ERROR("Framebuffer has incomplete draw buffer"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_READ_BUFFER: - DONUT_ERROR("Framebuffer has incomplete read buffer"); - break; - case GL_FRAMEBUFFER_UNSUPPORTED: - DONUT_ERROR("Framebuffer format is unsupported"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: - DONUT_ERROR("Framebuffer has incomplete multisample"); - break; - case GL_FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: - DONUT_ERROR("Framebuffer has incomplete layer targets"); - break; - default: - DONUT_ERROR("Framebuffer is incomplete (unknown error: {})", status); - break; - } - } - - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - auto Framebuffer::bind() -> void - { - glBindFramebuffer(GL_FRAMEBUFFER, m_renderer_id); - glViewport(0, 0, m_specification.Width, m_specification.Height); - } - - auto Framebuffer::unbind() -> void - { - glBindFramebuffer(GL_FRAMEBUFFER, 0); - } - - auto Framebuffer::resize(uint32_t width, uint32_t height) -> void - { - m_specification.Width = width; - m_specification.Height = height; - - invalidate(); - } - - auto Framebuffer::read_pixel(uint32_t attachment_index, int x, int y) -> int - { - glReadBuffer(GL_COLOR_ATTACHMENT0 + attachment_index); - int pixel_data; - glReadPixels(x, y, 1, 1, GL_RED_INTEGER, GL_INT, &pixel_data); - return pixel_data; - } - - auto Framebuffer::clear_attachment(uint32_t attachment_index, int value) -> void - { - glBindFramebuffer(GL_FRAMEBUFFER, m_renderer_id); - glClearBufferiv(GL_COLOR, static_cast(attachment_index), &value); - } - - auto Framebuffer::create(const FramebufferSpecification& spec) -> Ref - { - return create_ref(spec); - } -}; diff --git a/src/rendering/framebuffer.h b/src/rendering/framebuffer.h deleted file mode 100644 index cf1fbef..0000000 --- a/src/rendering/framebuffer.h +++ /dev/null @@ -1,80 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include "texture.h" - -#include - -namespace Donut -{ - enum class FramebufferTextureFormat - { - None = 0, - - RGBA8, - RED_INTEGER, - - DEPTH24STENCIL8, - - Depth = DEPTH24STENCIL8 - }; - - struct FramebufferTextureSpecification - { - FramebufferTextureSpecification() = default; - FramebufferTextureSpecification(FramebufferTextureFormat format) - : texture_format(format) {} - - FramebufferTextureFormat texture_format = FramebufferTextureFormat::None; - }; - - struct FramebufferAttachmentSpecification - { - FramebufferAttachmentSpecification() = default; - FramebufferAttachmentSpecification(std::initializer_list attachments) - : attachments(attachments) {} - - std::vector attachments; - }; - - struct FramebufferSpecification - { - uint32_t Width = 0, Height = 0; - FramebufferAttachmentSpecification attachments; - uint32_t Samples = 1; - - bool SwapChainTarget = false; - }; - - class Framebuffer - { - public: - Framebuffer(const FramebufferSpecification& spec); - ~Framebuffer(); - - auto bind() -> void; - auto unbind() -> void; - - auto resize(uint32_t width, uint32_t height) -> void; - auto read_pixel(uint32_t attachment_index, int x, int y) -> int; - - auto clear_attachment(uint32_t attachment_index, int value) -> void; - auto get_color_attachment_renderer_id(uint32_t index = 0) const -> uint32_t { return m_color_attachments[index]; } - - auto get_specification() const -> const FramebufferSpecification& { return m_specification; } - - static auto create(const FramebufferSpecification& spec) -> Ref; - - private: - auto invalidate() -> void; - - uint32_t m_renderer_id = 0; - FramebufferSpecification m_specification; - - std::vector m_color_attachment_specifications; - FramebufferTextureSpecification m_depth_attachment_specification = FramebufferTextureFormat::None; - - std::vector m_color_attachments; - uint32_t m_depth_attachment = 0; - }; -}; diff --git a/src/rendering/index_buffer.cpp b/src/rendering/index_buffer.cpp deleted file mode 100644 index 38abe49..0000000 --- a/src/rendering/index_buffer.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "index_buffer.h" - -#include - -namespace Donut -{ - IndexBuffer::IndexBuffer(const uint32_t* indices, uint32_t count) - : m_count(count) - { - glGenBuffers(1, &m_renderer_id); - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_renderer_id); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, count * sizeof(uint32_t), indices, GL_STATIC_DRAW); - } - - IndexBuffer::~IndexBuffer() - { - glDeleteBuffers(1, &m_renderer_id); - } - - auto IndexBuffer::bind() const -> void - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_renderer_id); - } - - auto IndexBuffer::unbind() const -> void - { - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); - } - - auto IndexBuffer::create(const uint32_t* indices, uint32_t count) -> IndexBuffer* - { - return new IndexBuffer(indices, count); - } -}; diff --git a/src/rendering/index_buffer.h b/src/rendering/index_buffer.h deleted file mode 100644 index 0b1b2b6..0000000 --- a/src/rendering/index_buffer.h +++ /dev/null @@ -1,23 +0,0 @@ -#pragma once - -#include - -namespace Donut -{ - class IndexBuffer - { - public: - IndexBuffer(const uint32_t* indices, uint32_t count); - ~IndexBuffer(); - - auto bind() const -> void; - auto unbind() const -> void; - auto get_count() const -> uint32_t { return m_count; } - - static auto create(const uint32_t* indices, uint32_t count) -> IndexBuffer*; - - private: - uint32_t m_renderer_id = 0; - uint32_t m_count = 0; - }; -}; diff --git a/src/rendering/render_api.h b/src/rendering/render_api.h new file mode 100644 index 0000000..94ab755 --- /dev/null +++ b/src/rendering/render_api.h @@ -0,0 +1,21 @@ +#pragma once + +namespace Donut +{ + class RendererAPI + { + public: + enum class API + { + None = 0, + OpenGL = 1, + Vulkan = 2, + }; + + static auto get_api() -> API { return s_api; } + static auto set_api(API api) -> void { s_api = api; } + + private: + inline static API s_api = API::None; + }; +} diff --git a/src/rendering/renderer.cpp b/src/rendering/renderer.cpp deleted file mode 100644 index 5ad8610..0000000 --- a/src/rendering/renderer.cpp +++ /dev/null @@ -1,167 +0,0 @@ -#include "renderer.h" - -#include "core/log.h" - -#include -#include -#include - -namespace Donut -{ - RendererAPI::API RendererAPI::s_api = RendererAPI::API::OpenGL; - - auto RendererAPI::create() -> Scope - { - return create_scope(); - } - - auto RendererAPI::init() -> void - { - if (!glfwGetCurrentContext()) - { - DONUT_ERROR("No OpenGL context is current! Cannot initialize GLAD."); - return; - } - - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - DONUT_ERROR("Failed to initialize GLAD!"); - return; - } - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - } - - auto RendererAPI::set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) -> void - { - glViewport(x, y, width, height); - } - - auto RendererAPI::set_clear_color(const glm::vec4& color) -> void - { - glClearColor(color.r, color.g, color.b, color.a); - } - - auto RendererAPI::clear() -> void - { - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - } - - auto RendererAPI::enable_depth_test() -> void - { - glEnable(GL_DEPTH_TEST); - } - - auto RendererAPI::disable_depth_test() -> void - { - glDisable(GL_DEPTH_TEST); - } - - auto RendererAPI::set_face_culling(bool enabled) -> void - { - if (enabled) - { - glEnable(GL_CULL_FACE); - glCullFace(GL_BACK); - glFrontFace(GL_CCW); - } - else - glDisable(GL_CULL_FACE); - } - - auto RendererAPI::enable_blending() -> void - { - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - } - - auto RendererAPI::disable_blending() -> void - { - glDisable(GL_BLEND); - } - - auto RendererAPI::draw_indexed(const Ref& vertex_array, uint32_t index_count) -> void - { - uint32_t count = index_count ? index_count : vertex_array->get_index_buffer()->get_count(); - glDrawElements(GL_TRIANGLES, count, GL_UNSIGNED_INT, nullptr); - glBindTexture(GL_TEXTURE_2D, 0); - } - - auto RendererAPI::draw_arrays(uint32_t vertex_count, uint32_t first) -> void - { - glDrawArrays(GL_TRIANGLES, first, vertex_count); - } - - auto RendererAPI::draw_lines(const Ref& vertex_array, uint32_t index_count) -> void - { - uint32_t count = index_count ? index_count : vertex_array->get_index_buffer()->get_count(); - glDrawElements(GL_LINES, count, GL_UNSIGNED_INT, nullptr); - } - - auto RendererAPI::bind_texture(uint32_t texture_id, uint32_t slot) -> void - { - glActiveTexture(GL_TEXTURE0 + slot); - glBindTexture(GL_TEXTURE_2D, texture_id); - } - - auto RendererAPI::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) -> void - { - if (glBindImageTexture == nullptr) - return; - glBindImageTexture(slot, texture_id, 0, GL_FALSE, 0, - read_only ? GL_READ_ONLY : GL_WRITE_ONLY, GL_RGBA8); - } - - auto RendererAPI::read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t format, uint32_t type, void* pixels) -> void - { - glReadPixels(x, y, width, height, format, type, pixels); - } - - auto Renderer::init() -> void - { - RenderCommand::init(); - RenderCommand::enable_depth_test(); - } - - auto Renderer::shutdown() -> void - { - } - - auto Renderer::on_window_resize(uint32_t width, uint32_t height) -> void - { - RenderCommand::set_viewport(0, 0, width, height); - } - - auto Renderer::submit(const Ref& shader, - const Ref& vertex_array, - const glm::mat4& transform, - const glm::mat4& view_projection) -> void - { - shader->bind(); - shader->set_mat4("u_ViewProjection", view_projection); - shader->set_mat4("u_Transform", transform); - - vertex_array->bind(); - RenderCommand::draw_indexed(vertex_array); - } - - Scope RenderCommand::s_renderer_api = RendererAPI::create(); - - auto Renderer::set_clear_color(const glm::vec4& color) -> void - { - RenderCommand::set_clear_color(color); - } - - auto Renderer::clear() -> void - { - RenderCommand::clear(); - } -}; diff --git a/src/rendering/renderer.h b/src/rendering/renderer.h deleted file mode 100644 index 632753a..0000000 --- a/src/rendering/renderer.h +++ /dev/null @@ -1,153 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include "vertex_array.h" -#include "shader.h" -#include "framebuffer.h" - -#include - -namespace Donut -{ - class RendererAPI - { - public: - enum class API - { - None = 0, - OpenGL = 1, - Vulkan = 2, - }; - - public: - RendererAPI() = default; - ~RendererAPI() = default; - - auto init() -> void; - auto set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) -> void; - auto set_clear_color(const glm::vec4& color) -> void; - auto clear() -> void; - auto enable_depth_test() -> void; - auto disable_depth_test() -> void; - auto set_face_culling(bool enabled) -> void; - auto enable_blending() -> void; - auto disable_blending() -> void; - - auto draw_indexed(const Ref& vertex_array, uint32_t index_count = 0) -> void; - auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void; - auto draw_lines(const Ref& vertex_array, uint32_t index_count = 0) -> void; - auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void; - auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void; - auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t format, uint32_t type, void* pixels) -> void; - - inline static auto get_api() -> API { return s_api; } - inline static auto set_api(API api) -> void { s_api = api; } - static auto create() -> Scope; - - private: - static API s_api; - }; - - class RenderCommand - { - public: - inline static auto init() -> void - { - s_renderer_api->init(); - } - - inline static auto set_viewport(uint32_t x, uint32_t y, uint32_t width, uint32_t height) -> void - { - s_renderer_api->set_viewport(x, y, width, height); - } - - inline static auto set_clear_color(const glm::vec4& color) -> void - { - s_renderer_api->set_clear_color(color); - } - - inline static auto clear() -> void - { - s_renderer_api->clear(); - } - - inline static auto enable_depth_test() -> void - { - s_renderer_api->enable_depth_test(); - } - - inline static auto disable_depth_test() -> void - { - s_renderer_api->disable_depth_test(); - } - - inline static auto set_face_culling(bool enabled) -> void - { - s_renderer_api->set_face_culling(enabled); - } - - inline static auto enable_blending() -> void - { - s_renderer_api->enable_blending(); - } - - inline static auto disable_blending() -> void - { - s_renderer_api->disable_blending(); - } - - inline static auto draw_indexed(const Ref& vertex_array, uint32_t index_count = 0) -> void - { - s_renderer_api->draw_indexed(vertex_array, index_count); - } - - inline static auto draw_arrays(uint32_t vertex_count, uint32_t first = 0) -> void - { - s_renderer_api->draw_arrays(vertex_count, first); - } - - inline static auto draw_lines(const Ref& vertex_array, uint32_t index_count = 0) -> void - { - s_renderer_api->draw_lines(vertex_array, index_count); - } - - inline static auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void - { - s_renderer_api->bind_texture(texture_id, slot); - } - - inline static auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void - { - s_renderer_api->bind_image_texture(texture_id, slot, read_only); - } - - inline static auto read_pixels(uint32_t x, uint32_t y, uint32_t width, uint32_t height, - uint32_t format, uint32_t type, void* pixels) -> void - { - s_renderer_api->read_pixels(x, y, width, height, format, type, pixels); - } - - private: - static Scope s_renderer_api; - }; - - class Renderer - { - public: - static auto init() -> void; - static auto shutdown() -> void; - - static auto on_window_resize(uint32_t width, uint32_t height) -> void; - - static auto submit(const Ref& shader, - const Ref& vertex_array, - const glm::mat4& transform, - const glm::mat4& view_projection) -> void; - - static auto set_clear_color(const glm::vec4& color) -> void; - static auto clear() -> void; - - inline static auto get_api() -> RendererAPI::API { return RendererAPI::get_api(); } - }; -}; diff --git a/src/rendering/renderer_backend.h b/src/rendering/renderer_backend.h index 51da214..d64a46b 100644 --- a/src/rendering/renderer_backend.h +++ b/src/rendering/renderer_backend.h @@ -1,9 +1,6 @@ #pragma once #include -#include -#include -#include namespace Donut { @@ -24,33 +21,4 @@ namespace Donut int quality_steps = 15000; float fov_degrees = 60.0f; }; - - class RendererBackend - { - public: - virtual ~RendererBackend() = default; - - virtual auto init(void* glfwWindow, int width, int height) -> bool = 0; - - virtual auto init_ui() -> bool = 0; - virtual auto shutdown() -> void = 0; - virtual auto resize(int width, int height) -> void = 0; - - virtual auto draw_frame(const glm::vec4& clear_color, - const std::function& build_ui) -> void = 0; - - virtual auto set_scene_mode(bool enabled) -> void = 0; - virtual auto is_scene_mode() const -> bool = 0; - virtual auto set_free_fly(bool enabled) -> void = 0; - virtual auto is_free_fly() const -> bool = 0; - virtual auto reset_camera() -> void = 0; - - virtual auto set_hdri(const std::string& path) -> void = 0; - virtual auto current_hdri() const -> const std::string& = 0; - virtual auto scene_objects() -> std::vector& = 0; - virtual auto set_selected_object(int index) -> void = 0; - virtual auto black_hole_params() -> BlackHoleParams& = 0; - - virtual auto device_name() const -> const std::string& = 0; - }; } diff --git a/src/rendering/rhi.h b/src/rendering/rhi.h new file mode 100644 index 0000000..1a61420 --- /dev/null +++ b/src/rendering/rhi.h @@ -0,0 +1,107 @@ +#pragma once + +#include "core/memory.h" +#include +#include +#include +#include +#include + +namespace Donut::RHI +{ + enum class Format + { + RGBA8, + RGBA16F, + D32, + }; + + enum class BufferType { Vertex, Index, Uniform }; + enum class Topology { Triangles, Lines }; + enum class CullMode { None, Back, Front }; + enum class BlendMode { Opaque, AlphaBlend }; + enum class CompareOp { Always, Less, LessEqual }; + enum class Filter { Nearest, Linear }; + + struct VertexAttribute { uint32_t location; uint32_t components; uint32_t offset; }; + struct VertexLayout { uint32_t stride = 0; std::vector attributes; }; + + enum class ResourceKind { UniformBuffer, Texture }; + struct ResourceSlot { ResourceKind kind; uint32_t binding; std::string name; }; + + class Buffer { public: virtual ~Buffer() = default; virtual auto update(const void* data, size_t size) -> void = 0; }; + class Texture { public: virtual ~Texture() = default; }; + class Pipeline{ public: virtual ~Pipeline() = default; }; + + class RenderTarget + { + public: + virtual ~RenderTarget() = default; + virtual auto width() const -> int = 0; + virtual auto height() const -> int = 0; + virtual auto color_texture() -> Texture* = 0; + }; + + struct PipelineDesc + { + std::string shader; + VertexLayout vertex_layout; + std::vector resources; + Topology topology = Topology::Triangles; + CullMode cull = CullMode::None; + BlendMode blend = BlendMode::Opaque; + bool depth_test = false; + bool depth_write = false; + CompareOp depth_op = CompareOp::Less; + Format color_format = Format::RGBA8; + bool has_depth = false; + }; + + class CommandList + { + public: + virtual ~CommandList() = default; + + virtual auto begin_render_pass(RenderTarget* target, const glm::vec4& clear) -> void = 0; + virtual auto end_render_pass() -> void = 0; + + virtual auto bind_pipeline(Pipeline* pipeline) -> void = 0; + virtual auto set_viewport(int x, int y, int w, int h, bool flip_y = false) -> void = 0; + + virtual auto bind_uniform(uint32_t binding, Buffer* ubo) -> void = 0; + virtual auto bind_texture(uint32_t binding, Texture* texture) -> void = 0; + + virtual auto bind_vertex_buffer(Buffer* vb) -> void = 0; + virtual auto bind_index_buffer(Buffer* ib) -> void = 0; + + virtual auto draw(uint32_t vertex_count) -> void = 0; + virtual auto draw_indexed(uint32_t index_count) -> void = 0; + }; + + class Device + { + public: + virtual ~Device() = default; + + virtual auto init(void* glfwWindow, int width, int height) -> bool = 0; + virtual auto shutdown() -> void = 0; + virtual auto resize(int width, int height) -> void = 0; + virtual auto wait_idle() -> void = 0; + + virtual auto create_buffer(BufferType type, size_t size, const void* data = nullptr) -> Ref = 0; + virtual auto create_texture(int width, int height, Format format, Filter filter, const void* data = nullptr) -> Ref = 0; + virtual auto create_cubemap_from_hdri(const std::string& equirect_path) -> Ref = 0; + virtual auto create_render_target(int width, int height, Format color, bool with_depth, + Filter sample_filter = Filter::Linear, int mip_levels = 1) -> Ref = 0; + virtual auto create_pipeline(const PipelineDesc& desc) -> Ref = 0; + + virtual auto begin_frame(const glm::vec4& clear) -> CommandList* = 0; + virtual auto end_frame() -> void = 0; + + virtual auto init_imgui() -> void = 0; + virtual auto imgui_new_frame() -> void = 0; + virtual auto imgui_render(CommandList& swapchain_cmds) -> void = 0; + + virtual auto device_name() const -> const std::string& = 0; + }; +} diff --git a/src/rendering/rhi/rhi.h b/src/rendering/rhi/rhi.h deleted file mode 100644 index b32df14..0000000 --- a/src/rendering/rhi/rhi.h +++ /dev/null @@ -1,108 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include -#include -#include -#include -#include - -namespace Donut::rhi -{ - enum class Format - { - RGBA8, - RGBA16F, - D32, - }; - - enum class BufferType { Vertex, Index, Uniform }; - enum class Topology { Triangles, Lines }; - enum class CullMode { None, Back, Front }; - enum class BlendMode { Opaque, AlphaBlend }; - enum class CompareOp { Always, Less, LessEqual }; - enum class Filter { Nearest, Linear }; - - struct VertexAttribute { uint32_t location; uint32_t components; uint32_t offset; }; - struct VertexLayout { uint32_t stride = 0; std::vector attributes; }; - - enum class ResourceKind { UniformBuffer, Texture }; - struct ResourceSlot { ResourceKind kind; uint32_t binding; }; - - class Buffer { public: virtual ~Buffer() = default; virtual auto update(const void* data, size_t size) -> void = 0; }; - class Texture { public: virtual ~Texture() = default; }; - class Pipeline{ public: virtual ~Pipeline() = default; }; - - class RenderTarget - { - public: - virtual ~RenderTarget() = default; - virtual auto width() const -> int = 0; - virtual auto height() const -> int = 0; - virtual auto color_texture() -> Texture* = 0; - }; - - struct PipelineDesc - { - std::string shader; - VertexLayout vertex_layout; - std::vector resources; - Topology topology = Topology::Triangles; - CullMode cull = CullMode::None; - BlendMode blend = BlendMode::Opaque; - bool depth_test = false; - bool depth_write = false; - CompareOp depth_op = CompareOp::Less; - Format color_format = Format::RGBA8; - bool has_depth = false; - }; - - class CommandList - { - public: - virtual ~CommandList() = default; - - virtual auto begin_render_pass(RenderTarget* target, const glm::vec4& clear) -> void = 0; - virtual auto end_render_pass() -> void = 0; - - virtual auto bind_pipeline(Pipeline* pipeline) -> void = 0; - virtual auto set_viewport(int x, int y, int w, int h, bool flip_y = false) -> void = 0; - - virtual auto bind_uniform(uint32_t binding, Buffer* ubo) -> void = 0; - virtual auto bind_texture(uint32_t binding, Texture* texture) -> void = 0; - - virtual auto bind_vertex_buffer(Buffer* vb) -> void = 0; - virtual auto bind_index_buffer(Buffer* ib) -> void = 0; - - virtual auto draw(uint32_t vertex_count) -> void = 0; - virtual auto draw_indexed(uint32_t index_count) -> void = 0; - }; - - class Device - { - public: - virtual ~Device() = default; - - virtual auto init(void* glfwWindow, int width, int height) -> bool = 0; - virtual auto shutdown() -> void = 0; - virtual auto resize(int width, int height) -> void = 0; - virtual auto wait_idle() -> void = 0; - - virtual auto create_buffer(BufferType type, size_t size, const void* data = nullptr) -> Ref = 0; - virtual auto create_texture(int width, int height, Format format, Filter filter, const void* data = nullptr) -> Ref = 0; - virtual auto create_cubemap_from_hdri(const std::string& equirect_path) -> Ref = 0; - virtual auto create_render_target(int width, int height, Format color, bool with_depth, - Filter sample_filter = Filter::Linear, int mip_levels = 1) -> Ref = 0; - virtual auto create_pipeline(const PipelineDesc& desc) -> Ref = 0; - - virtual auto begin_frame(const glm::vec4& clear) -> CommandList* = 0; - virtual auto end_frame() -> void = 0; - virtual auto record_offscreen(const std::function& record) -> void = 0; - - virtual auto init_imgui() -> void = 0; - virtual auto imgui_new_frame() -> void = 0; - virtual auto imgui_render(CommandList& swapchain_cmds) -> void = 0; - - virtual auto device_name() const -> const std::string& = 0; - }; -} diff --git a/src/rendering/scene_renderer.cpp b/src/rendering/scene_renderer.cpp new file mode 100644 index 0000000..076f6ba --- /dev/null +++ b/src/rendering/scene_renderer.cpp @@ -0,0 +1,202 @@ +#include "scene_renderer.h" + +#include "core/log.h" + +#include +#include +#include +#include +#include + +namespace Donut +{ + using namespace RHI; + + namespace + { + struct GridUBO { + glm::mat4 view_projection; + glm::mat4 transform; + float grid_size; float p0[3]; + glm::vec3 grid_color; + float grid_alpha; + glm::vec3 camera_pos; + float p1; + }; + static_assert(sizeof(GridUBO) == 176, "GridUBO std140 layout mismatch"); + + struct SphereUBO { + glm::mat4 view_projection; + glm::mat4 transform; + glm::vec3 color; float specular; + float emission; float p0[3]; + glm::vec3 light_pos; float p1; + glm::vec3 camera_pos; int is_selected; + glm::vec3 outline_color; float outline_width; + }; + static_assert(sizeof(SphereUBO) == 208, "SphereUBO std140 layout mismatch"); + + struct SkyboxUBO { glm::mat4 projection; glm::mat4 view; }; + static_assert(sizeof(SkyboxUBO) == 128, "SkyboxUBO std140 layout mismatch"); + } + + auto SceneRenderer::init(RHI::Device& device) -> bool + { + m_device = &device; + + { + std::vector lines; + const int N = 50; + for (int i = -N; i <= N; ++i) + { + lines.push_back({ (float)i, 0.0f, (float)-N }); + lines.push_back({ (float)i, 0.0f, (float) N }); + lines.push_back({ (float)-N, 0.0f, (float)i }); + lines.push_back({ (float) N, 0.0f, (float)i }); + } + m_grid_vertex_count = (int)lines.size(); + m_grid_vb = device.create_buffer(BufferType::Vertex, lines.size() * sizeof(glm::vec3), lines.data()); + m_grid_ubo = device.create_buffer(BufferType::Uniform, sizeof(GridUBO)); + + PipelineDesc d; + d.shader = "grid"; + d.vertex_layout = { sizeof(glm::vec3), { { 0, 3, 0 } } }; + d.resources = { { ResourceKind::UniformBuffer, 0, "GridU" } }; + d.topology = Topology::Lines; + d.blend = BlendMode::AlphaBlend; + d.depth_test = true; d.depth_write = false; d.depth_op = CompareOp::LessEqual; + d.has_depth = true; + m_grid_pipeline = device.create_pipeline(d); + } + + { + std::vector sv; std::vector si; + const int RINGS = 24, SECTORS = 48; + for (int r = 0; r <= RINGS; ++r) + { + float phi = (float)std::numbers::pi * r / RINGS; + for (int s = 0; s <= SECTORS; ++s) + { + float theta = 2.0f * (float)std::numbers::pi * s / SECTORS; + float x = sinf(phi) * cosf(theta), y = cosf(phi), z = sinf(phi) * sinf(theta); + sv.push_back(x); sv.push_back(y); sv.push_back(z); + sv.push_back(x); sv.push_back(y); sv.push_back(z); + } + } + for (int r = 0; r < RINGS; ++r) + for (int s = 0; s < SECTORS; ++s) + { + uint32_t a = r * (SECTORS + 1) + s, b = a + SECTORS + 1; + si.push_back(a); si.push_back(b); si.push_back(a + 1); + si.push_back(b); si.push_back(b + 1); si.push_back(a + 1); + } + m_sphere_index_count = (int)si.size(); + m_sphere_vb = device.create_buffer(BufferType::Vertex, sv.size() * sizeof(float), sv.data()); + m_sphere_ib = device.create_buffer(BufferType::Index, si.size() * sizeof(uint32_t), si.data()); + + PipelineDesc d; + d.shader = "sphere"; + d.vertex_layout = { 6 * sizeof(float), { { 0, 3, 0 }, { 1, 3, 3 * sizeof(float) } } }; + d.resources = { { ResourceKind::UniformBuffer, 0, "SphereU" }, + { ResourceKind::Texture, 1, "u_HDRIEnvironment" } }; + d.topology = Topology::Triangles; + d.depth_test = true; d.depth_write = true; d.depth_op = CompareOp::Less; + d.has_depth = true; + m_sphere_pipeline = device.create_pipeline(d); + } + + { + const float cube[] = { + -1,-1,-1, 1,-1,-1, 1, 1,-1, 1, 1,-1, -1, 1,-1, -1,-1,-1, + -1,-1, 1, 1,-1, 1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1,-1, 1, + -1, 1, 1, -1, 1,-1, -1,-1,-1, -1,-1,-1, -1,-1, 1, -1, 1, 1, + 1, 1, 1, 1, 1,-1, 1,-1,-1, 1,-1,-1, 1,-1, 1, 1, 1, 1, + -1,-1,-1, 1,-1,-1, 1,-1, 1, 1,-1, 1, -1,-1, 1, -1,-1,-1, + -1, 1,-1, 1, 1,-1, 1, 1, 1, 1, 1, 1, -1, 1, 1, -1, 1,-1 + }; + m_skybox_vb = device.create_buffer(BufferType::Vertex, sizeof(cube), cube); + m_skybox_ubo = device.create_buffer(BufferType::Uniform, sizeof(SkyboxUBO)); + + PipelineDesc d; + d.shader = "skybox"; + d.vertex_layout = { 3 * sizeof(float), { { 0, 3, 0 } } }; + d.resources = { { ResourceKind::UniformBuffer, 0, "SkyboxU" }, + { ResourceKind::Texture, 1, "u_Skybox" } }; + d.topology = Topology::Triangles; + d.depth_test = false; d.depth_write = false; + d.has_depth = true; + m_skybox_pipeline = device.create_pipeline(d); + } + + DONUT_INFO("SceneRenderer ready ({} grid verts, {} sphere indices, skybox)", + m_grid_vertex_count, m_sphere_index_count); + return true; + } + + auto SceneRenderer::render(RHI::CommandList& cmd, const CameraView& cam, + const std::vector& objects, int selected, + RHI::Texture* cubemap) -> void + { + cmd.set_viewport(0, 0, cam.fb_width, cam.fb_height, true); + + glm::mat4 vp = cam.projection * cam.view; + + { + SkyboxUBO sky{}; + sky.projection = cam.projection; + sky.view = glm::mat4(glm::mat3(cam.view)); + m_skybox_ubo->update(&sky, sizeof(sky)); + cmd.bind_pipeline(m_skybox_pipeline.get()); + cmd.bind_uniform(0, m_skybox_ubo.get()); + cmd.bind_texture(1, cubemap); + cmd.bind_vertex_buffer(m_skybox_vb.get()); + cmd.draw(36); + } + + { + int count = std::min((int)objects.size(), MAX_OBJECTS); + while ((int)m_sphere_ubos.size() < count) + m_sphere_ubos.push_back(m_device->create_buffer(BufferType::Uniform, sizeof(SphereUBO))); + + cmd.bind_pipeline(m_sphere_pipeline.get()); + for (int i = 0; i < count; ++i) + { + const SceneObject& o = objects[i]; + SphereUBO s{}; + s.view_projection = vp; + s.transform = glm::translate(glm::mat4(1.0f), o.position) + * glm::scale(glm::mat4(1.0f), glm::vec3(o.radius)); + s.color = o.color; + s.specular = 0.6f; + s.emission = 0.0f; + s.light_pos = glm::vec3(10.0f, 20.0f, 10.0f); + s.camera_pos = cam.position; + s.is_selected = (i == selected) ? 1 : 0; + s.outline_color = glm::vec3(1.0f, 1.0f, 0.0f); + s.outline_width = 0.15f; + m_sphere_ubos[i]->update(&s, sizeof(s)); + + cmd.bind_uniform(0, m_sphere_ubos[i].get()); + cmd.bind_texture(1, cubemap); + cmd.bind_vertex_buffer(m_sphere_vb.get()); + cmd.bind_index_buffer(m_sphere_ib.get()); + cmd.draw_indexed(m_sphere_index_count); + } + } + + { + GridUBO g{}; + g.view_projection = vp; + g.transform = glm::mat4(1.0f); + g.grid_size = 50.0f; + g.grid_color = glm::vec3(0.55f, 0.55f, 0.6f); + g.grid_alpha = 0.75f; + g.camera_pos = cam.position; + m_grid_ubo->update(&g, sizeof(g)); + cmd.bind_pipeline(m_grid_pipeline.get()); + cmd.bind_uniform(0, m_grid_ubo.get()); + cmd.bind_vertex_buffer(m_grid_vb.get()); + cmd.draw(m_grid_vertex_count); + } + } +} diff --git a/src/rendering/scene_renderer.h b/src/rendering/scene_renderer.h new file mode 100644 index 0000000..1f16afc --- /dev/null +++ b/src/rendering/scene_renderer.h @@ -0,0 +1,48 @@ +#pragma once + +#include "rhi.h" +#include "renderer_backend.h" +#include +#include + +namespace Donut +{ + struct CameraView + { + glm::mat4 view; + glm::mat4 projection; + glm::vec3 position; + int fb_width = 1; + int fb_height = 1; + }; + + class SceneRenderer + { + public: + auto init(RHI::Device& device) -> bool; + + auto render(RHI::CommandList& cmd, const CameraView& cam, + const std::vector& objects, int selected, + RHI::Texture* cubemap) -> void; + + private: + static constexpr int MAX_OBJECTS = 64; + + RHI::Device* m_device = nullptr; + + Ref m_grid_pipeline; + Ref m_grid_vb; + Ref m_grid_ubo; + int m_grid_vertex_count = 0; + + Ref m_sphere_pipeline; + Ref m_sphere_vb; + Ref m_sphere_ib; + int m_sphere_index_count = 0; + std::vector> m_sphere_ubos; + + Ref m_skybox_pipeline; + Ref m_skybox_vb; + Ref m_skybox_ubo; + }; +} diff --git a/src/rendering/texture_manager.cpp b/src/rendering/texture_manager.cpp deleted file mode 100644 index 3afba0d..0000000 --- a/src/rendering/texture_manager.cpp +++ /dev/null @@ -1,34 +0,0 @@ -#include "texture_manager.h" -#include "renderer.h" - -#include - -namespace Donut -{ - auto TextureManager::create_texture(uint32_t width, uint32_t height) -> Ref - { - return create_ref(width, height); - } - - auto TextureManager::bind_texture(uint32_t texture_id, uint32_t slot) -> void - { - RenderCommand::bind_texture(texture_id, slot); - } - - auto TextureManager::bind_image_texture(uint32_t texture_id, uint32_t slot, bool read_only) -> void - { - RenderCommand::bind_image_texture(texture_id, slot, read_only); - } - - auto TextureManager::set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height) -> void - { - glBindTexture(GL_TEXTURE_2D, texture_id); - glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, data); - } - - auto TextureManager::resize_texture(uint32_t texture_id, uint32_t width, uint32_t height) -> void - { - glBindTexture(GL_TEXTURE_2D, texture_id); - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, nullptr); - } -}; diff --git a/src/rendering/texture_manager.h b/src/rendering/texture_manager.h deleted file mode 100644 index 02c32b1..0000000 --- a/src/rendering/texture_manager.h +++ /dev/null @@ -1,19 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include "rendering/texture.h" -#include - -namespace Donut -{ - class TextureManager - { - public: - static auto create_texture(uint32_t width, uint32_t height) -> Ref; - - static auto bind_texture(uint32_t texture_id, uint32_t slot = 0) -> void; - static auto bind_image_texture(uint32_t texture_id, uint32_t slot = 0, bool read_only = false) -> void; - static auto set_texture_data(uint32_t texture_id, void* data, uint32_t width, uint32_t height) -> void; - static auto resize_texture(uint32_t texture_id, uint32_t width, uint32_t height) -> void; - }; -}; diff --git a/src/rendering/uniform_buffer.cpp b/src/rendering/uniform_buffer.cpp deleted file mode 100644 index c4118b8..0000000 --- a/src/rendering/uniform_buffer.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include "uniform_buffer.h" - -#include - -namespace Donut -{ - UniformBuffer::UniformBuffer(uint32_t size, uint32_t binding) - : m_size(size), m_binding(binding) - { - glGenBuffers(1, &m_renderer_id); - glBindBuffer(GL_UNIFORM_BUFFER, m_renderer_id); - glBufferData(GL_UNIFORM_BUFFER, size, nullptr, GL_DYNAMIC_DRAW); - glBindBufferBase(GL_UNIFORM_BUFFER, binding, m_renderer_id); - } - - UniformBuffer::~UniformBuffer() - { - glDeleteBuffers(1, &m_renderer_id); - } - - auto UniformBuffer::set_data(const void* data, uint32_t size, uint32_t offset) -> void - { - glBindBuffer(GL_UNIFORM_BUFFER, m_renderer_id); - glBufferSubData(GL_UNIFORM_BUFFER, offset, size, data); - } - - auto UniformBuffer::bind(uint32_t binding) -> void - { - glBindBufferBase(GL_UNIFORM_BUFFER, binding, m_renderer_id); - } - - auto UniformBuffer::create(uint32_t size, uint32_t binding) -> Ref - { - return create_ref(size, binding); - } -}; diff --git a/src/rendering/uniform_buffer.h b/src/rendering/uniform_buffer.h deleted file mode 100644 index b5617b9..0000000 --- a/src/rendering/uniform_buffer.h +++ /dev/null @@ -1,24 +0,0 @@ -#pragma once - -#include "core/memory.h" -#include - -namespace Donut -{ - class UniformBuffer - { - public: - UniformBuffer(uint32_t size, uint32_t binding); - ~UniformBuffer(); - - auto set_data(const void* data, uint32_t size, uint32_t offset = 0) -> void; - auto bind(uint32_t binding) -> void; - - static auto create(uint32_t size, uint32_t binding) -> Ref; - - private: - uint32_t m_renderer_id = 0; - uint32_t m_size = 0; - uint32_t m_binding = 0; - }; -}; diff --git a/src/rendering/vertex_array.cpp b/src/rendering/vertex_array.cpp deleted file mode 100644 index 9d13b52..0000000 --- a/src/rendering/vertex_array.cpp +++ /dev/null @@ -1,59 +0,0 @@ -#include - -#include "vertex_array.h" - -namespace Donut -{ - VertexArray::VertexArray() - { - glGenVertexArrays(1, &m_renderer_id); - } - - VertexArray::~VertexArray() - { - glDeleteVertexArrays(1, &m_renderer_id); - } - - auto VertexArray::bind() const -> void - { - glBindVertexArray(m_renderer_id); - } - - auto VertexArray::unbind() const -> void - { - glBindVertexArray(0); - } - - auto VertexArray::add_vertex_buffer(const Ref& vertex_buffer) -> void - { - glBindVertexArray(m_renderer_id); - vertex_buffer->bind(); - - const auto& layout = vertex_buffer->get_layout(); - for (const auto& element : layout.get_elements()) - { - glEnableVertexAttribArray(m_vertex_buffer_index); - glVertexAttribPointer(m_vertex_buffer_index, - element.count, - element.type, - element.normalized ? GL_TRUE : GL_FALSE, - layout.get_stride(), - reinterpret_cast(static_cast(element.offset))); - m_vertex_buffer_index++; - } - - m_vertex_buffers.push_back(vertex_buffer); - } - - auto VertexArray::set_index_buffer(const Ref& index_buffer) -> void - { - glBindVertexArray(m_renderer_id); - index_buffer->bind(); - m_index_buffer = index_buffer; - } - - auto VertexArray::create() -> VertexArray* - { - return new VertexArray(); - } -}; diff --git a/src/rendering/vertex_array.h b/src/rendering/vertex_array.h deleted file mode 100644 index 1f06758..0000000 --- a/src/rendering/vertex_array.h +++ /dev/null @@ -1,35 +0,0 @@ -#pragma once - -#include "core/memory.h" - -#include "vertex_buffer.h" -#include "index_buffer.h" - -#include - -namespace Donut -{ - class VertexArray - { - public: - VertexArray(); - ~VertexArray(); - - auto bind() const -> void; - auto unbind() const -> void; - - auto add_vertex_buffer(const Ref& vertex_buffer) -> void; - auto set_index_buffer(const Ref& index_buffer) -> void; - - auto get_vertex_buffers() const -> const std::vector>& { return m_vertex_buffers; } - auto get_index_buffer() const -> const Ref& { return m_index_buffer; } - - static auto create() -> VertexArray*; - - private: - uint32_t m_renderer_id = 0; - uint32_t m_vertex_buffer_index = 0; - std::vector> m_vertex_buffers; - Ref m_index_buffer; - }; -}; diff --git a/src/rendering/vertex_buffer.cpp b/src/rendering/vertex_buffer.cpp deleted file mode 100644 index b55abb5..0000000 --- a/src/rendering/vertex_buffer.cpp +++ /dev/null @@ -1,50 +0,0 @@ -#include "vertex_buffer.h" - -#include - -namespace Donut -{ - auto VertexBufferElement::get_size_of_type(uint32_t type) -> uint32_t - { - switch (type) - { - case 0x1406: return 4; - case 0x1405: return 4; - case 0x1401: return 1; - default: return 0; - } - } - - VertexBuffer::VertexBuffer(const void* data, uint32_t size) - { - glGenBuffers(1, &m_renderer_id); - glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id); - glBufferData(GL_ARRAY_BUFFER, size, data, GL_STATIC_DRAW); - } - - VertexBuffer::~VertexBuffer() - { - glDeleteBuffers(1, &m_renderer_id); - } - - auto VertexBuffer::bind() const -> void - { - glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id); - } - - auto VertexBuffer::unbind() const -> void - { - glBindBuffer(GL_ARRAY_BUFFER, 0); - } - - auto VertexBuffer::set_data(const void* data, uint32_t size) -> void - { - glBindBuffer(GL_ARRAY_BUFFER, m_renderer_id); - glBufferSubData(GL_ARRAY_BUFFER, 0, size, data); - } - - auto VertexBuffer::create(const void* data, uint32_t size) -> VertexBuffer* - { - return new VertexBuffer(data, size); - } -}; diff --git a/src/rendering/vertex_buffer.h b/src/rendering/vertex_buffer.h deleted file mode 100644 index 3b6aea1..0000000 --- a/src/rendering/vertex_buffer.h +++ /dev/null @@ -1,78 +0,0 @@ -#pragma once - -#include -#include - -namespace Donut -{ - struct VertexBufferElement - { - uint32_t type; - uint32_t count; - uint8_t normalized; - uint32_t offset; - - static auto get_size_of_type(uint32_t type) -> uint32_t; - }; - - class VertexBufferLayout - { - public: - VertexBufferLayout() = default; - ~VertexBufferLayout() = default; - - template - auto push(uint32_t count) -> void - { - static_assert(false); - } - - template<> - void push(uint32_t count) - { - m_elements.push_back({ 0x1406, count, 0, m_stride }); - m_stride += count * VertexBufferElement::get_size_of_type(0x1406); - } - - template<> - void push(uint32_t count) - { - m_elements.push_back({ 0x1405, count, 0, m_stride }); - m_stride += count * VertexBufferElement::get_size_of_type(0x1405); - } - - template<> - void push(uint32_t count) - { - m_elements.push_back({ 0x1401, count, 1, m_stride }); - m_stride += count * VertexBufferElement::get_size_of_type(0x1401); - } - - inline auto get_elements() const -> const std::vector& { return m_elements; } - inline auto get_stride() const -> uint32_t { return m_stride; } - - private: - std::vector m_elements; - uint32_t m_stride = 0; - }; - - class VertexBuffer - { - public: - VertexBuffer(const void* data, uint32_t size); - ~VertexBuffer(); - - auto bind() const -> void; - auto unbind() const -> void; - auto set_data(const void* data, uint32_t size) -> void; - - auto get_layout() const -> const VertexBufferLayout& { return m_layout; } - auto set_layout(const VertexBufferLayout& layout) -> void { m_layout = layout; } - - static auto create(const void* data, uint32_t size) -> VertexBuffer*; - - private: - uint32_t m_renderer_id = 0; - VertexBufferLayout m_layout; - }; -}; -- cgit v1.3