From 72c0cbcb38732b698d33d52459fed67af56ee2ec Mon Sep 17 00:00:00 2001 From: skal Date: Sat, 31 Jan 2026 15:36:45 +0100 Subject: feat: Implement Sequence and Effect system for demo choreography Refactors the rendering pipeline into a modular Sequence/Effect system. 'MainSequence' manages the final frame rendering and a list of 'Sequence' layers. 'Sequence' manages a timeline of 'Effect' objects (start/end/priority). Concrete effects (Heptagon, Particles) are moved to 'demo_effects.cc'. Updates main loop to pass beat and aspect ratio. --- src/gpu/effect.h | 117 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/gpu/effect.h (limited to 'src/gpu/effect.h') diff --git a/src/gpu/effect.h b/src/gpu/effect.h new file mode 100644 index 0000000..50b2d72 --- /dev/null +++ b/src/gpu/effect.h @@ -0,0 +1,117 @@ +// This file is part of the 64k demo project. +// It defines the Effect interface and Sequence management system. +// Used for choreographing visual effects. + +#pragma once + +#include +#include +#include + +#if defined(DEMO_CROSS_COMPILE_WIN32) +#include +#else +#include +#endif + +class MainSequence; + +// Abstract base class for all visual effects +class Effect { +public: + virtual ~Effect() = default; + + // One-time setup (load assets, create buffers). + // Idempotent: safe to call multiple times if effect is shared. + virtual void init(MainSequence *demo) { (void)demo; } + + // Called when the effect starts playing in a sequence segment. + virtual void start() {} + + // Dispatch compute shaders. + virtual void compute(WGPUCommandEncoder encoder, float time, float beat, + float intensity, float aspect_ratio) { + (void)encoder; + (void)time; + (void)beat; + (void)intensity; + (void)aspect_ratio; + } + + // Record render commands. + virtual void render(WGPURenderPassEncoder pass, float time, float beat, + float intensity, float aspect_ratio) = 0; + + // Called when the effect finishes in a sequence segment. + virtual void end() {} + + bool is_initialized = false; +}; + +struct SequenceItem { + std::shared_ptr effect; + float start_time; // Relative to Sequence start + float end_time; // Relative to Sequence start + int priority; // Render order within sequence (higher = later/top) + bool active; +}; + +class Sequence { +public: + int priority = 0; // Render order of this sequence (higher = later/top) + + void init(MainSequence *demo); + + // Add an effect to the sequence. + // start_time, end_time: Relative to sequence start. + // priority: Drawing order within this sequence. + void add_effect(std::shared_ptr effect, float start_time, + float end_time, int priority = 0); + + // Updates active state of effects based on sequence-local time. + // seq_time: Time relative to sequence start. + void update_active_list(float seq_time); + + // Calls compute() on all active effects (sorted by priority). + void dispatch_compute(WGPUCommandEncoder encoder, float seq_time, float beat, + float intensity, float aspect_ratio); + + // Calls render() on all active effects (sorted by priority). + void dispatch_render(WGPURenderPassEncoder pass, float seq_time, float beat, + float intensity, float aspect_ratio); + + void reset(); + +private: + std::vector items_; + bool is_sorted_ = false; + void sort_items(); +}; + +class MainSequence { +public: + WGPUDevice device; + WGPUQueue queue; + WGPUTextureFormat format; + + void init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format); + + // Add a sequence to the demo. + // start_time: Global time when this sequence starts. + // priority: Layering order (higher = on top). + void add_sequence(std::shared_ptr seq, float start_time, int priority = 0); + + // Renders the full frame: updates sequences, runs compute, runs render pass. + void render_frame(float global_time, float beat, float peak, + float aspect_ratio, WGPUSurface surface); + + void shutdown(); + +private: + struct ActiveSequence { + std::shared_ptr seq; + float start_time; + int priority; + }; + std::vector sequences_; +}; -- cgit v1.2.3