use concinnity_core::ecs::World;
use concinnity_core::render::backend::{GpuProfile, RenderBackend};
use concinnity_host::store::paths::StateTree;
use crate::animation::AnimationSystem;
use crate::app::budget::{MemoryBudget, ThreadBudget};
use crate::app::mem_drift::MemoryDrift;
use crate::ecs::ActiveRenderBackend;
use crate::gfx::streaming::system::{StreamingPressure, StreamingState, StreamingStats};
use crate::gfx::system::hot_reload_sources::HotReloadSources;
use crate::gfx::system::parked::{PushedFogSettings, TextureNameSlots};
pub fn renders(world: &World) -> bool {
world
.resource::<crate::ecs::render_mode::RenderMode>()
.is_some_and(|m| m.renders())
|| world.systems().iter().any(|s| {
s.downcast_ref::<crate::gfx::system::GraphicsSystem>()
.is_some()
})
}
pub fn streaming_stats(world: &World) -> Option<StreamingStats> {
world
.resource::<StreamingState>()
.map(|s| s.streaming_stats())
}
pub fn streaming_pressure(world: &World) -> Option<StreamingPressure> {
world.resource::<StreamingPressure>().copied()
}
pub fn memory_drift(world: &World) -> Option<MemoryDrift> {
world.resource::<MemoryDrift>().copied()
}
pub fn gpu_profile(world: &World) -> Option<GpuProfile> {
world.resource::<GpuProfile>().copied()
}
pub fn state_tree(world: &World) -> Option<&StateTree> {
world.resource::<StateTree>()
}
pub fn thread_budget(world: &World) -> Option<ThreadBudget> {
world.resource::<ThreadBudget>().copied()
}
pub fn memory_budget(world: &World) -> Option<MemoryBudget> {
world.resource::<MemoryBudget>().copied()
}
pub fn take_render_backend(world: &mut World) -> Option<Box<dyn RenderBackend>> {
world
.resource_mut::<ActiveRenderBackend>()
.and_then(|slot| slot.0.take())
}
pub struct RenderHandoff<'a> {
pub backend: Option<&'a mut (dyn RenderBackend + 'static)>,
pub fog: Option<&'a mut PushedFogSettings>,
pub texture_slots: Option<&'a TextureNameSlots>,
}
pub fn render_handoff(world: &mut World) -> RenderHandoff<'_> {
let (_, resources) = world.systems_and_resources();
let (backend, fog, texture_slots) =
resources.get_disjoint_mut::<ActiveRenderBackend, PushedFogSettings, TextureNameSlots>();
RenderHandoff {
backend: backend.and_then(|slot| slot.0.as_deref_mut()),
fog,
texture_slots: texture_slots.map(|slots| &*slots),
}
}
pub fn take_hot_reload_sources(world: &mut World) -> Option<HotReloadSources> {
world.remove_resource::<HotReloadSources>()
}
pub fn animation_system_mut(world: &mut World) -> Option<&mut AnimationSystem> {
world
.systems_mut()
.iter_mut()
.find_map(|system| system.downcast_mut::<AnimationSystem>())
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn the_published_run_mode_is_what_renders_reports() {
use crate::ecs::render_mode::RenderMode;
let mut world = World::new();
assert!(!renders(&world), "an unresolved world renders nothing");
world.insert_resource(RenderMode::Headless);
assert!(!renders(&world));
world.insert_resource(RenderMode::Rendered);
assert!(renders(&world));
}
#[test]
fn streaming_readouts_are_absent_before_graphics_init() {
let world = World::new();
assert!(streaming_stats(&world).is_none());
assert!(streaming_pressure(&world).is_none());
}
#[test]
fn render_backend_accessors_without_a_backend() {
let mut world = World::new();
assert!(take_render_backend(&mut world).is_none());
assert!(take_hot_reload_sources(&mut world).is_none());
assert!(animation_system_mut(&mut world).is_none());
let handoff = render_handoff(&mut world);
assert!(handoff.backend.is_none());
assert!(handoff.fog.is_none());
assert!(handoff.texture_slots.is_none());
}
#[test]
fn render_handoff_borrows_the_parked_state_together() {
let mut world = World::new();
world.insert_resource(PushedFogSettings(None));
world.insert_resource(TextureNameSlots(
[(concinnity_core::ecs::asset_id::AssetId(3), 7)].into(),
));
world.insert_resource(HotReloadSources::default());
let handoff = render_handoff(&mut world);
assert!(handoff.backend.is_none());
let slots = handoff.texture_slots.expect("texture-name map parked");
assert_eq!(slots.0.len(), 1);
let fog = concinnity_core::render::volumetric_fog::resolve_asset(
&concinnity_core::components::VolumetricFog {
enabled: true,
..Default::default()
},
);
handoff.fog.expect("fog parked").0 = fog;
assert!(world.resource::<PushedFogSettings>().unwrap().0.is_some());
assert!(take_hot_reload_sources(&mut world).is_some());
assert!(take_hot_reload_sources(&mut world).is_none());
}
}