bevy 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/Cargo.lock +4279 -0
- data/Cargo.toml +36 -0
- data/README.md +226 -0
- data/crates/bevy/Cargo.toml +52 -0
- data/crates/bevy/src/app.rs +43 -0
- data/crates/bevy/src/component.rs +111 -0
- data/crates/bevy/src/entity.rs +30 -0
- data/crates/bevy/src/error.rs +32 -0
- data/crates/bevy/src/event.rs +190 -0
- data/crates/bevy/src/input_bridge.rs +300 -0
- data/crates/bevy/src/lib.rs +42 -0
- data/crates/bevy/src/mesh_renderer.rs +328 -0
- data/crates/bevy/src/query.rs +53 -0
- data/crates/bevy/src/render_app.rs +689 -0
- data/crates/bevy/src/resource.rs +28 -0
- data/crates/bevy/src/schedule.rs +186 -0
- data/crates/bevy/src/sprite_renderer.rs +355 -0
- data/crates/bevy/src/system.rs +44 -0
- data/crates/bevy/src/text_renderer.rs +258 -0
- data/crates/bevy/src/types/color.rs +114 -0
- data/crates/bevy/src/types/dynamic.rs +131 -0
- data/crates/bevy/src/types/math.rs +260 -0
- data/crates/bevy/src/types/mod.rs +9 -0
- data/crates/bevy/src/types/transform.rs +166 -0
- data/crates/bevy/src/world.rs +163 -0
- data/crates/bevy_ruby_render/Cargo.toml +22 -0
- data/crates/bevy_ruby_render/src/asset.rs +360 -0
- data/crates/bevy_ruby_render/src/audio.rs +511 -0
- data/crates/bevy_ruby_render/src/camera.rs +365 -0
- data/crates/bevy_ruby_render/src/gamepad.rs +398 -0
- data/crates/bevy_ruby_render/src/lib.rs +26 -0
- data/crates/bevy_ruby_render/src/material.rs +310 -0
- data/crates/bevy_ruby_render/src/mesh.rs +491 -0
- data/crates/bevy_ruby_render/src/sprite.rs +289 -0
- data/ext/bevy/Cargo.toml +20 -0
- data/ext/bevy/extconf.rb +6 -0
- data/ext/bevy/src/conversions.rs +137 -0
- data/ext/bevy/src/lib.rs +29 -0
- data/ext/bevy/src/ruby_app.rs +65 -0
- data/ext/bevy/src/ruby_color.rs +149 -0
- data/ext/bevy/src/ruby_component.rs +189 -0
- data/ext/bevy/src/ruby_entity.rs +33 -0
- data/ext/bevy/src/ruby_math.rs +384 -0
- data/ext/bevy/src/ruby_query.rs +64 -0
- data/ext/bevy/src/ruby_render_app.rs +779 -0
- data/ext/bevy/src/ruby_system.rs +122 -0
- data/ext/bevy/src/ruby_world.rs +107 -0
- data/lib/bevy/animation.rb +597 -0
- data/lib/bevy/app.rb +675 -0
- data/lib/bevy/asset.rb +613 -0
- data/lib/bevy/audio.rb +545 -0
- data/lib/bevy/audio_effects.rb +224 -0
- data/lib/bevy/camera.rb +412 -0
- data/lib/bevy/component.rb +91 -0
- data/lib/bevy/diagnostics.rb +227 -0
- data/lib/bevy/ecs_advanced.rb +296 -0
- data/lib/bevy/event.rb +199 -0
- data/lib/bevy/gizmos.rb +158 -0
- data/lib/bevy/gltf.rb +227 -0
- data/lib/bevy/hierarchy.rb +444 -0
- data/lib/bevy/input.rb +514 -0
- data/lib/bevy/lighting.rb +369 -0
- data/lib/bevy/material.rb +248 -0
- data/lib/bevy/mesh.rb +257 -0
- data/lib/bevy/navigation.rb +344 -0
- data/lib/bevy/networking.rb +335 -0
- data/lib/bevy/particle.rb +337 -0
- data/lib/bevy/physics.rb +396 -0
- data/lib/bevy/plugins/default_plugins.rb +34 -0
- data/lib/bevy/plugins/input_plugin.rb +49 -0
- data/lib/bevy/reflect.rb +361 -0
- data/lib/bevy/render_graph.rb +210 -0
- data/lib/bevy/resource.rb +185 -0
- data/lib/bevy/scene.rb +254 -0
- data/lib/bevy/shader.rb +319 -0
- data/lib/bevy/shape.rb +195 -0
- data/lib/bevy/skeletal.rb +248 -0
- data/lib/bevy/sprite.rb +152 -0
- data/lib/bevy/sprite_sheet.rb +444 -0
- data/lib/bevy/state.rb +277 -0
- data/lib/bevy/system.rb +206 -0
- data/lib/bevy/text.rb +99 -0
- data/lib/bevy/text_advanced.rb +455 -0
- data/lib/bevy/timer.rb +147 -0
- data/lib/bevy/transform.rb +158 -0
- data/lib/bevy/ui.rb +454 -0
- data/lib/bevy/ui_advanced.rb +568 -0
- data/lib/bevy/version.rb +5 -0
- data/lib/bevy/visibility.rb +250 -0
- data/lib/bevy/window.rb +302 -0
- data/lib/bevy.rb +390 -0
- metadata +150 -0
|
@@ -0,0 +1,511 @@
|
|
|
1
|
+
use std::collections::HashMap;
|
|
2
|
+
|
|
3
|
+
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
|
4
|
+
pub enum PlaybackMode {
|
|
5
|
+
Once,
|
|
6
|
+
Loop,
|
|
7
|
+
Despawn,
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
impl Default for PlaybackMode {
|
|
11
|
+
fn default() -> Self {
|
|
12
|
+
Self::Once
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
#[derive(Debug, Clone)]
|
|
17
|
+
pub struct AudioSettings {
|
|
18
|
+
pub volume: f32,
|
|
19
|
+
pub speed: f32,
|
|
20
|
+
pub paused: bool,
|
|
21
|
+
pub mode: PlaybackMode,
|
|
22
|
+
pub fade_in: Option<FadeSettings>,
|
|
23
|
+
pub fade_out: Option<FadeSettings>,
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
impl Default for AudioSettings {
|
|
27
|
+
fn default() -> Self {
|
|
28
|
+
Self {
|
|
29
|
+
volume: 1.0,
|
|
30
|
+
speed: 1.0,
|
|
31
|
+
paused: false,
|
|
32
|
+
mode: PlaybackMode::Once,
|
|
33
|
+
fade_in: None,
|
|
34
|
+
fade_out: None,
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
impl AudioSettings {
|
|
40
|
+
pub fn new() -> Self {
|
|
41
|
+
Self::default()
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
pub fn with_volume(mut self, volume: f32) -> Self {
|
|
45
|
+
self.volume = volume.clamp(0.0, 2.0);
|
|
46
|
+
self
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
pub fn with_speed(mut self, speed: f32) -> Self {
|
|
50
|
+
self.speed = speed.clamp(0.1, 10.0);
|
|
51
|
+
self
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
pub fn with_mode(mut self, mode: PlaybackMode) -> Self {
|
|
55
|
+
self.mode = mode;
|
|
56
|
+
self
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
pub fn looping(mut self) -> Self {
|
|
60
|
+
self.mode = PlaybackMode::Loop;
|
|
61
|
+
self
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
pub fn with_fade_in(mut self, duration_secs: f32) -> Self {
|
|
65
|
+
self.fade_in = Some(FadeSettings::new(duration_secs));
|
|
66
|
+
self
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
pub fn with_fade_out(mut self, duration_secs: f32) -> Self {
|
|
70
|
+
self.fade_out = Some(FadeSettings::new(duration_secs));
|
|
71
|
+
self
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
#[derive(Debug, Clone, Copy)]
|
|
76
|
+
pub struct FadeSettings {
|
|
77
|
+
pub duration_secs: f32,
|
|
78
|
+
pub elapsed: f32,
|
|
79
|
+
pub target_volume: f32,
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
impl FadeSettings {
|
|
83
|
+
pub fn new(duration_secs: f32) -> Self {
|
|
84
|
+
Self {
|
|
85
|
+
duration_secs,
|
|
86
|
+
elapsed: 0.0,
|
|
87
|
+
target_volume: 1.0,
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
pub fn with_target(mut self, target: f32) -> Self {
|
|
92
|
+
self.target_volume = target;
|
|
93
|
+
self
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
pub fn progress(&self) -> f32 {
|
|
97
|
+
if self.duration_secs <= 0.0 {
|
|
98
|
+
1.0
|
|
99
|
+
} else {
|
|
100
|
+
(self.elapsed / self.duration_secs).clamp(0.0, 1.0)
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
pub fn is_complete(&self) -> bool {
|
|
105
|
+
self.elapsed >= self.duration_secs
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
pub fn update(&mut self, delta_secs: f32) {
|
|
109
|
+
self.elapsed += delta_secs;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
#[derive(Debug, Clone)]
|
|
114
|
+
pub struct AudioTrack {
|
|
115
|
+
pub path: String,
|
|
116
|
+
pub settings: AudioSettings,
|
|
117
|
+
pub current_time: f32,
|
|
118
|
+
pub duration: Option<f32>,
|
|
119
|
+
current_fade: Option<Fade>,
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
#[derive(Debug, Clone, Copy)]
|
|
123
|
+
pub enum Fade {
|
|
124
|
+
In(FadeSettings),
|
|
125
|
+
Out(FadeSettings),
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
impl AudioTrack {
|
|
129
|
+
pub fn new(path: String) -> Self {
|
|
130
|
+
Self {
|
|
131
|
+
path,
|
|
132
|
+
settings: AudioSettings::default(),
|
|
133
|
+
current_time: 0.0,
|
|
134
|
+
duration: None,
|
|
135
|
+
current_fade: None,
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
pub fn with_settings(mut self, settings: AudioSettings) -> Self {
|
|
140
|
+
self.settings = settings;
|
|
141
|
+
self
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
pub fn start_fade_in(&mut self, duration_secs: f32) {
|
|
145
|
+
self.current_fade = Some(Fade::In(FadeSettings::new(duration_secs)));
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
pub fn start_fade_out(&mut self, duration_secs: f32) {
|
|
149
|
+
self.current_fade = Some(Fade::Out(
|
|
150
|
+
FadeSettings::new(duration_secs).with_target(0.0),
|
|
151
|
+
));
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
pub fn update(&mut self, delta_secs: f32) {
|
|
155
|
+
if let Some(fade) = &mut self.current_fade {
|
|
156
|
+
match fade {
|
|
157
|
+
Fade::In(settings) | Fade::Out(settings) => {
|
|
158
|
+
settings.update(delta_secs);
|
|
159
|
+
if settings.is_complete() {
|
|
160
|
+
self.current_fade = None;
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
pub fn effective_volume(&self) -> f32 {
|
|
168
|
+
let base_volume = self.settings.volume;
|
|
169
|
+
match &self.current_fade {
|
|
170
|
+
Some(Fade::In(settings)) => base_volume * settings.progress(),
|
|
171
|
+
Some(Fade::Out(settings)) => base_volume * (1.0 - settings.progress()),
|
|
172
|
+
None => base_volume,
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
pub fn is_fading(&self) -> bool {
|
|
177
|
+
self.current_fade.is_some()
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
#[derive(Debug, Clone)]
|
|
182
|
+
pub struct AudioChannel {
|
|
183
|
+
pub name: String,
|
|
184
|
+
pub volume: f32,
|
|
185
|
+
pub muted: bool,
|
|
186
|
+
pub tracks: Vec<u32>,
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
impl AudioChannel {
|
|
190
|
+
pub fn new(name: String) -> Self {
|
|
191
|
+
Self {
|
|
192
|
+
name,
|
|
193
|
+
volume: 1.0,
|
|
194
|
+
muted: false,
|
|
195
|
+
tracks: Vec::new(),
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
pub fn with_volume(mut self, volume: f32) -> Self {
|
|
200
|
+
self.volume = volume.clamp(0.0, 2.0);
|
|
201
|
+
self
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
pub fn mute(&mut self) {
|
|
205
|
+
self.muted = true;
|
|
206
|
+
}
|
|
207
|
+
|
|
208
|
+
pub fn unmute(&mut self) {
|
|
209
|
+
self.muted = false;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
pub fn effective_volume(&self) -> f32 {
|
|
213
|
+
if self.muted {
|
|
214
|
+
0.0
|
|
215
|
+
} else {
|
|
216
|
+
self.volume
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
#[derive(Debug, Clone, Default)]
|
|
222
|
+
pub struct AudioMixer {
|
|
223
|
+
pub master_volume: f32,
|
|
224
|
+
pub muted: bool,
|
|
225
|
+
channels: HashMap<String, AudioChannel>,
|
|
226
|
+
tracks: HashMap<u32, AudioTrack>,
|
|
227
|
+
next_track_id: u32,
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
impl AudioMixer {
|
|
231
|
+
pub fn new() -> Self {
|
|
232
|
+
let mut mixer = Self {
|
|
233
|
+
master_volume: 1.0,
|
|
234
|
+
muted: false,
|
|
235
|
+
channels: HashMap::new(),
|
|
236
|
+
tracks: HashMap::new(),
|
|
237
|
+
next_track_id: 0,
|
|
238
|
+
};
|
|
239
|
+
mixer.add_channel("music".to_string());
|
|
240
|
+
mixer.add_channel("sfx".to_string());
|
|
241
|
+
mixer.add_channel("voice".to_string());
|
|
242
|
+
mixer
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
pub fn add_channel(&mut self, name: String) -> &mut AudioChannel {
|
|
246
|
+
self.channels
|
|
247
|
+
.entry(name.clone())
|
|
248
|
+
.or_insert_with(|| AudioChannel::new(name))
|
|
249
|
+
}
|
|
250
|
+
|
|
251
|
+
pub fn get_channel(&self, name: &str) -> Option<&AudioChannel> {
|
|
252
|
+
self.channels.get(name)
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
pub fn get_channel_mut(&mut self, name: &str) -> Option<&mut AudioChannel> {
|
|
256
|
+
self.channels.get_mut(name)
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
pub fn set_channel_volume(&mut self, name: &str, volume: f32) {
|
|
260
|
+
if let Some(channel) = self.channels.get_mut(name) {
|
|
261
|
+
channel.volume = volume.clamp(0.0, 2.0);
|
|
262
|
+
}
|
|
263
|
+
}
|
|
264
|
+
|
|
265
|
+
pub fn mute_channel(&mut self, name: &str) {
|
|
266
|
+
if let Some(channel) = self.channels.get_mut(name) {
|
|
267
|
+
channel.mute();
|
|
268
|
+
}
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
pub fn unmute_channel(&mut self, name: &str) {
|
|
272
|
+
if let Some(channel) = self.channels.get_mut(name) {
|
|
273
|
+
channel.unmute();
|
|
274
|
+
}
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
pub fn play(&mut self, path: String, channel: &str) -> u32 {
|
|
278
|
+
self.play_with_settings(path, channel, AudioSettings::default())
|
|
279
|
+
}
|
|
280
|
+
|
|
281
|
+
pub fn play_with_settings(
|
|
282
|
+
&mut self,
|
|
283
|
+
path: String,
|
|
284
|
+
channel: &str,
|
|
285
|
+
settings: AudioSettings,
|
|
286
|
+
) -> u32 {
|
|
287
|
+
let track_id = self.next_track_id;
|
|
288
|
+
self.next_track_id += 1;
|
|
289
|
+
|
|
290
|
+
let track = AudioTrack::new(path).with_settings(settings);
|
|
291
|
+
self.tracks.insert(track_id, track);
|
|
292
|
+
|
|
293
|
+
if let Some(ch) = self.channels.get_mut(channel) {
|
|
294
|
+
ch.tracks.push(track_id);
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
track_id
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
pub fn stop(&mut self, track_id: u32) {
|
|
301
|
+
self.tracks.remove(&track_id);
|
|
302
|
+
for channel in self.channels.values_mut() {
|
|
303
|
+
channel.tracks.retain(|&id| id != track_id);
|
|
304
|
+
}
|
|
305
|
+
}
|
|
306
|
+
|
|
307
|
+
pub fn stop_with_fade(&mut self, track_id: u32, fade_duration: f32) {
|
|
308
|
+
if let Some(track) = self.tracks.get_mut(&track_id) {
|
|
309
|
+
track.start_fade_out(fade_duration);
|
|
310
|
+
}
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
pub fn pause(&mut self, track_id: u32) {
|
|
314
|
+
if let Some(track) = self.tracks.get_mut(&track_id) {
|
|
315
|
+
track.settings.paused = true;
|
|
316
|
+
}
|
|
317
|
+
}
|
|
318
|
+
|
|
319
|
+
pub fn resume(&mut self, track_id: u32) {
|
|
320
|
+
if let Some(track) = self.tracks.get_mut(&track_id) {
|
|
321
|
+
track.settings.paused = false;
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
|
|
325
|
+
pub fn get_track(&self, track_id: u32) -> Option<&AudioTrack> {
|
|
326
|
+
self.tracks.get(&track_id)
|
|
327
|
+
}
|
|
328
|
+
|
|
329
|
+
pub fn get_track_mut(&mut self, track_id: u32) -> Option<&mut AudioTrack> {
|
|
330
|
+
self.tracks.get_mut(&track_id)
|
|
331
|
+
}
|
|
332
|
+
|
|
333
|
+
pub fn update(&mut self, delta_secs: f32) {
|
|
334
|
+
let mut completed = Vec::new();
|
|
335
|
+
for (&id, track) in self.tracks.iter_mut() {
|
|
336
|
+
track.update(delta_secs);
|
|
337
|
+
if let Some(Fade::Out(settings)) = &track.current_fade {
|
|
338
|
+
if settings.is_complete() {
|
|
339
|
+
completed.push(id);
|
|
340
|
+
}
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
for id in completed {
|
|
344
|
+
self.stop(id);
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
pub fn effective_volume(&self, track_id: u32, channel_name: &str) -> f32 {
|
|
349
|
+
if self.muted {
|
|
350
|
+
return 0.0;
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
let channel_volume = self
|
|
354
|
+
.channels
|
|
355
|
+
.get(channel_name)
|
|
356
|
+
.map_or(1.0, |c| c.effective_volume());
|
|
357
|
+
let track_volume = self
|
|
358
|
+
.tracks
|
|
359
|
+
.get(&track_id)
|
|
360
|
+
.map_or(1.0, |t| t.effective_volume());
|
|
361
|
+
|
|
362
|
+
self.master_volume * channel_volume * track_volume
|
|
363
|
+
}
|
|
364
|
+
}
|
|
365
|
+
|
|
366
|
+
#[derive(Debug, Clone)]
|
|
367
|
+
pub struct AudioQueue {
|
|
368
|
+
pub tracks: Vec<String>,
|
|
369
|
+
pub current_index: usize,
|
|
370
|
+
pub loop_queue: bool,
|
|
371
|
+
pub shuffle: bool,
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
impl Default for AudioQueue {
|
|
375
|
+
fn default() -> Self {
|
|
376
|
+
Self {
|
|
377
|
+
tracks: Vec::new(),
|
|
378
|
+
current_index: 0,
|
|
379
|
+
loop_queue: false,
|
|
380
|
+
shuffle: false,
|
|
381
|
+
}
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
impl AudioQueue {
|
|
386
|
+
pub fn new() -> Self {
|
|
387
|
+
Self::default()
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
pub fn add(&mut self, path: String) {
|
|
391
|
+
self.tracks.push(path);
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
pub fn add_all(&mut self, paths: Vec<String>) {
|
|
395
|
+
self.tracks.extend(paths);
|
|
396
|
+
}
|
|
397
|
+
|
|
398
|
+
pub fn current(&self) -> Option<&String> {
|
|
399
|
+
self.tracks.get(self.current_index)
|
|
400
|
+
}
|
|
401
|
+
|
|
402
|
+
pub fn next(&mut self) -> Option<&String> {
|
|
403
|
+
if self.tracks.is_empty() {
|
|
404
|
+
return None;
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
self.current_index += 1;
|
|
408
|
+
if self.current_index >= self.tracks.len() {
|
|
409
|
+
if self.loop_queue {
|
|
410
|
+
self.current_index = 0;
|
|
411
|
+
} else {
|
|
412
|
+
return None;
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
self.current()
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
pub fn previous(&mut self) -> Option<&String> {
|
|
419
|
+
if self.tracks.is_empty() {
|
|
420
|
+
return None;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
if self.current_index == 0 {
|
|
424
|
+
if self.loop_queue {
|
|
425
|
+
self.current_index = self.tracks.len() - 1;
|
|
426
|
+
} else {
|
|
427
|
+
return None;
|
|
428
|
+
}
|
|
429
|
+
} else {
|
|
430
|
+
self.current_index -= 1;
|
|
431
|
+
}
|
|
432
|
+
self.current()
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
pub fn clear(&mut self) {
|
|
436
|
+
self.tracks.clear();
|
|
437
|
+
self.current_index = 0;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
pub fn len(&self) -> usize {
|
|
441
|
+
self.tracks.len()
|
|
442
|
+
}
|
|
443
|
+
|
|
444
|
+
pub fn is_empty(&self) -> bool {
|
|
445
|
+
self.tracks.is_empty()
|
|
446
|
+
}
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
#[derive(Debug, Clone, Copy)]
|
|
450
|
+
pub struct SpatialAudio {
|
|
451
|
+
pub max_distance: f32,
|
|
452
|
+
pub reference_distance: f32,
|
|
453
|
+
pub rolloff_factor: f32,
|
|
454
|
+
pub cone_inner_angle: f32,
|
|
455
|
+
pub cone_outer_angle: f32,
|
|
456
|
+
pub cone_outer_gain: f32,
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
impl Default for SpatialAudio {
|
|
460
|
+
fn default() -> Self {
|
|
461
|
+
Self {
|
|
462
|
+
max_distance: 100.0,
|
|
463
|
+
reference_distance: 1.0,
|
|
464
|
+
rolloff_factor: 1.0,
|
|
465
|
+
cone_inner_angle: 360.0,
|
|
466
|
+
cone_outer_angle: 360.0,
|
|
467
|
+
cone_outer_gain: 0.0,
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
}
|
|
471
|
+
|
|
472
|
+
impl SpatialAudio {
|
|
473
|
+
pub fn new() -> Self {
|
|
474
|
+
Self::default()
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
pub fn with_max_distance(mut self, distance: f32) -> Self {
|
|
478
|
+
self.max_distance = distance.max(0.0);
|
|
479
|
+
self
|
|
480
|
+
}
|
|
481
|
+
|
|
482
|
+
pub fn with_reference_distance(mut self, distance: f32) -> Self {
|
|
483
|
+
self.reference_distance = distance.max(0.0);
|
|
484
|
+
self
|
|
485
|
+
}
|
|
486
|
+
|
|
487
|
+
pub fn with_rolloff(mut self, factor: f32) -> Self {
|
|
488
|
+
self.rolloff_factor = factor.max(0.0);
|
|
489
|
+
self
|
|
490
|
+
}
|
|
491
|
+
|
|
492
|
+
pub fn with_cone(mut self, inner: f32, outer: f32, outer_gain: f32) -> Self {
|
|
493
|
+
self.cone_inner_angle = inner.clamp(0.0, 360.0);
|
|
494
|
+
self.cone_outer_angle = outer.clamp(0.0, 360.0);
|
|
495
|
+
self.cone_outer_gain = outer_gain.clamp(0.0, 1.0);
|
|
496
|
+
self
|
|
497
|
+
}
|
|
498
|
+
|
|
499
|
+
pub fn calculate_attenuation(&self, distance: f32) -> f32 {
|
|
500
|
+
if distance <= self.reference_distance {
|
|
501
|
+
1.0
|
|
502
|
+
} else if distance >= self.max_distance {
|
|
503
|
+
0.0
|
|
504
|
+
} else {
|
|
505
|
+
let d = distance.clamp(self.reference_distance, self.max_distance);
|
|
506
|
+
self.reference_distance
|
|
507
|
+
/ (self.reference_distance
|
|
508
|
+
+ self.rolloff_factor * (d - self.reference_distance))
|
|
509
|
+
}
|
|
510
|
+
}
|
|
511
|
+
}
|