// 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_; };