summaryrefslogtreecommitdiff
path: root/src/effects
diff options
context:
space:
mode:
authorskal <pascal.massimino@gmail.com>2026-02-16 11:54:46 +0100
committerskal <pascal.massimino@gmail.com>2026-02-16 11:54:46 +0100
commitaf5d0e4c3a6cb773a4fb51ac32f4c33a7f8d8224 (patch)
treea76464ca40a43d6042ed5431547008cfbe746c34 /src/effects
parent8eeadaf0d5653c21b948103e4d328f634b739a17 (diff)
feat(sequence): complete v2 migration with DAG-based routing
Phase 4 complete: V1 system removed, v2 fully operational. Architecture Changes: - Explicit Node system with typed buffers (u8x4_norm, f32x4, depth24) - DAG effect routing with multi-input/multi-output support - Python compiler (seq_compiler_v2.py) with topological sort and ping-pong optimization - Compile-time node aliasing for framebuffer reuse V1 Removal (~4KB): - Deleted effect.h/cc base classes (1.4KB) - Deleted 19 v1 effect pairs: heptagon, particles, passthrough, gaussian_blur, solarize, scene1, chroma_aberration, vignette, hybrid_3d, flash_cube, theme_modulation, fade, flash, circle_mask, rotating_cube, sdf_test, distort, moving_ellipse, particle_spray (2.7KB) V2 Effects Ported: - PassthroughEffectV2, PlaceholderEffectV2 - GaussianBlurEffectV2 (multi-pass with temp nodes) - HeptagonEffectV2 (scene effect with dummy texture) - ParticlesEffectV2 (compute + render, format fixed) - RotatingCubeEffectV2 (3D with depth node) - Hybrid3DEffectV2 (Renderer3D integration, dummy textures for noise/sky) Compiler Features: - DAG validation (cycle detection, connectivity checks) - Topological sort for execution order - Ping-pong optimization (aliased node detection) - Surface-based and encoder-based RenderV2Timeline generation - init_effect_nodes() automatic generation Fixes Applied: - WebGPU binding layout validation (standard v2 post-process layout) - Surface format mismatch (ctx.format for blit, RGBA8Unorm for framebuffers) - Depth attachment compatibility (removed forced depth from gpu_create_render_pass) - Renderer3D texture initialization (created dummy 1x1 white textures) - ParticlesEffectV2 format (changed from ctx.format to RGBA8Unorm) - Encoder-based RenderV2Timeline (added missing preprocess() call) Testing: - 34/36 tests passing (2 v1-dependent tests disabled) - demo64k runs successfully (no crashes) - All seek positions work (--seek 12, --seek 15 validated) Documentation: - Updated PROJECT_CONTEXT.md (v2 status, reference to SEQUENCE_v2.md) - Added completion entry to COMPLETED.md TODO (Future): - Port CNN effects to v2 - Implement flatten mode (--flatten code generation) - Port remaining 10+ effects - Update HTML timeline editor for v2 (deferred) handoff(Claude): Sequence v2 migration complete, v1 removed, system operational. Phase 5 (editor) deferred per user preference. Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Diffstat (limited to 'src/effects')
-rw-r--r--src/effects/chroma_aberration_effect.cc39
-rw-r--r--src/effects/chroma_aberration_effect.h29
-rw-r--r--src/effects/circle_mask_effect.cc221
-rw-r--r--src/effects/circle_mask_effect.h44
-rw-r--r--src/effects/distort_effect.cc38
-rw-r--r--src/effects/distort_effect.h28
-rw-r--r--src/effects/fade_effect.cc99
-rw-r--r--src/effects/fade_effect.h20
-rw-r--r--src/effects/flash_cube_effect.cc104
-rw-r--r--src/effects/flash_cube_effect.h28
-rw-r--r--src/effects/flash_effect.cc95
-rw-r--r--src/effects/flash_effect.h45
-rw-r--r--src/effects/gaussian_blur_effect.cc39
-rw-r--r--src/effects/gaussian_blur_effect.h32
-rw-r--r--src/effects/gaussian_blur_effect_v2.cc3
-rw-r--r--src/effects/heptagon_effect.cc24
-rw-r--r--src/effects/heptagon_effect.h16
-rw-r--r--src/effects/heptagon_effect_v2.cc47
-rw-r--r--src/effects/heptagon_effect_v2.h4
-rw-r--r--src/effects/hybrid3_d_effect_v2.cc52
-rw-r--r--src/effects/hybrid3_d_effect_v2.h4
-rw-r--r--src/effects/hybrid_3d_effect.cc147
-rw-r--r--src/effects/hybrid_3d_effect.h29
-rw-r--r--src/effects/moving_ellipse_effect.cc24
-rw-r--r--src/effects/moving_ellipse_effect.h16
-rw-r--r--src/effects/particle_spray_effect.cc49
-rw-r--r--src/effects/particle_spray_effect.h21
-rw-r--r--src/effects/particles_effect.cc48
-rw-r--r--src/effects/particles_effect.h21
-rw-r--r--src/effects/particles_effect_v2.cc6
-rw-r--r--src/effects/passthrough_effect.cc18
-rw-r--r--src/effects/passthrough_effect.h14
-rw-r--r--src/effects/passthrough_effect_v2.cc2
-rw-r--r--src/effects/placeholder_effect_v2.cc2
-rw-r--r--src/effects/rotating_cube_effect.cc204
-rw-r--r--src/effects/rotating_cube_effect.h55
-rw-r--r--src/effects/rotating_cube_effect_v2.cc2
-rw-r--r--src/effects/scene1_effect.cc21
-rw-r--r--src/effects/scene1_effect.h19
-rw-r--r--src/effects/sdf_test_effect.cc36
-rw-r--r--src/effects/sdf_test_effect.h16
-rw-r--r--src/effects/solarize_effect.cc21
-rw-r--r--src/effects/solarize_effect.h16
-rw-r--r--src/effects/theme_modulation_effect.cc106
-rw-r--r--src/effects/theme_modulation_effect.h20
-rw-r--r--src/effects/vignette_effect.cc31
-rw-r--r--src/effects/vignette_effect.h26
47 files changed, 111 insertions, 1870 deletions
diff --git a/src/effects/chroma_aberration_effect.cc b/src/effects/chroma_aberration_effect.cc
deleted file mode 100644
index 4038696..0000000
--- a/src/effects/chroma_aberration_effect.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the ChromaAberrationEffect with parameterization.
-
-#include "effects/chroma_aberration_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-
-// --- ChromaAberrationEffect ---
-
-// Backward compatibility constructor (delegates to parameterized constructor)
-ChromaAberrationEffect::ChromaAberrationEffect(const GpuContext& ctx)
- : ChromaAberrationEffect(ctx, ChromaAberrationParams{}) {
-}
-
-// Parameterized constructor
-ChromaAberrationEffect::ChromaAberrationEffect(
- const GpuContext& ctx, const ChromaAberrationParams& params)
- : PostProcessEffect(ctx), params_(params) {
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- chroma_aberration_shader_wgsl);
- params_buffer_.init(ctx_.device);
-}
-
-void ChromaAberrationEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- // Update uniforms with current state and parameters
- uniforms_.update(ctx_.queue, uniforms);
- params_buffer_.update(ctx_.queue, params_);
-
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
-
-void ChromaAberrationEffect::update_bind_group(WGPUTextureView input_view) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- uniforms_.get(), params_buffer_.get());
-}
diff --git a/src/effects/chroma_aberration_effect.h b/src/effects/chroma_aberration_effect.h
deleted file mode 100644
index 1790952..0000000
--- a/src/effects/chroma_aberration_effect.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the ChromaAberrationEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/uniform_helper.h"
-
-// Parameters for ChromaAberrationEffect (set at construction time)
-struct ChromaAberrationParams {
- float offset_scale = 0.02f; // Default: 2% screen offset
- float angle = 0.0f; // Default: horizontal (0 radians)
-};
-
-class ChromaAberrationEffect : public PostProcessEffect {
- public:
- // Backward compatibility constructor (uses default params)
- ChromaAberrationEffect(const GpuContext& ctx);
- // New parameterized constructor
- ChromaAberrationEffect(const GpuContext& ctx,
- const ChromaAberrationParams& params);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- ChromaAberrationParams params_;
- UniformBuffer<ChromaAberrationParams> params_buffer_;
-};
diff --git a/src/effects/circle_mask_effect.cc b/src/effects/circle_mask_effect.cc
deleted file mode 100644
index 7a016d9..0000000
--- a/src/effects/circle_mask_effect.cc
+++ /dev/null
@@ -1,221 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements CircleMaskEffect for auxiliary texture masking demonstration.
-// Generates circular mask and renders green background outside circle.
-
-#include "effects/circle_mask_effect.h"
-#include "generated/assets.h"
-#include "gpu/bind_group_builder.h"
-#include "gpu/shader_composer.h"
-
-CircleMaskEffect::CircleMaskEffect(const GpuContext& ctx, float radius)
- : Effect(ctx), radius_(radius) {
-}
-
-CircleMaskEffect::~CircleMaskEffect() {
- if (mask_sampler_)
- wgpuSamplerRelease(mask_sampler_);
- if (render_bind_group_)
- wgpuBindGroupRelease(render_bind_group_);
- if (render_pipeline_)
- wgpuRenderPipelineRelease(render_pipeline_);
- if (compute_bind_group_)
- wgpuBindGroupRelease(compute_bind_group_);
- if (compute_pipeline_)
- wgpuRenderPipelineRelease(compute_pipeline_);
-}
-
-void CircleMaskEffect::init(MainSequence* demo) {
- demo_ = demo;
-
- // Register auxiliary texture (width_/height_ set by resize() before init())
- demo_->register_auxiliary_texture("circle_mask", width_, height_);
-
- 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;
- sampler_desc.magFilter = WGPUFilterMode_Linear;
- sampler_desc.minFilter = WGPUFilterMode_Linear;
- sampler_desc.mipmapFilter = WGPUMipmapFilterMode_Linear;
- sampler_desc.maxAnisotropy = 1;
- mask_sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc);
-
- size_t compute_size, render_size;
- const char* compute_shader = (const char*)GetAsset(
- AssetId::ASSET_CIRCLE_MASK_COMPUTE_SHADER, &compute_size);
- const char* render_shader = (const char*)GetAsset(
- AssetId::ASSET_CIRCLE_MASK_RENDER_SHADER, &render_size);
-
- // Compose shaders to resolve #include directives
- std::string composed_compute =
- ShaderComposer::Get().Compose({}, compute_shader);
-
- WGPUShaderSourceWGSL compute_wgsl = {};
- compute_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL;
- compute_wgsl.code = str_view(composed_compute.c_str());
-
- WGPUShaderModuleDescriptor compute_desc = {};
- compute_desc.nextInChain = &compute_wgsl.chain;
- WGPUShaderModule compute_module =
- wgpuDeviceCreateShaderModule(ctx_.device, &compute_desc);
-
- const WGPUColorTargetState compute_target = {
- .format = ctx_.format, // Match auxiliary texture format
- .writeMask = WGPUColorWriteMask_All,
- };
- WGPUFragmentState compute_frag = {};
- compute_frag.module = compute_module;
- compute_frag.entryPoint = str_view("fs_main");
- compute_frag.targetCount = 1;
- compute_frag.targets = &compute_target;
- WGPURenderPipelineDescriptor compute_pipeline_desc = {};
- compute_pipeline_desc.label = label_view("CircleMaskEffect_compute");
- compute_pipeline_desc.vertex.module = compute_module;
- compute_pipeline_desc.vertex.entryPoint = str_view("vs_main");
- compute_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
- compute_pipeline_desc.primitive.cullMode = WGPUCullMode_None;
- compute_pipeline_desc.multisample.count = 1;
- compute_pipeline_desc.multisample.mask = 0xFFFFFFFF;
- compute_pipeline_desc.fragment = &compute_frag;
- compute_pipeline_ =
- wgpuDeviceCreateRenderPipeline(ctx_.device, &compute_pipeline_desc);
- wgpuShaderModuleRelease(compute_module);
-
- WGPUBindGroupLayout compute_layout =
- wgpuRenderPipelineGetBindGroupLayout(compute_pipeline_, 0);
- compute_bind_group_ =
- BindGroupBuilder()
- .buffer(0, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms))
- .buffer(1, compute_params_.get().buffer, sizeof(CircleMaskParams))
- .build(ctx_.device, compute_layout);
- wgpuBindGroupLayoutRelease(compute_layout);
-
- std::string composed_render =
- ShaderComposer::Get().Compose({}, render_shader);
-
- WGPUShaderSourceWGSL render_wgsl = {};
- render_wgsl.chain.sType = WGPUSType_ShaderSourceWGSL;
- render_wgsl.code = str_view(composed_render.c_str());
-
- WGPUShaderModuleDescriptor render_desc = {};
- render_desc.nextInChain = &render_wgsl.chain;
- WGPUShaderModule render_module =
- wgpuDeviceCreateShaderModule(ctx_.device, &render_desc);
-
- const WGPUColorTargetState render_target = {
- .format = ctx_.format,
- .writeMask = WGPUColorWriteMask_All,
- };
- WGPUFragmentState render_frag = {};
- render_frag.module = render_module;
- render_frag.entryPoint = str_view("fs_main");
- render_frag.targetCount = 1;
- render_frag.targets = &render_target;
- const WGPUDepthStencilState depth_stencil = {
- .format = WGPUTextureFormat_Depth24Plus,
- .depthWriteEnabled = WGPUOptionalBool_False, // Don't write depth
- .depthCompare = WGPUCompareFunction_Always, // Always pass
- };
-
- WGPURenderPipelineDescriptor render_pipeline_desc = {};
- render_pipeline_desc.label = label_view("CircleMaskEffect_render");
- render_pipeline_desc.vertex.module = render_module;
- render_pipeline_desc.vertex.entryPoint = str_view("vs_main");
- render_pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
- render_pipeline_desc.primitive.cullMode = WGPUCullMode_None;
- render_pipeline_desc.depthStencil = &depth_stencil;
- render_pipeline_desc.multisample.count = 1;
- render_pipeline_desc.multisample.mask = 0xFFFFFFFF;
- render_pipeline_desc.fragment = &render_frag;
- render_pipeline_ =
- wgpuDeviceCreateRenderPipeline(ctx_.device, &render_pipeline_desc);
- wgpuShaderModuleRelease(render_module);
-
- WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask");
- const WGPUBindGroupEntry render_entries[] = {
- {.binding = 0, .textureView = mask_view},
- {.binding = 1, .sampler = mask_sampler_},
- {.binding = 2,
- .buffer = uniforms_.get().buffer,
- .size = sizeof(CommonPostProcessUniforms)},
- };
- const WGPUBindGroupDescriptor render_bg_desc = {
- .layout = wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0),
- .entryCount = 3,
- .entries = render_entries,
- };
- render_bind_group_ = wgpuDeviceCreateBindGroup(ctx_.device, &render_bg_desc);
-}
-
-void CircleMaskEffect::resize(int width, int height) {
- if (width == width_ && height == height_)
- return;
-
- Effect::resize(width, height);
-
- if (!demo_)
- return;
-
- // Resize auxiliary texture
- demo_->resize_auxiliary_texture("circle_mask", width, height);
-
- // Recreate render bind group with new texture view
- if (render_bind_group_)
- wgpuBindGroupRelease(render_bind_group_);
-
- WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask");
- WGPUBindGroupLayout render_layout =
- wgpuRenderPipelineGetBindGroupLayout(render_pipeline_, 0);
- render_bind_group_ =
- BindGroupBuilder()
- .texture(0, mask_view)
- .sampler(1, mask_sampler_)
- .buffer(2, uniforms_.get().buffer, sizeof(CommonPostProcessUniforms))
- .build(ctx_.device, render_layout);
- wgpuBindGroupLayoutRelease(render_layout);
-}
-
-void CircleMaskEffect::compute(WGPUCommandEncoder encoder,
- const CommonPostProcessUniforms& uniforms) {
- uniforms_.update(ctx_.queue, uniforms);
-
- const CircleMaskParams params = {
- .radius = radius_,
- };
- compute_params_.update(ctx_.queue, params);
-
- WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask");
- WGPURenderPassColorAttachment color_attachment = {};
- color_attachment.view = mask_view;
- color_attachment.loadOp = WGPULoadOp_Clear;
- color_attachment.storeOp = WGPUStoreOp_Store;
- color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0};
-#if !defined(DEMO_CROSS_COMPILE_WIN32)
- color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
-#endif
-
- WGPURenderPassDescriptor pass_desc = {};
- pass_desc.colorAttachmentCount = 1;
- pass_desc.colorAttachments = &color_attachment;
-
- WGPURenderPassEncoder pass =
- wgpuCommandEncoderBeginRenderPass(encoder, &pass_desc);
- wgpuRenderPassEncoderSetPipeline(pass, compute_pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, compute_bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
- wgpuRenderPassEncoderEnd(pass);
- wgpuRenderPassEncoderRelease(pass);
-}
-
-void CircleMaskEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- uniforms_.update(ctx_.queue, uniforms);
-
- wgpuRenderPassEncoderSetPipeline(pass, render_pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, render_bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
diff --git a/src/effects/circle_mask_effect.h b/src/effects/circle_mask_effect.h
deleted file mode 100644
index 53cc1bc..0000000
--- a/src/effects/circle_mask_effect.h
+++ /dev/null
@@ -1,44 +0,0 @@
-// This file is part of the 64k demo project.
-// It defines the CircleMaskEffect class for masking system demonstration.
-// Creates a circular mask and renders green outside the circle.
-
-#ifndef CIRCLE_MASK_EFFECT_H_
-#define CIRCLE_MASK_EFFECT_H_
-
-#include "gpu/effect.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/uniform_helper.h"
-
-class CircleMaskEffect : public Effect {
- public:
- CircleMaskEffect(const GpuContext& ctx, float radius = 0.4f);
- ~CircleMaskEffect() override;
-
- void init(MainSequence* demo) override;
- void resize(int width, int height) override;
- void compute(WGPUCommandEncoder encoder,
- const CommonPostProcessUniforms& uniforms) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- struct CircleMaskParams {
- float radius;
- float _pad[3];
- };
- static_assert(sizeof(CircleMaskParams) == 16,
- "CircleMaskParams must be 16 bytes for WGSL alignment");
-
- MainSequence* demo_ = nullptr;
- float radius_;
-
- WGPURenderPipeline compute_pipeline_ = nullptr;
- WGPUBindGroup compute_bind_group_ = nullptr;
- UniformBuffer<CircleMaskParams> compute_params_;
-
- WGPURenderPipeline render_pipeline_ = nullptr;
- WGPUBindGroup render_bind_group_ = nullptr;
- WGPUSampler mask_sampler_ = nullptr;
-};
-
-#endif /* CIRCLE_MASK_EFFECT_H_ */
diff --git a/src/effects/distort_effect.cc b/src/effects/distort_effect.cc
deleted file mode 100644
index aa72386..0000000
--- a/src/effects/distort_effect.cc
+++ /dev/null
@@ -1,38 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the DistortEffect.
-
-#include "effects/distort_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/shaders.h"
-
-// --- DistortEffect ---
-DistortEffect::DistortEffect(const GpuContext& ctx)
- : DistortEffect(ctx, DistortParams()) {
-}
-
-DistortEffect::DistortEffect(const GpuContext& ctx, const DistortParams& params)
- : PostProcessEffect(ctx), params_(params) {
- params_buffer_.init(ctx_.device);
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- distort_shader_wgsl);
-}
-
-void DistortEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- // Populate CommonPostProcessUniforms
- uniforms_.update(ctx_.queue, uniforms);
-
- // Populate DistortParams
- const DistortParams distort_p = {
- .strength = params_.strength,
- .speed = params_.speed,
- };
- params_buffer_.update(ctx_.queue, distort_p);
-
- PostProcessEffect::render(pass, uniforms);
-}
-
-void DistortEffect::update_bind_group(WGPUTextureView v) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(),
- params_buffer_);
-} \ No newline at end of file
diff --git a/src/effects/distort_effect.h b/src/effects/distort_effect.h
deleted file mode 100644
index 548cf91..0000000
--- a/src/effects/distort_effect.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the DistortEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/uniform_helper.h"
-
-// Parameters for DistortEffect
-struct DistortParams {
- float strength = 0.01f; // Default distortion strength
- float speed = 1.0f; // Default distortion speed
-};
-static_assert(sizeof(DistortParams) == 8,
- "DistortParams must be 8 bytes for WGSL alignment");
-
-class DistortEffect : public PostProcessEffect {
- public:
- DistortEffect(const GpuContext& ctx);
- DistortEffect(const GpuContext& ctx, const DistortParams& params);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- DistortParams params_;
- UniformBuffer<DistortParams> params_buffer_;
-};
diff --git a/src/effects/fade_effect.cc b/src/effects/fade_effect.cc
deleted file mode 100644
index 1dff6bd..0000000
--- a/src/effects/fade_effect.cc
+++ /dev/null
@@ -1,99 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the FadeEffect - fades to/from black based on time.
-
-#include "effects/fade_effect.h"
-#include "gpu/post_process_helper.h"
-#include <cmath>
-
-struct FadeParams {
- float fade_amount;
- float _pad[3];
-};
-static_assert(sizeof(FadeParams) == 16,
- "FadeParams must be 16 bytes for WGSL alignment");
-
-FadeEffect::FadeEffect(const GpuContext& ctx) : PostProcessEffect(ctx) {
- const char* shader_code = R"(
- struct VertexOutput {
- @builtin(position) position: vec4<f32>,
- @location(0) uv: vec2<f32>,
- };
-
- struct CommonUniforms {
- resolution: vec2<f32>,
- _pad0: f32,
- _pad1: f32,
- aspect_ratio: f32,
- time: f32,
- beat: f32,
- audio_intensity: f32,
- };
-
- struct FadeParams {
- fade_amount: f32,
- _pad0: f32,
- _pad1: f32,
- _pad2: f32,
- };
-
- @group(0) @binding(0) var inputSampler: sampler;
- @group(0) @binding(1) var inputTexture: texture_2d<f32>;
- @group(0) @binding(2) var<uniform> uniforms: CommonUniforms;
- @group(0) @binding(3) var<uniform> params: FadeParams;
-
- @vertex
- fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
- var output: VertexOutput;
- var pos = array<vec2<f32>, 3>(
- vec2<f32>(-1.0, -1.0),
- vec2<f32>(3.0, -1.0),
- vec2<f32>(-1.0, 3.0)
- );
- output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
- output.uv = pos[vertexIndex] * 0.5 + 0.5;
- return output;
- }
-
- @fragment
- fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
- let color = textureSample(inputTexture, inputSampler, input.uv);
- // Fade to black: 0.0 = black, 1.0 = full color
- return vec4<f32>(color.rgb * params.fade_amount, color.a);
- }
- )";
-
- pipeline_ =
- create_post_process_pipeline(ctx_.device, ctx_.format, shader_code);
- params_buffer_ = gpu_create_buffer(
- ctx_.device, 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
-}
-
-void FadeEffect::update_bind_group(WGPUTextureView input_view) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- uniforms_.get(), params_buffer_);
-}
-
-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 (uniforms.time < 2.0f) {
- // Fade in from black over first 2 seconds
- fade_amount = uniforms.time / 2.0f;
- } else if (uniforms.time > 36.0f) {
- // Fade out to black after 36 seconds
- fade_amount = 1.0f - ((uniforms.time - 36.0f) / 4.0f);
- fade_amount = fmaxf(fade_amount, 0.0f);
- }
-
- FadeParams params = {fade_amount, {0.0f, 0.0f, 0.0f}};
- wgpuQueueWriteBuffer(ctx_.queue, params_buffer_.buffer, 0, &params,
- sizeof(params));
-
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
diff --git a/src/effects/fade_effect.h b/src/effects/fade_effect.h
deleted file mode 100644
index 6993152..0000000
--- a/src/effects/fade_effect.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the FadeEffect - fades to/from black.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/uniform_helper.h"
-
-class FadeEffect : public PostProcessEffect {
- public:
- FadeEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- GpuBuffer params_buffer_;
-};
diff --git a/src/effects/flash_cube_effect.cc b/src/effects/flash_cube_effect.cc
deleted file mode 100644
index c578776..0000000
--- a/src/effects/flash_cube_effect.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the FlashCubeEffect - a flashing background cube with Perlin
-// noise.
-
-#include "effects/flash_cube_effect.h"
-#include "generated/assets.h"
-#include "util/asset_manager_utils.h"
-#include <cmath>
-#include <iostream>
-
-FlashCubeEffect::FlashCubeEffect(const GpuContext& ctx) : Effect(ctx) {
-}
-
-void FlashCubeEffect::resize(int width, int height) {
- if (width == width_ && height == height_)
- return;
-
- Effect::resize(width, height);
-
- if (!initialized_)
- return;
-
- renderer_.resize(width_, height_);
-}
-
-void FlashCubeEffect::init(MainSequence* demo) {
- (void)demo;
- WGPUTextureFormat format = demo->gpu_ctx.format;
-
- renderer_.init(ctx_.device, ctx_.queue, ctx_.format);
- renderer_.resize(width_, height_);
- initialized_ = true;
-
- // Texture Manager
- texture_manager_.init(ctx_.device, ctx_.queue);
-
- // Load Perlin noise texture
- TextureAsset noise_tex = GetTextureAsset(AssetId::ASSET_NOISE_TEX);
- if (noise_tex.pixels && noise_tex.width == 256 && noise_tex.height == 256) {
- texture_manager_.create_texture("noise", noise_tex.width, noise_tex.height,
- noise_tex.pixels);
- renderer_.set_noise_texture(texture_manager_.get_texture_view("noise"));
- } else {
- std::cerr << "Failed to load NOISE_TEX asset for FlashCubeEffect."
- << std::endl;
- }
-
- // Create a very large background cube
- // Scale and distance ensure it's clearly behind foreground objects
- scene_.clear();
- Object3D cube(ObjectType::BOX);
- cube.position = vec3(0, 0, 0);
- cube.scale = vec3(30.0f, 30.0f, 30.0f); // Much larger cube
- cube.color = vec4(0.3f, 0.3f, 0.5f, 1.0f); // Dark blue base color
- scene_.add_object(cube);
-}
-
-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 (uniforms.audio_intensity > 0.5f &&
- flash_intensity_ < 0.2f) { // High intensity + flash cooled down
- flash_intensity_ = 1.0f; // Trigger full flash
- }
-
- // Exponential decay of flash
- flash_intensity_ *= 0.95f; // Slower fade for more visible effect
-
- // Always have base brightness, add flash on top
- float base_brightness = 0.2f;
- float flash_boost =
- base_brightness + flash_intensity_ * 0.8f; // 0.2 to 1.0 range
-
- scene_.objects[0].color =
- vec4(0.4f * flash_boost, // Reddish tint
- 0.6f * flash_boost, // More green
- 1.0f * flash_boost, // Strong blue for background feel
- 1.0f);
-
- // Slowly rotate the cube for visual interest
- scene_.objects[0].rotation =
- quat::from_axis(vec3(0.3f, 1, 0.2f), uniforms.time * 0.04f);
-
- // 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 = uniforms.time * 0.1f;
-
- camera_.set_look_at(
- vec3(std::sin(orbit_angle) * cam_distance,
- std::cos(orbit_angle * 0.3f) * 30.0f,
- std::cos(orbit_angle) * cam_distance), // Camera orbits around
- vec3(0, 0, 0), // Look at cube center
- vec3(0, 1, 0));
-
- 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_, uniforms.time);
-}
diff --git a/src/effects/flash_cube_effect.h b/src/effects/flash_cube_effect.h
deleted file mode 100644
index df30b5b..0000000
--- a/src/effects/flash_cube_effect.h
+++ /dev/null
@@ -1,28 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements a flashing cube effect with Perlin noise texture.
-// The cube is large and we're inside it, flashing in sync with the beat.
-
-#pragma once
-#include "3d/camera.h"
-#include "3d/renderer.h"
-#include "3d/scene.h"
-#include "gpu/effect.h"
-#include "gpu/texture_manager.h"
-
-class FlashCubeEffect : public Effect {
- public:
- FlashCubeEffect(const GpuContext& ctx);
- void init(MainSequence* demo) override;
- void resize(int width, int height) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- Renderer3D renderer_;
- TextureManager texture_manager_;
- Scene scene_;
- Camera camera_;
- float last_beat_ = 0.0f;
- float flash_intensity_ = 0.0f;
- bool initialized_ = false;
-};
diff --git a/src/effects/flash_effect.cc b/src/effects/flash_effect.cc
deleted file mode 100644
index 00b5217..0000000
--- a/src/effects/flash_effect.cc
+++ /dev/null
@@ -1,95 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the FlashEffect - brief flash on u.beat hits.
-// Now supports parameterized color with per-frame animation.
-
-#include "effects/flash_effect.h"
-#include "gpu/post_process_helper.h"
-#include <cmath>
-
-// Backward compatibility constructor (delegates to parameterized constructor)
-FlashEffect::FlashEffect(const GpuContext& ctx)
- : FlashEffect(ctx, FlashEffectParams{}) {
-}
-
-// Parameterized constructor
-FlashEffect::FlashEffect(const GpuContext& ctx, const FlashEffectParams& params)
- : PostProcessEffect(ctx), params_(params) {
- const char* shader_code = R"(
- struct VertexOutput {
- @builtin(position) position: vec4<f32>,
- @location(0) uv: vec2<f32>,
- };
-
- struct Uniforms {
- flash_intensity: f32,
- audio_intensity: f32,
- flash_color: vec3<f32>, // Parameterized color
- _pad: f32,
- };
-
- @group(0) @binding(0) var inputSampler: sampler;
- @group(0) @binding(1) var inputTexture: texture_2d<f32>;
- @group(0) @binding(2) var<uniform> uniforms: Uniforms;
-
- @vertex
- fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
- var output: VertexOutput;
- var pos = array<vec2<f32>, 3>(
- vec2<f32>(-1.0, -1.0),
- vec2<f32>(3.0, -1.0),
- vec2<f32>(-1.0, 3.0)
- );
- output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
- output.uv = pos[vertexIndex] * 0.5 + 0.5;
- return output;
- }
-
- @fragment
- fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
- let color = textureSample(inputTexture, inputSampler, input.uv);
- // Use parameterized flash color instead of hardcoded white
- var flashed = mix(color.rgb, uniforms.flash_color, uniforms.flash_intensity);
- return vec4<f32>(flashed, color.a);
- }
- )";
-
- pipeline_ =
- create_post_process_pipeline(ctx_.device, ctx_.format, shader_code);
- flash_uniforms_.init(ctx_.device);
-}
-
-void FlashEffect::update_bind_group(WGPUTextureView input_view) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- flash_uniforms_.get(), {});
-}
-
-void FlashEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- // Trigger flash based on configured threshold
- if (uniforms.audio_intensity > params_.trigger_threshold &&
- flash_intensity_ < 0.2f) {
- flash_intensity_ = 0.8f; // Trigger flash
- }
-
- // Decay based on configured rate
- flash_intensity_ *= params_.decay_rate;
-
- // *** PER-FRAME PARAMETER COMPUTATION ***
- // Animate color based on time and 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_phase);
-
- // Update uniforms with computed (animated) values
- const FlashUniforms u = {
- .flash_intensity = flash_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};
- flash_uniforms_.update(ctx_.queue, u);
-
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
diff --git a/src/effects/flash_effect.h b/src/effects/flash_effect.h
deleted file mode 100644
index 1ac75a4..0000000
--- a/src/effects/flash_effect.h
+++ /dev/null
@@ -1,45 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the FlashEffect - brief white flash on beat hits.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/gpu.h"
-#include "gpu/uniform_helper.h"
-
-// Parameters for FlashEffect (set at construction time)
-struct FlashEffectParams {
- float color[3] = {1.0f, 1.0f, 1.0f}; // Default: white
- float decay_rate = 0.98f; // Default: fast decay
- float trigger_threshold = 0.7f; // Default: trigger on strong beats
-};
-
-// Uniform data sent to GPU shader
-// IMPORTANT: Must match WGSL struct layout with proper alignment
-// vec3<f32> in WGSL has 16-byte alignment, not 12-byte!
-struct FlashUniforms {
- float flash_intensity; // offset 0
- float intensity; // offset 4
- float _pad1[2]; // offset 8-15 (padding for vec3 alignment)
- float color[3]; // offset 16-27 (vec3 aligned to 16 bytes)
- float _pad2; // offset 28-31
-};
-static_assert(sizeof(FlashUniforms) == 32,
- "FlashUniforms must be 32 bytes for WGSL alignment");
-
-class FlashEffect : public PostProcessEffect {
- public:
- // Backward compatibility constructor (uses default params)
- FlashEffect(const GpuContext& ctx);
- // New parameterized constructor
- FlashEffect(const GpuContext& ctx, const FlashEffectParams& params);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- FlashEffectParams params_;
- UniformBuffer<FlashUniforms> flash_uniforms_;
- UniformBuffer<FlashEffectParams> params_buffer_;
- float flash_intensity_ = 0.0f;
-};
diff --git a/src/effects/gaussian_blur_effect.cc b/src/effects/gaussian_blur_effect.cc
deleted file mode 100644
index b5961fa..0000000
--- a/src/effects/gaussian_blur_effect.cc
+++ /dev/null
@@ -1,39 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the GaussianBlurEffect with parameterization.
-
-#include "effects/gaussian_blur_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-
-// --- GaussianBlurEffect ---
-
-// Backward compatibility constructor (delegates to parameterized constructor)
-GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx)
- : GaussianBlurEffect(ctx, GaussianBlurParams{}) {
-}
-
-// Parameterized constructor
-GaussianBlurEffect::GaussianBlurEffect(const GpuContext& ctx,
- const GaussianBlurParams& params)
- : PostProcessEffect(ctx), params_(params) {
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- gaussian_blur_shader_wgsl);
- params_buffer_.init(ctx_.device);
-}
-
-void GaussianBlurEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- // Update uniforms with current state and parameters
- uniforms_.update(ctx_.queue, uniforms);
- params_buffer_.update(ctx_.queue, params_);
-
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
-
-void GaussianBlurEffect::update_bind_group(WGPUTextureView input_view) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- uniforms_.get(), params_buffer_.get());
-}
diff --git a/src/effects/gaussian_blur_effect.h b/src/effects/gaussian_blur_effect.h
deleted file mode 100644
index bf1062f..0000000
--- a/src/effects/gaussian_blur_effect.h
+++ /dev/null
@@ -1,32 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the GaussianBlurEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/uniform_helper.h"
-
-// Parameters for GaussianBlurEffect (set at construction time)
-struct GaussianBlurParams {
- float strength = 1.0f; // Default
- float strength_audio = 0.5f; // how much to pulse with audio
- float stretch = 1.f; // y/x axis ratio
- float _pad = 0.;
-};
-static_assert(sizeof(GaussianBlurParams) == 16,
- "GaussianBlurParams must be 16 bytes for WGSL alignment");
-
-class GaussianBlurEffect : public PostProcessEffect {
- public:
- // Backward compatibility constructor (uses default params)
- GaussianBlurEffect(const GpuContext& ctx);
- // New parameterized constructor
- GaussianBlurEffect(const GpuContext& ctx, const GaussianBlurParams& params);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- GaussianBlurParams params_;
- UniformBuffer<GaussianBlurParams> params_buffer_;
-};
diff --git a/src/effects/gaussian_blur_effect_v2.cc b/src/effects/gaussian_blur_effect_v2.cc
index f87de8b..0c90fa2 100644
--- a/src/effects/gaussian_blur_effect_v2.cc
+++ b/src/effects/gaussian_blur_effect_v2.cc
@@ -64,6 +64,9 @@ void GaussianBlurEffectV2::render(WGPUCommandEncoder encoder,
// Render pass
WGPURenderPassColorAttachment color_attachment = {};
color_attachment.view = output_view;
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
+ color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
+#endif
color_attachment.loadOp = WGPULoadOp_Clear;
color_attachment.storeOp = WGPUStoreOp_Store;
color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0};
diff --git a/src/effects/heptagon_effect.cc b/src/effects/heptagon_effect.cc
deleted file mode 100644
index d15882d..0000000
--- a/src/effects/heptagon_effect.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the HeptagonEffect.
-
-#include "effects/heptagon_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/shaders.h"
-#include "util/mini_math.h"
-
-// --- HeptagonEffect ---
-HeptagonEffect::HeptagonEffect(const GpuContext& ctx) : Effect(ctx) {
- // uniforms_ is initialized by Effect base class
- ResourceBinding bindings[] = {
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, main_shader_wgsl,
- bindings, 1);
- pass_.vertex_count = 21;
-}
-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/effects/heptagon_effect.h b/src/effects/heptagon_effect.h
deleted file mode 100644
index fe19839..0000000
--- a/src/effects/heptagon_effect.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the HeptagonEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-
-class HeptagonEffect : public Effect {
- public:
- HeptagonEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- RenderPass pass_;
-};
diff --git a/src/effects/heptagon_effect_v2.cc b/src/effects/heptagon_effect_v2.cc
index 3512ec7..6a2135e 100644
--- a/src/effects/heptagon_effect_v2.cc
+++ b/src/effects/heptagon_effect_v2.cc
@@ -2,21 +2,47 @@
#include "effects/heptagon_effect_v2.h"
#include "gpu/gpu.h"
+#include "gpu/post_process_helper.h"
#include "gpu/shaders.h"
HeptagonEffectV2::HeptagonEffectV2(const GpuContext& ctx,
const std::vector<std::string>& inputs,
const std::vector<std::string>& outputs)
- : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr) {
+ : EffectV2(ctx, inputs, outputs), pipeline_(nullptr), bind_group_(nullptr), sampler_(nullptr) {
// Init uniforms
uniforms_buffer_.init(ctx_.device);
- // Create render pass using helper
- ResourceBinding bindings[] = {{uniforms_buffer_.get(), WGPUBufferBindingType_Uniform}};
- RenderPass pass = gpu_create_render_pass(ctx_.device, WGPUTextureFormat_RGBA8Unorm,
- heptagon_v2_shader_wgsl, bindings, 1);
- pipeline_ = pass.pipeline;
- bind_group_ = pass.bind_group;
+ // Create pipeline (standard v2 post-process, no depth)
+ pipeline_ = create_post_process_pipeline(ctx_.device, WGPUTextureFormat_RGBA8Unorm,
+ heptagon_v2_shader_wgsl);
+
+ // Create dummy sampler (scene effects don't use texture input)
+ WGPUSamplerDescriptor sampler_desc = {};
+ sampler_desc.addressModeU = WGPUAddressMode_ClampToEdge;
+ sampler_desc.addressModeV = WGPUAddressMode_ClampToEdge;
+ sampler_desc.magFilter = WGPUFilterMode_Nearest;
+ sampler_desc.minFilter = WGPUFilterMode_Nearest;
+ sampler_desc.maxAnisotropy = 1;
+ sampler_ = wgpuDeviceCreateSampler(ctx_.device, &sampler_desc);
+
+ // Create 1×1 dummy texture
+ WGPUTextureDescriptor tex_desc = {};
+ tex_desc.size = {1, 1, 1};
+ tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
+ tex_desc.usage = WGPUTextureUsage_TextureBinding;
+ tex_desc.dimension = WGPUTextureDimension_2D;
+ tex_desc.mipLevelCount = 1;
+ tex_desc.sampleCount = 1;
+ dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc);
+ dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr);
+}
+
+HeptagonEffectV2::~HeptagonEffectV2() {
+ if (bind_group_) wgpuBindGroupRelease(bind_group_);
+ if (pipeline_) wgpuRenderPipelineRelease(pipeline_);
+ if (sampler_) wgpuSamplerRelease(sampler_);
+ if (dummy_texture_view_) wgpuTextureViewRelease(dummy_texture_view_);
+ if (dummy_texture_) wgpuTextureRelease(dummy_texture_);
}
void HeptagonEffectV2::render(WGPUCommandEncoder encoder,
@@ -28,9 +54,16 @@ void HeptagonEffectV2::render(WGPUCommandEncoder encoder,
// Update uniforms
uniforms_buffer_.update(ctx_.queue, params);
+ // Create bind group (use dummy texture for scene effect)
+ pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, dummy_texture_view_,
+ uniforms_buffer_.get(), {nullptr, 0});
+
// Render pass
WGPURenderPassColorAttachment color_attachment = {};
color_attachment.view = output_view;
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
+ color_attachment.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED;
+#endif
color_attachment.loadOp = WGPULoadOp_Clear;
color_attachment.storeOp = WGPUStoreOp_Store;
color_attachment.clearValue = {0.0, 0.0, 0.0, 1.0};
diff --git a/src/effects/heptagon_effect_v2.h b/src/effects/heptagon_effect_v2.h
index f740769..1737a46 100644
--- a/src/effects/heptagon_effect_v2.h
+++ b/src/effects/heptagon_effect_v2.h
@@ -9,6 +9,7 @@ class HeptagonEffectV2 : public EffectV2 {
public:
HeptagonEffectV2(const GpuContext& ctx, const std::vector<std::string>& inputs,
const std::vector<std::string>& outputs);
+ ~HeptagonEffectV2();
void render(WGPUCommandEncoder encoder, const UniformsSequenceParams& params,
NodeRegistry& nodes) override;
@@ -16,5 +17,8 @@ class HeptagonEffectV2 : public EffectV2 {
private:
WGPURenderPipeline pipeline_;
WGPUBindGroup bind_group_;
+ WGPUSampler sampler_;
+ WGPUTexture dummy_texture_;
+ WGPUTextureView dummy_texture_view_;
UniformBuffer<UniformsSequenceParams> uniforms_buffer_;
};
diff --git a/src/effects/hybrid3_d_effect_v2.cc b/src/effects/hybrid3_d_effect_v2.cc
index 5b44133..38e4e66 100644
--- a/src/effects/hybrid3_d_effect_v2.cc
+++ b/src/effects/hybrid3_d_effect_v2.cc
@@ -8,9 +8,51 @@
Hybrid3DEffectV2::Hybrid3DEffectV2(const GpuContext& ctx,
const std::vector<std::string>& inputs,
const std::vector<std::string>& outputs)
- : EffectV2(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth") {
+ : EffectV2(ctx, inputs, outputs), depth_node_(outputs[0] + "_depth"),
+ dummy_texture_(nullptr), dummy_texture_view_(nullptr) {
// Initialize renderer (format is always RGBA8Unorm for v2)
renderer_.init(ctx_.device, ctx_.queue, WGPUTextureFormat_RGBA8Unorm);
+
+ // Create 1×1 white dummy texture for noise/sky (Renderer3D requires these)
+ WGPUTextureDescriptor tex_desc = {};
+ tex_desc.size = {1, 1, 1};
+ tex_desc.format = WGPUTextureFormat_RGBA8Unorm;
+ tex_desc.usage = WGPUTextureUsage_TextureBinding | WGPUTextureUsage_CopyDst;
+ tex_desc.dimension = WGPUTextureDimension_2D;
+ tex_desc.mipLevelCount = 1;
+ tex_desc.sampleCount = 1;
+ dummy_texture_ = wgpuDeviceCreateTexture(ctx_.device, &tex_desc);
+ dummy_texture_view_ = wgpuTextureCreateView(dummy_texture_, nullptr);
+
+ // Write white pixel
+ uint32_t white_pixel = 0xFFFFFFFF;
+#if defined(DEMO_CROSS_COMPILE_WIN32)
+ WGPUImageCopyTexture dst = {
+ .texture = dummy_texture_,
+ .mipLevel = 0,
+ .origin = {0, 0, 0}
+ };
+ WGPUTextureDataLayout data_layout = {
+ .bytesPerRow = 4,
+ .rowsPerImage = 1
+ };
+#else
+ WGPUTexelCopyTextureInfo dst = {
+ .texture = dummy_texture_,
+ .mipLevel = 0,
+ .origin = {0, 0, 0}
+ };
+ WGPUTexelCopyBufferLayout data_layout = {
+ .bytesPerRow = 4,
+ .rowsPerImage = 1
+ };
+#endif
+ WGPUExtent3D size = {1, 1, 1};
+ wgpuQueueWriteTexture(ctx_.queue, &dst, &white_pixel, 4, &data_layout, &size);
+
+ renderer_.set_noise_texture(dummy_texture_view_);
+ renderer_.set_sky_texture(dummy_texture_view_);
+
initialized_ = true;
// Setup simple scene (1 center cube + 8 surrounding objects)
@@ -40,6 +82,14 @@ Hybrid3DEffectV2::Hybrid3DEffectV2(const GpuContext& ctx,
}
}
+Hybrid3DEffectV2::~Hybrid3DEffectV2() {
+ if (dummy_texture_view_)
+ wgpuTextureViewRelease(dummy_texture_view_);
+ if (dummy_texture_)
+ wgpuTextureRelease(dummy_texture_);
+ renderer_.shutdown();
+}
+
void Hybrid3DEffectV2::declare_nodes(NodeRegistry& registry) {
// Declare depth buffer node
registry.declare_node(depth_node_, NodeType::DEPTH24, -1, -1);
diff --git a/src/effects/hybrid3_d_effect_v2.h b/src/effects/hybrid3_d_effect_v2.h
index 078b047..c8116b0 100644
--- a/src/effects/hybrid3_d_effect_v2.h
+++ b/src/effects/hybrid3_d_effect_v2.h
@@ -14,7 +14,7 @@ class Hybrid3DEffectV2 : public EffectV2 {
Hybrid3DEffectV2(const GpuContext& ctx,
const std::vector<std::string>& inputs,
const std::vector<std::string>& outputs);
- ~Hybrid3DEffectV2() override = default;
+ ~Hybrid3DEffectV2() override;
void declare_nodes(NodeRegistry& registry) override;
void render(WGPUCommandEncoder encoder,
@@ -27,4 +27,6 @@ class Hybrid3DEffectV2 : public EffectV2 {
Camera camera_;
bool initialized_ = false;
std::string depth_node_;
+ WGPUTexture dummy_texture_;
+ WGPUTextureView dummy_texture_view_;
};
diff --git a/src/effects/hybrid_3d_effect.cc b/src/effects/hybrid_3d_effect.cc
deleted file mode 100644
index 61f3165..0000000
--- a/src/effects/hybrid_3d_effect.cc
+++ /dev/null
@@ -1,147 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the Hybrid3DEffect.
-
-#include "effects/hybrid_3d_effect.h"
-#include "generated/assets.h"
-#include "util/asset_manager_utils.h"
-#include <cassert>
-#include <cmath>
-#include <iostream>
-
-Hybrid3DEffect::Hybrid3DEffect(const GpuContext& ctx) : Effect(ctx) {
-}
-
-void Hybrid3DEffect::resize(int width, int height) {
- if (width == width_ && height == height_)
- return;
-
- Effect::resize(width, height);
-
- if (!initialized_)
- return;
-
- renderer_.resize(width_, height_);
-}
-
-void Hybrid3DEffect::init(MainSequence* demo) {
- (void)demo;
- WGPUTextureFormat format =
- demo->gpu_ctx.format; // Get current format from MainSequence (might be
- // different than constructor if resized)
-
- renderer_.init(ctx_.device, ctx_.queue, ctx_.format);
- renderer_.resize(width_, height_);
- initialized_ = true;
-
- // Texture Manager
- texture_manager_.init(ctx_.device, ctx_.queue);
-
- // Load Noise Asset
- TextureAsset noise_tex = GetTextureAsset(AssetId::ASSET_NOISE_TEX);
- if (noise_tex.pixels && noise_tex.width == 256 && noise_tex.height == 256) {
- texture_manager_.create_texture("noise", noise_tex.width, noise_tex.height,
- noise_tex.pixels);
- renderer_.set_noise_texture(texture_manager_.get_texture_view("noise"));
- } else {
- std::cerr << "Failed to load NOISE_TEX asset." << std::endl;
- }
-
- // Setup Scene
- scene_.clear();
- Object3D center(ObjectType::BOX); // Use BOX for bumps
- center.position = vec3(0, 0, 0);
- center.color = vec4(1, 0, 0, 1);
- scene_.add_object(center);
-
- for (int i = 0; i < 8; ++i) {
- ObjectType type = ObjectType::SPHERE;
- if (i % 3 == 1)
- type = ObjectType::TORUS;
- if (i % 3 == 2)
- type = ObjectType::BOX;
-
- Object3D obj(type);
-
- float angle = (i / 8.0f) * 6.28318f;
-
- obj.position = vec3(std::cos(angle) * 4.0f, 0, std::sin(angle) * 4.0f);
-
- obj.scale = vec3(0.7f, 0.7f, 0.7f); // Increased scale by 40%
-
- if (type == ObjectType::SPHERE)
- obj.color = vec4(0, 1, 0, 1);
-
- else if (type == ObjectType::TORUS)
- obj.color = vec4(0, 0.5, 1, 1);
- else
- obj.color = vec4(1, 1, 0, 1);
-
- scene_.add_object(obj);
- }
-}
-
-// Cubic ease-in/out function for non-linear motion
-
-static float ease_in_out_cubic(float t) {
- t *= 2.0f;
-
- if (t < 1.0f) {
- return 0.5f * t * t * t;
- }
-
- t -= 2.0f;
-
- return 0.5f * (t * t * t + 2.0f);
-}
-
-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), uniforms.time * 2.0f + i);
-
- 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)(uniforms.time / 2.0f);
- int camera_preset = pattern_num % 4; // Cycle through 4 different angles
-
- vec3 cam_pos, cam_target;
-
- switch (camera_preset) {
- case 0: // High angle, orbiting
- {
- 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 = 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(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 = 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 = uniforms.aspect_ratio;
-
- // Draw
-
- renderer_.draw(pass, scene_, camera_, uniforms.time);
-}
diff --git a/src/effects/hybrid_3d_effect.h b/src/effects/hybrid_3d_effect.h
deleted file mode 100644
index 818b65c..0000000
--- a/src/effects/hybrid_3d_effect.h
+++ /dev/null
@@ -1,29 +0,0 @@
-// This file is part of the 64k demo project.
-// It defines the Hybrid3DEffect, integrating the 3D renderer into the demo
-// timeline.
-
-#pragma once
-
-#include "3d/camera.h"
-#include "3d/renderer.h"
-#include "3d/scene.h"
-#include "gpu/effect.h"
-#include "gpu/texture_manager.h"
-
-class Hybrid3DEffect : public Effect {
- public:
- Hybrid3DEffect(const GpuContext& ctx);
- virtual ~Hybrid3DEffect() override = default;
-
- void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void resize(int width, int height) override;
-
- private:
- Renderer3D renderer_;
- TextureManager texture_manager_;
- Scene scene_;
- Camera camera_;
- bool initialized_ = false;
-};
diff --git a/src/effects/moving_ellipse_effect.cc b/src/effects/moving_ellipse_effect.cc
deleted file mode 100644
index 6fb0195..0000000
--- a/src/effects/moving_ellipse_effect.cc
+++ /dev/null
@@ -1,24 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the MovingEllipseEffect.
-
-#include "effects/moving_ellipse_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-
-// --- MovingEllipseEffect ---
-MovingEllipseEffect::MovingEllipseEffect(const GpuContext& ctx) : Effect(ctx) {
- // uniforms_ is initialized by Effect base class
- ResourceBinding bindings[] = {
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, ellipse_shader_wgsl,
- bindings, 1);
- pass_.vertex_count = 3;
-}
-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/effects/moving_ellipse_effect.h b/src/effects/moving_ellipse_effect.h
deleted file mode 100644
index 46c1f0e..0000000
--- a/src/effects/moving_ellipse_effect.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the MovingEllipseEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-
-class MovingEllipseEffect : public Effect {
- public:
- MovingEllipseEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- RenderPass pass_;
-};
diff --git a/src/effects/particle_spray_effect.cc b/src/effects/particle_spray_effect.cc
deleted file mode 100644
index 1acf67d..0000000
--- a/src/effects/particle_spray_effect.cc
+++ /dev/null
@@ -1,49 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the ParticleSprayEffect.
-
-#include "effects/particle_spray_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-#include <vector>
-
-// --- ParticleSprayEffect ---
-ParticleSprayEffect::ParticleSprayEffect(const GpuContext& ctx) : Effect(ctx) {
- std::vector<Particle> init_p(NUM_PARTICLES);
- for (Particle& p : init_p)
- p.pos[3] = 0.0f;
- particles_buffer_ = gpu_create_buffer(
- ctx_.device, sizeof(Particle) * NUM_PARTICLES,
- WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data());
- ResourceBinding cb[] = {{particles_buffer_, WGPUBufferBindingType_Storage},
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- compute_pass_ =
- gpu_create_compute_pass(ctx_.device, particle_spray_compute_wgsl, cb, 2);
- compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64;
- ResourceBinding rb[] = {
- {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage},
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- render_pass_ = gpu_create_render_pass(ctx_.device, ctx_.format,
- particle_render_wgsl, rb, 2);
- render_pass_.vertex_count = 6;
- render_pass_.instance_count = NUM_PARTICLES;
-}
-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,
- nullptr);
- wgpuComputePassEncoderDispatchWorkgroups(pass, compute_pass_.workgroup_size_x,
- 1, 1);
- wgpuComputePassEncoderEnd(pass);
-}
-void ParticleSprayEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- (void)uniforms;
- wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0,
- nullptr);
- wgpuRenderPassEncoderDraw(pass, 6, NUM_PARTICLES, 0, 0);
-}
diff --git a/src/effects/particle_spray_effect.h b/src/effects/particle_spray_effect.h
deleted file mode 100644
index 216e13f..0000000
--- a/src/effects/particle_spray_effect.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the ParticleSprayEffect.
-
-#pragma once
-
-#include "effects/particle_defs.h"
-#include "gpu/effect.h"
-
-class ParticleSprayEffect : public Effect {
- public:
- ParticleSprayEffect(const GpuContext& ctx);
- void compute(WGPUCommandEncoder encoder,
- const CommonPostProcessUniforms& uniforms) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- ComputePass compute_pass_;
- RenderPass render_pass_;
- GpuBuffer particles_buffer_;
-};
diff --git a/src/effects/particles_effect.cc b/src/effects/particles_effect.cc
deleted file mode 100644
index 25589fd..0000000
--- a/src/effects/particles_effect.cc
+++ /dev/null
@@ -1,48 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the ParticlesEffect.
-
-#include "effects/particles_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-#include <vector>
-
-// --- ParticlesEffect ---
-ParticlesEffect::ParticlesEffect(const GpuContext& ctx) : Effect(ctx) {
- std::vector<Particle> init_p(NUM_PARTICLES);
- particles_buffer_ = gpu_create_buffer(
- ctx_.device, sizeof(Particle) * NUM_PARTICLES,
- WGPUBufferUsage_Storage | WGPUBufferUsage_Vertex, init_p.data());
- ResourceBinding cb[] = {{particles_buffer_, WGPUBufferBindingType_Storage},
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- compute_pass_ =
- gpu_create_compute_pass(ctx_.device, particle_compute_wgsl, cb, 2);
- compute_pass_.workgroup_size_x = (NUM_PARTICLES + 63) / 64;
- ResourceBinding rb[] = {
- {particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage},
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- render_pass_ = gpu_create_render_pass(ctx_.device, ctx_.format,
- particle_render_wgsl, rb, 2);
- render_pass_.vertex_count = 6;
- render_pass_.instance_count = NUM_PARTICLES;
-}
-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,
- nullptr);
- wgpuComputePassEncoderDispatchWorkgroups(pass, compute_pass_.workgroup_size_x,
- 1, 1);
- wgpuComputePassEncoderEnd(pass);
-}
-void ParticlesEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- (void)uniforms;
- wgpuRenderPassEncoderSetPipeline(pass, render_pass_.pipeline);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, render_pass_.bind_group, 0,
- nullptr);
- wgpuRenderPassEncoderDraw(pass, render_pass_.vertex_count,
- render_pass_.instance_count, 0, 0);
-}
diff --git a/src/effects/particles_effect.h b/src/effects/particles_effect.h
deleted file mode 100644
index a69039f..0000000
--- a/src/effects/particles_effect.h
+++ /dev/null
@@ -1,21 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the ParticlesEffect.
-
-#pragma once
-
-#include "effects/particle_defs.h"
-#include "gpu/effect.h"
-
-class ParticlesEffect : public Effect {
- public:
- ParticlesEffect(const GpuContext& ctx);
- void compute(WGPUCommandEncoder encoder,
- const CommonPostProcessUniforms& uniforms) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- ComputePass compute_pass_;
- RenderPass render_pass_;
- GpuBuffer particles_buffer_;
-};
diff --git a/src/effects/particles_effect_v2.cc b/src/effects/particles_effect_v2.cc
index 5a1a07c..69da4da 100644
--- a/src/effects/particles_effect_v2.cc
+++ b/src/effects/particles_effect_v2.cc
@@ -53,8 +53,8 @@ ParticlesEffectV2::ParticlesEffectV2(const GpuContext& ctx,
ResourceBinding render_bindings[] = {
{particles_buffer_, WGPUBufferBindingType_ReadOnlyStorage},
{uniforms_.get(), WGPUBufferBindingType_Uniform}};
- render_pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, particle_render_v2_wgsl,
- render_bindings, 2);
+ render_pass_ = gpu_create_render_pass(ctx_.device, WGPUTextureFormat_RGBA8Unorm,
+ particle_render_v2_wgsl, render_bindings, 2);
render_pass_.vertex_count = 6;
render_pass_.instance_count = NUM_PARTICLES;
}
@@ -77,7 +77,9 @@ void ParticlesEffectV2::render(WGPUCommandEncoder encoder,
WGPURenderPassColorAttachment color_attachment = {
.view = output_view,
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
+#endif
.loadOp = WGPULoadOp_Clear,
.storeOp = WGPUStoreOp_Store,
.clearValue = {0.0, 0.0, 0.0, 1.0}};
diff --git a/src/effects/passthrough_effect.cc b/src/effects/passthrough_effect.cc
deleted file mode 100644
index 50f5a5c..0000000
--- a/src/effects/passthrough_effect.cc
+++ /dev/null
@@ -1,18 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the PassthroughEffect.
-
-#include "effects/passthrough_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/shaders.h"
-
-// --- PassthroughEffect ---
-PassthroughEffect::PassthroughEffect(const GpuContext& ctx)
- : PostProcessEffect(ctx) {
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- passthrough_shader_wgsl);
-}
-void PassthroughEffect::update_bind_group(WGPUTextureView input_view) {
- uniforms_.update(ctx_.queue, get_common_uniforms());
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- uniforms_.get(), {});
-}
diff --git a/src/effects/passthrough_effect.h b/src/effects/passthrough_effect.h
deleted file mode 100644
index 36f93f2..0000000
--- a/src/effects/passthrough_effect.h
+++ /dev/null
@@ -1,14 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the PassthroughEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-
-class PassthroughEffect : public PostProcessEffect {
- public:
- PassthroughEffect(const GpuContext& ctx);
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
-};
diff --git a/src/effects/passthrough_effect_v2.cc b/src/effects/passthrough_effect_v2.cc
index 5203f97..765c1f0 100644
--- a/src/effects/passthrough_effect_v2.cc
+++ b/src/effects/passthrough_effect_v2.cc
@@ -44,7 +44,9 @@ void PassthroughEffectV2::render(WGPUCommandEncoder encoder,
// Render pass
WGPURenderPassColorAttachment color_attachment = {
.view = output_view,
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
+#endif
.loadOp = WGPULoadOp_Clear,
.storeOp = WGPUStoreOp_Store,
.clearValue = {0.0, 0.0, 0.0, 1.0}
diff --git a/src/effects/placeholder_effect_v2.cc b/src/effects/placeholder_effect_v2.cc
index 12692fa..d1fa212 100644
--- a/src/effects/placeholder_effect_v2.cc
+++ b/src/effects/placeholder_effect_v2.cc
@@ -42,7 +42,9 @@ void PlaceholderEffectV2::render(WGPUCommandEncoder encoder,
WGPURenderPassColorAttachment color_attachment = {
.view = output_view,
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
+#endif
.loadOp = WGPULoadOp_Clear,
.storeOp = WGPUStoreOp_Store,
.clearValue = {0.0, 0.0, 0.0, 1.0}
diff --git a/src/effects/rotating_cube_effect.cc b/src/effects/rotating_cube_effect.cc
deleted file mode 100644
index c03eccb..0000000
--- a/src/effects/rotating_cube_effect.cc
+++ /dev/null
@@ -1,204 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements RotatingCubeEffect for bump-mapped rotating cube rendering.
-// Uses auxiliary texture masking to render only inside a circular region.
-
-#include "effects/rotating_cube_effect.h"
-#include "generated/assets.h"
-#include "gpu/bind_group_builder.h"
-#include "gpu/gpu.h"
-#include "gpu/sampler_cache.h"
-#include "gpu/shader_composer.h"
-#include "util/asset_manager_utils.h"
-
-RotatingCubeEffect::RotatingCubeEffect(const GpuContext& ctx) : Effect(ctx) {
-}
-
-RotatingCubeEffect::~RotatingCubeEffect() {
- // Samplers owned by SamplerCache - don't release
- if (noise_view_)
- wgpuTextureViewRelease(noise_view_);
- if (noise_texture_)
- wgpuTextureRelease(noise_texture_);
- if (bind_group_1_)
- wgpuBindGroupRelease(bind_group_1_);
- if (bind_group_0_)
- wgpuBindGroupRelease(bind_group_0_);
- if (pipeline_)
- wgpuRenderPipelineRelease(pipeline_);
-}
-
-void RotatingCubeEffect::init(MainSequence* demo) {
- demo_ = demo;
-
- uniform_buffer_ =
- gpu_create_buffer(ctx_.device, sizeof(Uniforms),
- WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
- object_buffer_ =
- gpu_create_buffer(ctx_.device, sizeof(ObjectData),
- WGPUBufferUsage_Storage | WGPUBufferUsage_CopyDst);
-
- TextureWithView noise = gpu_create_texture_2d(
- ctx_.device, 1, 1, WGPUTextureFormat_RGBA8Unorm,
- (WGPUTextureUsage)(WGPUTextureUsage_TextureBinding |
- WGPUTextureUsage_RenderAttachment),
- 1);
- noise_texture_ = noise.texture;
- noise_view_ = noise.view;
-
- noise_sampler_ =
- SamplerCache::Get().get_or_create(ctx_.device, SamplerCache::linear());
- mask_sampler_ =
- SamplerCache::Get().get_or_create(ctx_.device, SamplerCache::clamp());
-
- size_t shader_size;
- const char* shader_code =
- (const char*)GetAsset(AssetId::ASSET_MASKED_CUBE_SHADER, &shader_size);
-
- ShaderComposer::CompositionMap composition_map;
- composition_map["render/scene_query_mode"] = "render/scene_query_linear";
- composed_shader_ = ShaderComposer::Get().Compose(
- {}, std::string(shader_code, shader_size), composition_map);
-
- WGPUShaderSourceWGSL wgsl_src = {};
- wgsl_src.chain.sType = WGPUSType_ShaderSourceWGSL;
- wgsl_src.code = str_view(composed_shader_.c_str());
-
- WGPUShaderModuleDescriptor shader_desc = {};
- shader_desc.nextInChain = &wgsl_src.chain;
- WGPUShaderModule shader_module =
- wgpuDeviceCreateShaderModule(ctx_.device, &shader_desc);
-
- WGPUBindGroupLayout bgl_0 =
- BindGroupLayoutBuilder()
- .uniform(0, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment,
- sizeof(Uniforms))
- .storage(1, WGPUShaderStage_Vertex | WGPUShaderStage_Fragment,
- sizeof(ObjectData))
- .texture(3, WGPUShaderStage_Fragment)
- .sampler(4, WGPUShaderStage_Fragment)
- .build(ctx_.device);
-
- WGPUBindGroupLayout bgl_1 = BindGroupLayoutBuilder()
- .texture(0, WGPUShaderStage_Fragment)
- .sampler(1, WGPUShaderStage_Fragment)
- .build(ctx_.device);
-
- const WGPUBindGroupLayout bgls[] = {bgl_0, bgl_1};
- const WGPUPipelineLayoutDescriptor pl_desc = {
- .bindGroupLayoutCount = 2,
- .bindGroupLayouts = bgls,
- };
- WGPUPipelineLayout pipeline_layout =
- wgpuDeviceCreatePipelineLayout(ctx_.device, &pl_desc);
-
- const WGPUColorTargetState color_target = {
- .format = ctx_.format,
- .writeMask = WGPUColorWriteMask_All,
- };
-
- const WGPUDepthStencilState depth_stencil = {
- .format = WGPUTextureFormat_Depth24Plus,
- .depthWriteEnabled = WGPUOptionalBool_True,
- .depthCompare = WGPUCompareFunction_Less,
- };
-
- WGPUFragmentState fragment = {};
- fragment.module = shader_module;
- fragment.entryPoint = str_view("fs_main");
- fragment.targetCount = 1;
- fragment.targets = &color_target;
-
- WGPURenderPipelineDescriptor pipeline_desc = {};
- pipeline_desc.layout = pipeline_layout;
- pipeline_desc.vertex.module = shader_module;
- pipeline_desc.vertex.entryPoint = str_view("vs_main");
- pipeline_desc.primitive.topology = WGPUPrimitiveTopology_TriangleList;
- pipeline_desc.primitive.cullMode = WGPUCullMode_None;
- pipeline_desc.depthStencil = &depth_stencil;
- pipeline_desc.multisample.count = 1;
- pipeline_desc.multisample.mask = 0xFFFFFFFF;
- pipeline_desc.fragment = &fragment;
-
- pipeline_ = wgpuDeviceCreateRenderPipeline(ctx_.device, &pipeline_desc);
- wgpuShaderModuleRelease(shader_module);
- wgpuPipelineLayoutRelease(pipeline_layout);
-
- const WGPUBindGroupEntry entries_0[] = {
- {.binding = 0,
- .buffer = uniform_buffer_.buffer,
- .size = sizeof(Uniforms)},
- {.binding = 1,
- .buffer = object_buffer_.buffer,
- .size = sizeof(ObjectData)},
- {.binding = 3, .textureView = noise_view_},
- {.binding = 4, .sampler = noise_sampler_},
- };
-
- const WGPUBindGroupDescriptor bg_desc_0 = {
- .layout = bgl_0,
- .entryCount = 4,
- .entries = entries_0,
- };
- bind_group_0_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc_0);
- wgpuBindGroupLayoutRelease(bgl_0);
-
- WGPUTextureView mask_view = demo_->get_auxiliary_view("circle_mask");
- const WGPUBindGroupEntry entries_1[] = {
- {.binding = 0, .textureView = mask_view},
- {.binding = 1, .sampler = mask_sampler_},
- };
-
- const WGPUBindGroupDescriptor bg_desc_1 = {
- .layout = bgl_1,
- .entryCount = 2,
- .entries = entries_1,
- };
- bind_group_1_ = wgpuDeviceCreateBindGroup(ctx_.device, &bg_desc_1);
- wgpuBindGroupLayoutRelease(bgl_1);
-}
-
-void RotatingCubeEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& u) {
- rotation_ += 0.016f * 1.5f;
-
- const vec3 camera_pos = vec3(0, 0, 5);
- const vec3 target = vec3(0, 0, 0);
- const vec3 up = vec3(0, 1, 0);
-
- 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, 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_);
- const mat4 T = mat4::translate(vec3(0, 0, 0));
- const mat4 R = rot.to_mat();
- const mat4 S = mat4::scale(vec3(1.5f, 1.5f, 1.5f));
- const mat4 model = T * R * S;
- const mat4 inv_model = model.inverse();
-
- 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, u.time),
- .params = vec4(1.0f, 0.0f, 0.0f, 0.0f),
- .resolution = u.resolution,
- };
-
- const ObjectData obj_data = {
- .model = model,
- .inv_model = inv_model,
- .color = vec4(0.8f, 0.4f, 0.2f, 1.0f),
- .params = vec4(1.0f, 0.0f, 0.0f, 0.0f),
- };
-
- wgpuQueueWriteBuffer(ctx_.queue, uniform_buffer_.buffer, 0, &uniforms,
- sizeof(Uniforms));
- wgpuQueueWriteBuffer(ctx_.queue, object_buffer_.buffer, 0, &obj_data,
- sizeof(ObjectData));
-
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_0_, 0, nullptr);
- wgpuRenderPassEncoderSetBindGroup(pass, 1, bind_group_1_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 36, 1, 0, 0);
-}
diff --git a/src/effects/rotating_cube_effect.h b/src/effects/rotating_cube_effect.h
deleted file mode 100644
index fdf67ab..0000000
--- a/src/effects/rotating_cube_effect.h
+++ /dev/null
@@ -1,55 +0,0 @@
-// This file is part of the 64k demo project.
-// It defines RotatingCubeEffect for rendering a bump-mapped rotating cube.
-// Uses auxiliary texture masking to render only inside a circular region.
-
-#ifndef ROTATING_CUBE_EFFECT_H_
-#define ROTATING_CUBE_EFFECT_H_
-
-#include "gpu/effect.h"
-#include "gpu/gpu.h"
-#include "util/mini_math.h"
-#include <string>
-
-class RotatingCubeEffect : public Effect {
- public:
- RotatingCubeEffect(const GpuContext& ctx);
- ~RotatingCubeEffect() override;
-
- void init(MainSequence* demo) override;
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- struct Uniforms {
- mat4 view_proj;
- mat4 inv_view_proj;
- vec4 camera_pos_time;
- vec4 params;
- vec2 resolution;
- vec2 padding;
- };
-
- struct ObjectData {
- mat4 model;
- mat4 inv_model;
- vec4 color;
- vec4 params;
- };
-
- MainSequence* demo_ = nullptr;
- WGPURenderPipeline pipeline_ = nullptr;
- WGPUBindGroup bind_group_0_ = nullptr;
- WGPUBindGroup bind_group_1_ = nullptr;
- GpuBuffer uniform_buffer_;
- GpuBuffer object_buffer_;
- WGPUTexture noise_texture_ = nullptr;
- WGPUTextureView noise_view_ = nullptr;
- WGPUSampler noise_sampler_ = nullptr;
- WGPUSampler mask_sampler_ = nullptr;
- float rotation_ = 0.0f;
-
- // Store composed shader to keep it alive for WebGPU
- std::string composed_shader_;
-};
-
-#endif /* ROTATING_CUBE_EFFECT_H_ */
diff --git a/src/effects/rotating_cube_effect_v2.cc b/src/effects/rotating_cube_effect_v2.cc
index 02ed2d3..1a28cad 100644
--- a/src/effects/rotating_cube_effect_v2.cc
+++ b/src/effects/rotating_cube_effect_v2.cc
@@ -159,7 +159,9 @@ void RotatingCubeEffectV2::render(WGPUCommandEncoder encoder,
// Render pass with depth
WGPURenderPassColorAttachment color_attachment = {
.view = color_view,
+#if !defined(DEMO_CROSS_COMPILE_WIN32)
.depthSlice = WGPU_DEPTH_SLICE_UNDEFINED,
+#endif
.loadOp = WGPULoadOp_Clear,
.storeOp = WGPUStoreOp_Store,
.clearValue = {0.0, 0.0, 0.0, 1.0}};
diff --git a/src/effects/scene1_effect.cc b/src/effects/scene1_effect.cc
deleted file mode 100644
index 3d6df3b..0000000
--- a/src/effects/scene1_effect.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// This file is part of the 64k demo project.
-// Scene1 effect - ShaderToy conversion (raymarching scene)
-
-#include "gpu/demo_effects.h"
-#include "gpu/gpu.h"
-
-Scene1Effect::Scene1Effect(const GpuContext& ctx) : Effect(ctx) {
- ResourceBinding bindings[] = {
- {uniforms_.get(), WGPUBufferBindingType_Uniform}};
- pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, scene1_shader_wgsl,
- bindings, 1);
- pass_.vertex_count = 3;
-}
-
-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/effects/scene1_effect.h b/src/effects/scene1_effect.h
deleted file mode 100644
index 190ffa9..0000000
--- a/src/effects/scene1_effect.h
+++ /dev/null
@@ -1,19 +0,0 @@
-// This file is part of the 64k demo project.
-// Scene1 effect - ShaderToy conversion (raymarching scene)
-
-#ifndef SCENE1_EFFECT_H_
-#define SCENE1_EFFECT_H_
-
-#include "gpu/effect.h"
-
-class Scene1Effect : public Effect {
- public:
- Scene1Effect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- RenderPass pass_;
-};
-
-#endif /* SCENE1_EFFECT_H_ */
diff --git a/src/effects/sdf_test_effect.cc b/src/effects/sdf_test_effect.cc
deleted file mode 100644
index 264809f..0000000
--- a/src/effects/sdf_test_effect.cc
+++ /dev/null
@@ -1,36 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the SDFTestEffect.
-
-#include "effects/sdf_test_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/shaders.h"
-
-SDFTestEffect::SDFTestEffect(const GpuContext& ctx) : SDFEffect(ctx) {
- ResourceBinding bindings[] = {
- {uniforms_.get(), WGPUBufferBindingType_Uniform},
- {camera_params_.get(), WGPUBufferBindingType_Uniform}};
- pass_ = gpu_create_render_pass(ctx_.device, ctx_.format, sdf_test_shader_wgsl,
- bindings, 2);
- pass_.vertex_count = 3;
-}
-
-void SDFTestEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- // Update common uniforms
- uniforms_.update(ctx_.queue, uniforms);
-
- // Update camera (simple orbiting camera)
- const float radius = 5.0f;
- const float speed = 0.3f;
- vec3 cam_pos(std::cos(uniforms.time * speed) * radius, 2.0f,
- std::sin(uniforms.time * speed) * radius);
- vec3 cam_target(0.0f, 0.0f, 0.0f);
- vec3 cam_up(0.0f, 1.0f, 0.0f);
- update_camera(cam_pos, cam_target, cam_up, 0.785398f, 0.1f, 100.0f,
- uniforms.aspect_ratio);
-
- // Render
- wgpuRenderPassEncoderSetPipeline(pass, pass_.pipeline);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, pass_.bind_group, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, pass_.vertex_count, 1, 0, 0);
-}
diff --git a/src/effects/sdf_test_effect.h b/src/effects/sdf_test_effect.h
deleted file mode 100644
index 41baf83..0000000
--- a/src/effects/sdf_test_effect.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// This file is part of the 64k demo project.
-// It demonstrates SDFEffect base class usage.
-
-#pragma once
-
-#include "gpu/sdf_effect.h"
-
-class SDFTestEffect : public SDFEffect {
- public:
- SDFTestEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
-
- private:
- RenderPass pass_;
-};
diff --git a/src/effects/solarize_effect.cc b/src/effects/solarize_effect.cc
deleted file mode 100644
index a367e51..0000000
--- a/src/effects/solarize_effect.cc
+++ /dev/null
@@ -1,21 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the SolarizeEffect.
-
-#include "effects/solarize_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/shaders.h"
-
-// --- SolarizeEffect ---
-SolarizeEffect::SolarizeEffect(const GpuContext& ctx) : PostProcessEffect(ctx) {
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- solarize_shader_wgsl);
-}
-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/effects/solarize_effect.h b/src/effects/solarize_effect.h
deleted file mode 100644
index 6132f58..0000000
--- a/src/effects/solarize_effect.h
+++ /dev/null
@@ -1,16 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the SolarizeEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-
-class SolarizeEffect : public PostProcessEffect {
- public:
- SolarizeEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
-};
diff --git a/src/effects/theme_modulation_effect.cc b/src/effects/theme_modulation_effect.cc
deleted file mode 100644
index 82bfeb8..0000000
--- a/src/effects/theme_modulation_effect.cc
+++ /dev/null
@@ -1,106 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements theme modulation (bright/dark alternation).
-
-#include "effects/theme_modulation_effect.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-#include <cmath>
-
-struct ThemeModulationParams {
- float theme_brightness;
- float _pad[3];
-};
-static_assert(sizeof(ThemeModulationParams) == 16,
- "ThemeModulationParams must be 16 bytes for WGSL alignment");
-
-ThemeModulationEffect::ThemeModulationEffect(const GpuContext& ctx)
- : PostProcessEffect(ctx) {
- const char* shader_code = R"(
- struct VertexOutput {
- @builtin(position) position: vec4<f32>,
- @location(0) uv: vec2<f32>,
- };
-
- struct CommonUniforms {
- resolution: vec2<f32>,
- _pad0: f32,
- _pad1: f32,
- aspect_ratio: f32,
- time: f32,
- beat: f32,
- audio_intensity: f32,
- };
-
- struct ThemeModulationParams {
- theme_brightness: f32,
- _pad0: f32,
- _pad1: f32,
- _pad2: f32,
- };
-
- @group(0) @binding(0) var inputSampler: sampler;
- @group(0) @binding(1) var inputTexture: texture_2d<f32>;
- @group(0) @binding(2) var<uniform> uniforms: CommonUniforms;
- @group(0) @binding(3) var<uniform> params: ThemeModulationParams;
-
- @vertex
- fn vs_main(@builtin(vertex_index) vertexIndex: u32) -> VertexOutput {
- var output: VertexOutput;
- // Large triangle trick for fullscreen coverage
- var pos = array<vec2<f32>, 3>(
- vec2<f32>(-1.0, -1.0),
- vec2<f32>(3.0, -1.0),
- vec2<f32>(-1.0, 3.0)
- );
- output.position = vec4<f32>(pos[vertexIndex], 0.0, 1.0);
- output.uv = pos[vertexIndex] * 0.5 + 0.5;
- return output;
- }
-
- @fragment
- fn fs_main(input: VertexOutput) -> @location(0) vec4<f32> {
- let color = textureSample(inputTexture, inputSampler, input.uv);
- // Apply theme brightness modulation
- return vec4<f32>(color.rgb * params.theme_brightness, color.a);
- }
- )";
-
- pipeline_ =
- create_post_process_pipeline(ctx_.device, ctx_.format, shader_code);
-
- params_buffer_ = gpu_create_buffer(
- ctx_.device, 16, WGPUBufferUsage_Uniform | WGPUBufferUsage_CopyDst);
-}
-
-void ThemeModulationEffect::update_bind_group(WGPUTextureView input_view) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, input_view,
- uniforms_.get(), params_buffer_);
-}
-
-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(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(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 =
- bright_value + (dark_value - bright_value) * transition;
-
- // Update params buffer
- ThemeModulationParams params = {theme_brightness, {0.0f, 0.0f, 0.0f}};
- wgpuQueueWriteBuffer(ctx_.queue, params_buffer_.buffer, 0, &params,
- sizeof(params));
-
- // Render
- wgpuRenderPassEncoderSetPipeline(pass, pipeline_);
- wgpuRenderPassEncoderSetBindGroup(pass, 0, bind_group_, 0, nullptr);
- wgpuRenderPassEncoderDraw(pass, 3, 1, 0, 0);
-}
diff --git a/src/effects/theme_modulation_effect.h b/src/effects/theme_modulation_effect.h
deleted file mode 100644
index e4d4e0a..0000000
--- a/src/effects/theme_modulation_effect.h
+++ /dev/null
@@ -1,20 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements a theme modulation effect that alternates between bright and
-// dark. Pattern changes every 2 seconds, so we alternate every 4 seconds (2
-// patterns).
-
-#pragma once
-#include "gpu/effect.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/uniform_helper.h"
-
-class ThemeModulationEffect : public PostProcessEffect {
- public:
- ThemeModulationEffect(const GpuContext& ctx);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- GpuBuffer params_buffer_;
-};
diff --git a/src/effects/vignette_effect.cc b/src/effects/vignette_effect.cc
deleted file mode 100644
index 3ddbee3..0000000
--- a/src/effects/vignette_effect.cc
+++ /dev/null
@@ -1,31 +0,0 @@
-// This file is part of the 64k demo project.
-// It implements the VignetteEffect.
-
-#include "effects/vignette_effect.h"
-#include "gpu/gpu.h"
-#include "gpu/post_process_helper.h"
-#include "gpu/shaders.h"
-
-VignetteEffect::VignetteEffect(const GpuContext& ctx)
- : VignetteEffect(ctx, VignetteParams()) {
-}
-
-VignetteEffect::VignetteEffect(const GpuContext& ctx,
- const VignetteParams& params)
- : PostProcessEffect(ctx), params_(params) {
- params_buffer_.init(ctx_.device);
- pipeline_ = create_post_process_pipeline(ctx_.device, ctx_.format,
- vignette_shader_wgsl);
-}
-
-void VignetteEffect::render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) {
- uniforms_.update(ctx_.queue, uniforms);
- params_buffer_.update(ctx_.queue, params_);
- PostProcessEffect::render(pass, uniforms);
-}
-
-void VignetteEffect::update_bind_group(WGPUTextureView v) {
- pp_update_bind_group(ctx_.device, pipeline_, &bind_group_, v, uniforms_.get(),
- params_buffer_.get());
-}
diff --git a/src/effects/vignette_effect.h b/src/effects/vignette_effect.h
deleted file mode 100644
index f891d14..0000000
--- a/src/effects/vignette_effect.h
+++ /dev/null
@@ -1,26 +0,0 @@
-// This file is part of the 64k demo project.
-// It declares the VignetteEffect.
-
-#pragma once
-
-#include "gpu/effect.h"
-#include "gpu/uniform_helper.h"
-
-// Parameters for VignetteEffect
-struct VignetteParams {
- float radius = 0.5f; // Radius of the clear center
- float softness = 0.5f; // Softness of the vignette edge
-};
-
-class VignetteEffect : public PostProcessEffect {
- public:
- VignetteEffect(const GpuContext& ctx);
- VignetteEffect(const GpuContext& ctx, const VignetteParams& params);
- void render(WGPURenderPassEncoder pass,
- const CommonPostProcessUniforms& uniforms) override;
- void update_bind_group(WGPUTextureView input_view) override;
-
- private:
- VignetteParams params_;
- UniformBuffer<VignetteParams> params_buffer_;
-};