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        if !resource_manager.registry_is_loaded() {
355            return Err(VisitError::User(format!(
356                "Unable to load a scene from {} path, because the \
357            resource registry isn't loaded!",
358                path.as_ref().display()
359            )));
360        }
361
362        let data = io.load_file(path.as_ref()).await?;
363        let mut visitor = Visitor::load_from_memory(&data)?;
364        let loader = Self::load(
365            "Scene",
366            serialization_context,
367            dyn_type_constructors,
368            resource_manager,
369            &mut visitor,
370            Some(path.as_ref().to_path_buf()),
371        )?;
372        Ok((loader, data))
373    }
374
375    /// Tries to load a scene using specified visitor and region name.
376    pub fn load(
377        region_name: &str,
378        serialization_context: Arc<SerializationContext>,
379        dyn_type_constructors: Arc<DynTypeConstructorContainer>,
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.blackboard.register(dyn_type_constructors);
392        visitor
393            .blackboard
394            .register(Arc::new(resource_manager.clone()));
395
396        let mut scene = Scene::default();
397        scene.visit(region_name, visitor)?;
398
399        Ok(Self {
400            scene,
401            path,
402            resource_manager,
403        })
404    }
405
406    /// Finishes scene loading.
407    pub async fn finish(self) -> Scene {
408        let mut scene = self.scene;
409
410        Log::info("SceneLoader::finish() - Collecting resources used by the scene...");
411
412        let mut used_resources = scene.collect_used_resources();
413
414        // Do not wait for self resources.
415        if let Some(path) = self.path {
416            let exclusion_list = used_resources
417                .iter()
418                .filter(|res| {
419                    let uuid = res.resource_uuid();
420                    let state = self.resource_manager.state();
421                    let registry = state.resource_registry.safe_lock();
422                    registry.uuid_to_path(uuid) == Some(&path)
423                })
424                .cloned()
425                .collect::<Vec<_>>();
426
427            for excluded_resource in exclusion_list {
428                assert!(used_resources.remove(&excluded_resource));
429            }
430        }
431
432        let used_resources_count = used_resources.len();
433
434        Log::info(format!(
435            "SceneLoader::finish() - {used_resources_count} resources collected. Waiting them to load..."
436        ));
437
438        // Wait everything.
439        let results = join_all(used_resources.into_iter()).await;
440
441        for result in results {
442            if let Err(err) = result {
443                Log::err(format!("Scene resource loading error: {:?}", err));
444            }
445        }
446
447        Log::info(format!(
448            "SceneLoader::finish() - All {used_resources_count} resources have finished loading."
449        ));
450
451        // We have to wait until skybox textures are all loaded, because we need to read their data
452        // to re-create cube map.
453        let mut skybox_textures = Vec::new();
454        if let Some(skybox) = scene.skybox_ref() {
455            skybox_textures.extend(skybox.textures().iter().filter_map(|t| t.clone()));
456        }
457        join_all(skybox_textures).await;
458
459        // And do resolve to extract correct graphical data and so on.
460        scene.resolve();
461
462        scene
463    }
464}
465
466impl Scene {
467    /// Creates new scene with single root node.
468    ///
469    /// # Notes
470    ///
471    /// This method differs from Default trait implementation! Scene::default() creates
472    /// empty graph with no nodes.
473    #[inline]
474    pub fn new() -> Self {
475        Self {
476            // Graph must be created with `new` method because it differs from `default`
477            graph: Graph::new(),
478            rendering_options: Default::default(),
479            drawing_context: Default::default(),
480            performance_statistics: Default::default(),
481            enabled: true.into(),
482            sky_box: Some(SkyBoxKind::built_in_skybox().clone()).into(),
483        }
484    }
485
486    /// Sets new skybox. Could be None if no skybox needed.
487    pub fn set_skybox(&mut self, skybox: Option<SkyBox>) -> Option<SkyBox> {
488        self.sky_box.set_value_and_mark_modified(skybox)
489    }
490
491    /// Return optional mutable reference to current skybox.
492    pub fn skybox_mut(&mut self) -> Option<&mut SkyBox> {
493        self.sky_box.get_value_mut_and_mark_modified().as_mut()
494    }
495
496    /// Return optional shared reference to current skybox.
497    pub fn skybox_ref(&self) -> Option<&SkyBox> {
498        self.sky_box.as_ref()
499    }
500
501    /// Replaces the skybox.
502    pub fn replace_skybox(&mut self, new: Option<SkyBox>) -> Option<SkyBox> {
503        std::mem::replace(self.sky_box.get_value_mut_and_mark_modified(), new)
504    }
505
506    /// Synchronizes the state of the scene with external resources.
507    pub fn resolve(&mut self) {
508        Log::writeln(MessageKind::Information, "Starting resolve...");
509
510        // Update cube maps for sky boxes.
511        if let Some(skybox) = self.skybox_mut() {
512            Log::verify(skybox.create_cubemap());
513        }
514
515        self.graph.resolve();
516
517        Log::writeln(MessageKind::Information, "Resolve succeeded!");
518    }
519
520    /// Collects all resources used by the scene. It uses reflection to "scan" the contents of the scene, so
521    /// if some fields marked with `#[reflect(hidden)]` attribute, then such field will be ignored!
522    pub fn collect_used_resources(&self) -> FxHashSet<UntypedResource> {
523        let mut collection = FxHashSet::default();
524        asset::collect_used_resources(self, &mut collection);
525        collection
526    }
527
528    /// Performs single update tick with given delta time from last frame. Internally
529    /// it updates physics, animations, and each graph node. In most cases there is
530    /// no need to call it directly, engine automatically updates all available scenes.
531    pub fn update(&mut self, frame_size: Vector2<f32>, dt: f32, switches: GraphUpdateSwitches) {
532        self.graph.update(frame_size, dt, switches);
533        self.performance_statistics.graph = self.graph.performance_statistics.clone();
534    }
535
536    /// Creates deep copy of a scene, filter predicate allows you to filter out nodes
537    /// by your criteria.
538    pub fn clone_ex<F, Pre, Post>(
539        &self,
540        root: Handle<Node>,
541        preserve_handles: bool,
542        filter: &mut F,
543        pre_process_callback: &mut Pre,
544        post_process_callback: &mut Post,
545    ) -> (Self, NodeHandleMap<Node>)
546    where
547        F: FnMut(Handle<Node>, &Node) -> bool,
548        Pre: FnMut(Handle<Node>, &mut Node),
549        Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
550    {
551        let (graph, old_new_map) = self.graph.clone_ex(
552            root,
553            preserve_handles,
554            filter,
555            pre_process_callback,
556            post_process_callback,
557        );
558
559        (
560            Self {
561                graph,
562                rendering_options: self.rendering_options.clone(),
563                drawing_context: self.drawing_context.clone(),
564                performance_statistics: Default::default(),
565                enabled: self.enabled.clone(),
566                sky_box: self.sky_box.clone(),
567            },
568            old_new_map,
569        )
570    }
571
572    /// Creates deep copy of a scene. Same as [`Self::clone`], but does 1:1 cloning.
573    pub fn clone_one_to_one(&self) -> (Self, NodeHandleMap<Node>) {
574        self.clone_ex(
575            self.graph.get_root(),
576            true,
577            &mut |_, _| true,
578            &mut |_, _| {},
579            &mut |_, _, _| {},
580        )
581    }
582
583    fn visit(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
584        let mut region = visitor.enter_region(region_name)?;
585
586        self.graph.visit("Graph", &mut region)?;
587        self.enabled.visit("Enabled", &mut region)?;
588        self.rendering_options
589            .visit("RenderingOptions", &mut region)?;
590        self.sky_box.visit("SkyBox", &mut region)?;
591
592        Ok(())
593    }
594
595    /// Tries to serialize the scene using the specified serializer. The serializer must be in write mode, otherwise
596    /// serialization will fail. The `region_name` argument must be `Scene` (scene loader expects this value, you can
597    /// use any other if you don't plan to load scenes using the standard mechanism).. Keep in mind, that this method
598    /// does **not** write anything to a file, instead it just fills in the serializer.
599    ///
600    /// ## Example
601    ///
602    /// ```rust,no_run
603    /// # use fyrox_impl::{
604    /// #     core::visitor::Visitor,
605    /// #     scene::{
606    /// #         base::BaseBuilder,
607    /// #         mesh::{
608    /// #             surface::{SurfaceBuilder, SurfaceData, SurfaceResource},
609    /// #             MeshBuilder,
610    /// #         },
611    /// #         Scene,
612    /// #     },
613    /// # };
614    /// use fyrox_resource::untyped::ResourceKind;
615    /// #
616    /// // Create a scene.
617    /// let mut scene = Scene::new();
618    ///
619    /// MeshBuilder::new(BaseBuilder::new())
620    ///     .with_surfaces(vec![SurfaceBuilder::new(SurfaceResource::new_embedded(SurfaceData::make_cube(Default::default()),
621    ///     ))
622    ///     .build()])
623    ///     .build(&mut scene.graph);
624    ///
625    /// // Serialize the content.
626    /// let mut visitor = Visitor::new();
627    /// scene.save("Scene", &mut visitor).unwrap();
628    ///
629    /// // Write the data to a file.
630    /// visitor.save_binary_to_file("path/to/a/scene.rgs").unwrap();
631    /// ```
632    pub fn save(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
633        if visitor.is_reading() {
634            return Err(VisitError::User(
635                "Visitor must be in write mode!".to_string(),
636            ));
637        }
638
639        self.visit(region_name, visitor)
640    }
641}
642
643/// Container for scenes in the engine.
644pub struct SceneContainer {
645    pool: Pool<Scene>,
646    sound_engine: SoundEngine,
647    pub(crate) destruction_list: Vec<(Handle<Scene>, Scene)>,
648}
649
650impl SceneContainer {
651    pub(crate) fn new(sound_engine: SoundEngine) -> Self {
652        Self {
653            pool: Pool::new(),
654            sound_engine,
655            destruction_list: Default::default(),
656        }
657    }
658
659    /// Return true if given handle is valid and "points" to "alive" scene.
660    pub fn is_valid_handle(&self, handle: Handle<Scene>) -> bool {
661        self.pool.is_valid_handle(handle)
662    }
663
664    /// Returns pair iterator which yields (handle, scene_ref) pairs.
665    pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<Scene>, &Scene)> {
666        self.pool.pair_iter()
667    }
668
669    /// Returns pair iterator which yields (handle, scene_ref) pairs.
670    pub fn pair_iter_mut(&mut self) -> impl Iterator<Item = (Handle<Scene>, &mut Scene)> {
671        self.pool.pair_iter_mut()
672    }
673
674    /// Tries to borrow a scene using its handle.
675    pub fn try_get(&self, handle: Handle<Scene>) -> Result<&Scene, PoolError> {
676        self.pool.try_borrow(handle)
677    }
678
679    /// Tries to borrow a scene using its handle.
680    pub fn try_get_mut(&mut self, handle: Handle<Scene>) -> Result<&mut Scene, PoolError> {
681        self.pool.try_borrow_mut(handle)
682    }
683
684    /// Creates new iterator over scenes in container.
685    #[inline]
686    pub fn iter(&self) -> impl Iterator<Item = &Scene> {
687        self.pool.iter()
688    }
689
690    /// Creates new mutable iterator over scenes in container.
691    #[inline]
692    pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Scene> {
693        self.pool.iter_mut()
694    }
695
696    /// Adds new scene into container.
697    #[inline]
698    pub fn add(&mut self, scene: Scene) -> Handle<Scene> {
699        self.sound_engine
700            .state()
701            .add_context(scene.graph.sound_context.native.clone());
702        self.pool.spawn(scene)
703    }
704
705    /// Removes all scenes from container.
706    #[inline]
707    pub fn clear(&mut self) {
708        self.pool.clear()
709    }
710
711    /// Removes given scene from container. The scene will be destroyed on a next update call.
712    #[inline]
713    pub fn remove(&mut self, handle: Handle<Scene>) {
714        self.sound_engine
715            .state()
716            .remove_context(self.pool[handle].graph.sound_context.native.clone());
717        self.destruction_list.push((handle, self.pool.free(handle)));
718    }
719
720    /// Takes scene from the container and transfers ownership to caller. You must either
721    /// put scene back using ticket or call `forget_ticket` to make memory used by scene
722    /// vacant again.
723    pub fn take_reserve(&mut self, handle: Handle<Scene>) -> (Ticket<Scene>, Scene) {
724        self.pool.take_reserve(handle)
725    }
726
727    /// Puts scene back using its ticket.
728    pub fn put_back(&mut self, ticket: Ticket<Scene>, scene: Scene) -> Handle<Scene> {
729        self.pool.put_back(ticket, scene)
730    }
731
732    /// Forgets ticket of a scene, making place at which ticket points, vacant again.
733    pub fn forget_ticket(&mut self, ticket: Ticket<Scene>) {
734        self.pool.forget_ticket(ticket)
735    }
736}
737
738impl Index<Handle<Scene>> for SceneContainer {
739    type Output = Scene;
740
741    #[inline]
742    fn index(&self, index: Handle<Scene>) -> &Self::Output {
743        &self.pool[index]
744    }
745}
746
747impl IndexMut<Handle<Scene>> for SceneContainer {
748    #[inline]
749    fn index_mut(&mut self, index: Handle<Scene>) -> &mut Self::Output {
750        &mut self.pool[index]
751    }
752}