#pragma once #include "gpu/gpu.h" #include #include #include #if defined(DEMO_CROSS_COMPILE_WIN32) #include #else #include #endif /* defined(DEMO_CROSS_COMPILE_WIN32) */ 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) {} virtual void end() { } bool is_initialized = false; virtual bool is_post_process() const { return false; } protected: WGPUDevice device_; WGPUQueue queue_; GpuBuffer uniforms_; }; 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(); private: std::vector items_; bool is_sorted_ = false; 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; }; std::vector sequences_; 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); };