1#![warn(missing_docs)]
2
3pub mod accel;
8pub mod base;
9pub mod camera;
10pub mod collider;
11pub mod debug;
12pub mod decal;
13pub mod dim2;
14pub mod graph;
15pub mod joint;
16pub mod legacy_physics;
17pub mod light;
18pub mod mesh;
19pub mod node;
20pub mod particle_system;
21pub mod rigidbody;
22pub mod sprite;
23pub mod terrain;
24pub mod transform;
25pub mod variable;
26pub mod visibility;
27
28use crate::scene::base::legacy::PhysicsBinding;
29use crate::scene::legacy_physics::dim3::RigidBodyHandle;
30use crate::{
31 animation::AnimationContainer,
32 core::{
33 algebra::{UnitQuaternion, Vector2},
34 color::Color,
35 instant,
36 pool::{Handle, Pool, PoolIterator, PoolIteratorMut, Ticket},
37 sstorage::ImmutableString,
38 visitor::{Visit, VisitError, VisitResult, Visitor},
39 },
40 engine::{resource_manager::ResourceManager, PhysicsBinder},
41 material::{shader::SamplerFallback, PropertyValue},
42 resource::texture::Texture,
43 scene::{
44 base::BaseBuilder,
45 collider::{ColliderBuilder, ColliderShape, GeometrySource},
46 debug::SceneDrawingContext,
47 graph::{
48 physics::{
49 collider_shape_from_native_collider, joint_params_from_native,
50 PhysicsPerformanceStatistics,
51 },
52 Graph,
53 },
54 joint::JointBuilder,
55 legacy_physics::LegacyPhysics,
56 mesh::buffer::{
57 VertexAttributeDataType, VertexAttributeDescriptor, VertexAttributeUsage,
58 VertexWriteTrait,
59 },
60 node::Node,
61 rigidbody::{RigidBodyBuilder, RigidBodyType},
62 transform::TransformBuilder,
63 },
64 sound::{context::SoundContext, engine::SoundEngine},
65 utils::{lightmap::Lightmap, log::Log, log::MessageKind, navmesh::Navmesh},
66};
67use fxhash::FxHashMap;
68use std::{
69 fmt::{Display, Formatter},
70 ops::{Index, IndexMut},
71 path::Path,
72 sync::{Arc, Mutex},
73};
74
75#[derive(Default, Clone, Debug)]
77pub struct NavMeshContainer {
78 pool: Pool<Navmesh>,
79}
80
81impl NavMeshContainer {
82 pub fn add(&mut self, navmesh: Navmesh) -> Handle<Navmesh> {
84 self.pool.spawn(navmesh)
85 }
86
87 pub fn remove(&mut self, handle: Handle<Navmesh>) -> Navmesh {
89 self.pool.free(handle)
90 }
91
92 pub fn iter(&self) -> impl Iterator<Item = &Navmesh> {
94 self.pool.iter()
95 }
96
97 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Navmesh> {
99 self.pool.iter_mut()
100 }
101
102 pub fn handle_from_index(&self, i: u32) -> Handle<Navmesh> {
104 self.pool.handle_from_index(i)
105 }
106
107 pub fn clear(&mut self) {
109 self.pool.clear()
110 }
111
112 pub fn is_valid_handle(&self, handle: Handle<Navmesh>) -> bool {
114 self.pool.is_valid_handle(handle)
115 }
116}
117
118impl Index<Handle<Navmesh>> for NavMeshContainer {
119 type Output = Navmesh;
120
121 fn index(&self, index: Handle<Navmesh>) -> &Self::Output {
122 &self.pool[index]
123 }
124}
125
126impl IndexMut<Handle<Navmesh>> for NavMeshContainer {
127 fn index_mut(&mut self, index: Handle<Navmesh>) -> &mut Self::Output {
128 &mut self.pool[index]
129 }
130}
131
132impl Visit for NavMeshContainer {
133 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
134 visitor.enter_region(name)?;
135
136 self.pool.visit("Pool", visitor)?;
137
138 visitor.leave_region()
139 }
140}
141
142#[derive(Debug)]
144pub struct Scene {
145 pub graph: Graph,
149
150 pub animations: AnimationContainer,
153
154 pub render_target: Option<Texture>,
162
163 pub drawing_context: SceneDrawingContext,
165
166 pub sound_context: SoundContext,
168
169 pub navmeshes: NavMeshContainer,
171
172 lightmap: Option<Lightmap>,
174
175 pub performance_statistics: PerformanceStatistics,
177
178 pub ambient_lighting_color: Color,
180
181 pub enabled: bool,
189
190 legacy_physics: LegacyPhysics,
192
193 legacy_physics_binder: PhysicsBinder<Node, RigidBodyHandle>,
195}
196
197impl Default for Scene {
198 fn default() -> Self {
199 Self {
200 graph: Default::default(),
201 animations: Default::default(),
202 legacy_physics: Default::default(),
203 legacy_physics_binder: Default::default(),
204 render_target: None,
205 lightmap: None,
206 drawing_context: Default::default(),
207 sound_context: Default::default(),
208 navmeshes: Default::default(),
209 performance_statistics: Default::default(),
210 ambient_lighting_color: Color::opaque(100, 100, 100),
211 enabled: true,
212 }
213 }
214}
215
216fn map_texture(tex: Option<Texture>, rm: ResourceManager) -> Option<Texture> {
217 if let Some(shallow_texture) = tex {
218 let shallow_texture = shallow_texture.state();
219 Some(rm.request_texture(shallow_texture.path()))
220 } else {
221 None
222 }
223}
224
225#[derive(Clone, Default, Debug)]
227pub struct PerformanceStatistics {
228 pub physics: PhysicsPerformanceStatistics,
230
231 pub physics2d: PhysicsPerformanceStatistics,
233
234 pub graph_update_time: f32,
236
237 pub animations_update_time: f32,
239
240 pub sound_update_time: f32,
242}
243
244impl Display for PerformanceStatistics {
245 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
246 write!(
247 f,
248 "{}\nGraph: {} ms\nAnimations: {} ms\nSounds: {} ms",
249 self.physics,
250 self.graph_update_time * 1000.0,
251 self.animations_update_time * 1000.0,
252 self.sound_update_time * 1000.0
253 )
254 }
255}
256
257impl Scene {
258 #[inline]
265 pub fn new() -> Self {
266 Self {
267 graph: Graph::new(),
269 legacy_physics: Default::default(),
270 animations: Default::default(),
271 legacy_physics_binder: Default::default(),
272 render_target: None,
273 lightmap: None,
274 drawing_context: Default::default(),
275 sound_context: SoundContext::new(),
276 navmeshes: Default::default(),
277 performance_statistics: Default::default(),
278 ambient_lighting_color: Color::opaque(100, 100, 100),
279 enabled: true,
280 }
281 }
282
283 pub async fn from_file<P: AsRef<Path>>(
286 path: P,
287 resource_manager: ResourceManager,
288 ) -> Result<Self, VisitError> {
289 let mut scene = Scene::default();
290 {
291 let mut visitor = Visitor::load_binary(path.as_ref()).await?;
292 scene.visit("Scene", &mut visitor)?;
293 }
294
295 let mut resources = Vec::new();
297 for node in scene.graph.linear_iter_mut() {
298 if let Some(shallow_resource) = node.resource.clone() {
299 let resource = resource_manager
300 .clone()
301 .request_model(&shallow_resource.state().path());
302 node.resource = Some(resource.clone());
303 resources.push(resource);
304 }
305 }
306
307 let _ = crate::core::futures::future::join_all(resources).await;
308
309 for node in scene.graph.linear_iter_mut() {
313 match node {
314 Node::Mesh(mesh) => {
315 for surface in mesh.surfaces_mut() {
316 surface.material().lock().resolve(resource_manager.clone());
317 }
318 }
319 Node::Sprite(sprite) => {
320 sprite.set_texture(map_texture(sprite.texture(), resource_manager.clone()));
321 }
322 Node::ParticleSystem(particle_system) => {
323 particle_system.set_texture(map_texture(
324 particle_system.texture(),
325 resource_manager.clone(),
326 ));
327 }
328 Node::Camera(camera) => {
329 camera.set_environment(map_texture(
330 camera.environment_map(),
331 resource_manager.clone(),
332 ));
333
334 if let Some(skybox) = camera.skybox_mut() {
335 skybox.bottom =
336 map_texture(skybox.bottom.clone(), resource_manager.clone());
337 skybox.top = map_texture(skybox.top.clone(), resource_manager.clone());
338 skybox.left = map_texture(skybox.left.clone(), resource_manager.clone());
339 skybox.right = map_texture(skybox.right.clone(), resource_manager.clone());
340 skybox.front = map_texture(skybox.front.clone(), resource_manager.clone());
341 skybox.back = map_texture(skybox.back.clone(), resource_manager.clone());
342 }
343 }
344 Node::Terrain(terrain) => {
345 for layer in terrain.layers() {
346 layer.material.lock().resolve(resource_manager.clone());
347 }
348 }
349 Node::Rectangle(rectangle) => {
350 rectangle.set_texture(map_texture(
351 rectangle.texture_value(),
352 resource_manager.clone(),
353 ));
354 }
355 Node::Decal(decal) => {
356 decal.set_diffuse_texture(map_texture(
357 decal.diffuse_texture_value(),
358 resource_manager.clone(),
359 ));
360 decal.set_normal_texture(map_texture(
361 decal.normal_texture_value(),
362 resource_manager.clone(),
363 ));
364 }
365 _ => (),
366 }
367 }
368
369 if let Some(lightmap) = scene.lightmap.as_mut() {
370 for entries in lightmap.map.values_mut() {
371 for entry in entries.iter_mut() {
372 entry.texture = map_texture(entry.texture.clone(), resource_manager.clone());
373 }
374 }
375 }
376
377 let mut skybox_textures = Vec::new();
380 for node in scene.graph.linear_iter() {
381 if let Node::Camera(camera) = node {
382 if let Some(skybox) = camera.skybox_ref() {
383 skybox_textures.extend(skybox.textures().iter().filter_map(|t| t.clone()));
384 }
385 }
386 }
387 crate::core::futures::future::join_all(skybox_textures).await;
388
389 scene.resolve();
391
392 Ok(scene)
393 }
394
395 pub fn remove_node(&mut self, handle: Handle<Node>) {
402 for descendant in self.graph.traverse_handle_iter(handle) {
403 self.animations.retain(|animation| {
405 for track in animation.get_tracks() {
406 if track.get_node() == descendant {
407 return false;
408 }
409 }
410 true
411 });
412 }
413
414 self.graph.remove_node(handle)
415 }
416
417 fn convert_legacy_physics(&mut self) {
418 let mut body_map = FxHashMap::default();
420 for (node, body_handle) in self.legacy_physics_binder.forward_map() {
421 let body_ref = if let Some(body_ref) = self.legacy_physics.bodies.get(body_handle) {
422 body_ref
423 } else {
424 continue;
425 };
426
427 let [x_rotation_locked, y_rotation_locked, z_rotation_locked] =
428 body_ref.is_rotation_locked();
429
430 let body_node_handle = RigidBodyBuilder::new(
431 BaseBuilder::new()
432 .with_name("Rigid Body")
433 .with_local_transform(
434 TransformBuilder::new()
435 .with_local_position(body_ref.position().translation.vector)
436 .with_local_rotation(body_ref.position().rotation)
437 .build(),
438 ),
439 )
440 .with_body_type(RigidBodyType::from(body_ref.body_type()))
441 .with_mass(body_ref.mass())
442 .with_ang_vel(*body_ref.angvel())
443 .with_lin_vel(*body_ref.linvel())
444 .with_lin_damping(body_ref.linear_damping())
445 .with_ang_damping(body_ref.angular_damping())
446 .with_x_rotation_locked(x_rotation_locked)
447 .with_y_rotation_locked(y_rotation_locked)
448 .with_z_rotation_locked(z_rotation_locked)
449 .with_translation_locked(body_ref.is_translation_locked())
450 .with_ccd_enabled(body_ref.is_ccd_enabled())
451 .build(&mut self.graph);
452
453 body_map.insert(body_handle, body_node_handle);
454
455 for c in body_ref.colliders() {
456 let collider_ref =
457 if let Some(collider_ref) = self.legacy_physics.colliders.native_ref(*c) {
458 collider_ref
459 } else {
460 continue;
461 };
462
463 let mut shape = collider_shape_from_native_collider(collider_ref.shape());
464
465 let name = match shape {
466 ColliderShape::Ball(_) => "Ball Collider",
467 ColliderShape::Cylinder(_) => "Cylinder Collider",
468 ColliderShape::Cone(_) => "Cone Collider",
469 ColliderShape::Cuboid(_) => "Cuboid Collider",
470 ColliderShape::Capsule(_) => "Capsule Collider",
471 ColliderShape::Segment(_) => "Segment Collider",
472 ColliderShape::Triangle(_) => "Triangle Collider",
473 ColliderShape::Trimesh(_) => "Trimesh Collider",
474 ColliderShape::Heightfield(_) => "Heightfield Collider",
475 ColliderShape::Polyhedron(_) => "Convex Polyhedron",
476 };
477
478 match shape {
480 ColliderShape::Trimesh(ref mut trimesh) => {
481 trimesh.sources = self
482 .graph
483 .traverse_handle_iter(*node)
484 .filter(|h| self.graph[*h].is_mesh())
485 .map(GeometrySource)
486 .collect::<Vec<_>>();
487 }
488 ColliderShape::Heightfield(ref mut heightfield) => {
489 heightfield.geometry_source = GeometrySource(*node);
490 }
491 _ => (),
492 }
493
494 let collider_handle = ColliderBuilder::new(
495 BaseBuilder::new().with_name(name).with_local_transform(
496 TransformBuilder::new()
497 .with_local_position(
498 collider_ref
499 .position_wrt_parent()
500 .map(|p| p.translation.vector)
501 .unwrap_or_default(),
502 )
503 .with_local_rotation(
504 collider_ref
505 .position_wrt_parent()
506 .map(|p| p.rotation)
507 .unwrap_or_default(),
508 )
509 .build(),
510 ),
511 )
512 .with_friction_combine_rule(collider_ref.friction_combine_rule().into())
513 .with_restitution_combine_rule(collider_ref.restitution_combine_rule().into())
514 .with_shape(shape)
515 .with_sensor(collider_ref.is_sensor())
516 .with_restitution(collider_ref.restitution())
517 .with_density(collider_ref.density())
518 .with_collision_groups(collider_ref.collision_groups().into())
519 .with_solver_groups(collider_ref.solver_groups().into())
520 .with_friction(collider_ref.friction())
521 .build(&mut self.graph);
522
523 self.graph.link_nodes(collider_handle, body_node_handle);
524 }
525
526 let node_ref = &mut self.graph[*node];
527 node_ref
528 .local_transform_mut()
529 .set_position(Default::default())
530 .set_rotation(UnitQuaternion::default());
531 let parent = node_ref.parent();
532
533 match node_ref.physics_binding {
534 PhysicsBinding::NodeWithBody => {
535 self.graph.link_nodes(*node, body_node_handle);
536 self.graph.link_nodes(body_node_handle, parent);
537 }
538 PhysicsBinding::BodyWithNode => {
539 self.graph.link_nodes(body_node_handle, *node);
540 }
541 }
542 }
543
544 for joint in self.legacy_physics.joints.iter() {
546 let body1 = if let Some(body1) = self
547 .legacy_physics
548 .bodies
549 .handle_map()
550 .key_of(&joint.body1)
551 .and_then(|h| body_map.get(h))
552 {
553 *body1
554 } else {
555 continue;
556 };
557
558 let body2 = if let Some(body2) = self
559 .legacy_physics
560 .bodies
561 .handle_map()
562 .key_of(&joint.body2)
563 .and_then(|h| body_map.get(h))
564 {
565 *body2
566 } else {
567 continue;
568 };
569
570 let joint_handle = JointBuilder::new(BaseBuilder::new())
571 .with_params(joint_params_from_native(&joint.params))
572 .with_body1(body1)
573 .with_body2(body2)
574 .build(&mut self.graph);
575
576 self.graph.link_nodes(joint_handle, body1);
577 }
578 }
579
580 pub(in crate) fn resolve(&mut self) {
581 Log::writeln(MessageKind::Information, "Starting resolve...".to_owned());
582
583 self.graph.resolve();
584 self.animations.resolve(&self.graph);
585
586 self.graph.update_hierarchical_data();
587 self.legacy_physics
588 .resolve(&self.legacy_physics_binder, &self.graph, None);
589
590 self.convert_legacy_physics();
591
592 if let Some(lightmap) = self.lightmap.as_mut() {
596 let mut unique_data_set = FxHashMap::default();
599 for &handle in lightmap.map.keys() {
600 if let Node::Mesh(mesh) = &mut self.graph[handle] {
601 for surface in mesh.surfaces() {
602 let data = surface.data();
603 let key = &*data as *const _ as u64;
604 unique_data_set.entry(key).or_insert(data);
605 }
606 }
607 }
608
609 for (_, data) in unique_data_set.into_iter() {
610 let mut data = data.lock();
611
612 if let Some(patch) = lightmap.patches.get(&data.content_hash()) {
613 if !data
614 .vertex_buffer
615 .has_attribute(VertexAttributeUsage::TexCoord1)
616 {
617 data.vertex_buffer
618 .modify()
619 .add_attribute(
620 VertexAttributeDescriptor {
621 usage: VertexAttributeUsage::TexCoord1,
622 data_type: VertexAttributeDataType::F32,
623 size: 2,
624 divisor: 0,
625 shader_location: 6, },
627 Vector2::<f32>::default(),
628 )
629 .unwrap();
630 }
631
632 data.geometry_buffer.set_triangles(patch.triangles.clone());
633
634 let mut vertex_buffer_mut = data.vertex_buffer.modify();
635 for &v in patch.additional_vertices.iter() {
636 vertex_buffer_mut.duplicate(v as usize);
637 }
638
639 assert_eq!(
640 vertex_buffer_mut.vertex_count() as usize,
641 patch.second_tex_coords.len()
642 );
643 for (mut view, &tex_coord) in vertex_buffer_mut
644 .iter_mut()
645 .zip(patch.second_tex_coords.iter())
646 {
647 view.write_2_f32(VertexAttributeUsage::TexCoord1, tex_coord)
648 .unwrap();
649 }
650 } else {
651 Log::writeln(
652 MessageKind::Warning,
653 "Failed to get surface data patch while resolving lightmap!\
654 This means that surface has changed and lightmap must be regenerated!"
655 .to_owned(),
656 );
657 }
658 }
659
660 for (&handle, entries) in lightmap.map.iter_mut() {
662 if let Node::Mesh(mesh) = &mut self.graph[handle] {
663 for (entry, surface) in entries.iter_mut().zip(mesh.surfaces_mut()) {
664 if let Err(e) = surface.material().lock().set_property(
665 &ImmutableString::new("lightmapTexture"),
666 PropertyValue::Sampler {
667 value: entry.texture.clone(),
668 fallback: SamplerFallback::Black,
669 },
670 ) {
671 Log::writeln(
672 MessageKind::Error,
673 format!(
674 "Failed to apply light map texture to material. Reason {:?}",
675 e
676 ),
677 )
678 }
679 }
680 }
681 }
682 }
683
684 Log::writeln(MessageKind::Information, "Resolve succeeded!".to_owned());
685 }
686
687 pub fn set_lightmap(&mut self, lightmap: Lightmap) -> Result<Option<Lightmap>, &'static str> {
689 for (handle, lightmaps) in lightmap.map.iter() {
691 if let Node::Mesh(mesh) = &mut self.graph[*handle] {
692 if mesh.surfaces().len() != lightmaps.len() {
693 return Err("failed to set lightmap, surface count mismatch");
694 }
695
696 for (surface, entry) in mesh.surfaces_mut().iter_mut().zip(lightmaps) {
697 let texture = entry.texture.clone().unwrap();
700 if let Err(e) = surface.material().lock().set_property(
701 &ImmutableString::new("lightmapTexture"),
702 PropertyValue::Sampler {
703 value: Some(texture),
704 fallback: SamplerFallback::Black,
705 },
706 ) {
707 Log::writeln(
708 MessageKind::Error,
709 format!(
710 "Failed to apply light map texture to material. Reason {:?}",
711 e
712 ),
713 )
714 }
715 }
716 }
717 }
718 Ok(std::mem::replace(&mut self.lightmap, Some(lightmap)))
719 }
720
721 pub fn update(&mut self, frame_size: Vector2<f32>, dt: f32) {
725 let last = instant::Instant::now();
726 self.animations.update_animations(dt);
727 self.performance_statistics.animations_update_time =
728 (instant::Instant::now() - last).as_secs_f32();
729
730 let last = instant::Instant::now();
731 self.graph.update(frame_size, dt);
732 self.performance_statistics.physics = self.graph.physics.performance_statistics.clone();
733 self.performance_statistics.physics2d = self.graph.physics2d.performance_statistics.clone();
734 self.performance_statistics.graph_update_time =
735 (instant::Instant::now() - last).as_secs_f32();
736
737 self.performance_statistics.sound_update_time = self
738 .sound_context
739 .state()
740 .full_render_duration()
741 .as_secs_f32();
742 }
743
744 pub fn clone<F>(&self, filter: &mut F) -> (Self, FxHashMap<Handle<Node>, Handle<Node>>)
747 where
748 F: FnMut(Handle<Node>, &Node) -> bool,
749 {
750 let (graph, old_new_map) = self.graph.clone(filter);
751 let mut animations = self.animations.clone();
752 for animation in animations.iter_mut() {
753 animation.retain_tracks(|track| old_new_map.contains_key(&track.get_node()));
755 for track in animation.get_tracks_mut() {
757 track.set_node(old_new_map[&track.get_node()]);
758 }
759 }
760 (
761 Self {
762 graph,
763 animations,
764 legacy_physics: Default::default(),
765 legacy_physics_binder: Default::default(),
766 render_target: Default::default(),
769 lightmap: self.lightmap.clone(),
770 drawing_context: self.drawing_context.clone(),
771 sound_context: self.sound_context.deep_clone(),
772 navmeshes: self.navmeshes.clone(),
773 performance_statistics: Default::default(),
774 ambient_lighting_color: self.ambient_lighting_color,
775 enabled: self.enabled,
776 },
777 old_new_map,
778 )
779 }
780}
781
782impl Visit for Scene {
783 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
784 visitor.enter_region(name)?;
785 self.graph.visit("Graph", visitor)?;
786 self.animations.visit("Animations", visitor)?;
787 self.lightmap.visit("Lightmap", visitor)?;
788 self.sound_context.visit("SoundContext", visitor)?;
789 self.navmeshes.visit("NavMeshes", visitor)?;
790 self.ambient_lighting_color
791 .visit("AmbientLightingColor", visitor)?;
792 self.enabled.visit("Enabled", visitor)?;
793 if visitor.is_reading() {
795 let _ = self.legacy_physics.visit("Physics", visitor);
796 let _ = self.legacy_physics_binder.visit("PhysicsBinder", visitor);
797 }
798 visitor.leave_region()
799 }
800}
801
802#[derive(Default)]
804pub struct SceneContainer {
805 pool: Pool<Scene>,
806 sound_engine: Arc<Mutex<SoundEngine>>,
807}
808
809impl SceneContainer {
810 pub(in crate) fn new(sound_engine: Arc<Mutex<SoundEngine>>) -> Self {
811 Self {
812 pool: Pool::new(),
813 sound_engine,
814 }
815 }
816
817 pub fn is_valid_handle(&self, handle: Handle<Scene>) -> bool {
819 self.pool.is_valid_handle(handle)
820 }
821
822 pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<Scene>, &Scene)> {
824 self.pool.pair_iter()
825 }
826
827 #[inline]
829 pub fn iter(&self) -> PoolIterator<Scene> {
830 self.pool.iter()
831 }
832
833 #[inline]
835 pub fn iter_mut(&mut self) -> PoolIteratorMut<Scene> {
836 self.pool.iter_mut()
837 }
838
839 #[inline]
841 pub fn add(&mut self, scene: Scene) -> Handle<Scene> {
842 self.sound_engine
843 .lock()
844 .unwrap()
845 .add_context(scene.sound_context.clone());
846 self.pool.spawn(scene)
847 }
848
849 #[inline]
851 pub fn clear(&mut self) {
852 self.pool.clear()
853 }
854
855 #[inline]
857 pub fn remove(&mut self, handle: Handle<Scene>) {
858 self.sound_engine
859 .lock()
860 .unwrap()
861 .remove_context(self.pool[handle].sound_context.clone());
862 self.pool.free(handle);
863 }
864
865 pub fn take_reserve(&mut self, handle: Handle<Scene>) -> (Ticket<Scene>, Scene) {
869 self.pool.take_reserve(handle)
870 }
871
872 pub fn put_back(&mut self, ticket: Ticket<Scene>, scene: Scene) -> Handle<Scene> {
874 self.pool.put_back(ticket, scene)
875 }
876
877 pub fn forget_ticket(&mut self, ticket: Ticket<Scene>) {
879 self.pool.forget_ticket(ticket)
880 }
881}
882
883impl Index<Handle<Scene>> for SceneContainer {
884 type Output = Scene;
885
886 #[inline]
887 fn index(&self, index: Handle<Scene>) -> &Self::Output {
888 &self.pool[index]
889 }
890}
891
892impl IndexMut<Handle<Scene>> for SceneContainer {
893 #[inline]
894 fn index_mut(&mut self, index: Handle<Scene>) -> &mut Self::Output {
895 &mut self.pool[index]
896 }
897}
898
899impl Visit for SceneContainer {
900 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
901 visitor.enter_region(name)?;
902
903 self.pool.visit("Pool", visitor)?;
904 self.sound_engine.visit("SoundEngine", visitor)?;
905
906 visitor.leave_region()
907 }
908}