1#![warn(missing_docs)]
22
23pub 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 ragdoll;
44pub mod rigidbody;
45pub mod sound;
46pub mod sprite;
47pub mod terrain;
48pub mod tilemap;
49pub mod transform;
50
51use crate::renderer::framework::PolygonFillMode;
52use crate::{
53 asset::{self, manager::ResourceManager, untyped::UntypedResource},
54 core::{
55 algebra::Vector2,
56 color::Color,
57 futures::future::join_all,
58 log::{Log, MessageKind},
59 pool::{Handle, Pool, Ticket},
60 reflect::prelude::*,
61 visitor::{Visit, VisitError, VisitResult, Visitor},
62 },
63 engine::SerializationContext,
64 graph::NodeHandleMap,
65 resource::texture::TextureResource,
66 scene::{
67 base::BaseBuilder,
68 camera::Camera,
69 debug::SceneDrawingContext,
70 graph::{Graph, GraphPerformanceStatistics, GraphUpdateSwitches},
71 navmesh::NavigationalMeshBuilder,
72 node::Node,
73 sound::SoundEngine,
74 },
75 utils::navmesh::Navmesh,
76};
77use asset::io::ResourceIo;
78use fxhash::FxHashSet;
79use fyrox_core::variable::InheritableVariable;
80use std::{
81 fmt::{Display, Formatter},
82 ops::{Index, IndexMut},
83 path::Path,
84 path::PathBuf,
85 sync::Arc,
86};
87
88#[derive(Default, Clone, Debug, Visit)]
90pub struct NavMeshContainer {
91 pool: Pool<Navmesh>,
92}
93
94impl NavMeshContainer {
95 pub fn add(&mut self, navmesh: Navmesh) -> Handle<Navmesh> {
97 self.pool.spawn(navmesh)
98 }
99
100 pub fn remove(&mut self, handle: Handle<Navmesh>) -> Navmesh {
102 self.pool.free(handle)
103 }
104
105 pub fn iter(&self) -> impl Iterator<Item = &Navmesh> {
107 self.pool.iter()
108 }
109
110 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Navmesh> {
112 self.pool.iter_mut()
113 }
114
115 pub fn handle_from_index(&self, i: u32) -> Handle<Navmesh> {
117 self.pool.handle_from_index(i)
118 }
119
120 pub fn clear(&mut self) {
122 self.pool.clear()
123 }
124
125 pub fn is_valid_handle(&self, handle: Handle<Navmesh>) -> bool {
127 self.pool.is_valid_handle(handle)
128 }
129
130 pub fn at(&self, i: u32) -> Option<&Navmesh> {
132 self.pool.at(i)
133 }
134
135 pub fn try_get(&self, handle: Handle<Navmesh>) -> Option<&Navmesh> {
137 self.pool.try_borrow(handle)
138 }
139
140 pub fn at_mut(&mut self, i: u32) -> Option<&mut Navmesh> {
142 self.pool.at_mut(i)
143 }
144
145 pub fn try_get_mut(&mut self, handle: Handle<Navmesh>) -> Option<&mut Navmesh> {
147 self.pool.try_borrow_mut(handle)
148 }
149}
150
151impl Index<Handle<Navmesh>> for NavMeshContainer {
152 type Output = Navmesh;
153
154 fn index(&self, index: Handle<Navmesh>) -> &Self::Output {
155 &self.pool[index]
156 }
157}
158
159impl IndexMut<Handle<Navmesh>> for NavMeshContainer {
160 fn index_mut(&mut self, index: Handle<Navmesh>) -> &mut Self::Output {
161 &mut self.pool[index]
162 }
163}
164
165#[derive(Debug, Visit, Reflect, PartialEq)]
167pub struct SceneRenderingOptions {
168 pub render_target: Option<TextureResource>,
174
175 pub clear_color: Option<Color>,
178
179 pub polygon_rasterization_mode: PolygonFillMode,
182
183 pub ambient_lighting_color: Color,
185}
186
187impl Default for SceneRenderingOptions {
188 fn default() -> Self {
189 Self {
190 render_target: None,
191 clear_color: None,
192 polygon_rasterization_mode: Default::default(),
193 ambient_lighting_color: Color::opaque(100, 100, 100),
194 }
195 }
196}
197
198impl Clone for SceneRenderingOptions {
199 fn clone(&self) -> Self {
200 Self {
201 render_target: None, clear_color: self.clear_color,
203 polygon_rasterization_mode: self.polygon_rasterization_mode,
204 ambient_lighting_color: self.ambient_lighting_color,
205 }
206 }
207}
208
209#[derive(Debug, Reflect)]
211pub struct Scene {
212 pub graph: Graph,
216
217 pub rendering_options: InheritableVariable<SceneRenderingOptions>,
219
220 #[reflect(hidden)]
222 pub drawing_context: SceneDrawingContext,
223
224 #[reflect(hidden)]
226 pub performance_statistics: PerformanceStatistics,
227
228 pub enabled: InheritableVariable<bool>,
236}
237
238impl Default for Scene {
239 fn default() -> Self {
240 Self {
241 graph: Default::default(),
242 rendering_options: Default::default(),
243 drawing_context: Default::default(),
244 performance_statistics: Default::default(),
245 enabled: true.into(),
246 }
247 }
248}
249
250#[derive(Clone, Default, Debug)]
252pub struct PerformanceStatistics {
253 pub graph: GraphPerformanceStatistics,
255}
256
257impl Display for PerformanceStatistics {
258 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
259 write!(
260 f,
261 "Graph: {:?}\n\
262 \tSync Time: {:?}\n\
263 \tSound: {:?}\n\
264 \tPhysics: {:?}\n\
265 \t\tSimulation: {:?}\n\
266 \t\tRay cast: {:?}\n\
267 \tPhysics 2D: {:?}\n\
268 \t\tSimulation: {:?}\n\
269 \t\tRay cast: {:?}\n\
270 \tHierarchy: {:?}",
271 self.graph.total(),
272 self.graph.sync_time,
273 self.graph.sound_update_time,
274 self.graph.physics.total(),
275 self.graph.physics.step_time,
276 self.graph.physics.total_ray_cast_time.get(),
277 self.graph.physics2d.total(),
278 self.graph.physics2d.step_time,
279 self.graph.physics2d.total_ray_cast_time.get(),
280 self.graph.hierarchical_properties_time,
281 )
282 }
283}
284
285pub struct SceneLoader {
287 scene: Scene,
288 path: Option<PathBuf>,
289}
290
291impl SceneLoader {
292 pub async fn from_file<P: AsRef<Path>>(
295 path: P,
296 io: &dyn ResourceIo,
297 serialization_context: Arc<SerializationContext>,
298 resource_manager: ResourceManager,
299 ) -> Result<(Self, Vec<u8>), VisitError> {
300 let data = io.load_file(path.as_ref()).await?;
301 let mut visitor = Visitor::load_from_memory(&data)?;
302 let loader = Self::load(
303 "Scene",
304 serialization_context,
305 resource_manager,
306 &mut visitor,
307 Some(path.as_ref().to_path_buf()),
308 )?;
309 Ok((loader, data))
310 }
311
312 pub fn load(
314 region_name: &str,
315 serialization_context: Arc<SerializationContext>,
316 resource_manager: ResourceManager,
317 visitor: &mut Visitor,
318 path: Option<PathBuf>,
319 ) -> Result<Self, VisitError> {
320 if !visitor.is_reading() {
321 return Err(VisitError::User(
322 "Visitor must be in read mode!".to_string(),
323 ));
324 }
325
326 visitor.blackboard.register(serialization_context);
327 visitor.blackboard.register(Arc::new(resource_manager));
328
329 let mut scene = Scene::default();
330 scene.visit(region_name, visitor)?;
331
332 Ok(Self { scene, path })
333 }
334
335 pub async fn finish(self) -> Scene {
337 let mut scene = self.scene;
338
339 Log::info("SceneLoader::finish() - Collecting resources used by the scene...");
340
341 let mut used_resources = scene.collect_used_resources();
342
343 if let Some(path) = self.path {
345 let exclusion_list = used_resources
346 .iter()
347 .filter(|res| res.kind().path() == Some(&path))
348 .cloned()
349 .collect::<Vec<_>>();
350
351 for excluded_resource in exclusion_list {
352 assert!(used_resources.remove(&excluded_resource));
353 }
354 }
355
356 let used_resources_count = used_resources.len();
357
358 Log::info(format!(
359 "SceneLoader::finish() - {used_resources_count} resources collected. Waiting them to load..."
360 ));
361
362 join_all(used_resources.into_iter()).await;
364
365 Log::info(format!(
366 "SceneLoader::finish() - All {used_resources_count} resources have finished loading."
367 ));
368
369 let mut skybox_textures = Vec::new();
373 for node in scene.graph.linear_iter() {
374 if let Some(camera) = node.cast::<Camera>() {
375 if let Some(skybox) = camera.skybox_ref() {
376 skybox_textures.extend(skybox.textures().iter().filter_map(|t| t.clone()));
377 }
378 }
379 }
380 join_all(skybox_textures).await;
381
382 scene.resolve();
384
385 scene
386 }
387}
388
389impl Scene {
390 #[inline]
397 pub fn new() -> Self {
398 Self {
399 graph: Graph::new(),
401 rendering_options: Default::default(),
402 drawing_context: Default::default(),
403 performance_statistics: Default::default(),
404 enabled: true.into(),
405 }
406 }
407
408 pub fn resolve(&mut self) {
410 Log::writeln(MessageKind::Information, "Starting resolve...");
411
412 self.graph.resolve();
413
414 Log::writeln(MessageKind::Information, "Resolve succeeded!");
415 }
416
417 pub fn collect_used_resources(&self) -> FxHashSet<UntypedResource> {
420 let mut collection = FxHashSet::default();
421 asset::collect_used_resources(self, &mut collection);
422 collection
423 }
424
425 pub fn update(&mut self, frame_size: Vector2<f32>, dt: f32, switches: GraphUpdateSwitches) {
429 self.graph.update(frame_size, dt, switches);
430 self.performance_statistics.graph = self.graph.performance_statistics.clone();
431 }
432
433 pub fn clone<F, Pre, Post>(
436 &self,
437 root: Handle<Node>,
438 filter: &mut F,
439 pre_process_callback: &mut Pre,
440 post_process_callback: &mut Post,
441 ) -> (Self, NodeHandleMap<Node>)
442 where
443 F: FnMut(Handle<Node>, &Node) -> bool,
444 Pre: FnMut(Handle<Node>, &mut Node),
445 Post: FnMut(Handle<Node>, Handle<Node>, &mut Node),
446 {
447 let (graph, old_new_map) =
448 self.graph
449 .clone(root, filter, pre_process_callback, post_process_callback);
450
451 (
452 Self {
453 graph,
454 rendering_options: self.rendering_options.clone(),
455 drawing_context: self.drawing_context.clone(),
456 performance_statistics: Default::default(),
457 enabled: self.enabled.clone(),
458 },
459 old_new_map,
460 )
461 }
462
463 pub fn clone_one_to_one(&self) -> (Self, NodeHandleMap<Node>) {
465 self.clone(
466 self.graph.get_root(),
467 &mut |_, _| true,
468 &mut |_, _| {},
469 &mut |_, _, _| {},
470 )
471 }
472
473 fn visit(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
474 let mut region = visitor.enter_region(region_name)?;
475
476 self.graph.visit("Graph", &mut region)?;
477
478 self.enabled.visit("Enabled", &mut region)?;
479 let _ = self
480 .rendering_options
481 .visit("RenderingOptions", &mut region);
482
483 let mut navmeshes = NavMeshContainer::default();
485 if navmeshes.visit("NavMeshes", &mut region).is_ok() {
486 for (i, navmesh) in navmeshes.iter().enumerate() {
487 NavigationalMeshBuilder::new(BaseBuilder::new().with_name(format!("Navmesh{i}")))
488 .with_navmesh(navmesh.clone())
489 .build(&mut self.graph);
490 }
491 }
492
493 Ok(())
494 }
495
496 pub fn save(&mut self, region_name: &str, visitor: &mut Visitor) -> VisitResult {
535 if visitor.is_reading() {
536 return Err(VisitError::User(
537 "Visitor must be in write mode!".to_string(),
538 ));
539 }
540
541 self.visit(region_name, visitor)
542 }
543}
544
545pub struct SceneContainer {
547 pool: Pool<Scene>,
548 sound_engine: SoundEngine,
549 pub(crate) destruction_list: Vec<(Handle<Scene>, Scene)>,
550}
551
552impl SceneContainer {
553 pub(crate) fn new(sound_engine: SoundEngine) -> Self {
554 Self {
555 pool: Pool::new(),
556 sound_engine,
557 destruction_list: Default::default(),
558 }
559 }
560
561 pub fn is_valid_handle(&self, handle: Handle<Scene>) -> bool {
563 self.pool.is_valid_handle(handle)
564 }
565
566 pub fn pair_iter(&self) -> impl Iterator<Item = (Handle<Scene>, &Scene)> {
568 self.pool.pair_iter()
569 }
570
571 pub fn pair_iter_mut(&mut self) -> impl Iterator<Item = (Handle<Scene>, &mut Scene)> {
573 self.pool.pair_iter_mut()
574 }
575
576 pub fn try_get(&self, handle: Handle<Scene>) -> Option<&Scene> {
578 self.pool.try_borrow(handle)
579 }
580
581 pub fn try_get_mut(&mut self, handle: Handle<Scene>) -> Option<&mut Scene> {
583 self.pool.try_borrow_mut(handle)
584 }
585
586 #[inline]
588 pub fn iter(&self) -> impl Iterator<Item = &Scene> {
589 self.pool.iter()
590 }
591
592 #[inline]
594 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Scene> {
595 self.pool.iter_mut()
596 }
597
598 #[inline]
600 pub fn add(&mut self, scene: Scene) -> Handle<Scene> {
601 self.sound_engine
602 .state()
603 .add_context(scene.graph.sound_context.native.clone());
604 self.pool.spawn(scene)
605 }
606
607 #[inline]
609 pub fn clear(&mut self) {
610 self.pool.clear()
611 }
612
613 #[inline]
615 pub fn remove(&mut self, handle: Handle<Scene>) {
616 self.sound_engine
617 .state()
618 .remove_context(self.pool[handle].graph.sound_context.native.clone());
619 self.destruction_list.push((handle, self.pool.free(handle)));
620 }
621
622 pub fn take_reserve(&mut self, handle: Handle<Scene>) -> (Ticket<Scene>, Scene) {
626 self.pool.take_reserve(handle)
627 }
628
629 pub fn put_back(&mut self, ticket: Ticket<Scene>, scene: Scene) -> Handle<Scene> {
631 self.pool.put_back(ticket, scene)
632 }
633
634 pub fn forget_ticket(&mut self, ticket: Ticket<Scene>) {
636 self.pool.forget_ticket(ticket)
637 }
638}
639
640impl Index<Handle<Scene>> for SceneContainer {
641 type Output = Scene;
642
643 #[inline]
644 fn index(&self, index: Handle<Scene>) -> &Self::Output {
645 &self.pool[index]
646 }
647}
648
649impl IndexMut<Handle<Scene>> for SceneContainer {
650 #[inline]
651 fn index_mut(&mut self, index: Handle<Scene>) -> &mut Self::Output {
652 &mut self.pool[index]
653 }
654}