#pragma once #include "gpu/gpu.h" #include #include #include class MainSequence; class PostProcessEffect; class Effect { public: Effect(WGPUDevice device, WGPUQueue queue) : device_(device), queue_(queue) { } virtual ~Effect() = default; virtual void init(MainSequence* demo) { (void)demo; } virtual void start() { } 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; } virtual void render(WGPURenderPassEncoder pass, float time, float beat, float intensity, float aspect_ratio) = 0; virtual void resize(int width, int height) { width_ = width; height_ = height; } virtual void end() { } bool is_initialized = false; virtual bool is_post_process() const { return false; } protected: WGPUDevice device_; WGPUQueue queue_; GpuBuffer uniforms_; int width_ = 1280; int height_ = 720; }; class PostProcessEffect : public Effect { public: PostProcessEffect(WGPUDevice device, WGPUQueue queue) : Effect(device, queue) { } bool is_post_process() const override { return true; } void compute(WGPUCommandEncoder, float, float, float, float) override { } void render(WGPURenderPassEncoder pass, float time, float beat, float intensity, float aspect_ratio) override; virtual void update_bind_group(WGPUTextureView input_view) = 0; protected: WGPURenderPipeline pipeline_ = nullptr; WGPUBindGroup bind_group_ = nullptr; }; 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); void add_effect(std::shared_ptr effect, float start_time, float end_time, int priority = 0); void update_active_list(float seq_time); void resize(int width, int height); void collect_active_effects(std::vector& scene_effects, std::vector& post_effects); void reset(); void set_end_time(float end_time) { end_time_ = end_time; } float get_end_time() const { return end_time_; } private: std::vector items_; bool is_sorted_ = false; float end_time_ = -1.0f; // Optional: -1.0 means "no explicit end" void sort_items(); }; class MainSequence { public: MainSequence(); ~MainSequence(); WGPUDevice device; WGPUQueue queue; WGPUTextureFormat format; void init(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format, int width, int height); void init_test(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format); void add_sequence(std::shared_ptr seq, float start_time, int priority = 0); void render_frame(float global_time, float beat, float peak, float aspect_ratio, WGPUSurface surface); void resize(int width, int height); void shutdown(); #if !defined(STRIP_ALL) void simulate_until(float target_time, float step_rate); #endif /* !defined(STRIP_ALL) */ private: struct ActiveSequence { std::shared_ptr seq; float start_time; int priority; bool activated = false; // Track if sequence has been activated for debug output }; std::vector sequences_; int width_ = 1280; int height_ = 720; WGPUTexture framebuffer_a_ = nullptr; WGPUTextureView framebuffer_view_a_ = nullptr; WGPUTexture framebuffer_b_ = nullptr; WGPUTextureView framebuffer_view_b_ = nullptr; WGPUTexture depth_texture_ = nullptr; WGPUTextureView depth_view_ = nullptr; std::unique_ptr passthrough_effect_; void create_framebuffers(int width, int height); };