1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
|
#pragma once
#include <algorithm>
#include <memory>
#include <vector>
#if defined(DEMO_CROSS_COMPILE_WIN32)
#include <webgpu/webgpu.h>
#else
#include <webgpu.h>
#endif /* defined(DEMO_CROSS_COMPILE_WIN32) */
class MainSequence;
class PostProcessEffect;
class Effect {
public:
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 end() {
}
bool is_initialized = false;
virtual bool is_post_process() const {
return false;
}
};
class PostProcessEffect : public Effect {
public:
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> 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> effect, float start_time,
float end_time, int priority = 0);
void update_active_list(float seq_time);
void collect_active_effects(std::vector<SequenceItem*>& scene_effects,
std::vector<SequenceItem*>& post_effects);
void reset();
private:
std::vector<SequenceItem> 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 add_sequence(std::shared_ptr<Sequence> seq, float start_time,
int priority = 0);
void render_frame(float global_time, float beat, float peak,
float aspect_ratio, WGPUSurface surface);
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<Sequence> seq;
float start_time;
int priority;
};
std::vector<ActiveSequence> sequences_;
WGPUTexture framebuffer_a_ = nullptr;
WGPUTextureView framebuffer_view_a_ = nullptr;
WGPUTexture framebuffer_b_ = nullptr;
WGPUTextureView framebuffer_view_b_ = nullptr;
public: // Made public for testing
void init_test(WGPUDevice device, WGPUQueue queue, WGPUTextureFormat format);
private: // Restore private access for other members
std::unique_ptr<PostProcessEffect> passthrough_effect_;
void create_framebuffers(int width, int height);
};
|