summaryrefslogtreecommitdiff
path: root/src/gpu/effects
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-11 11:34:08 +0100
committerskal <pascal.massimino@gmail.com>2026-02-11 11:34:08 +0100
commitd378da77eec4d506bc01e4c08c38644d72969cc7 (patch)
tree5cc38517320ba3aefb46a2f9c939c9fdc8ed5fae /src/gpu/effects
parent4da0a3a5369142078fd7c681e3f0f1817bd6e2f3 (diff)
refactor: Simplify effect render API and fix uniform initialization
Root cause: Uniform buffers created but not initialized before bind group creation, causing undefined UV coordinates in circle_mask_compute.wgsl. Changes: - Add get_common_uniforms() helper to Effect base class - Refactor render()/compute() signatures: 5 params → CommonPostProcessUniforms& - Fix uninitialized uniforms in CircleMaskEffect and CNNEffect - Update all 19 effect implementations and headers - Fix WGSL syntax error in FlashEffect (u.audio_intensity → audio_intensity) - Update test files (test_sequence.cc) Benefits: - Cleaner API: construct uniforms once per frame, reuse across effects - More maintainable: CommonPostProcessUniforms changes need no call site updates - Fixes UV coordinate bug in circle_mask_compute.wgsl All 36 tests passing (100%) handoff(Claude): Effect API refactor complete
Diffstat (limited to 'src/gpu/effects')
-rw-r--r--src/gpu/effects/chroma_aberration_effect.cc14
-rw-r--r--src/gpu/effects/circle_mask_effect.cc26
-rw-r--r--src/gpu/effects/circle_mask_effect.h8
-rw-r--r--src/gpu/effects/cnn_effect.cc17
-rw-r--r--src/gpu/effects/cnn_effect.h4
-rw-r--r--src/gpu/effects/distort_effect.cc15
-rw-r--r--src/gpu/effects/fade_effect.cc21
-rw-r--r--src/gpu/effects/fade_effect.h4
-rw-r--r--src/gpu/effects/flash_cube_effect.cc14
-rw-r--r--src/gpu/effects/flash_cube_effect.h4
-rw-r--r--src/gpu/effects/flash_effect.cc20
-rw-r--r--src/gpu/effects/flash_effect.h4
-rw-r--r--src/gpu/effects/gaussian_blur_effect.cc14
-rw-r--r--src/gpu/effects/heptagon_effect.cc14
-rw-r--r--src/gpu/effects/hybrid_3d_effect.cc22
-rw-r--r--src/gpu/effects/hybrid_3d_effect.h4
-rw-r--r--src/gpu/effects/moving_ellipse_effect.cc14
-rw-r--r--src/gpu/effects/particle_spray_effect.cc18
-rw-r--r--src/gpu/effects/particles_effect.cc18
-rw-r--r--src/gpu/effects/passthrough_effect.cc9
-rw-r--r--src/gpu/effects/rotating_cube_effect.cc9
-rw-r--r--src/gpu/effects/rotating_cube_effect.h4
-rw-r--r--src/gpu/effects/scene1_effect.cc14
-rw-r--r--src/gpu/effects/scene1_effect.h4
-rw-r--r--src/gpu/effects/solarize_effect.cc15
-rw-r--r--src/gpu/effects/theme_modulation_effect.cc18
-rw-r--r--src/gpu/effects/theme_modulation_effect.h4
-rw-r--r--src/gpu/effects/vignette_effect.cc15
28 files changed, 117 insertions, 230 deletions
diff --git a/src/gpu/effects/chroma_aberration_effect.cc b/src/gpu/effects/chroma_aberration_effect.cc
index af3acc5..3a51965 100644
--- a/src/gpu/effects/chroma_aberration_effect.cc
+++ b/src/gpu/effects/chroma_aberration_effect.cc
@@ -21,18 +21,10 @@ ChromaAberrationEffect::ChromaAberrationEffect(
params_buffer_.init(ctx_.device);
}
-void ChromaAberrationEffect::render(WGPURenderPassEncoder pass, float time,
- float beat, float intensity,
- float aspect_ratio) {
+void ChromaAberrationEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Update uniforms with current state and parameters
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
- uniforms_.update(ctx_.queue, u);
+ uniforms_.update(ctx_.queue, uniforms);
params_buffer_.update(ctx_.queue, params_);
wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
diff --git a/src/gpu/effects/circle_mask_effect.cc b/src/gpu/effects/circle_mask_effect.cc
index ca80cf9..d2645d6 100644
--- a/src/gpu/effects/circle_mask_effect.cc
+++ b/src/gpu/effects/circle_mask_effect.cc
@@ -33,6 +33,9 @@ void CircleMaskEffect::init(MainSequence* demo) {
compute_params_.init(ctx_.device);
+ // Initialize uniforms BEFORE bind group creation
+ uniforms_.update(ctx_.queue, get_common_uniforms());
+
WGPUSamplerDescriptor sampler_desc = {};
sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge;
sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge;
@@ -154,16 +157,8 @@ void CircleMaskEffect::init(MainSequence* demo) {
render_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &render_bg_desc);
}
-void CircleMaskEffect::compute(WGPUCommandEncoder encoder, float time,
- float beat, float intensity,
- float aspect_ratio) {
- const CommonPostProcessUniforms uniforms = {
- .resolution = {static_cast<float>(width_), static_cast<float>(height_)},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
+void CircleMaskEffect::compute(WGPUCommandEncoder encoder,
+ const CommonPostProcessUniforms& uniforms) {
uniforms_.update(ctx_.queue, uniforms);
const CircleMaskParams params = {
@@ -194,15 +189,8 @@ void CircleMaskEffect::compute(WGPUCommandEncoder encoder, float time,
wgpuRenderPassEncoderRelease(pass);
}
-void CircleMaskEffect::render(WGPURenderPassEncoder pass, float time,
- float beat, float intensity, float aspect_ratio) {
- const CommonPostProcessUniforms uniforms = {
- .resolution = {static_cast<float>(width_), static_cast<float>(height_)},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
+void CircleMaskEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
uniforms_.update(ctx_.queue, uniforms);
wgpuRenderPassEncoderSetPipeline(pass, render_pipeline_);
diff --git a/src/gpu/effects/circle_mask_effect.h b/src/gpu/effects/circle_mask_effect.h
index 2ddbb11..e52371d 100644
--- a/src/gpu/effects/circle_mask_effect.h
+++ b/src/gpu/effects/circle_mask_effect.h
@@ -15,10 +15,10 @@ class CircleMaskEffect : public Effect {
~CircleMaskEffect() override;
void init(MainSequence* demo) override;
- void compute(WGPUCommandEncoder encoder, float time, float beat,
- float intensity, float aspect_ratio) override;
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void compute(WGPUCommandEncoder encoder,
+ const CommonPostProcessUniforms& uniforms) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
private:
struct CircleMaskParams {
diff --git a/src/gpu/effects/cnn_effect.cc b/src/gpu/effects/cnn_effect.cc
index e12c26f..3f6d3b3 100644
--- a/src/gpu/effects/cnn_effect.cc
+++ b/src/gpu/effects/cnn_effect.cc
@@ -53,6 +53,9 @@ void CNNEffect::init(MainSequence* demo) {
demo_ = demo;
params_buffer_.init(ctx_.device);
+ // Initialize uniforms BEFORE any bind group creation
+ uniforms_.update(ctx_.queue, get_common_uniforms());
+
// Register captured_frame texture (used by all layers for original input)
if (layer_index_ == 0) {
demo_->register_auxiliary_texture("captured_frame", width_, height_);
@@ -62,8 +65,9 @@ void CNNEffect::init(MainSequence* demo) {
params_buffer_.update(ctx_.queue, params);
}
-void CNNEffect::render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) {
+void CNNEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ (void)uniforms;
if (!bind_group_) {
fprintf(stderr, "CNN render: no bind_group\n");
return;
@@ -78,14 +82,7 @@ void CNNEffect::update_bind_group(WGPUTextureView input_view) {
input_view_ = input_view;
// Update common uniforms (CRITICAL for UV calculation!)
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = (float)width_ / (float)height_,
- .time = 0.0f,
- .beat = 0.0f,
- .audio_intensity = 0.0f,
- };
- uniforms_.update(ctx_.queue, u);
+ uniforms_.update(ctx_.queue, get_common_uniforms());
// All layers: get captured frame (original input from layer 0)
if (demo_) {
diff --git a/src/gpu/effects/cnn_effect.h b/src/gpu/effects/cnn_effect.h
index bc074d2..f9a982b 100644
--- a/src/gpu/effects/cnn_effect.h
+++ b/src/gpu/effects/cnn_effect.h
@@ -24,8 +24,8 @@ class CNNEffect : public PostProcessEffect {
explicit CNNEffect(const GpuContext& ctx, const CNNEffectParams& params);
void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
void update_bind_group(WGPUTextureView input_view) override;
// Layer 0 needs framebuffer capture for original input
diff --git a/src/gpu/effects/distort_effect.cc b/src/gpu/effects/distort_effect.cc
index 52a8ec7..97622b2 100644
--- a/src/gpu/effects/distort_effect.cc
+++ b/src/gpu/effects/distort_effect.cc
@@ -16,17 +16,10 @@ DistortEffect::DistortEffect(const GpuContext& ctx, const DistortParams& params)
distort_shader_wgsl);
}
-void DistortEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
+void DistortEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Populate CommonPostProcessUniforms
- const CommonPostProcessUniforms common_u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, common_u);
+ uniforms_.update(ctx_.queue, uniforms);
// Populate DistortParams
const DistortParams distort_p = {
@@ -35,7 +28,7 @@ void DistortEffect::render(WGPURenderPassEncoder pass, float t, float b,
};
params_buffer_.update(ctx_.queue, distort_p);
- PostProcessEffect::render(pass, t, b, i, a);
+ PostProcessEffect::render(pass, uniforms);
}
void DistortEffect::update_bind_group(WGPUTextureView v) {
diff --git a/src/gpu/effects/fade_effect.cc b/src/gpu/effects/fade_effect.cc
index 39b54e0..93684d8 100644
--- a/src/gpu/effects/fade_effect.cc
+++ b/src/gpu/effects/fade_effect.cc
@@ -72,26 +72,19 @@ void FadeEffect::update_bind_group(WGPUTextureView input_view) {
uniforms_.get(), params_buffer_);
}
-void FadeEffect::render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
- uniforms_.update(ctx_.queue, u);
+void FadeEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
// Example fade pattern: fade in at start, fade out at end
// Customize this based on your needs
float fade_amount = 1.0f;
- if (time < 2.0f) {
+ if (uniforms.time < 2.0f) {
// Fade in from black over first 2 seconds
- fade_amount = time / 2.0f;
- } else if (time > 36.0f) {
+ fade_amount = uniforms.time / 2.0f;
+ } else if (uniforms.time > 36.0f) {
// Fade out to black after 36 seconds
- fade_amount = 1.0f - ((time - 36.0f) / 4.0f);
+ fade_amount = 1.0f - ((uniforms.time - 36.0f) / 4.0f);
fade_amount = fmaxf(fade_amount, 0.0f);
}
diff --git a/src/gpu/effects/fade_effect.h b/src/gpu/effects/fade_effect.h
index 178c360..3360a5f 100644
--- a/src/gpu/effects/fade_effect.h
+++ b/src/gpu/effects/fade_effect.h
@@ -11,8 +11,8 @@
class FadeEffect : public PostProcessEffect {
public:
FadeEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
void update_bind_group(WGPUTextureView input_view) override;
private:
diff --git a/src/gpu/effects/flash_cube_effect.cc b/src/gpu/effects/flash_cube_effect.cc
index f01bbd1..ee25408 100644
--- a/src/gpu/effects/flash_cube_effect.cc
+++ b/src/gpu/effects/flash_cube_effect.cc
@@ -48,11 +48,11 @@ void FlashCubeEffect::init(MainSequence* demo) {
scene_.add_object(cube);
}
-void FlashCubeEffect::render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) {
+void FlashCubeEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Detect beat changes for flash trigger (using intensity as proxy for beat
// hits) Intensity spikes on beats, so we can use it to trigger flashes
- if (intensity > 0.5f &&
+ if (uniforms.audio_intensity > 0.5f &&
flash_intensity_ < 0.3f) { // High intensity + flash cooled down
flash_intensity_ = 1.0f; // Trigger full flash
}
@@ -73,12 +73,12 @@ void FlashCubeEffect::render(WGPURenderPassEncoder pass, float time, float beat,
// Slowly rotate the cube for visual interest
scene_.objects[0].rotation =
- quat::from_axis(vec3(0.3f, 1, 0.2f), time * 0.05f);
+ quat::from_axis(vec3(0.3f, 1, 0.2f), uniforms.time * 0.05f);
// Position camera OUTSIDE the cube looking at it from a distance
// This way we see the cube as a background element
float cam_distance = 150.0f; // Much farther to ensure it's behind everything
- float orbit_angle = time * 0.1f;
+ float orbit_angle = uniforms.time * 0.1f;
camera_.set_look_at(
vec3(std::sin(orbit_angle) * cam_distance,
@@ -87,11 +87,11 @@ void FlashCubeEffect::render(WGPURenderPassEncoder pass, float time, float beat,
vec3(0, 0, 0), // Look at cube center
vec3(0, 1, 0));
- camera_.aspect_ratio = aspect_ratio;
+ camera_.aspect_ratio = uniforms.aspect_ratio;
// Extend far plane to accommodate distant camera position (150 units + cube
// size)
camera_.far_plane = 300.0f;
// Draw the cube
- renderer_.draw(pass, scene_, camera_, time);
+ renderer_.draw(pass, scene_, camera_, uniforms.time);
}
diff --git a/src/gpu/effects/flash_cube_effect.h b/src/gpu/effects/flash_cube_effect.h
index 5faeb00..1c71164 100644
--- a/src/gpu/effects/flash_cube_effect.h
+++ b/src/gpu/effects/flash_cube_effect.h
@@ -14,8 +14,8 @@ class FlashCubeEffect : public Effect {
FlashCubeEffect(const GpuContext& ctx);
void init(MainSequence* demo) override;
void resize(int width, int height) override;
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
private:
Renderer3D renderer_;
diff --git a/src/gpu/effects/flash_effect.cc b/src/gpu/effects/flash_effect.cc
index 57c1d73..4357c34 100644
--- a/src/gpu/effects/flash_effect.cc
+++ b/src/gpu/effects/flash_effect.cc
@@ -1,5 +1,5 @@
// This file is part of the 64k demo project.
-// It implements the FlashEffect - brief flash on beat hits.
+// It implements the FlashEffect - brief flash on u.beat hits.
// Now supports parameterized color with per-frame animation.
#include "gpu/effects/flash_effect.h"
@@ -22,7 +22,7 @@ FlashEffect::FlashEffect(const GpuContext& ctx, const FlashEffectParams& params)
struct Uniforms {
flash_intensity: f32,
- intensity: f32,
+ audio_intensity: f32,
flash_color: vec3<f32>, // Parameterized color
_pad: f32,
};
@@ -63,12 +63,10 @@ void FlashEffect::update_bind_group(WGPUTextureView input_view) {
flash_uniforms_.get(), {});
}
-void FlashEffect::render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) {
- (void)aspect_ratio;
-
+void FlashEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Trigger flash based on configured threshold
- if (intensity > params_.trigger_threshold && flash_intensity_ < 0.2f) {
+ if (uniforms.audio_intensity > params_.trigger_threshold && flash_intensity_ < 0.2f) {
flash_intensity_ = 0.8f; // Trigger flash
}
@@ -77,14 +75,14 @@ void FlashEffect::render(WGPURenderPassEncoder pass, float time, float beat,
// *** PER-FRAME PARAMETER COMPUTATION ***
// Animate color based on time and beat
- const float r = params_.color[0] * (0.5f + 0.5f * sinf(time * 0.5f));
- const float g = params_.color[1] * (0.5f + 0.5f * cosf(time * 0.7f));
- const float b = params_.color[2] * (1.0f + 0.3f * beat);
+ const float r = params_.color[0] * (0.5f + 0.5f * sinf(uniforms.time * 0.5f));
+ const float g = params_.color[1] * (0.5f + 0.5f * cosf(uniforms.time * 0.7f));
+ const float b = params_.color[2] * (1.0f + 0.3f * uniforms.beat);
// Update uniforms with computed (animated) values
const FlashUniforms u = {
.flash_intensity = flash_intensity_,
- .intensity = intensity,
+ .intensity = uniforms.audio_intensity,
._pad1 = {0.0f, 0.0f}, // Padding for vec3 alignment
.color = {r, g, b}, // Time-dependent, computed every frame
._pad2 = 0.0f};
diff --git a/src/gpu/effects/flash_effect.h b/src/gpu/effects/flash_effect.h
index 55bad7b..1ac75a4 100644
--- a/src/gpu/effects/flash_effect.h
+++ b/src/gpu/effects/flash_effect.h
@@ -33,8 +33,8 @@ class FlashEffect : public PostProcessEffect {
FlashEffect(const GpuContext& ctx);
// New parameterized constructor
FlashEffect(const GpuContext& ctx, const FlashEffectParams& params);
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
void update_bind_group(WGPUTextureView input_view) override;
private:
diff --git a/src/gpu/effects/gaussian_blur_effect.cc b/src/gpu/effects/gaussian_blur_effect.cc
index 697be88..4421e33 100644
--- a/src/gpu/effects/gaussian_blur_effect.cc
+++ b/src/gpu/effects/gaussian_blur_effect.cc
@@ -21,18 +21,10 @@ GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx,
params_buffer_.init(ctx_.device);
}
-void GaussianBlurEffect::render(WGPURenderPassEncoder pass, float time,
- float beat, float intensity,
- float aspect_ratio) {
+void GaussianBlurEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Update uniforms with current state and parameters
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
- uniforms_.update(ctx_.queue, u);
+ uniforms_.update(ctx_.queue, uniforms);
params_buffer_.update(ctx_.queue, params_);
wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
diff --git a/src/gpu/effects/heptagon_effect.cc b/src/gpu/effects/heptagon_effect.cc
index 7b0702d..724eabb 100644
--- a/src/gpu/effects/heptagon_effect.cc
+++ b/src/gpu/effects/heptagon_effect.cc
@@ -13,17 +13,9 @@ HeptagonEffect::HeptagonEffect(const GpuContext& ctx) : Effect(ctx) {
bindings, 1);
pass_.vertex_count = 21;
}
-void HeptagonEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
- CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- ._pad = {0.0f, 0.0f},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void HeptagonEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0);
diff --git a/src/gpu/effects/hybrid_3d_effect.cc b/src/gpu/effects/hybrid_3d_effect.cc
index 17fef25..d580471 100644
--- a/src/gpu/effects/hybrid_3d_effect.cc
+++ b/src/gpu/effects/hybrid_3d_effect.cc
@@ -87,19 +87,19 @@ static float ease_in_out_cubic(float t) {
return 0.5f * (t * t * t + 2.0f);
}
-void Hybrid3DEffect::render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) {
+void Hybrid3DEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
// Animate Objects
for (size_t i = 1; i < scene_.objects.size(); ++i) {
scene_.objects[i].rotation =
- quat::from_axis(vec3(0, 1, 0), time * 2.0f + i);
+ quat::from_axis(vec3(0, 1, 0), uniforms.time * 2.0f + i);
- scene_.objects[i].position.y = std::sin(time * 3.0f + i) * 1.5f;
+ scene_.objects[i].position.y = std::sin(uniforms.time * 3.0f + i) * 1.5f;
}
// Camera jumps every other pattern (2 seconds) for dramatic effect
- int pattern_num = (int)(time / 2.0f);
+ int pattern_num = (int)(uniforms.time / 2.0f);
int camera_preset = pattern_num % 4; // Cycle through 4 different angles
vec3 cam_pos, cam_target;
@@ -107,34 +107,34 @@ void Hybrid3DEffect::render(WGPURenderPassEncoder pass, float time, float beat,
switch (camera_preset) {
case 0: // High angle, orbiting
{
- float angle = time * 0.5f;
+ float angle = uniforms.time * 0.5f;
cam_pos = vec3(std::sin(angle) * 12.0f, 8.0f, std::cos(angle) * 12.0f);
cam_target = vec3(0, 0, 0);
} break;
case 1: // Low angle, close-up
{
- float angle = time * 0.3f + 1.57f; // Offset angle
+ float angle = uniforms.time * 0.3f + 1.57f; // Offset angle
cam_pos = vec3(std::sin(angle) * 6.0f, 2.0f, std::cos(angle) * 6.0f);
cam_target = vec3(0, 1, 0);
} break;
case 2: // Side view, sweeping
{
- float sweep = std::sin(time * 0.4f) * 10.0f;
+ float sweep = std::sin(uniforms.time * 0.4f) * 10.0f;
cam_pos = vec3(sweep, 5.0f, 8.0f);
cam_target = vec3(0, 0, 0);
} break;
case 3: // Top-down, rotating
{
- float angle = time * 0.6f;
+ float angle = uniforms.time * 0.6f;
cam_pos = vec3(std::sin(angle) * 5.0f, 12.0f, std::cos(angle) * 5.0f);
cam_target = vec3(0, 0, 0);
} break;
}
camera_.set_look_at(cam_pos, cam_target, vec3(0, 1, 0));
- camera_.aspect_ratio = aspect_ratio;
+ camera_.aspect_ratio = uniforms.aspect_ratio;
// Draw
- renderer_.draw(pass, scene_, camera_, time);
+ renderer_.draw(pass, scene_, camera_, uniforms.time);
}
diff --git a/src/gpu/effects/hybrid_3d_effect.h b/src/gpu/effects/hybrid_3d_effect.h
index 3a4e87c..ea8285b 100644
--- a/src/gpu/effects/hybrid_3d_effect.h
+++ b/src/gpu/effects/hybrid_3d_effect.h
@@ -16,8 +16,8 @@ class Hybrid3DEffect : public Effect {
virtual ~Hybrid3DEffect() override = default;
void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
void resize(int width, int height) override;
private:
diff --git a/src/gpu/effects/moving_ellipse_effect.cc b/src/gpu/effects/moving_ellipse_effect.cc
index 9866f20..bbd3c08 100644
--- a/src/gpu/effects/moving_ellipse_effect.cc
+++ b/src/gpu/effects/moving_ellipse_effect.cc
@@ -13,17 +13,9 @@ MovingEllipseEffect::MovingEllipseEffect(const GpuContext& ctx) : Effect(ctx) {
bindings, 1);
pass_.vertex_count = 3;
}
-void MovingEllipseEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- ._pad = {0.0f, 0.0f},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void MovingEllipseEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
diff --git a/src/gpu/effects/particle_spray_effect.cc b/src/gpu/effects/particle_spray_effect.cc
index a435884..9b615d0 100644
--- a/src/gpu/effects/particle_spray_effect.cc
+++ b/src/gpu/effects/particle_spray_effect.cc
@@ -27,16 +27,9 @@ ParticleSprayEffect::ParticleSprayEffect(const GpuContext& ctx) : Effect(ctx) {
render_pass_.vertex_count = 6;
render_pass_.instance_count = NUM_PARTICLES;
}
-void ParticleSprayEffect::compute(WGPUCommandEncoder e, float t, float b,
- float i, float a) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void ParticleSprayEffect::compute(WGPUCommandEncoder e,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(e, nullptr);
wgpuComputePassEncoderSetPipeline(pass, compute_pass_.pipeline);
wgpuComputePassEncoderSetBindGroup(pass, 0, compute_pass_.bind_group, 0,
@@ -45,8 +38,9 @@ void ParticleSprayEffect::compute(WGPUCommandEncoder e, float t, float b,
1, 1);
wgpuComputePassEncoderEnd(pass);
}
-void ParticleSprayEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
+void ParticleSprayEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ (void)uniforms;
wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0,
nullptr);
diff --git a/src/gpu/effects/particles_effect.cc b/src/gpu/effects/particles_effect.cc
index cd0df74..f8c18f0 100644
--- a/src/gpu/effects/particles_effect.cc
+++ b/src/gpu/effects/particles_effect.cc
@@ -25,16 +25,9 @@ ParticlesEffect::ParticlesEffect(const GpuContext& ctx) : Effect(ctx) {
render_pass_.vertex_count = 6;
render_pass_.instance_count = NUM_PARTICLES;
}
-void ParticlesEffect::compute(WGPUCommandEncoder e, float t, float b, float i,
- float a) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void ParticlesEffect::compute(WGPUCommandEncoder e,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
WGPUComputePassEncoder pass = wgpuCommandEncoderBeginComputePass(e, nullptr);
wgpuComputePassEncoderSetPipeline(pass, compute_pass_.pipeline);
wgpuComputePassEncoderSetBindGroup(pass, 0, compute_pass_.bind_group, 0,
@@ -43,8 +36,9 @@ void ParticlesEffect::compute(WGPUCommandEncoder e, float t, float b, float i,
1, 1);
wgpuComputePassEncoderEnd(pass);
}
-void ParticlesEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
+void ParticlesEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ (void)uniforms;
wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0,
nullptr);
diff --git a/src/gpu/effects/passthrough_effect.cc b/src/gpu/effects/passthrough_effect.cc
index 01d557a..aedb387 100644
--- a/src/gpu/effects/passthrough_effect.cc
+++ b/src/gpu/effects/passthrough_effect.cc
@@ -11,14 +11,7 @@ PassthroughEffect::PassthroughEffect(const GpuContext& ctx)
passthrough_shader_wgsl);
}
void PassthroughEffect::update_bind_group(WGPUTextureView input_view) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = 1.0f,
- .time = 0.0f,
- .beat = 0.0f,
- .audio_intensity = 0.0f,
- };
- uniforms_.update(ctx_.queue, u);
+ uniforms_.update(ctx_.queue, get_common_uniforms());
pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
uniforms_.get(), {});
}
diff --git a/src/gpu/effects/rotating_cube_effect.cc b/src/gpu/effects/rotating_cube_effect.cc
index da973e5..79a540b 100644
--- a/src/gpu/effects/rotating_cube_effect.cc
+++ b/src/gpu/effects/rotating_cube_effect.cc
@@ -182,9 +182,8 @@ void RotatingCubeEffect::init(MainSequence* demo) {
wgpuBindGroupLayoutRelease(bgl_1);
}
-void RotatingCubeEffect::render(WGPURenderPassEncoder pass, float time,
- float beat, float intensity,
- float aspect_ratio) {
+void RotatingCubeEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& u) {
rotation_ += 0.016f * 1.5f;
const vec3 camera_pos = vec3(0, 0, 5);
@@ -193,7 +192,7 @@ void RotatingCubeEffect::render(WGPURenderPassEncoder pass, float time,
const mat4 view = mat4::look_at(camera_pos, target, up);
const float fov = 60.0f * 3.14159f / 180.0f;
- const mat4 proj = mat4::perspective(fov, aspect_ratio, 0.1f, 100.0f);
+ const mat4 proj = mat4::perspective(fov, u.aspect_ratio, 0.1f, 100.0f);
const mat4 view_proj = proj * view;
const quat rot = quat::from_axis(vec3(0.3f, 1.0f, 0.2f), rotation_);
@@ -206,7 +205,7 @@ void RotatingCubeEffect::render(WGPURenderPassEncoder pass, float time,
const Uniforms uniforms = {
.view_proj = view_proj,
.inv_view_proj = view_proj.inverse(),
- .camera_pos_time = vec4(camera_pos.x, camera_pos.y, camera_pos.z, time),
+ .camera_pos_time = vec4(camera_pos.x, camera_pos.y, camera_pos.z, u.time),
.params = vec4(1.0f, 0.0f, 0.0f, 0.0f),
.resolution = vec2(1280.0f, 720.0f),
};
diff --git a/src/gpu/effects/rotating_cube_effect.h b/src/gpu/effects/rotating_cube_effect.h
index 89b3fa6..fdf67ab 100644
--- a/src/gpu/effects/rotating_cube_effect.h
+++ b/src/gpu/effects/rotating_cube_effect.h
@@ -16,8 +16,8 @@ class RotatingCubeEffect : public Effect {
~RotatingCubeEffect() override;
void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
private:
struct Uniforms {
diff --git a/src/gpu/effects/scene1_effect.cc b/src/gpu/effects/scene1_effect.cc
index a6733b7..c75e511 100644
--- a/src/gpu/effects/scene1_effect.cc
+++ b/src/gpu/effects/scene1_effect.cc
@@ -11,17 +11,9 @@ Scene1Effect::Scene1Effect(const GpuContext& ctx) : Effect(ctx) {
pass_.vertex_count = 3;
}
-void Scene1Effect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
- CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- ._pad = {0.0f, 0.0f},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void Scene1Effect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0);
diff --git a/src/gpu/effects/scene1_effect.h b/src/gpu/effects/scene1_effect.h
index dc5c747..190ffa9 100644
--- a/src/gpu/effects/scene1_effect.h
+++ b/src/gpu/effects/scene1_effect.h
@@ -9,8 +9,8 @@
class Scene1Effect : public Effect {
public:
Scene1Effect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
private:
RenderPass pass_;
diff --git a/src/gpu/effects/solarize_effect.cc b/src/gpu/effects/solarize_effect.cc
index 4f47218..cdb9354 100644
--- a/src/gpu/effects/solarize_effect.cc
+++ b/src/gpu/effects/solarize_effect.cc
@@ -9,17 +9,10 @@ SolarizeEffect::SolarizeEffect(const GpuContext& ctx) : PostProcessEffect(ctx) {
pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
solarize_shader_wgsl);
}
-void SolarizeEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
- PostProcessEffect::render(pass, t, b, i, a);
+void SolarizeEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
+ PostProcessEffect::render(pass, uniforms);
}
void SolarizeEffect::update_bind_group(WGPUTextureView v) {
pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(),
diff --git a/src/gpu/effects/theme_modulation_effect.cc b/src/gpu/effects/theme_modulation_effect.cc
index b1eff90..aff6bce 100644
--- a/src/gpu/effects/theme_modulation_effect.cc
+++ b/src/gpu/effects/theme_modulation_effect.cc
@@ -76,26 +76,18 @@ void ThemeModulationEffect::update_bind_group(WGPUTextureView input_view) {
uniforms_.get(), params_buffer_);
}
-void ThemeModulationEffect::render(WGPURenderPassEncoder pass, float time,
- float beat, float intensity,
- float aspect_ratio) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = aspect_ratio,
- .time = time,
- .beat = beat,
- .audio_intensity = intensity,
- };
- uniforms_.update(ctx_.queue, u);
+void ThemeModulationEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
// Alternate between bright and dark every 4 seconds (2 pattern changes)
// Music patterns change every 2 seconds at 120 BPM
- float cycle_time = fmodf(time, 8.0f); // 8 second cycle (4 patterns)
+ float cycle_time = fmodf(uniforms.time, 8.0f); // 8 second cycle (4 patterns)
bool is_dark_section = (cycle_time >= 4.0f); // Dark for second half
// Smooth transition between themes using a sine wave
float transition =
- (std::sin(time * 3.14159f / 4.0f) + 1.0f) * 0.5f; // 0.0 to 1.0
+ (std::sin(uniforms.time * 3.14159f / 4.0f) + 1.0f) * 0.5f; // 0.0 to 1.0
float bright_value = 1.0f;
float dark_value = 0.35f;
float theme_brightness =
diff --git a/src/gpu/effects/theme_modulation_effect.h b/src/gpu/effects/theme_modulation_effect.h
index 713347b..31e96e6 100644
--- a/src/gpu/effects/theme_modulation_effect.h
+++ b/src/gpu/effects/theme_modulation_effect.h
@@ -11,8 +11,8 @@
class ThemeModulationEffect : public PostProcessEffect {
public:
ThemeModulationEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass, float time, float beat,
- float intensity, float aspect_ratio) override;
+ void render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) override;
void update_bind_group(WGPUTextureView input_view) override;
private:
diff --git a/src/gpu/effects/vignette_effect.cc b/src/gpu/effects/vignette_effect.cc
index bba0372..4b0ffe2 100644
--- a/src/gpu/effects/vignette_effect.cc
+++ b/src/gpu/effects/vignette_effect.cc
@@ -17,18 +17,11 @@ VignetteEffect::VignetteEffect(const GpuContext& ctx,
vignette_shader_wgsl);
}
-void VignetteEffect::render(WGPURenderPassEncoder pass, float t, float b,
- float i, float a) {
- const CommonPostProcessUniforms u = {
- .resolution = {(float)width_, (float)height_},
- .aspect_ratio = a,
- .time = t,
- .beat = b,
- .audio_intensity = i,
- };
- uniforms_.update(ctx_.queue, u);
+void VignetteEffect::render(WGPURenderPassEncoder pass,
+ const CommonPostProcessUniforms& uniforms) {
+ uniforms_.update(ctx_.queue, uniforms);
params_buffer_.update(ctx_.queue, params_);
- PostProcessEffect::render(pass, t, b, i, a);
+ PostProcessEffect::render(pass, uniforms);
}
void VignetteEffect::update_bind_group(WGPUTextureView v) {