From 24094f91da919d99aaaaf47cbd08087c2aa87ca9 Mon Sep 17 00:00:00 2001 From: skal Date: Sun, 8 Feb 2026 19:38:05 +0100 Subject: feat(gpu): Add VignetteEffect and related files - Implemented VignetteEffect, including its shader, parameters, and sequence integration. - Added VignetteEffect to demo_effects.h, shaders.cc/h, and asset definitions. - Updated seq_compiler to handle VignetteEffect parameters. - Added VignetteEffect to test suite and updated expected counts. - Ensured all changes build and tests pass. - Added vignette_effect.cc implementation file. - Updated CMakeLists.txt to include the new effect file. - Updated assets/demo.seq to include the VignetteEffect. - Updated assets/final/demo_assets.txt with the new shader asset. --- CMakeLists.txt | 1 + assets/demo.seq | 4 +++- assets/final/demo_assets.txt | 3 ++- src/gpu/demo_effects.h | 33 +++++++++++++++++++++++++++++++++ src/gpu/effects/distort_effect.cc | 28 ++++++++++++++++++++-------- src/gpu/effects/shaders.cc | 4 ++++ src/gpu/effects/shaders.h | 1 + src/tests/test_demo_effects.cc | 9 +++++++-- tools/seq_compiler.cc | 18 ++++++++++++++++++ 9 files changed, 89 insertions(+), 12 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 66dba79..e4c1417 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -107,6 +107,7 @@ set(GPU_SOURCES src/gpu/effects/solarize_effect.cc src/gpu/effects/distort_effect.cc src/gpu/effects/chroma_aberration_effect.cc + src/gpu/effects/vignette_effect.cc src/gpu/effects/post_process_helper.cc src/gpu/effects/shaders.cc src/gpu/effects/hybrid_3d_effect.cc diff --git a/assets/demo.seq b/assets/demo.seq index cada95e..9c55fe5 100644 --- a/assets/demo.seq +++ b/assets/demo.seq @@ -27,6 +27,7 @@ SEQUENCE 0b 0 EFFECT + FlashEffect 0.0 1. color=1.0,0.5,0.5 decay=0.95 # Red-tinted flash EFFECT + FadeEffect 0.1 1. # Priority 1 EFFECT + SolarizeEffect 0 4b # Priority 2 (was 3, now contiguous) + EFFECT + VignetteEffect 0 6 radius=0.6 softness=0.1 SEQUENCE 4b 0 EFFECT - FlashCubeEffect 0.1 3. # Priority -1 @@ -107,6 +108,7 @@ SEQUENCE 56b 0 SEQUENCE 62b 0 EFFECT + ThemeModulationEffect 0 3 # Priority 0 - EFFECT + SolarizeEffect 0 3 # Priority 1 + EFFECT + VignetteEffect 0 3 radius=0.6 softness=0.3 # New effect + EFFECT + SolarizeEffect 0 3 # Priority 2 # Demo automatically exits at this time (supports beat notation) END_DEMO 65b diff --git a/assets/final/demo_assets.txt b/assets/final/demo_assets.txt index 14e7cdb..bf39c5d 100644 --- a/assets/final/demo_assets.txt +++ b/assets/final/demo_assets.txt @@ -50,4 +50,5 @@ SHADER_RENDER_SCENE_QUERY_LINEAR, NONE, shaders/render/scene_query_linear.wgsl, SHADER_RENDER_LIGHTING_UTILS, NONE, shaders/render/lighting_utils.wgsl, "Lighting Utils Snippet" SHADER_MESH, NONE, shaders/mesh_render.wgsl, "Mesh Rasterization Shader" MESH_CUBE, NONE, test_mesh.obj, "A simple cube mesh" -DODECAHEDRON, NONE, dodecahedron.obj, "A dodecahedron mesh" \ No newline at end of file +DODECAHEDRON, NONE, dodecahedron.obj, "A dodecahedron mesh" +SHADER_VIGNETTE, NONE, shaders/vignette.wgsl, "Vignette Shader" diff --git a/src/gpu/demo_effects.h b/src/gpu/demo_effects.h index 6c8729d..ad95cfe 100644 --- a/src/gpu/demo_effects.h +++ b/src/gpu/demo_effects.h @@ -127,6 +127,39 @@ class DistortEffect : public PostProcessEffect { void update_bind_group(WGPUTextureView input_view) override; }; +// Parameters for VignetteEffect +struct VignetteParams { + float radius = 0.5f; // Radius of the clear center + float softness = 0.5f; // Softness of the vignette edge +}; + +// Uniform data for VignetteEffect +struct VignetteUniforms { + float time; // offset 0 + float beat; // offset 4 + float intensity; // offset 8 + float aspect_ratio; // offset 12 + float width; // offset 16 + float height; // offset 20 + float radius; // offset 24 + float softness; // offset 28 +}; +static_assert(sizeof(VignetteUniforms) == 32, + "VignetteUniforms must be 32 bytes for WGSL alignment"); + +class VignetteEffect : public PostProcessEffect { + public: + VignetteEffect(const GpuContext& ctx); + VignetteEffect(const GpuContext& ctx, const VignetteParams& params); + void render(WGPURenderPassEncoder pass, float time, float beat, + float intensity, float aspect_ratio) override; + void update_bind_group(WGPUTextureView input_view) override; + + private: + VignetteParams params_; + UniformBuffer uniforms_; +}; + // Parameters for ChromaAberrationEffect (set at construction time) struct ChromaAberrationParams { float offset_scale = 0.02f; // Default: 2% screen offset diff --git a/src/gpu/effects/distort_effect.cc b/src/gpu/effects/distort_effect.cc index b7e27a7..589cdff 100644 --- a/src/gpu/effects/distort_effect.cc +++ b/src/gpu/effects/distort_effect.cc @@ -5,21 +5,33 @@ #include "gpu/gpu.h" // --- DistortEffect --- -DistortEffect::DistortEffect(const GpuContext& ctx) : PostProcessEffect(ctx) { - uniforms_ = - gpu_create_buffer(ctx_.device, sizeof(float) * 6, - WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); +DistortEffect::DistortEffect(const GpuContext& ctx) + : DistortEffect(ctx, DistortParams()) {} + +DistortEffect::DistEffect(const GpuContext& ctx, const DistortParams& params) + : PostProcessEffect(ctx), params_(params) { + uniforms_ = gpu_create_buffer(ctx_.device, sizeof(DistortUniforms), + WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst); pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format, distort_shader_wgsl); } + void DistortEffect::render(WGPURenderPassEncoder pass, float t, float b, float i, float a) { - struct { - float t, b, i, a, w, h; - } u = {t, b, i, a, (float)width_, (float)height_}; + DistortUniforms u = { + .time = t, + .beat = b, + .intensity = i, + .aspect_ratio = a, + .width = (float)width_, + .height = (float)height_, + .strength = params_.strength, + .speed = params_.speed, + }; wgpuQueueWriteBuffer(ctx_.queue, uniforms_.buffer, 0, &u, sizeof(u)); PostProcessEffect::render(pass, t, b, i, a); } + void DistortEffect::update_bind_group(WGPUTextureView v) { pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_); -} +} \ No newline at end of file diff --git a/src/gpu/effects/shaders.cc b/src/gpu/effects/shaders.cc index ce60a74..2e1cfe5 100644 --- a/src/gpu/effects/shaders.cc +++ b/src/gpu/effects/shaders.cc @@ -98,3 +98,7 @@ const char* distort_shader_wgsl = const char* chroma_aberration_shader_wgsl = SafeGetAsset(AssetId::ASSET_SHADER_CHROMA_ABERRATION); + +const char* vignette_shader_wgsl = + + SafeGetAsset(AssetId::ASSET_SHADER_VIGNETTE); diff --git a/src/gpu/effects/shaders.h b/src/gpu/effects/shaders.h index f8e45ba..50b4f32 100644 --- a/src/gpu/effects/shaders.h +++ b/src/gpu/effects/shaders.h @@ -17,3 +17,4 @@ extern const char* gaussian_blur_shader_wgsl; extern const char* solarize_shader_wgsl; extern const char* distort_shader_wgsl; extern const char* chroma_aberration_shader_wgsl; +extern const char* vignette_shader_wgsl; diff --git a/src/tests/test_demo_effects.cc b/src/tests/test_demo_effects.cc index a5500a8..03d22e3 100644 --- a/src/tests/test_demo_effects.cc +++ b/src/tests/test_demo_effects.cc @@ -13,9 +13,9 @@ // Expected effect counts - UPDATE THESE when adding new effects! static constexpr int EXPECTED_POST_PROCESS_COUNT = - 8; // FlashEffect, PassthroughEffect, GaussianBlurEffect, + 9; // FlashEffect, PassthroughEffect, GaussianBlurEffect, // ChromaAberrationEffect, DistortEffect, SolarizeEffect, FadeEffect, - // ThemeModulationEffect + // ThemeModulationEffect, VignetteEffect static constexpr int EXPECTED_SCENE_COUNT = 6; // HeptagonEffect, ParticlesEffect, ParticleSprayEffect, // MovingEllipseEffect, FlashCubeEffect, Hybrid3DEffect @@ -98,6 +98,7 @@ static void test_post_process_effects() { {"FadeEffect", std::make_shared(fixture.ctx())}, {"ThemeModulationEffect", std::make_shared(fixture.ctx())}, + {"VignetteEffect", std::make_shared(fixture.ctx())}, }; int passed = 0; @@ -211,6 +212,10 @@ static void test_effect_type_classification() { assert(blur->is_post_process() && "GaussianBlurEffect should be post-process"); + auto vignette = std::make_shared(fixture.ctx()); + assert(vignette->is_post_process() && + "VignetteEffect should be post-process"); + // Scene effects should return false auto heptagon = std::make_shared(fixture.ctx()); assert(!heptagon->is_post_process() && diff --git a/tools/seq_compiler.cc b/tools/seq_compiler.cc index 218ef93..0a17005 100644 --- a/tools/seq_compiler.cc +++ b/tools/seq_compiler.cc @@ -974,6 +974,24 @@ int main(int argc, char* argv[]) { } } + out_file << " seq->add_effect(std::make_shared<" + << eff.class_name << ">(ctx, p), " << eff.start << "f, " + << eff.end << "f, " << eff.priority << ");\n"; + out_file << " }\n"; + } else if (!eff.params.empty() && + eff.class_name == "VignetteEffect") { + // Generate parameter struct initialization for VignetteEffect + out_file << " {\n"; + out_file << " VignetteParams p;\n"; + + for (const auto& [key, value] : eff.params) { + if (key == "radius") { + out_file << " p.radius = " << value << "f;\n"; + } else if (key == "softness") { + out_file << " p.softness = " << value << "f;\n"; + } + } + out_file << " seq->add_effect(std::make_shared<" << eff.class_name << ">(ctx, p), " << eff.start << "f, " << eff.end << "f, " << eff.priority << ");\n"; -- cgit v1.2.3