Skip to main content

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