fyrox_impl/scene/
mod.rs

1// Copyright (c) 2019-present Dmitry Stepanov and Fyrox Engine contributors.
2//
3// Permission is hereby granted, free of charge, to any person obtaining a copy
4// of this software and associated documentation files (the "Software"), to deal
5// in the Software without restriction, including without limitation the rights
6// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
7// copies of the Software, and to permit persons to whom the Software is
8// furnished to do so, subject to the following conditions:
9//
10// The above copyright notice and this permission notice shall be included in all
11// copies or substantial portions of the Software.
12//
13// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19// SOFTWARE.
20
21#![warn(missing_docs)]
22
23//! Contains all structures and methods to create and manage 3D scenes.
24//!
25//! A `Scene` is a container for graph nodes, animations and physics.
26
27pub mod accel;
28pub mod animation;
29pub mod base;
30pub mod camera;
31pub mod collider;
32pub mod debug;
33pub mod decal;
34pub mod dim2;
35pub mod graph;
36pub mod joint;
37pub mod light;
38pub mod mesh;
39pub mod navmesh;
40pub mod node;
41pub mod particle_system;
42pub mod pivot;
43pub mod probe;
44pub mod ragdoll;
45pub mod rigidbody;
46pub mod skybox;
47pub mod sound;
48pub mod sprite;
49pub mod terrain;
50pub mod tilemap;
51pub mod transform;
52
53use crate::{
54    asset::{
55        self, io::ResourceIo, manager::ResourceManager, registry::ResourceRegistryStatus,
56        untyped::UntypedResource,
57    },
58    core::{
59        algebra::Vector2,
60        color::Color,
61        futures::future::join_all,
62        log::{Log, MessageKind},
63        pool::{Handle, Pool, Ticket},
64        reflect::prelude::*,
65        type_traits::prelude::*,
66        variable::InheritableVariable,
67        visitor::{error::VisitError, Visit, VisitResult, Visitor},
68        SafeLock,
69    },
70    engine::SerializationContext,
71    graph::NodeHandleMap,
72    graphics::PolygonFillMode,
73    resource::texture::TextureResource,
74    scene::{
75        base::BaseBuilder,
76        debug::SceneDrawingContext,
77        graph::{Graph, GraphPerformanceStatistics, GraphUpdateSwitches},
78        navmesh::NavigationalMeshBuilder,
79        node::Node,
80        skybox::{SkyBox, SkyBoxKind},
81        sound::SoundEngine,
82    },
83    utils::navmesh::Navmesh,
84};
85use fxhash::FxHashSet;
86use std::{
87    fmt::{Display, Formatter},
88    ops::{Index, IndexMut},
89    path::Path,
90    path::PathBuf,
91    sync::Arc,
92};
93use strum_macros::{AsRefStr, EnumString, VariantNames};
94
95/// A container for navigational meshes.
96#[derive(Default, Clone, Debug, Visit)]
97pub struct NavMeshContainer {
98    pool: Pool<Navmesh>,
99}
100
101impl NavMeshContainer {
102    /// Adds new navigational mesh to the container and returns its handle.
103    pub fn add(&mut self, navmesh: Navmesh) -> Handle<Navmesh> {
104        self.pool.spawn(navmesh)
105    }
106
107    /// Removes navigational mesh by its handle.
108    pub fn remove(&mut self, handle: Handle<Navmesh>) -> Navmesh {
109        self.pool.free(handle)
110    }
111
112    /// Creates new immutable iterator.
113    pub fn iter(&self) -> impl Iterator<Item = &Navmesh> {
114        self.pool.iter()
115    }
116
117    /// Creates new immutable iterator.
118    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Navmesh> {
119        self.pool.iter_mut()
120    }
121
122    /// Creates a handle to navmesh from its index.
123    pub fn handle_from_index(&self, i: u32) -> Handle<Navmesh> {
124        self.pool.handle_from_index(i)
125    }
126
127    /// Destroys all navmeshes. All handles will become invalid.
128    pub fn clear(&mut self) {
129        self.pool.clear()
130    }
131
132    /// Checks if given handle is valid.
133    pub fn is_valid_handle(&self, handle: Handle<Navmesh>) -> bool {
134        self.pool.is_valid_handle(handle)
135    }
136
137    /// Tries to borrow a navmesh by its index.
138    pub fn at(&self, i: u32) -> Option<&Navmesh> {
139        self.pool.at(i)
140    }
141
142    /// Tries to borrow a navmesh by its handle.
143    pub fn try_get(&self, handle: Handle<Navmesh>) -> Option<&Navmesh> {
144        self.pool.try_borrow(handle)
145    }
146
147    /// Tries to borrow a navmesh by its index.
148    pub fn at_mut(&mut self, i: u32) -> Option<&mut Navmesh> {
149        self.pool.at_mut(i)
150    }
151
152    /// Tries to borrow a navmesh by its handle.
153    pub fn try_get_mut(&mut self, handle: Handle<Navmesh>) -> Option<&mut Navmesh> {
154        self.pool.try_borrow_mut(handle)
155    }
156}
157
158impl Index<Handle<Navmesh>> for NavMeshContainer {
159    type Output = Navmesh;
160
161    fn index(&self, index: Handle<Navmesh>) -> &Self::Output {
162        &self.pool[index]
163    }
164}
165
166impl IndexMut<Handle<Navmesh>> for NavMeshContainer {
167    fn index_mut(&mut self, index: Handle<Navmesh>) -> &mut Self::Output {
168        &mut self.pool[index]
169    }
170}
171
172/// A set of options, that allows selecting the source of environment lighting for a scene. By
173/// default, it is set to [`EnvironmentLightingSource::SkyBox`].
174#[derive(
175    Reflect,
176    Visit,
177    Debug,
178    Default,
179    Clone,
180    Copy,
181    PartialEq,
182    AsRefStr,
183    EnumString,
184    VariantNames,
185    TypeUuidProvider,
186)]
187#[type_uuid(id = "28f22fe7-22ed-47e1-ae43-779866a46cdf")]
188pub enum EnvironmentLightingSource {
189    /// Sky box of a scene will be the source of lighting.
190    #[default]
191    SkyBox,
192    /// Ambient color of the scene will be the source of lighting.
193    AmbientColor,
194}
195
196/// Rendering options of a scene. It allows you to specify a render target to render the scene to, change its clear color, etc.
197#[derive(Debug, Visit, Reflect, PartialEq)]
198pub struct SceneRenderingOptions {
199    /// A texture to draw the scene to. If empty, then the scene will be drawn on screen directly. It is useful to "embed" some scene into other
200    /// by drawing a quad with this texture. This can be used to make in-game video conference - you can make separate scene with
201    /// your characters and draw scene into a texture, then in the main scene you can attach this texture to some quad which will be used
202    /// as a monitor. Other usage could be a previewer of models, like a pictogram of character in real-time strategies, in other words
203    /// there are plenty of possible uses.
204    pub render_target: Option<TextureResource>,
205
206    /// Default color of the render target. Default is [`None`], which forces the renderer to use clear color of the back buffer.
207    /// Could be set to transparent to make background transparent.
208    pub clear_color: Option<Color>,
209
210    /// Defines how polygons of the scene will be rasterized. By default it set to [`PolygonFillMode::Fill`],
211    /// [`PolygonFillMode::Line`] could be used to render the scene in wireframe mode.
212    pub polygon_rasterization_mode: PolygonFillMode,
213
214    /// Color of the ambient lighting. This color is only used if `environment_lighting_source`
215    /// is set to [`EnvironmentLightingSource::AmbientColor`].
216    pub ambient_lighting_color: Color,
217
218    /// A switch, that allows selecting the source of environment lighting. By default, it is set to
219    /// [`EnvironmentLightingSource::SkyBox`].
220    pub environment_lighting_source: EnvironmentLightingSource,
221}
222
223impl Default for SceneRenderingOptions {
224    fn default() -> Self {
225        Self {
226            render_target: None,
227            clear_color: None,
228            polygon_rasterization_mode: Default::default(),
229            ambient_lighting_color: Color::opaque(100, 100, 100),
230            environment_lighting_source: Default::default(),
231        }
232    }
233}
234
235impl Clone for SceneRenderingOptions {
236    fn clone(&self) -> Self {
237        Self {
238            render_target: None, // Intentionally not copied!
239            clear_color: self.clear_color,
240            polygon_rasterization_mode: self.polygon_rasterization_mode,
241            ambient_lighting_color: self.ambient_lighting_color,
242            environment_lighting_source: self.environment_lighting_source,
243        }
244    }
245}
246
247/// See module docs.
248#[derive(Debug, Reflect)]
249pub struct Scene {
250    /// Graph is main container for all scene nodes. It calculates global transforms for nodes,
251    /// updates them and performs all other important work. See `graph` module docs for more
252    /// info.
253    pub graph: Graph,
254
255    /// Rendering options of a scene. See [`SceneRenderingOptions`] docs for more info.
256    pub rendering_options: InheritableVariable<SceneRenderingOptions>,
257
258    /// Drawing context for simple graphics.
259    #[reflect(hidden)]
260    pub drawing_context: SceneDrawingContext,
261
262    /// Performance statistics from last `update` call.
263    #[reflect(hidden)]
264    pub performance_statistics: PerformanceStatistics,
265
266    #[reflect(setter = "set_skybox")]
267    sky_box: InheritableVariable<Option<SkyBox>>,
268
269    /// Whether the scene will be updated and rendered or not. Default is true.
270    /// This flag allowing you to build a scene manager for your game. For example,
271    /// you may have a scene for menu and one per level. Menu's scene is persistent,
272    /// however you don't want it to be updated and renderer while you have a level
273    /// loaded and playing a game. When you're start playing, just set `enabled` flag
274    /// to false for menu's scene and when you need to open a menu - set it to true and
275    /// set `enabled` flag to false for level's scene.
276    pub enabled: InheritableVariable<bool>,
277}
278
279impl Clone for Scene {
280    fn clone(&self) -> Self {
281        self.clone_one_to_one().0
282    }
283}
284
285impl Default for Scene {
286    fn default() -> Self {
287        Self {
288            graph: Default::default(),
289            rendering_options: Default::default(),
290            drawing_context: Default::default(),
291            performance_statistics: Default::default(),
292            enabled: true.into(),
293            sky_box: Some(SkyBoxKind::built_in_skybox().clone()).into(),
294        }
295    }
296}
297
298/// A structure that holds times that specific update step took.
299#[derive(Clone, Default, Debug)]
300pub struct PerformanceStatistics {
301    /// Graph performance statistics.
302    pub graph: GraphPerformanceStatistics,
303}
304
305impl Display for PerformanceStatistics {
306    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
307        write!(
308            f,
309            "Graph: {:?}\n\
310            \tSync Time: {:?}\n\
311            \tSound: {:?}\n\
312            \tPhysics: {:?}\n\
313            \t\tSimulation: {:?}\n\
314            \t\tRay cast: {:?}\n\
315            \tPhysics 2D: {:?}\n\
316            \t\tSimulation: {:?}\n\
317            \t\tRay cast: {:?}\n\
318            \tHierarchy: {:?}",
319            self.graph.total(),
320            self.graph.sync_time,
321            self.graph.sound_update_time,
322            self.graph.physics.total(),
323            self.graph.physics.step_time,
324            self.graph.physics.total_ray_cast_time.get(),
325            self.graph.physics2d.total(),
326            self.graph.physics2d.step_time,
327            self.graph.physics2d.total_ray_cast_time.get(),
328            self.graph.hierarchical_properties_time,
329        )
330    }
331}
332
333/// Scene loader.
334pub struct SceneLoader {
335    scene: Scene,
336    path: Option<PathBuf>,
337    resource_manager: ResourceManager,
338}
339
340impl SceneLoader {
341    /// Tries to load scene from given file. File can contain any scene in native engine format.
342    /// Such scenes can be made in rusty editor.
343    pub async fn from_file<P: AsRef<Path>>(
344        path: P,
345        io: &dyn ResourceIo,
346        serialization_context: Arc<SerializationContext>,
347        resource_manager: ResourceManager,
348    ) -> Result<(Self, Vec<u8>), VisitError> {
349        let registry_status = resource_manager
350            .state()
351            .resource_registry
352            .safe_lock()
353            .status_flag();
354        // Wait until the registry is fully loaded.
355        let registry_status = registry_status.await;
356        if registry_status == ResourceRegistryStatus::Unknown {
357            return Err(VisitError::User(format!(
358                "Unable to load a scene from {} path, because the \
359            resource registry isn't loaded!",
360                path.as_ref().display()
361            )));
362        }
363
364        let data = io.load_file(path.as_ref()).await?;
365        let mut visitor = Visitor::load_from_memory(&data)?;
366        let loader = Self::load(
367            "Scene",
368            serialization_context,
369            resource_manager,
370            &mut visitor,
371            Some(path.as_ref().to_path_buf()),
372        )?;
373        Ok((loader, data))
374    }
375
376    /// Tries to load a scene using specified visitor and region name.
377    pub fn load(
378        region_name: &str,
379        serialization_context: Arc<SerializationContext>,
380        resource_manager: ResourceManager,
381        visitor: &mut Visitor,
382        path: Option<PathBuf>,
383    ) -> Result<Self, VisitError> {
384        if !visitor.is_reading() {
385            return Err(VisitError::User(
386                "Visitor must be in read mode!".to_string(),
387            ));
388        }
389
390        visitor.blackboard.register(serialization_context);
391        visitor
392            .blackboard
393            .register(Arc::new(resource_manager.clone()));
394
395        let mut scene = Scene::default();
396        scene.visit(region_name, visitor)?;
397
398        Ok(Self {
399            scene,
400            path,
401            resource_manager,
402        })
403    }
404
405    /// Finishes scene loading.
406    pub async fn finish(self) -> Scene {
407        let mut scene = self.scene;
408
409        Log::info("SceneLoader::finish() - Collecting resources used by the scene...");
410
411        let mut used_resources = scene.collect_used_resources();
412
413        // Do not wait for self resources.
414        if let Some(path) = self.path {
415            let exclusion_list = used_resources
416                .iter()
417                .filter(|res| {
418                    let uuid = res.resource_uuid();
419                    let state = self.resource_manager.state();
420                    let registry = state.resource_registry.safe_lock();
421                    registry.uuid_to_path(uuid) == Some(&path)
422                })
423                .cloned()
424                .collect::<Vec<_>>();
425
426            for excluded_resource in exclusion_list {
427                assert!(used_resources.remove(&excluded_resource));
428            }
429        }
430
431        let used_resources_count = used_resources.len();
432
433        Log::info(format!(
434            "SceneLoader::finish() - {used_resources_count} resources collected. Waiting them to load..."
435        ));
436
437        // Wait everything.
438        let results = join_all(used_resources.into_iter()).await;
439
440        for result in results {
441            if let Err(err) = result {
442                Log::err(format!("Scene resource loading error: {:?}", err));
443            }
444        }
445
446        Log::info(format!(
447            "SceneLoader::finish() - All {used_resources_count} resources have finished loading."
448        ));
449
450        // We have to wait until skybox textures are all loaded, because we need to read their data
451        // to re-create cube map.
452        let mut skybox_textures = Vec::new();
453        if let Some(skybox) = scene.skybox_ref() {
454            skybox_textures.extend(skybox.textures().iter().filter_map(|t| t.clone()));
455        }
456        join_all(skybox_textures).await;
457
458        // And do resolve to extract correct graphical data and so on.
459        scene.resolve();
460
461        scene
462    }
463}
464
465impl Scene {
466    /// Creates new scene with single root node.
467    ///
468    /// # Notes
469    ///
470    /// This method differs from Default trait implementation! Scene::default() creates
471    /// empty graph with no nodes.
472    #[inline]
473    pub fn new() -> Self {
474        Self {
475            // Graph must be created with `new` method because it differs from `default`
476            graph: Graph::new(),
477            rendering_options: Default::default(),
478            drawing_context: Default::default(),
479            performance_statistics: Default::default(),
480            enabled: true.into(),
481            sky_box: Some(SkyBoxKind::built_in_skybox().clone()).into(),
482        }
483    }
484
485    /// Sets new skybox. Could be None if no skybox needed.
486    pub fn set_skybox(&mut self, skybox: Option<SkyBox>) -> Option<SkyBox> {
487        self.sky_box.set_value_and_mark_modified(skybox)
488    }
489
490    /// Return optional mutable reference to current skybox.
491    pub fn skybox_mut(&mut self) -> Option<&mut SkyBox> {
492        self.sky_box.get_value_mut_and_mark_modified().as_mut()
493    }
494
495    /// Return optional shared reference to current skybox.
496    pub fn skybox_ref(&self) -> Option<&SkyBox> {
497        self.sky_box.as_ref()
498    }
499
500    /// Replaces the skybox.
501    pub fn replace_skybox(&mut self, new: Option<SkyBox>) -> Option<SkyBox> {
502        std::mem::replace(self.sky_box.get_value_mut_and_mark_modified(), new)
503    }
504
505    /// Synchronizes the state of the scene with external resources.
506    pub fn resolve(&mut self) {
507        Log::writeln(MessageKind::Information, "Starting resolve...");
508
509        // Update cube maps for sky boxes.
510        if let Some(skybox) = self.skybox_mut() {
511            Log::verify(skybox.create_cubemap());
512        }
513
514        self.graph.resolve();
515
516        Log::writeln(MessageKind::Information, "Resolve succeeded!");
517    }
518
519    /// Collects all resources used by the scene. It uses reflection to "scan" the contents of the scene, so
520    /// if some fields marked with `#[reflect(hidden)]` attribute, then such field will be ignored!
521    pub fn collect_used_resources(&self) -> FxHashSet<UntypedResource> {
522        let mut collection = FxHashSet::default();
523        asset::collect_used_resources(self, &mut collection);
524        collection
525    }
526
527    /// Performs single update tick with given delta time from last frame. Internally
528    /// it updates physics, animations, and each graph node. In most cases there is
529    /// no need to call it directly, engine automatically updates all available scenes.
530    pub fn update(&mut self, frame_size: Vector2<f32>, dt: f32, switches: GraphUpdateSwitches) {
531        self.graph.update(frame_size, dt, switches);
532        self.performance_statistics.graph = self.graph.performance_statistics.clone();
533    }
534
535    /// Creates deep copy of a scene, filter predicate allows you to filter out nodes
536    /// by your criteria.
537    pub fn clone_ex<F, Pre, Post>(
538        &self,
539        root: Handle<Node>,
540        filter: &mut F,
541        pre_process_callback: &mut Pre,
542        post_process_callback: &mut Post,
543    ) -> (Self, NodeHandleMap<Node>)
544    where
545        F: FnMut(Handle<Node>, &Node) -> bool,
546        Pre: FnMut(Handle<Node>, &mut Node),
547        Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
548    {
549        let (graph, old_new_map) =
550            self.graph
551                .clone_ex(root, filter, pre_process_callback, post_process_callback);
552
553        (
554            Self {
555                graph,
556                rendering_options: self.rendering_options.clone(),
557                drawing_context: self.drawing_context.clone(),
558                performance_statistics: Default::default(),
559                enabled: self.enabled.clone(),
560                sky_box: self.sky_box.clone(),
561            },
562            old_new_map,
563        )
564    }
565
566    /// Creates deep copy of a scene. Same as [`Self::clone`], but does 1:1 cloning.
567    pub fn clone_one_to_one(&self) -> (Self, NodeHandleMap<Node>) {
568        self.clone_ex(
569            self.graph.get_root(),
570            &mut |_, _| true,
571            &mut |_, _| {},
572            &mut |_, _, _| {},
573        )
574    }
575
576    fn visit(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
577        let mut region = visitor.enter_region(region_name)?;
578
579        self.graph.visit("Graph", &mut region)?;
580        self.enabled.visit("Enabled", &mut region)?;
581        let _ = self
582            .rendering_options
583            .visit("RenderingOptions", &mut region);
584        let _ = self.sky_box.visit("SkyBox", &mut region);
585
586        // Backward compatibility.
587        if region.is_reading() {
588            let mut navmeshes = NavMeshContainer::default();
589            if navmeshes.visit("NavMeshes", &mut region).is_ok() {
590                for (i, navmesh) in navmeshes.iter().enumerate() {
591                    NavigationalMeshBuilder::new(
592                        BaseBuilder::new().with_name(format!("Navmesh{i}")),
593                    )
594                    .with_navmesh(navmesh.clone())
595                    .build(&mut self.graph);
596                }
597            }
598        }
599
600        Ok(())
601    }
602
603    /// Tries to serialize the scene using the specified serializer. The serializer must be in write mode, otherwise
604    /// serialization will fail. The `region_name` argument must be `Scene` (scene loader expects this value, you can
605    /// use any other if you don't plan to load scenes using the standard mechanism).. Keep in mind, that this method
606    /// does **not** write anything to a file, instead it just fills in the serializer.
607    ///
608    /// ## Example
609    ///
610    /// ```rust,no_run
611    /// # use fyrox_impl::{
612    /// #     core::visitor::Visitor,
613    /// #     scene::{
614    /// #         base::BaseBuilder,
615    /// #         mesh::{
616    /// #             surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
617    /// #             MeshBuilder,
618    /// #         },
619    /// #         Scene,
620    /// #     },
621    /// # };
622    /// use fyrox_resource::untyped::ResourceKind;
623    /// #
624    /// // Create a scene.
625    /// let mut scene = Scene::new();
626    ///
627    /// MeshBuilder::new(BaseBuilder::new())
628    ///     .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_embedded(SurfaceData::make_cube(Default::default()),
629    ///     ))
630    ///     .build()])
631    ///     .build(&mut scene.graph);
632    ///
633    /// // Serialize the content.
634    /// let mut visitor = Visitor::new();
635    /// scene.save("Scene", &mut visitor).unwrap();
636    ///
637    /// // Write the data to a file.
638    /// visitor.save_binary_to_file("path/to/a/scene.rgs").unwrap();
639    /// ```
640    pub fn save(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
641        if visitor.is_reading() {
642            return Err(VisitError::User(
643                "Visitor must be in write mode!".to_string(),
644            ));
645        }
646
647        self.visit(region_name, visitor)
648    }
649}
650
651/// Container for scenes in the engine.
652pub struct SceneContainer {
653    pool: Pool<Scene>,
654    sound_engine: SoundEngine,
655    pub(crate) destruction_list: Vec<(Handle<Scene>, Scene)>,
656}
657
658impl SceneContainer {
659    pub(crate) fn new(sound_engine: SoundEngine) -> Self {
660        Self {
661            pool: Pool::new(),
662            sound_engine,
663            destruction_list: Default::default(),
664        }
665    }
666
667    /// Return true if given handle is valid and "points" to "alive" scene.
668    pub fn is_valid_handle(&self, handle: Handle<Scene>) -> bool {
669        self.pool.is_valid_handle(handle)
670    }
671
672    /// Returns pair iterator which yields (handle, scene_ref) pairs.
673    pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<Scene>, &Scene)> {
674        self.pool.pair_iter()
675    }
676
677    /// Returns pair iterator which yields (handle, scene_ref) pairs.
678    pub fn pair_iter_mut(&mut self) -> impl Iterator<Item = (Handle<Scene>, &mut Scene)> {
679        self.pool.pair_iter_mut()
680    }
681
682    /// Tries to borrow a scene using its handle.
683    pub fn try_get(&self, handle: Handle<Scene>) -> Option<&Scene> {
684        self.pool.try_borrow(handle)
685    }
686
687    /// Tries to borrow a scene using its handle.
688    pub fn try_get_mut(&mut self, handle: Handle<Scene>) -> Option<&mut Scene> {
689        self.pool.try_borrow_mut(handle)
690    }
691
692    /// Creates new iterator over scenes in container.
693    #[inline]
694    pub fn iter(&self) -> impl Iterator<Item = &Scene> {
695        self.pool.iter()
696    }
697
698    /// Creates new mutable iterator over scenes in container.
699    #[inline]
700    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Scene> {
701        self.pool.iter_mut()
702    }
703
704    /// Adds new scene into container.
705    #[inline]
706    pub fn add(&mut self, scene: Scene) -> Handle<Scene> {
707        self.sound_engine
708            .state()
709            .add_context(scene.graph.sound_context.native.clone());
710        self.pool.spawn(scene)
711    }
712
713    /// Removes all scenes from container.
714    #[inline]
715    pub fn clear(&mut self) {
716        self.pool.clear()
717    }
718
719    /// Removes given scene from container. The scene will be destroyed on a next update call.
720    #[inline]
721    pub fn remove(&mut self, handle: Handle<Scene>) {
722        self.sound_engine
723            .state()
724            .remove_context(self.pool[handle].graph.sound_context.native.clone());
725        self.destruction_list.push((handle, self.pool.free(handle)));
726    }
727
728    /// Takes scene from the container and transfers ownership to caller. You must either
729    /// put scene back using ticket or call `forget_ticket` to make memory used by scene
730    /// vacant again.
731    pub fn take_reserve(&mut self, handle: Handle<Scene>) -> (Ticket<Scene>, Scene) {
732        self.pool.take_reserve(handle)
733    }
734
735    /// Puts scene back using its ticket.
736    pub fn put_back(&mut self, ticket: Ticket<Scene>, scene: Scene) -> Handle<Scene> {
737        self.pool.put_back(ticket, scene)
738    }
739
740    /// Forgets ticket of a scene, making place at which ticket points, vacant again.
741    pub fn forget_ticket(&mut self, ticket: Ticket<Scene>) {
742        self.pool.forget_ticket(ticket)
743    }
744}
745
746impl Index<Handle<Scene>> for SceneContainer {
747    type Output = Scene;
748
749    #[inline]
750    fn index(&self, index: Handle<Scene>) -> &Self::Output {
751        &self.pool[index]
752    }
753}
754
755impl IndexMut<Handle<Scene>> for SceneContainer {
756    #[inline]
757    fn index_mut(&mut self, index: Handle<Scene>) -> &mut Self::Output {
758        &mut self.pool[index]
759    }
760}