hachem.wtf
aboutsummaryrefslogtreecommitdiff
path: root/src/rendering/black_hole_renderer.cpp
diff options
context:
space:
mode:
authorhachem <im@hachem.wtf>2026-08-23 16:19:19 +0200
committerhachem <im@hachem.wtf>2026-08-23 16:19:19 +0200
commit0ee2712029f53175552d459f908b163ad61de197 (patch)
treea58bc213d91acb8b42aec0b19cd678e63bb3ecd4 /src/rendering/black_hole_renderer.cpp
parent380b4d5d5a3e66d89ca7b3b1601bb23e5a01bf7b (diff)
feat: RHI interface with shared scene and black hole renderers
Diffstat (limited to 'src/rendering/black_hole_renderer.cpp')
-rw-r--r--src/rendering/black_hole_renderer.cpp134
1 files changed, 134 insertions, 0 deletions
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 <algorithm>
+#include <cstdint>
+#include <cstring>
+
+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<uint8_t> 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);
+ }
+}