From a34c49f103c8950a57687ea3d866c244d95b4414 Mon Sep 17 00:00:00 2001 From: hachem Date: Mon, 24 Aug 2026 18:28:39 +0200 Subject: [docs]: added a few comments cause i wont be able to read this in a week's time --- assets/shaders/equirect_to_cubemap.slang | 4 +- assets/shaders/geodesic.slang | 71 +++++++++++++++++--------------- assets/shaders/grid.slang | 2 +- assets/shaders/skybox.slang | 2 +- assets/shaders/sphere.slang | 2 +- assets/shaders/textured_quad.slang | 4 +- assets/shaders/vk_pipeline_test.slang | 4 +- src/core/application.cpp | 16 +++---- src/core/application.h | 10 ++--- src/core/window.cpp | 10 ++--- src/platform/opengl/opengl_device.cpp | 23 ++++------- src/platform/opengl/shader.cpp | 16 +++---- src/platform/opengl/shader.h | 2 +- src/platform/opengl/texture.cpp | 18 ++++---- src/platform/vulkan/vulkan_common.h | 25 +++++------ src/platform/vulkan/vulkan_device.cpp | 4 +- src/platform/vulkan/vulkan_device.h | 4 +- src/platform/vulkan/vulkan_resources.cpp | 10 ++--- src/platform/vulkan/vulkan_swapchain.cpp | 8 ++-- src/rendering/black_hole_renderer.cpp | 18 ++++---- src/rendering/black_hole_renderer.h | 12 +++--- src/rendering/export_config.h | 12 +++--- src/rendering/render_api.h | 4 +- src/rendering/render_path.cpp | 18 ++++---- src/rendering/render_path.h | 14 +++---- src/rendering/rhi.h | 38 ++++++++--------- src/rendering/scene_renderer.cpp | 18 ++++---- src/rendering/scene_renderer.h | 8 ++-- src/rendering/view.h | 8 ++-- src/scene/scene.cpp | 6 +-- src/scene/scene.h | 13 +++--- src/scene/scene_types.h | 12 +++--- src/ui/ui_layer.cpp | 24 +++++------ src/ui/ui_layer.h | 16 +++---- src/ui/workspace.h | 8 ++-- 35 files changed, 231 insertions(+), 233 deletions(-) diff --git a/assets/shaders/equirect_to_cubemap.slang b/assets/shaders/equirect_to_cubemap.slang index 510e6b0..5b4caff 100644 --- a/assets/shaders/equirect_to_cubemap.slang +++ b/assets/shaders/equirect_to_cubemap.slang @@ -1,7 +1,7 @@ -// Equirectangular HDRI -> cubemap face projection. NOTE: the OpenGL path uses the +// equirectangular HDRI -> cubemap face projection. NOTE: the OpenGL path uses the // hand-written assets/shaders/EquirectToCubemap.glsl instead; this Slang version // feeds the Vulkan cubemap bake (vulkan_cubemap.cpp), which binds the view / -// projection as a $Globals UBO. Kept as loose `uniform` globals (not a +// projection as a $Globals UBO. kept as loose `uniform` globals (not a // ConstantBuffer) so both paths bind them the same way. uniform float4x4 u_projection; diff --git a/assets/shaders/geodesic.slang b/assets/shaders/geodesic.slang index eb536c9..937674e 100644 --- a/assets/shaders/geodesic.slang +++ b/assets/shaders/geodesic.slang @@ -1,8 +1,8 @@ -// Ray-traced Schwarzschild black hole: back-traces one null geodesic per pixel +// ray-traced Schwarzschild black hole: back-traces one null geodesic per pixel // through curved spacetime, shading the accretion disk, the lensed HDRI -// background, and placed objects. Runs as a full-screen fragment pass. Uniforms +// background, and placed objects. runs as a full-screen fragment pass. uniforms // live in ConstantBuffers (UBOs) driven through the RHI; the HDRI is a cubemap -// sampler. See docs/physics.md for the maths. +// sampler. see docs/physics.md for the maths. struct VSInput { float2 position : POSITION; float2 texCoord : TEXCOORD0; }; struct VSOutput { float4 position : SV_Position; float2 texCoord : TEXCOORD0; }; @@ -61,7 +61,7 @@ ConstantBuffer sim; SamplerCube u_HDRIEnvironment; -// Schwarzschild radius of Sgr A* (metres). Geometric units with c = G = 1 are +// Schwarzschild radius of Sgr A* (metres). geometric units with c = G = 1 are // used throughout the geodesic integration; the black-hole mass is M = r_s / 2. static const float SagA_rs = 1.269e10; static const float D_LAMBDA = 1e7; @@ -69,7 +69,7 @@ static const float ESCAPE_R = 1e30; static const float R_ISCO = 3.0 * SagA_rs; // innermost stable circular orbit (6M) static const float R_PHOTON = 1.5 * SagA_rs; // photon sphere (3M) -static const float FLUX_PEAK = 0.0569; // peak of the r^-3(1-sqrt(r_in/r)) profile (at r/r_in ~ 1.36) +static const float FLUX_PEAK = 0.0569; // peak of the r^-3(1-sqrt(r_in/r)) profile (~r/r_in 1.36); worked it out once, now it's just the normaliser static const int DEFAULT_MAX_STEPS_MOVING = 12000; static const int DEFAULT_MAX_STEPS_STATIC = 8000; @@ -78,8 +78,8 @@ static const float DEFAULT_EARLY_EXIT_DISTANCE = 2e12; static const float MIN_STEP_SIZE = 1e6; static const float MAX_STEP_SIZE = 2e10; -// Display mapping for the (relative) Novikov-Thorne flux -> visible colour. -// The RADIAL PROFILE is physical; the absolute temperature scale is a display +// display mapping for the (relative) Novikov-Thorne flux -> visible colour. +// the RADIAL PROFILE is physical; the absolute temperature scale is a display // choice (a real Sgr A* disk is far cooler / redder than this). struct Hit @@ -91,6 +91,7 @@ struct Hit float hash(float3 p) { + // magic primes, don't ask — they just scramble bits into a clean 0..1 hash p = frac(p * float3(0.1031, 0.1030, 0.0973)); p += dot(p, p.yxz + 33.33); return frac((p.x + p.y) * p.z); @@ -129,8 +130,10 @@ float fbm(float3 x, int octaves) return v; } -// Planckian-locus blackbody colour (Tanner Helland approximation), T in Kelvin. -// Returns an sRGB-ish chromaticity normalised so the brightest channel ~ 1. +// blackbody colour along the Planckian locus, T in Kelvin. it's Tanner Helland's +// curve fit and the coefficients below are pure magic-number soup — idk exactly +// how they were derived, so like just trust them. returns an sRGB-ish +// chromaticity normalised so the brightest channel ~ 1. float3 Blackbody(float T) { T = clamp(T, 1000.0, 40000.0); @@ -149,11 +152,11 @@ float3 Blackbody(float T) return c; } -// Emission from the thin accretion disk at an equatorial crossing point P, seen -// along the (backward-traced) ray direction rayDir. Combines a Novikov-Thorne +// emission from the thin accretion disk at an equatorial crossing point P, seen +// along the (backward-traced) ray direction rayDir. combines a Novikov-Thorne // temperature profile with the full gravitational + Doppler redshift. // g = sqrt(1 - 3M/r) / (1 - beta . nhat) (verified: g -> sqrt(1/2) at ISCO) -// Brightness follows relativistic beaming (I_obs = g^4 I_emit); colour follows +// brightness follows relativistic beaming (I_obs = g^4 I_emit); colour follows // the redshifted blackbody at T_obs = g * T_emit. float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit) { @@ -171,7 +174,7 @@ float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit) float Tn = pow(flux / FLUX_PEAK, 0.25); // normalised temperature, peak ~ 1 float Temit = disk.u_temperature * Tn; - // Keplerian orbit (prograde about +Y). Locally-measured orbital speed for a + // Keplerian orbit (prograde about +Y). locally-measured orbital speed for a // Schwarzschild circular geodesic: v = sqrt( M / (r - 2M) ) = 0.5 c at ISCO. float3 rhat = normalize(float3(P.x, 0.0, P.z)); float3 phiHat = normalize(cross(float3(0.0, 1.0, 0.0), rhat)); @@ -184,17 +187,17 @@ float3 DiskEmission(float3 P, float3 rayDir, out float outG, out float outTemit) float Tobs = g * Temit; float3 colour = Blackbody(Tobs); - // Physical bolometric intensity is ~ T_emit^4 * g^4, an enormous dynamic - // range. The g^4 relativistic beaming (the physical asymmetry) is kept; the + // physical bolometric intensity is ~ T_emit^4 * g^4, an enormous dynamic + // range. the g^4 relativistic beaming (the physical asymmetry) is kept; the // radial falloff is display-compressed (Tn^2) so the colour gradient across // the disk stays visible instead of collapsing to a thin saturated ring. float bright = pow(Tn, 2.0) * pow(g, 4.0); - // Soft inner/outer edges (disks have no hard rim); also tames rim aliasing. + // soft inner/outer edges (disks have no hard rim); also tames rim aliasing. float edge = smoothstep(rin, rin * 1.12, rc) * (1.0 - smoothstep(rout * 0.88, rout, rc)); bright *= edge; - // Optional turbulence overlay (disk.u_turbulence = strength; 0 = smooth). + // optional turbulence overlay (disk.u_turbulence = strength; 0 = smooth). if (disk.u_turbulence > 0.0) { float ang = sim.u_time * 0.3 / sqrt(xr); @@ -304,13 +307,13 @@ void RK4Step(inout Ray ray, float dL) float CalculateAdaptiveStepSize(Ray ray, float baseStepSize) { - // Step proportional to the distance from the photon sphere: near-flat space + // step proportional to the distance from the photon sphere: near-flat space // far from the hole is crossed in a few huge steps, while the sharply curved - // region near the photon sphere is resolved with tiny ones. This keeps the + // region near the photon sphere is resolved with tiny ones. this keeps the // integration accurate near the hole regardless of how far the camera is. float step = 0.02 * max(ray.r - R_PHOTON, 0.0); - // Slow down when near the disk plane (within its radial extent) so the thin + // slow down when near the disk plane (within its radial extent) so the thin // slab is never stepped over -- otherwise grazing rays leak through it. float rc = length(float2(ray.x, ray.z)); if (rc < disk.u_outer_radius * 3.0 && abs(ray.y) < disk.u_thickness * 8.0) @@ -319,12 +322,14 @@ float CalculateAdaptiveStepSize(Ray ray, float baseStepSize) return clamp(step, MIN_STEP_SIZE, MAX_STEP_SIZE); } +// Narkowicz's ACES filmic tonemap. the constants are just The Numbers everyone +// copies — idk the derivation, but it squashes HDR radiance into a nice 0..1 curve. float3 ACESFilm(float3 x) { return clamp((x * (2.51 * x + 0.03)) / (x * (2.43 * x + 0.59) + 0.14), 0.0, 1.0); } -// A jet-ish false-colour ramp (blue -> cyan -> green -> yellow -> red) for the +// a jet-ish false-colour ramp (blue -> cyan -> green -> yellow -> red) for the // observable export channels. t is expected in [0, 1]. float3 Falsecolor(float t) { @@ -334,8 +339,8 @@ float3 Falsecolor(float t) 1.5 - abs(4.0 * t - 1.0)), 0.0, 1.0); } -// Trace one primary ray for the given image UV and return its linear, -// pre-tone-map radiance. Called once per sub-sample by fragmentMain. +// trace one primary ray for the given image UV and return its linear, +// pre-tone-map radiance. called once per sub-sample by fragmentMain. float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool outHitDisk) { outG = 0.0; outTemit = 0.0; outHitDisk = false; @@ -371,9 +376,9 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool RK4Step(ray, stepSize); float3 newPos = float3(ray.x, ray.y, ray.z); - // Opaque disk of small half-thickness H (a slab about the midplane y=0). - // The ray hits when it first crosses the midplane OR enters the slab - // while grazing along it. Real (nonzero) thickness stops the zero-height + // opaque disk of small half-thickness H (a slab about the midplane y=0). + // the ray hits when it first crosses the midplane OR enters the slab + // while grazing along it. real (nonzero) thickness stops the zero-height // edge-on "razor" from aliasing into a beam streaking across the frame. { float H = disk.u_thickness; @@ -397,13 +402,13 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool if (i % objectCheckInterval == 0 && InterceptObject(ray, hit)) { hitObject = true; break; } - // Principled escape: once outbound in near-flat spacetime (r >> r_s) the + // principled escape: once outbound in near-flat spacetime (r >> r_s) the // ray direction no longer changes, so stop and read the background. if (ray.dr > 0.0 && ray.r > 50.0 * SagA_rs) break; } - // Escape direction + environment mip LOD from the ray's angular divergence. - // Computed UNCONDITIONALLY (before the branch) so ddx/ddy are valid; strongly + // escape direction + environment mip LOD from the ray's angular divergence. + // computed UNCONDITIONALLY (before the branch) so ddx/ddy are valid; strongly // lensed background rays diverge fast, so they read a blurred cubemap mip and // the starfield stops aliasing into a fan along the equatorial plane. float3 rayDir = normalize(float3(ray.x, ray.y, ray.z) - cam.u_cam_pos); @@ -438,14 +443,14 @@ float3 TracePixel(float2 texCoord, out float outG, out float outTemit, out bool [shader("fragment")] float4 fragmentMain(VSOutput input) : SV_Target { - // Moving frame: one sample for responsiveness. Settled frame: rotated-grid + // moving frame: one sample for responsiveness. settled frame: rotated-grid // 4x supersampling (the 4-rook pattern gives 4 distinct sub-pixel positions // on BOTH axes, far better on the near-horizontal lensed edges than an - // ordered grid). Radiance is averaged before tone-mapping; ddx/ddy give the + // ordered grid). radiance is averaged before tone-mapping; ddx/ddy give the // resolution-correct per-pixel UV footprint. - // Observable export channels: the chosen scalar quantity, either as a raw + // observable export channels: the chosen scalar quantity, either as a raw // float (u_raw_output: value in RGB, validity mask in A) or false-coloured. - // Channel 0 is the normal colour image. + // channel 0 is the normal colour image. if (cam.u_output_channel != 0) { float g, Temit; bool hitDisk; diff --git a/assets/shaders/grid.slang b/assets/shaders/grid.slang index 8dc4362..13aa349 100644 --- a/assets/shaders/grid.slang +++ b/assets/shaders/grid.slang @@ -1,4 +1,4 @@ -// Reference grid on the XZ plane. Uniforms live in a ConstantBuffer (UBO) so both +// reference grid on the XZ plane. uniforms live in a ConstantBuffer (UBO) so both // backends drive it through the same RHI path (bind a uniform buffer at binding 0). struct Grid { diff --git a/assets/shaders/skybox.slang b/assets/shaders/skybox.slang index f7aeb50..ae7634c 100644 --- a/assets/shaders/skybox.slang +++ b/assets/shaders/skybox.slang @@ -1,4 +1,4 @@ -// Full-screen skybox cube. View/projection in a ConstantBuffer (UBO, binding 0) +// full-screen skybox cube. view/projection in a ConstantBuffer (UBO, binding 0) // so both backends drive it through the RHI; the cubemap is a sampler at binding 1. struct Skybox { diff --git a/assets/shaders/sphere.slang b/assets/shaders/sphere.slang index 41badde..2c547e6 100644 --- a/assets/shaders/sphere.slang +++ b/assets/shaders/sphere.slang @@ -1,4 +1,4 @@ -// Lit sphere (Blinn-Phong + HDRI ambient + selection rim). Uniforms in a +// lit sphere (Blinn-Phong + HDRI ambient + selection rim). uniforms in a // ConstantBuffer (UBO, binding 0) so both backends drive it through the RHI; // the environment cubemap is a separate sampler at binding 1. struct Sphere diff --git a/assets/shaders/textured_quad.slang b/assets/shaders/textured_quad.slang index b72db81..9ff81fd 100644 --- a/assets/shaders/textured_quad.slang +++ b/assets/shaders/textured_quad.slang @@ -1,5 +1,5 @@ -// Full-screen textured quad: samples one 2D texture straight to the target. -// Used to blit an off-screen colour buffer to the swapchain. +// full-screen textured quad: samples one 2D texture straight to the target. +// used to blit an off-screen colour buffer to the swapchain. struct VSInput { float2 position : POSITION; float2 texCoord : TEXCOORD0; }; struct VSOutput { float4 position : SV_Position; float2 texCoord : TEXCOORD0; }; diff --git a/assets/shaders/vk_pipeline_test.slang b/assets/shaders/vk_pipeline_test.slang index 453fcd3..c644d7c 100644 --- a/assets/shaders/vk_pipeline_test.slang +++ b/assets/shaders/vk_pipeline_test.slang @@ -1,5 +1,5 @@ -// Minimal shader used only to verify the Vulkan graphics-pipeline path (SPIR-V -// module -> pipeline -> draw -> read-back). Draws a full-screen gradient triangle +// minimal shader used only to verify the Vulkan graphics-pipeline path (SPIR-V +// module -> pipeline -> draw -> read-back). draws a full-screen gradient triangle // from the vertex id, so it needs no vertex buffer, UBO, or sampler. struct VSOutput { float4 position : SV_Position; float3 color : COLOR0; }; diff --git a/src/core/application.cpp b/src/core/application.cpp index c24e029..5a3a21b 100644 --- a/src/core/application.cpp +++ b/src/core/application.cpp @@ -17,7 +17,7 @@ namespace Donut { Application* Application::s_instance = nullptr; - // Scroll is delivered through a GLFW callback; accumulate it here and drain it + // scroll is delivered through a GLFW callback; accumulate it here and drain it // once per frame in update_input (chaining ImGui's own scroll handler). static double g_scroll_accum = 0.0; static GLFWscrollfun g_prev_scroll = nullptr; @@ -31,7 +31,7 @@ namespace Donut { s_instance = this; - // Select the render API before the window is created: the window is built + // select the render API before the window is created: the window is built // differently for Vulkan (GLFW_NO_API) than for OpenGL. Logger::init(); SettingsManager::initialize(); @@ -79,7 +79,7 @@ namespace Donut m_ui = create_scope(); m_device->init_imgui(); - // Load the UI font into the device-created ImGui context (backend-agnostic; + // load the UI font into the device-created ImGui context (backend-agnostic; // the backend rebuilds the atlas on the next frame). ImGuiIO& io = ImGui::GetIO(); if (!io.Fonts->AddFontFromFileTTF("assets/fonts/inter/static/Inter_18pt-Regular.ttf", 16.0f)) @@ -103,7 +103,7 @@ namespace Donut if (!m_minimized && m_device) render_frame(); - // With vsync off, cap to the target FPS (vsync itself paces otherwise). + // with vsync off, cap to the target FPS (vsync itself paces otherwise). if (!SettingsManager::get_v_sync_enabled()) { int fps = SettingsManager::get_target_fps(); @@ -159,8 +159,8 @@ namespace Donut m_device->imgui_new_frame(); - // Keep the scene camera's projection current before the UI builds, so the - // scene-tab gizmo and the render agree on the same matrices this frame. + // keep the scene camera's projection current before the UI builds, so the + // scene-view gizmo and the render agree on the same matrices this frame. int w = 0, h = 0; glfwGetFramebufferSize((GLFWwindow*)m_window->get_native_window(), &w, &h); m_scene->scene_camera.set_projection(45.0f, (float)w / (float)std::max(h, 1), 0.1f, 1000.0f); @@ -188,11 +188,11 @@ namespace Donut glfwGetCursorPos(window, &mx, &my); bool left_down = glfwGetMouseButton(window, GLFW_MOUSE_BUTTON_LEFT) == GLFW_PRESS; - // Tabs without a live viewport (Setup / Export) have no camera to drive. + // a None view has no live viewport, so there's no camera to drive. if (view == View::None) { m_left_was_down = left_down; // keep the drag-edge state coherent - g_scroll_accum = 0.0; // discard scroll over inert tabs + g_scroll_accum = 0.0; // no live view: nothing to scroll m_user_moving = false; return; } diff --git a/src/core/application.h b/src/core/application.h index f1e40c8..bb88919 100644 --- a/src/core/application.h +++ b/src/core/application.h @@ -15,10 +15,10 @@ namespace Donut { - // Thin shell: owns the window, the RHI device, the Scene (document), the - // RenderPath (device-side rendering) and the UILayer (tabbed workspaces), and - // runs the frame loop that wires them together. All the rendering lives in the - // RHI + shared renderers; all the editing lives in the Scene + workspaces. + // thin shell: owns the window, the RHI device, the Scene (document), the + // RenderPath (device-side rendering) and the UILayer (docking UI), and runs + // the frame loop that wires them together. all the rendering lives in the + // RHI + shared renderers; all the editing lives in the Scene + UI panels. class Application : public AppActions { public: @@ -32,7 +32,7 @@ namespace Donut auto get_window() -> Window& { return *m_window; } static auto get() -> Application& { return *s_instance; } - // AppActions — window/device changes requested by the Setup workspace. + // AppActions — window/device changes requested by the Settings panel. auto set_resolution(int w, int h) -> void override; auto set_fullscreen(bool on) -> void override; auto set_vsync(bool on) -> void override; diff --git a/src/core/window.cpp b/src/core/window.cpp index dd5882c..085d7bc 100644 --- a/src/core/window.cpp +++ b/src/core/window.cpp @@ -39,16 +39,16 @@ namespace Donut if (RendererAPI::get_api() == RendererAPI::API::Vulkan) { - // Vulkan manages presentation itself; GLFW must not create a GL context. + // Vulkan does its own presentation, so GLFW must NOT sneak in a GL context. glfwWindowHint(GLFW_CLIENT_API, GLFW_NO_API); } else { #ifdef __APPLE__ - // macOS only exposes OpenGL up to 4.1 Core Profile, and requires a - // forward-compatible core-profile context for any modern (>= 3.3) - // shader to compile. Without these hints GLFW hands back a legacy - // 2.1 context and every GLSL shader in the project fails to build. + // macOS caps OpenGL at 4.1 Core Profile and demands a forward-compat + // core-profile context for anything modern (>= 3.3) to even compile. + // skip these hints and GLFW hands you a dusty 2.1 context and every + // single shader in the project refuses to build. so, we ask nicely: glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 1); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); diff --git a/src/platform/opengl/opengl_device.cpp b/src/platform/opengl/opengl_device.cpp index 614e515..dd5581d 100644 --- a/src/platform/opengl/opengl_device.cpp +++ b/src/platform/opengl/opengl_device.cpp @@ -21,7 +21,6 @@ namespace Donut::RHI auto gl_filter(Filter f) -> GLint { return f == Filter::Nearest ? GL_NEAREST : GL_LINEAR; } auto gl_internal(Format f) -> GLint { return f == Format::RGBA16F ? GL_RGBA16F : f == Format::RGBA32F ? GL_RGBA32F : f == Format::D32 ? GL_DEPTH_COMPONENT32F : GL_RGBA8; } - // ---- Buffer ------------------------------------------------------- class GLBuffer : public Buffer { public: @@ -42,7 +41,6 @@ namespace Donut::RHI GLuint m_id = 0; GLenum m_target = GL_ARRAY_BUFFER; }; - // ---- Texture ------------------------------------------------------ class GLTexture : public Texture { public: @@ -69,7 +67,6 @@ namespace Donut::RHI Ref m_cube; // keepalive for cubemaps }; - // ---- RenderTarget ------------------------------------------------- class GLRenderTarget : public RenderTarget { public: @@ -102,7 +99,6 @@ namespace Donut::RHI GLuint m_fbo = 0, m_depth = 0; int m_w, m_h; Scope m_color; }; - // ---- Pipeline ----------------------------------------------------- class GLPipeline : public Pipeline { public: @@ -120,12 +116,12 @@ namespace Donut::RHI { GLuint bi = glGetUniformBlockIndex(m_prog, r.name.c_str()); if (bi != GL_INVALID_INDEX) glUniformBlockBinding(m_prog, bi, r.binding); - // Not found: the ConstantBuffer<> type name in the shader no longer + // not found: the ConstantBuffer<> type name in the shader no longer // matches this resource string, so the UBO silently won't bind. else DONUT_WARN("GL RHI: shader '{}' has no uniform block '{}' (binding {})", d.shader, r.name, r.binding); } - else // Texture: point the sampler at texture unit == binding + else // texture: point the sampler at texture unit == binding { GLint loc = glGetUniformLocation(m_prog, r.name.c_str()); if (loc >= 0) glUniform1i(loc, (GLint)r.binding); @@ -138,7 +134,7 @@ namespace Donut::RHI PipelineDesc m_desc; Ref m_shader; GLuint m_prog = 0; }; - // ---- CommandList (immediate) -------------------------------------- + // GL has no command buffers, so every call here executes immediately. class GLCommandList : public CommandList { public: @@ -155,7 +151,7 @@ namespace Donut::RHI glClearColor(clear.r, clear.g, clear.b, clear.a); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); } - auto end_render_pass() -> void override {} + auto end_render_pass() -> void override {} // GL passes are a fiction; nothing to close auto bind_pipeline(Pipeline* p) -> void override { @@ -208,7 +204,6 @@ namespace Donut::RHI GLuint m_vao; GLPipeline* m_pipe = nullptr; int m_default_w = 1, m_default_h = 1; }; - // ---- Device ------------------------------------------------------- class GLDevice : public Device { public: @@ -220,17 +215,17 @@ namespace Donut::RHI m_width = window.width; m_height = window.height; const char* name = (const char*)glGetString(GL_RENDERER); m_name = name ? name : "OpenGL"; - glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); // GL core needs one bound VAO + glGenVertexArrays(1, &m_vao); glBindVertexArray(m_vao); // GL core wants one VAO bound at all times, so like, here's one m_cmds = create_scope(m_vao); DONUT_INFO("GL RHI device: {} ({}x{})", m_name, m_width, m_height); return true; } auto shutdown() -> void override { - // Free the HDRIManager's cached GL cubemaps while our context is - // still current (they are static-singleton-owned; letting them - // destruct at program exit would glDeleteTextures after the context - // is gone and crash on close). + // nuke the HDRIManager's cached GL cubemaps while our context is + // still alive. they're static-singleton-owned, so if we let them + // destruct at program exit they'd glDeleteTextures into a dead + // context and crash on close. no thanks. HDRIManager::get().clear_cache(); if (m_imgui) { ImGui_ImplOpenGL3_Shutdown(); ImGui_ImplGlfw_Shutdown(); ImGui::DestroyContext(); m_imgui = false; } if (m_vao) { glDeleteVertexArrays(1, &m_vao); m_vao = 0; } diff --git a/src/platform/opengl/shader.cpp b/src/platform/opengl/shader.cpp index 80015e6..757382b 100644 --- a/src/platform/opengl/shader.cpp +++ b/src/platform/opengl/shader.cpp @@ -19,8 +19,8 @@ namespace Donut return 0; } - // Shaders are authored in Slang and compiled to assets/shaders/generated/ - // .glsl by tools/compile-shaders.sh. Given a legacy ".../.glsl" + // shaders are authored in Slang and compiled to assets/shaders/generated/ + // .glsl by tools/compile-shaders.sh. given a legacy ".../.glsl" // path, prefer that generated file when present; otherwise fall back to the // hand-written GLSL (e.g. shaders not yet ported to Slang). static std::string ResolveShaderPath(const std::string& filepath) @@ -145,9 +145,9 @@ namespace Donut glDeleteShader(id); glDeleteProgram(program); m_renderer_id = 0; - // info_log.data() is null when the driver returns an empty log - // (e.g. macOS rejecting a compute shader); streaming a null - // char* into std::cout calls strlen(NULL) and crashes. + // info_log.data() is null when the driver hands back an empty log + // (e.g. macOS rejecting a compute shader). streaming a null char* + // into std::cout does strlen(NULL) and just explodes. cool cool cool. const char* log = info_log.empty() ? "" : info_log.data(); std::cout << "Shader compilation failure!" << std::endl << log << std::endl; return; @@ -278,9 +278,9 @@ namespace Donut auto Shader::dispatch(uint32_t x, uint32_t y, uint32_t z) -> void { - // Compute shaders require OpenGL 4.3+. On drivers that cap out earlier - // (e.g. macOS, which is frozen at 4.1) glDispatchCompute is never - // loaded and the pointer is null. Guard so we no-op instead of crash. + // compute shaders want OpenGL 4.3+ and macOS is frozen at 4.1, so + // glDispatchCompute never even loads and the pointer is null. guard it + // and quietly no-op instead of face-planting. if (m_renderer_id == 0 || glDispatchCompute == nullptr) return; glDispatchCompute(x, y, z); diff --git a/src/platform/opengl/shader.h b/src/platform/opengl/shader.h index 409aca3..89963c7 100644 --- a/src/platform/opengl/shader.h +++ b/src/platform/opengl/shader.h @@ -59,7 +59,7 @@ namespace Donut uint32_t m_renderer_id = 0; std::string m_name; - // True when loaded from a Slang-compiled GLSL. Slang expects row-major + // true when loaded from a Slang-compiled GLSL. Slang expects row-major // matrix data, so matrix uniforms are transposed on upload (glm is // column-major) to keep all matrix math correct. bool m_is_slang = false; diff --git a/src/platform/opengl/texture.cpp b/src/platform/opengl/texture.cpp index 12e07f1..d2d2233 100644 --- a/src/platform/opengl/texture.cpp +++ b/src/platform/opengl/texture.cpp @@ -11,10 +11,10 @@ #include #include -// NOTE: This file targets OpenGL 4.1 (the maximum macOS exposes). It uses the +// this file targets OpenGL 4.1 (the maximum macOS exposes). it uses the // classic bind-based texture API rather than 4.5 Direct State Access // (glCreateTextures / glTextureStorage2D / glTextureParameteri / glBindTextureUnit), -// none of which exist on macOS. It also hosts the single STB_IMAGE_IMPLEMENTATION +// none of which exist on macOS. it also hosts the single STB_IMAGE_IMPLEMENTATION // for the whole build (the Vulkan backend links stbi_loadf from here too). namespace Donut @@ -84,7 +84,7 @@ namespace Donut auto Texture2D::bind_as_image(uint32_t slot, bool read_only) const -> void { - // Image load/store is OpenGL 4.2 and unavailable on macOS. Guard the + // image load/store is OpenGL 4.2 and unavailable on macOS. guard the // function pointer so this degrades to a no-op instead of crashing. if (glBindImageTexture == nullptr) return; @@ -148,12 +148,12 @@ namespace Donut DONUT_ERROR("Failed to load HDRI: {}", path); float default_sky[6 * 4] = { - 0.5f, 0.7f, 1.0f, 1.0f, // Right - 0.5f, 0.7f, 1.0f, 1.0f, // Left - 0.5f, 0.7f, 1.0f, 1.0f, // Top - 0.5f, 0.7f, 1.0f, 1.0f, // Bottom - 0.5f, 0.7f, 1.0f, 1.0f, // Front - 0.5f, 0.7f, 1.0f, 1.0f // Back + 0.5f, 0.7f, 1.0f, 1.0f, // right + 0.5f, 0.7f, 1.0f, 1.0f, // left + 0.5f, 0.7f, 1.0f, 1.0f, // top + 0.5f, 0.7f, 1.0f, 1.0f, // bottom + 0.5f, 0.7f, 1.0f, 1.0f, // front + 0.5f, 0.7f, 1.0f, 1.0f // back }; glBindTexture(GL_TEXTURE_CUBE_MAP, m_renderer_id); diff --git a/src/platform/vulkan/vulkan_common.h b/src/platform/vulkan/vulkan_common.h index 8f02f17..cb86d69 100644 --- a/src/platform/vulkan/vulkan_common.h +++ b/src/platform/vulkan/vulkan_common.h @@ -1,10 +1,10 @@ #pragma once -// Shared internals of the Vulkan RHI backend: the enum-mapping helpers, the +// shared internals of the Vulkan RHI backend: the enum-mapping helpers, the // opaque resource classes (Buffer/Texture/RenderTarget/Pipeline/CommandList), and -// the VulkanDevice declaration. The implementation is split across vulkan_device +// the VulkanDevice declaration. the implementation is split across vulkan_device // (lifecycle + frame loop), vulkan_swapchain (instance/device/swapchain/passes), -// vulkan_resources (buffer/texture/target/pipeline) and vulkan_cubemap. This +// vulkan_resources (buffer/texture/target/pipeline) and vulkan_cubemap. this // header is private to platform/vulkan/ — nothing outside includes it. #include "vulkan_device.h" // rendering/rhi.h (base classes + factory decls) @@ -63,7 +63,7 @@ namespace Donut::RHI inline auto vk_cull(CullMode c) -> VkCullModeFlags { return c == CullMode::None ? VK_CULL_MODE_NONE : c == CullMode::Back ? VK_CULL_MODE_BACK_BIT : VK_CULL_MODE_FRONT_BIT; } - // Buffer: host-visible + coherent, persistently mapped. + // buffer: host-visible + coherent, persistently mapped. class VkBufferR : public Buffer { public: @@ -81,7 +81,7 @@ namespace Donut::RHI VkDevice m_device; VkBuffer m_buf; VkDeviceMemory m_mem; void* m_mapped; size_t m_size; }; - // Texture: sampled image (2D or cube). Owns its handles unless it is a borrowed + // texture: sampled image (2D or cube). owns its handles unless it is a borrowed // wrapper around a render-target view. class VkTextureR : public Texture { @@ -138,7 +138,7 @@ namespace Donut::RHI VkTextureR m_color; // borrowed wrapper (view+sampler) for sampling }; - // Pipeline: the graphics pipeline + its (set-0) descriptor layout. + // pipeline: the graphics pipeline + its (set-0) descriptor layout. class VkPipelineR : public Pipeline { public: @@ -155,8 +155,9 @@ namespace Donut::RHI std::vector m_resources; }; - // CommandList: records into the frame's command buffer. Per-draw descriptor - // sets are allocated from a per-frame pool (no push-descriptor extension). + // CommandList: records into the frame's command buffer. MoltenVK has no + // push-descriptor extension, so we just grab a fresh descriptor set per draw + // from a per-frame pool. kinda wasteful, but it works and that's what counts. class VkCommandListR : public CommandList { public: @@ -219,7 +220,7 @@ namespace Donut::RHI auto draw_indexed(uint32_t index_count) -> void override { flush_descriptors(); vkCmdDrawIndexed(m_cmd, index_count, 1, 0, 0, 0); } - // Allocate + write + bind a descriptor set for the current pipeline's + // allocate + write + bind a descriptor set for the current pipeline's // declared resources, using whatever was bound since bind_pipeline. auto flush_descriptors() -> void { @@ -246,7 +247,7 @@ namespace Donut::RHI vkCmdBindDescriptorSets(m_cmd, VK_PIPELINE_BIND_POINT_GRAPHICS, m_pipe->m_layout, 0, 1, &set, 0, nullptr); } - // Set by the device at begin_frame: + // set by the device at begin_frame: VkDevice m_device = VK_NULL_HANDLE; VkCommandBuffer m_cmd = VK_NULL_HANDLE; VkRenderPass m_swapchain_rp = VK_NULL_HANDLE; @@ -259,7 +260,7 @@ namespace Donut::RHI VkDescriptorImageInfo m_img_info[MAX_BINDINGS]{}; }; - // The backend device. Its methods are defined across vulkan_device.cpp, + // the backend device. its methods are defined across vulkan_device.cpp, // vulkan_swapchain.cpp, vulkan_resources.cpp and vulkan_cubemap.cpp. class VulkanDevice : public Device { @@ -298,7 +299,7 @@ namespace Donut::RHI auto pick_physical_and_device() -> bool; auto create_swapchain() -> bool; auto create_image_views() -> bool; - // Render passes are format-driven and cached: a pipeline/target's + // render passes are format-driven and cached: a pipeline/target's // attachment signature (colour + optional depth, present vs sampled) // maps to one pass. `present` = presented swapchain image. auto get_render_pass(VkFormat color, VkFormat depth, bool present) -> VkRenderPass; diff --git a/src/platform/vulkan/vulkan_device.cpp b/src/platform/vulkan/vulkan_device.cpp index ff2e296..a4f9ac7 100644 --- a/src/platform/vulkan/vulkan_device.cpp +++ b/src/platform/vulkan/vulkan_device.cpp @@ -58,7 +58,7 @@ namespace Donut::RHI if (!pick_physical_and_device()) return false; if (!create_swapchain()) return false; if (!create_image_views()) return false; - // The swapchain is a "present" target: its colour format + a D32 depth. + // the swapchain is a "present" target: its colour format + a D32 depth. m_swapchain_rp = get_render_pass(m_swapchain_format, VK_FORMAT_D32_SFLOAT, true); if (!m_swapchain_rp) return false; if (!create_depth_and_framebuffers())return false; @@ -156,7 +156,7 @@ namespace Donut::RHI VkCommandBuffer cmd; vkAllocateCommandBuffers(m_device, &cbai, &cmd); VkCommandBufferBeginInfo bi{ VK_STRUCTURE_TYPE_COMMAND_BUFFER_BEGIN_INFO }; bi.flags = VK_COMMAND_BUFFER_USAGE_ONE_TIME_SUBMIT_BIT; vkBeginCommandBuffer(cmd, &bi); - // The target ended its render pass in SHADER_READ_ONLY; move it to TRANSFER_SRC to copy. + // the target ended its render pass in SHADER_READ_ONLY; move it to TRANSFER_SRC to copy. VkImageMemoryBarrier b{ VK_STRUCTURE_TYPE_IMAGE_MEMORY_BARRIER }; b.oldLayout = VK_IMAGE_LAYOUT_SHADER_READ_ONLY_OPTIMAL; b.newLayout = VK_IMAGE_LAYOUT_TRANSFER_SRC_OPTIMAL; b.image = rt->m_image; b.subresourceRange = { VK_IMAGE_ASPECT_COLOR_BIT, 0, 1, 0, 1 }; diff --git a/src/platform/vulkan/vulkan_device.h b/src/platform/vulkan/vulkan_device.h index efc2433..85cc5ca 100644 --- a/src/platform/vulkan/vulkan_device.h +++ b/src/platform/vulkan/vulkan_device.h @@ -4,13 +4,13 @@ namespace Donut::RHI { - // Vulkan implementation of the RHI Device (MoltenVK on macOS). Owns the + // Vulkan implementation of the RHI Device (MoltenVK on macOS). owns the // instance/device/swapchain and translates the RHI's baked pipelines + // recorded command lists into native Vulkan; the geometry it draws is the // shared SceneRenderer / BlackHoleRenderer, identical to every other backend. auto create_vulkan_device() -> Scope; - // Must run BEFORE glfwInit() when Vulkan is the selected API: points GLFW at + // must run BEFORE glfwInit() when Vulkan is the selected API: points GLFW at // the loader the app links against (its own dlopen fails on macOS/Homebrew) // and configures the MoltenVK ICD / layer paths. auto vulkan_prepare_glfw() -> void; diff --git a/src/platform/vulkan/vulkan_resources.cpp b/src/platform/vulkan/vulkan_resources.cpp index e40ded3..ee2091b 100644 --- a/src/platform/vulkan/vulkan_resources.cpp +++ b/src/platform/vulkan/vulkan_resources.cpp @@ -93,7 +93,7 @@ namespace Donut::RHI smci.addressModeU = smci.addressModeV = smci.addressModeW = VK_SAMPLER_ADDRESS_MODE_CLAMP_TO_EDGE; vkCreateSampler(m_device, &smci, nullptr, &rt->m_sampler); - // Optional depth attachment (for off-screen passes that need a depth test). + // optional depth attachment (for off-screen passes that need a depth test). rt->m_has_depth = depth != Format::None; VkFormat dfmt = VK_FORMAT_UNDEFINED; if (rt->m_has_depth) @@ -126,9 +126,9 @@ namespace Donut::RHI return rt; } - // Builds an environment cubemap from an equirectangular HDRI: render the 6 + // builds an environment cubemap from an equirectangular HDRI: render the 6 // faces with the EquirectToCubemap pipeline, then a full mip chain by - // linear down-blits (so divergence-based LOD reads a blurred sky). Returns + // linear down-blits (so divergence-based LOD reads a blurred sky). returns // a Texture owning the cube image/view/sampler. auto VulkanDevice::create_pipeline(const PipelineDesc& desc) -> Ref @@ -190,8 +190,8 @@ namespace Donut::RHI gpci.stageCount = 2; gpci.pStages = stages; gpci.pVertexInputState = &vin; gpci.pInputAssemblyState = &ia; gpci.pViewportState = &vps; gpci.pRasterizationState = &rs; gpci.pMultisampleState = &ms; gpci.pColorBlendState = &cb; gpci.pDynamicState = &dsci; - // Resolve the target's attachment signature to a (cached) render pass. - // Pipeline<->pass compatibility is by attachment format, so this is the + // resolve the target's attachment signature to a (cached) render pass. + // pipeline<->pass compatibility is by attachment format, so this is the // same pass the matching swapchain / render target renders into. VkFormat pcolor = (desc.target.color == Format::Swapchain) ? m_swapchain_format : vk_format(desc.target.color); VkFormat pdepth = (desc.target.depth == Format::None) ? VK_FORMAT_UNDEFINED : vk_format(desc.target.depth); diff --git a/src/platform/vulkan/vulkan_swapchain.cpp b/src/platform/vulkan/vulkan_swapchain.cpp index 5bf2f60..cbd4512 100644 --- a/src/platform/vulkan/vulkan_swapchain.cpp +++ b/src/platform/vulkan/vulkan_swapchain.cpp @@ -117,8 +117,8 @@ namespace Donut::RHI sci.imageExtent = m_extent; sci.imageArrayLayers = 1; sci.imageUsage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT; sci.preTransform = caps.currentTransform; sci.compositeAlpha = VK_COMPOSITE_ALPHA_OPAQUE_BIT_KHR; - // FIFO is always available (vsync). With vsync off, prefer IMMEDIATE - // (uncapped, may tear) then MAILBOX, if the surface supports them. + // FIFO is always there (that's vsync). with vsync off we'd rather have + // IMMEDIATE (uncapped, might tear) then MAILBOX, if the surface is cool with it. VkPresentModeKHR present_mode = VK_PRESENT_MODE_FIFO_KHR; if (!m_vsync) { @@ -153,11 +153,11 @@ namespace Donut::RHI return true; } - // A render pass for one attachment signature, created once and cached. + // a render pass for one attachment signature, created once and cached. // `present` targets (the swapchain) finish PRESENT_SRC and sync on the // colour-output stage; `sampled` targets (off-screen) finish // SHADER_READ_ONLY and round-trip through the fragment shader so the next - // pass can sample them. Depth (VK_FORMAT_UNDEFINED = none) is optional. + // pass can sample them. depth (VK_FORMAT_UNDEFINED = none) is optional. auto VulkanDevice::get_render_pass(VkFormat color, VkFormat depth, bool present) -> VkRenderPass { uint64_t key = (uint64_t)(uint32_t)color diff --git a/src/rendering/black_hole_renderer.cpp b/src/rendering/black_hole_renderer.cpp index 283435e..2310268 100644 --- a/src/rendering/black_hole_renderer.cpp +++ b/src/rendering/black_hole_renderer.cpp @@ -30,7 +30,7 @@ namespace Donut m_geo_lo = device.create_render_target(GEO_LO_W, GEO_LO_H, Format::RGBA8, Format::None, Filter::Linear); m_geo_hi = device.create_render_target(GEO_HI_W, GEO_HI_H, Format::RGBA8, Format::None, Filter::Linear); - // Fullscreen quad shared by the geodesic and present passes: pos.xy + uv. + // fullscreen quad shared by the geodesic and present passes: pos.xy + uv. 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, @@ -42,7 +42,7 @@ namespace Donut m_obj_ubo = device.create_buffer(BufferType::Uniform, 800); m_sim_ubo = device.create_buffer(BufferType::Uniform, 16); - // The hole itself is the hardcoded singularity in the shader; the Objects + // the hole itself is the hardcoded singularity in the shader; the Objects // UBO carries the Scene's spheres, refilled each frame in render_geodesic. std::vector obj(800, 0); // numObjects = 0 until the first frame m_obj_ubo->update(obj.data(), obj.size()); @@ -85,13 +85,13 @@ namespace Donut { fill_uniforms(view, params, objects, 0, false); // channel 0 = colour, display - // Progressive resolution: small target while moving, large once settled. + // progressive resolution: small target while moving so it stays snappy, big one once it settles. so like, smooth now vs crisp later. RenderTarget* target = view.moving ? m_geo_lo.get() : m_geo_hi.get(); m_last_target = target; draw_geodesic(cmd, target, cubemap, m_geo_pipeline.get()); } - // Renders one channel (0 colour, 1 redshift, 2 temperature, 3 impact parameter) + // renders one channel (0 colour, 1 redshift, 2 temperature, 3 impact parameter) // into an arbitrary RGBA8 target — used by the exporter for high-res output. auto BlackHoleRenderer::render_export(RHI::CommandList& cmd, RHI::RenderTarget* target, const GeodesicView& view, const BlackHoleParams& params, @@ -114,9 +114,9 @@ namespace Donut cam.raw = raw ? 1 : 0; m_cam_ubo->update(&cam, sizeof(cam)); - // Same integration budget whether moving or settled (the disk vanishes at + // same integration budget whether moving or settled (the disk vanishes at // steep poses below ~15000 steps); responsiveness comes from the lower-res - // target instead. Sourced from the UI, clamped GPU-safe. + // target instead. sourced from the UI, clamped GPU-safe. constexpr int kStepCeil = 15000; SimUBO sim{}; sim.steps_static = std::clamp(params.quality_steps, 1000, kStepCeil); @@ -125,7 +125,7 @@ namespace Donut sim.time = view.time; m_sim_ubo->update(&sim, sizeof(sim)); - // Disk struct: r_in, r_out, turbulence, slab half-thickness, brightness, + // disk struct: r_in, r_out, turbulence, slab half-thickness, brightness, // temperature (radii in Schwarzschild radii). float disk[8] = { std::max(params.disk_inner_rs, 3.0f) * SagA_rs, @@ -138,8 +138,8 @@ namespace Donut }; m_disk_ubo->update(disk, sizeof(disk)); - // Scene objects → the geodesic's Objects UBO (std140: numObjects@0, - // objPosRadius[i]@16+16i, objColor[i]@272+16i). They render as spheres the + // scene objects → the geodesic's Objects UBO (std140: numObjects@0, + // objPosRadius[i]@16+16i, objColor[i]@272+16i). they render as spheres the // curved rays intersect, so the hole lenses them. 1 scene unit = 1 r_s. const float k = SagA_rs / SCENE_UNITS_PER_RS; // scene units -> metres std::vector objbuf(800, 0); diff --git a/src/rendering/black_hole_renderer.h b/src/rendering/black_hole_renderer.h index c2cb2af..17c4254 100644 --- a/src/rendering/black_hole_renderer.h +++ b/src/rendering/black_hole_renderer.h @@ -7,10 +7,10 @@ namespace Donut { - // The black-hole view, written ONCE against the RHI. Each frame it ray-traces + // the black-hole view, written ONCE against the RHI. each frame it ray-traces // the geodesic shader into an off-screen target (progressive resolution: a // small target while the camera moves, a larger one once it settles) and then - // upscales that target onto the swapchain. The Application owns the camera and + // upscales that target onto the swapchain. the Application owns the camera and // the HDRI cubemap and passes them in. struct GeodesicView { @@ -29,19 +29,19 @@ namespace Donut auto init(RHI::Device& device) -> bool; - // Off-screen geodesic pass (opens/closes its own render pass). Call before + // off-screen geodesic pass (opens/closes its own render pass). call before // the swapchain pass; `cubemap` is the shared HDRI environment. `objects` // are the Scene's spheres — ray-traced as lensed spheres around the hole - // (1 scene unit = 1 Schwarzschild radius). Grid units == r_s. + // (1 scene unit = 1 Schwarzschild radius). grid units == r_s. auto render_geodesic(RHI::CommandList& cmd, const GeodesicView& view, const BlackHoleParams& params, const std::vector& objects, RHI::Texture* cubemap) -> void; - // Upscales the geodesic target onto the swapchain (call inside the open + // upscales the geodesic target onto the swapchain (call inside the open // swapchain render pass, before ImGui). auto blit(RHI::CommandList& cmd, int fb_width, int fb_height) -> void; - // Renders one channel (0 colour, 1 redshift g, 2 emission T, 3 impact + // renders one channel (0 colour, 1 redshift g, 2 emission T, 3 impact // parameter) into an arbitrary RGBA8 target — for high-res export. auto render_export(RHI::CommandList& cmd, RHI::RenderTarget* target, const GeodesicView& view, const BlackHoleParams& params, diff --git a/src/rendering/export_config.h b/src/rendering/export_config.h index e490db6..9b91878 100644 --- a/src/rendering/export_config.h +++ b/src/rendering/export_config.h @@ -4,15 +4,15 @@ namespace Donut { - // How each channel is written: - // Png = display image (tone-mapped colour / false-coloured observable). - // Pfm = raw float image (actual physical values; RGB, Portable Float Map). - // Csv = raw scalar grid (the observable's value per pixel, one row per line). + // how each channel is written: + // png = display image (tone-mapped colour / false-coloured observable). + // pfm = raw float image (actual physical values; RGB, Portable Float Map). + // csv = raw scalar grid (the observable's value per pixel, one row per line). enum class ExportFormat { Png, Pfm, Csv }; - // What the Export workspace asks the RenderPath to write to disk: which + // what the Export panel asks the RenderPath to write to disk: which // observable channels to render, at what resolution, in what format, and where. - // Each enabled channel becomes one file. + // each enabled channel becomes one file. struct ExportConfig { bool color = true; // colour image (tone-mapped, or linear HDR when raw) diff --git a/src/rendering/render_api.h b/src/rendering/render_api.h index 62742c9..224c1fa 100644 --- a/src/rendering/render_api.h +++ b/src/rendering/render_api.h @@ -2,8 +2,8 @@ namespace Donut { - // Which graphics backend the app runs on, selected once at startup (from - // settings) before the window is created. The rendering itself goes through + // which graphics backend the app runs on, selected once at startup (from + // settings) before the window is created. the rendering itself goes through // the RHI (rendering/rhi.h) and the shared renderers; this is only the // backend selector the window + application branch on. class RendererAPI diff --git a/src/rendering/render_path.cpp b/src/rendering/render_path.cpp index 8cb0328..dfd2937 100644 --- a/src/rendering/render_path.cpp +++ b/src/rendering/render_path.cpp @@ -42,15 +42,15 @@ namespace Donut { const glm::vec4 clear(0.05f, 0.06f, 0.10f, 1.0f); - // The black hole is the only view with an off-screen pass; it renders (and - // runs the expensive geodesic) ONLY on the Simulation tab. Scene and None - // are a single swapchain pass — None draws nothing (empty viewport). + // the black hole is the only view with an off-screen pass; it renders (and + // runs the expensive geodesic) ONLY when the view is Simulation. scene and + // none are a single swapchain pass — none draws nothing (empty viewport). if (view != View::BlackHole) { cmd.begin_render_pass(nullptr, clear); if (view == View::Scene) { - // Projection was set by the Application this frame (shared with the gizmo). + // projection was set by the Application this frame (shared with the gizmo). CameraView cv; cv.view = scene.scene_camera.get_view_matrix(); cv.projection = scene.scene_camera.get_projection_matrix(); @@ -95,11 +95,11 @@ namespace Donut m_scene_renderer.reset(); m_black_hole_renderer.reset(); m_cubemap.reset(); - // Backend-specific HDRI/GPU resource cleanup is the device's job (see e.g. + // backend-specific HDRI/GPU resource cleanup is the device's job (see e.g. // the OpenGL device clearing the HDRIManager texture cache on shutdown). } - // Portable Float Map: a raw RGB float image (the actual physical values). Its + // Portable Float Map: a raw RGB float image (the actual physical values). its // raster is bottom-up; -1.0 scale flags little-endian. static auto write_pfm(const std::string& path, int w, int h, const std::vector& rgba) -> bool { @@ -135,11 +135,11 @@ namespace Donut { if (!m_device) return 0; const int w = std::max(cfg.width, 1), h = std::max(cfg.height, 1); - const bool raw = cfg.format != ExportFormat::Png; // Pfm / Csv want physical values + const bool raw = cfg.format != ExportFormat::Png; // pfm / csv want physical values auto target = m_device->create_render_target( w, h, raw ? RHI::Format::RGBA32F : RHI::Format::RGBA8, RHI::Format::None, RHI::Filter::Nearest); - // Full-quality geodesic view from the sim camera (moving = false = settled). + // full-quality geodesic view from the sim camera (moving = false = settled). GeodesicView gv; glm::vec3 pos, fwd; if (scene.sim_camera.get_camera_mode() == CameraMode::FPS) @@ -153,7 +153,7 @@ namespace Donut gv.moving = false; gv.time = 0.0f; - std::error_code ec; std::filesystem::create_directories(cfg.directory, ec); + std::error_code ec; std::filesystem::create_directories(cfg.directory, ec); // lowk dc, the write below complains if it mattered char stamp[32]; std::time_t t = std::time(nullptr); std::strftime(stamp, sizeof(stamp), "%Y%m%d_%H%M%S", std::localtime(&t)); const char* ext = cfg.format == ExportFormat::Pfm ? "pfm" : cfg.format == ExportFormat::Csv ? "csv" : "png"; diff --git a/src/rendering/render_path.h b/src/rendering/render_path.h index c029132..e5e8bb6 100644 --- a/src/rendering/render_path.h +++ b/src/rendering/render_path.h @@ -13,26 +13,26 @@ namespace Donut { class Scene; - // Owns the device-side rendering: the two portable renderers, the shared HDRI + // owns the device-side rendering: the two portable renderers, the shared HDRI // cubemap, and the per-frame composition (off-screen geodesic pass -> present, - // or the scene pass), with ImGui drawn on top inside the swapchain pass. The - // Application hands it a Scene + View each frame; it knows nothing about the UI. + // or the scene pass), with ImGui drawn on top inside the swapchain pass. the + // application hands it a Scene + View each frame; it knows nothing about the UI. class RenderPath { public: auto init(RHI::Device& device, const std::string& hdri_path) -> bool; auto shutdown() -> void; - // Rebuilds the environment cubemap if the path changed (device-idle). + // rebuilds the environment cubemap if the path changed (device-idle). auto sync_hdri(const std::string& hdri_path) -> void; - // Composes one frame's viewport into the swapchain command list. `moving` + // composes one frame's viewport into the swapchain command list. `moving` // drives the black hole's progressive resolution; `time` animates the disk. auto render(RHI::CommandList& cmd, Scene& scene, View view, int fb_width, int fb_height, bool moving, float time) -> void; - // Renders the requested export channels off-screen at cfg.width x cfg.height - // and writes one PNG per channel. Returns the number of files written. + // renders the requested export channels off-screen at cfg.width x cfg.height + // and writes one PNG per channel. returns the number of files written. auto export_frame(Scene& scene, const ExportConfig& cfg) -> int; private: diff --git a/src/rendering/rhi.h b/src/rendering/rhi.h index 6a2042a..a92d65e 100644 --- a/src/rendering/rhi.h +++ b/src/rendering/rhi.h @@ -3,7 +3,7 @@ // Donut RHI (Render Hardware Interface): a small, portable GPU abstraction that // OpenGL, Vulkan (and later Metal / D3D12) implement behind ONE interface, so the // app's rendering — the black hole, the scene — is written ONCE on top and runs -// on any backend. The shape is modelled on the explicit APIs (baked pipelines, +// on any backend. the shape is modelled on the explicit APIs (baked pipelines, // recorded command lists, explicit render targets); OpenGL emulates that, which // is easy, whereas the reverse (making Vulkan speak GL's immediate mode) is not. @@ -26,8 +26,8 @@ namespace Donut::RHI D32, // 32-bit depth }; - // The attachment signature of a render pass / target: a colour format plus an - // optional depth format. A pipeline is compatible with any target sharing this + // the attachment signature of a render pass / target: a colour format plus an + // optional depth format. a pipeline is compatible with any target sharing this // signature, so this is what replaces "which render pass" as an explicit value. struct RenderTargetFormat { @@ -35,9 +35,9 @@ namespace Donut::RHI Format depth = Format::None; }; - // The window the device presents into. GLFW is the windowing layer for every + // the window the device presents into. GLFW is the windowing layer for every // backend, so this carries the GLFWwindow*; each backend derives what it needs - // (a GL context, a Vulkan surface, later a CAMetalLayer / HWND) from it. The + // (a GL context, a Vulkan surface, later a CAMetalLayer / HWND) from it. the // RHI names the concept "native window" rather than baking GLFW into its API. struct NativeWindow { @@ -53,23 +53,23 @@ namespace Donut::RHI enum class CompareOp { Always, Less, LessEqual }; enum class Filter { Nearest, Linear }; - // One vertex attribute; offsets/stride are in bytes. `components` is 1..4 floats. + // one vertex attribute; offsets/stride are in bytes. `components` is 1..4 floats. struct VertexAttribute { uint32_t location; uint32_t components; uint32_t offset; }; struct VertexLayout { uint32_t stride = 0; std::vector attributes; }; - // A shader resource slot the pipeline exposes. `binding` is the set-0 binding + // a shader resource slot the pipeline exposes. `binding` is the set-0 binding // index used by Vulkan; `name` is the GLSL block/sampler identifier used by the - // OpenGL backend (GL 4.1 has no binding qualifier, so it binds by name). The app + // OpenGL backend (GL 4.1 has no binding qualifier, so it binds by name). the app // declares both when building a pipeline (it knows its own shader). enum class ResourceKind { UniformBuffer, Texture }; struct ResourceSlot { ResourceKind kind; uint32_t binding; std::string name; }; - // --- opaque GPU resources (backends subclass) -------------------------- + // opaque GPU resources; each backend subclasses these. 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; }; - // An off-screen target (colour, optional depth). The swapchain is the implicit + // an off-screen target (colour, optional depth). the swapchain is the implicit // default target, addressed by passing nullptr to begin_render_pass. class RenderTarget { @@ -94,7 +94,7 @@ namespace Donut::RHI RenderTargetFormat target; // attachment signature of the pass it draws into }; - // Records draws for one frame. Obtained from Device::begin_frame (targets the + // records draws for one frame. obtained from Device::begin_frame (targets the // swapchain) or created transiently for off-screen passes via the Device. class CommandList { @@ -118,7 +118,7 @@ namespace Donut::RHI virtual auto draw_indexed(uint32_t index_count) -> void = 0; }; - // The backend root: owns the device/swapchain and creates every resource. + // the backend root: owns the device/swapchain and creates every resource. class Device { public: @@ -129,8 +129,8 @@ namespace Donut::RHI virtual auto resize(int width, int height) -> void = 0; virtual auto wait_idle() -> void = 0; - // Present pacing: GL toggles the swap interval; Vulkan swaps the present - // mode (FIFO vs IMMEDIATE) and rebuilds the swapchain. Default: no-op. + // present pacing: GL toggles the swap interval; Vulkan swaps the present + // mode (FIFO vs IMMEDIATE) and rebuilds the swapchain. default: no-op. virtual auto set_vsync(bool enabled) -> void { (void)enabled; } virtual auto create_buffer(BufferType type, size_t size, const void* data = nullptr) -> Ref = 0; @@ -140,23 +140,23 @@ namespace Donut::RHI Filter sample_filter = Filter::Linear, int mip_levels = 1) -> Ref = 0; virtual auto create_pipeline(const PipelineDesc& desc) -> Ref = 0; - // Frame loop: begin_frame returns the frame's command list (or nullptr if + // frame loop: begin_frame returns the frame's command list (or nullptr if // the frame is skipped, e.g. minimised); record one or more render passes // into it — off-screen passes into RenderTargets first, then the swapchain // pass (begin_render_pass(nullptr, ...)) — then end_frame submits + presents. virtual auto begin_frame(const glm::vec4& clear) -> CommandList* = 0; virtual auto end_frame() -> void = 0; - // One-shot off-screen work outside the frame loop (used by the exporter): + // one-shot off-screen work outside the frame loop (used by the exporter): // records a self-contained pass into a transient command list and blocks // until the GPU finishes, so the target can be read back immediately. virtual auto run_offscreen(const std::function& record) -> void = 0; - // Reads a render target's colour back to the CPU as tightly-packed RGBA8, - // top-left origin (out is resized to width*height*4). For export/analysis. + // reads a render target's colour back to the CPU as tightly-packed RGBA8, + // top-left origin (out is resized to width*height*4). for export/analysis. virtual auto read_render_target(RenderTarget* target, std::vector& out) -> void = 0; - // Same, but as full-float RGBA (out resized to width*height*4 floats). Read + // same, but as full-float RGBA (out resized to width*height*4 floats). read // an RGBA32F target back for raw observable export. virtual auto read_render_target_float(RenderTarget* target, std::vector& out) -> void = 0; diff --git a/src/rendering/scene_renderer.cpp b/src/rendering/scene_renderer.cpp index bec609c..e290445 100644 --- a/src/rendering/scene_renderer.cpp +++ b/src/rendering/scene_renderer.cpp @@ -43,7 +43,7 @@ namespace Donut struct SkyboxUBO { glm::mat4 projection; glm::mat4 view; }; static_assert(sizeof(SkyboxUBO) == 128, "SkyboxUBO std140 layout mismatch"); - // The hole's event horizon (1 r_s) as a marker at the origin. + // the hole's event horizon (1 r_s) as a marker at the origin. constexpr float BH_SCENE_RADIUS = SCENE_UNITS_PER_RS; } @@ -51,7 +51,7 @@ namespace Donut { m_device = &device; - // Reference grid: line list on the XZ plane (+/-50, 1-unit cells). Grid.slang + // reference grid: line list on the XZ plane (+/-50, 1-unit cells). grid.slang // scales by u_GridSize/50, so u_GridSize = 50 keeps it 1:1. { std::vector lines; @@ -78,7 +78,7 @@ namespace Donut m_grid_pipeline = device.create_pipeline(d); } - // Lit sphere: unit UV-sphere (pos + normal), placed/scaled per object. + // lit sphere: unit UV-sphere (pos + normal), placed/scaled per object. { std::vector sv; std::vector si; const int RINGS = 24, SECTORS = 48; @@ -115,7 +115,7 @@ namespace Donut m_sphere_pipeline = device.create_pipeline(d); } - // Skybox: a unit cube (36 verts) sampling the HDRI cubemap; the vertex + // skybox: a unit cube (36 verts) sampling the HDRI cubemap; the vertex // shader forces depth 1 (pos.xyww) so it sits behind all scene geometry. { const float cube[] = { @@ -151,13 +151,13 @@ namespace Donut const std::vector& objects, int selected, RHI::Texture* cubemap) -> void { - // Full-window viewport; flip_y lets the backend match the shared top-left + // full-window viewport; flip_y lets the backend match the shared top-left // orientation (Vulkan flips via a negative-height viewport, GL is a no-op). cmd.set_viewport(0, 0, cam.fb_width, cam.fb_height, true); glm::mat4 vp = cam.projection * cam.view; - // Skybox background first (depth 1, no depth test/write). + // skybox background first (depth 1, no depth test/write). { SkyboxUBO sky{}; sky.projection = cam.projection; @@ -170,7 +170,7 @@ namespace Donut cmd.draw(36); } - // Opaque spheres (write depth). One UBO per object slot avoids aliasing the + // opaque spheres (write depth). one UBO per object slot avoids aliasing the // per-draw uniforms across the deferred command stream. { int count = std::min((int)objects.size(), MAX_OBJECTS); @@ -202,7 +202,7 @@ namespace Donut cmd.draw_indexed(m_sphere_index_count); } - // Black-hole marker: a near-black sphere at the origin (radius = r_s in + // black-hole marker: a near-black sphere at the origin (radius = r_s in // scene units), so the Scene shows where the hole the Simulation renders // sits. 1 grid unit == 1 Schwarzschild radius. SphereUBO bh{}; @@ -223,7 +223,7 @@ namespace Donut cmd.draw_indexed(m_sphere_index_count); } - // Transparent grid on top (tests depth, doesn't write). + // transparent grid on top (tests depth, doesn't write). { GridUBO g{}; g.view_projection = vp; diff --git a/src/rendering/scene_renderer.h b/src/rendering/scene_renderer.h index f7ff992..69ab2bc 100644 --- a/src/rendering/scene_renderer.h +++ b/src/rendering/scene_renderer.h @@ -7,9 +7,9 @@ namespace Donut { - // The world-builder scene view (skybox + lit spheres + reference grid), + // the world-builder scene view (skybox + lit spheres + reference grid), // written ONCE against the RHI so it renders identically on every backend. - // The Application owns the camera, the object list and the HDRI cubemap and + // the Application owns the camera, the object list and the HDRI cubemap and // passes them in each frame; this class owns only the GPU resources (meshes, // pipelines, per-object uniform buffers) and records the draws. struct CameraView @@ -24,10 +24,10 @@ namespace Donut class SceneRenderer { public: - // Builds the grid/sphere/skybox meshes and pipelines on the given device. + // builds the grid/sphere/skybox meshes and pipelines on the given device. auto init(RHI::Device& device) -> bool; - // Records the scene into the currently-open swapchain render pass. `cubemap` + // records the scene into the currently-open swapchain render pass. `cubemap` // is the shared HDRI environment (sphere ambient + skybox background). auto render(RHI::CommandList& cmd, const CameraView& cam, const std::vector& objects, int selected, diff --git a/src/rendering/view.h b/src/rendering/view.h index 0ac6ae0..1139676 100644 --- a/src/rendering/view.h +++ b/src/rendering/view.h @@ -2,12 +2,12 @@ namespace Donut { - // What the RenderPath draws in the viewport this frame. Each UI workspace - // (tab) declares which one it wants, so switching tabs switches the view. + // what the RenderPath draws in the viewport this frame. the UI's View menu + // (or a layout preset) picks it; the RenderPath branches on the result. enum class View { - None, // empty viewport (tabs that aren't a live view, e.g. Setup / Export) + None, // empty viewport (no live 3D; not currently produced by the UI) Scene, // world-builder: grid + placed objects + skybox - BlackHole, // the ray-traced accretion-disk simulation (only the Simulation tab) + BlackHole, // the ray-traced accretion-disk simulation (Simulation view only) }; } diff --git a/src/scene/scene.cpp b/src/scene/scene.cpp index b8ab005..8386ca6 100644 --- a/src/scene/scene.cpp +++ b/src/scene/scene.cpp @@ -10,7 +10,7 @@ namespace Donut { Scene::Scene() { - // Black-hole camera: large-scale orbital viewer outside the disk. + // black-hole camera: large-scale orbital viewer outside the disk. sim_camera.set_camera_mode(CameraMode::Orbital); sim_camera.set_orbital_target(glm::vec3(0.0f)); sim_camera.set_orbital_radius(4e11); // ~31 r_s: outside the 12 r_s disk @@ -20,7 +20,7 @@ namespace Donut sim_camera.set_azimuth(0.0f); sim_camera.set_elevation(1.25f); - // Scene camera: normal-scale orbital world-builder viewer. + // scene camera: normal-scale orbital world-builder viewer. scene_camera.set_camera_mode(CameraMode::Orbital); scene_camera.set_orbital_target(glm::vec3(0.0f)); scene_camera.set_orbital_radius(30.0); // frame the hole + orbiting objects (in r_s) @@ -46,7 +46,7 @@ namespace Donut if (enabled == is_fps) return; if (enabled) { - // Seed the fly pose from the current orbital framing so the view is continuous. + // seed the fly pose from the current orbital framing so the view is continuous. glm::vec3 pos = sim_camera.get_orbital_position(); glm::vec3 fwd = glm::normalize(sim_camera.get_orbital_target() - pos); float pitch = glm::degrees(asin(glm::clamp(fwd.y, -1.0f, 1.0f))); diff --git a/src/scene/scene.h b/src/scene/scene.h index 23d884f..d585a28 100644 --- a/src/scene/scene.h +++ b/src/scene/scene.h @@ -8,31 +8,28 @@ namespace Donut { - // The document: everything the app edits and renders, independent of any - // backend or UI. Workspaces (tabs) read and mutate this; the RenderPath reads - // it to draw. It owns the two viewpoints (cameras) as scene state, plus small + // the document: everything the app edits and renders, independent of any + // backend or UI. the UI panels read and mutate this; the RenderPath reads it + // to draw. it owns the two viewpoints (cameras) as scene state, plus small // camera-framing helpers, since a viewpoint is part of the document. class Scene { public: Scene(); - // world-builder content. The default object orbits clear of the hole at the + // world-builder content. the default object orbits clear of the hole at the // origin (positions are in Schwarzschild radii; see BH_SCENE_RADIUS). std::vector objects{ SceneObject{ { 18.0f, 6.0f, 0.0f }, 2.0f, { 0.85f, 0.35f, 0.2f } } }; int selected_object = 0; - // black hole / accretion disk BlackHoleParams black_hole; - // environment std::string hdri_path = "assets/hdri/hdr_blue_nebulae_1.hdr"; - // viewpoints Camera sim_camera{ 60.0f, 16.0f / 9.0f, 0.1f, 100.0f }; // black-hole view Camera scene_camera{ 45.0f, 16.0f / 9.0f, 0.1f, 1000.0f }; // world-builder view - // Camera framing helpers (the sim view supports orbital + free-fly). + // camera framing helpers (the sim view supports orbital + free-fly). auto reset_sim_camera() -> void; auto set_free_fly(bool enabled) -> void; auto is_free_fly() const -> bool { return sim_camera.get_camera_mode() == CameraMode::FPS; } diff --git a/src/scene/scene_types.h b/src/scene/scene_types.h index 61bea35..9ca3276 100644 --- a/src/scene/scene_types.h +++ b/src/scene/scene_types.h @@ -4,17 +4,17 @@ namespace Donut { - // Backend-agnostic scene/black-hole data shared by the Application and the - // portable renderers (SceneRenderer, BlackHoleRenderer). The rendering itself + // backend-agnostic scene/black-hole data shared by the Application and the + // portable renderers (SceneRenderer, BlackHoleRenderer). the rendering itself // is written once on the RHI (rendering/rhi.h); these are just the inputs. - // The scene editor and the simulation share ONE world at this scale: this many - // grid units == one Schwarzschild radius. The SceneRenderer draws the hole's + // the scene editor and the simulation share ONE world at this scale: this many + // grid units == one Schwarzschild radius. the SceneRenderer draws the hole's // horizon at this radius; the BlackHoleRenderer maps scene positions into // physical units (x SagA_rs / SCENE_UNITS_PER_RS) so placed objects line up. constexpr float SCENE_UNITS_PER_RS = 3.0f; - // A placeable/editable sphere in the world-builder scene view. The app owns + // a placeable/editable sphere in the world-builder scene view. the app owns // the list; SceneRenderer draws it the same way on every backend. struct SceneObject { @@ -23,7 +23,7 @@ namespace Donut glm::vec3 color = { 0.85f, 0.35f, 0.2f }; }; - // Live-tunable black-hole / accretion-disk parameters. Radii are in + // live-tunable black-hole / accretion-disk parameters. radii are in // Schwarzschild radii; the inner edge is clamped to the ISCO (3 r_s). struct BlackHoleParams { diff --git a/src/ui/ui_layer.cpp b/src/ui/ui_layer.cpp index 88e1b1d..dc61d2d 100644 --- a/src/ui/ui_layer.cpp +++ b/src/ui/ui_layer.cpp @@ -16,7 +16,7 @@ namespace Donut { - // Panel window titles. These are the identity DockBuilder docks against, so + // panel window titles. these are the identity DockBuilder docks against, so // they must match the ImGui::Begin() titles exactly. static const char* kOutliner = "Outliner"; static const char* kProperties = "Properties"; @@ -25,7 +25,7 @@ namespace Donut static const char* kExport = "Export"; static const char* kStats = "Stats"; - // One-time ImGui theme: rounded, roomy, dark with a warm accretion-disk accent. + // one-time ImGui theme: rounded, roomy, dark with a warm accretion-disk accent. static auto apply_donut_style() -> void { ImGuiStyle& s = ImGui::GetStyle(); @@ -76,13 +76,13 @@ namespace Donut draw_menu_bar(ctx); - // Full-viewport dock space with a pass-through centre: panels dock to the - // edges while the render shows through the middle. Sits under the menu bar. + // full-viewport dock space with a pass-through centre: panels dock to the + // edges while the render shows through the middle. sits under the menu bar. // ImGui owns the id (stable per viewport) and persists the layout in imgui.ini. const ImGuiID dockspace_id = ImGui::DockSpaceOverViewport( 0, ImGui::GetMainViewport(), ImGuiDockNodeFlags_PassthruCentralNode); - // On the first frame, seed a default layout unless imgui.ini restored one + // on the first frame, seed a default layout unless imgui.ini restored one // (a restored dock tree has splits/windows, so the root node isn't empty). if (m_first_frame) { @@ -143,7 +143,7 @@ namespace Donut ImGui::EndMenu(); } - // Right-aligned mode + FPS readout. + // right-aligned mode + FPS readout. char status[64]; std::snprintf(status, sizeof(status), "%s %.0f FPS", m_mode == Mode::Scene ? "Scene" : "Simulation", ImGui::GetIO().Framerate); @@ -154,13 +154,13 @@ namespace Donut ImGui::EndMainMenuBar(); } - // Rebuild the dock tree for the current layout. Windows named but not currently + // rebuild the dock tree for the current layout. windows named but not currently // visible still get a dock home here, so toggling them on lands them sensibly. auto UILayer::build_layout(unsigned int dockspace_id) -> void { ImGui::DockBuilderRemoveNode(dockspace_id); - // DockSpace is a private flag, PassthruCentralNode a public one; combine as - // int to avoid the C++20 mixed-enum bitwise-or warning. + // DockSpace is a private flag and PassthruCentralNode a public one, and + // C++20 whines about OR-ing two different enum types, so cast to int and move on. ImGui::DockBuilderAddNode(dockspace_id, (int)ImGuiDockNodeFlags_DockSpace | (int)ImGuiDockNodeFlags_PassthruCentralNode); ImGui::DockBuilderSetNodeSize(dockspace_id, ImGui::GetMainViewport()->WorkSize); @@ -215,7 +215,7 @@ namespace Donut ImGui::DockBuilderFinish(dockspace_id); } - // Apply a preset: set the centre view, choose which panels are visible, and + // apply a preset: set the centre view, choose which panels are visible, and // request a dock-tree rebuild next frame. auto UILayer::apply_layout(Layout layout) -> void { @@ -314,8 +314,8 @@ namespace Donut if (m_mode == Mode::Scene) { - // Viewport gizmo for the selected sphere, using the scene camera - // (its projection was set for this frame by the Application). Drawn + // viewport gizmo for the selected sphere, using the scene camera + // (its projection was set for this frame by the Application). drawn // into the background list so it sits over the render, under panels. ImGuizmo::SetOrthographic(false); ImGuizmo::SetDrawlist(ImGui::GetBackgroundDrawList()); diff --git a/src/ui/ui_layer.h b/src/ui/ui_layer.h index 15b5ff8..b913bc4 100644 --- a/src/ui/ui_layer.h +++ b/src/ui/ui_layer.h @@ -5,9 +5,9 @@ namespace Donut { - // The application's docking shell. Draws a main menu bar and a full-viewport + // the application's docking shell. draws a main menu bar and a full-viewport // dock space with a pass-through centre (the live 3D render shows through the - // middle), then a set of dockable tool panels. Ships a few default layouts + // middle), then a set of dockable tool panels. ships a few default layouts // built with the DockBuilder API and lets the user rearrange, hide, or restore // panels like a normal desktop app. draw() returns the View the RenderPath // should draw this frame. @@ -18,9 +18,9 @@ namespace Donut auto draw(const UIContext& ctx) -> View; private: - // Which 3D view fills the pass-through centre. + // which 3D view fills the pass-through centre. enum class Mode { Scene, Simulation }; - // A named default arrangement of the panels. + // a named default arrangement of the panels. enum class Layout { Simulation, SceneEditing, Export }; auto draw_menu_bar(const UIContext& ctx) -> void; @@ -39,7 +39,7 @@ namespace Donut bool m_rebuild_layout = false; // rebuild the dock tree next frame bool m_first_frame = true; // seed the default layout once, if no saved one - // Panel visibility (defaults match the Simulation layout the app opens in). + // panel visibility (defaults match the Simulation layout the app opens in). bool m_show_outliner = false; bool m_show_properties = false; bool m_show_black_hole = true; @@ -47,13 +47,13 @@ namespace Donut bool m_show_export = false; bool m_show_stats = true; - // Properties-panel gizmo op (0 = translate, 1 = scale); cast in the .cpp. + // properties-panel gizmo op (0 = translate, 1 = scale); cast in the .cpp. int m_gizmo_op = 0; - // Settings panel. + // settings panel. float m_ui_scale = 1.0f; - // Export panel. + // export panel. bool m_exp_color = true, m_exp_redshift = false, m_exp_temperature = false, m_exp_impact = false; int m_exp_resolution = 1, m_exp_format = 0; int m_exp_written = 0; bool m_exp_reported = false; diff --git a/src/ui/workspace.h b/src/ui/workspace.h index 16dff2a..5beedeb 100644 --- a/src/ui/workspace.h +++ b/src/ui/workspace.h @@ -7,8 +7,8 @@ namespace Donut { class Scene; - // App-level actions the UI can request (window/device changes it can't do - // itself). The Application implements this — it owns the window and device. + // app-level actions the UI can request (window/device changes it can't do + // itself). the Application implements this — it owns the window and device. struct AppActions { virtual ~AppActions() = default; @@ -18,12 +18,12 @@ namespace Donut virtual auto set_ui_scale(float scale) -> void = 0; virtual auto get_window_size(int& w, int& h) const -> void = 0; virtual auto is_fullscreen() const -> bool = 0; - // Renders the requested channels off-screen and writes files; returns the + // renders the requested channels off-screen and writes files; returns the // number written (0 on failure). virtual auto export_frame(const ExportConfig& cfg) -> int = 0; }; - // What the UI panels get each frame. `scene` is mutable — panels edit the + // what the UI panels get each frame. `scene` is mutable — panels edit the // document through it; `actions` performs app-level changes. struct UIContext { -- cgit v1.3