khora_data/ecs/systems/
ibl_bake.rs1use std::sync::Arc;
22
23use khora_core::lane::OutputDeck;
24use khora_core::math::Vec3;
25use khora_core::renderer::api::resource::CpuTexture;
26use khora_core::renderer::light::LightType;
27use khora_core::renderer::traits::PipelineSystem;
28use khora_core::renderer::GraphicsDevice;
29use khora_core::Runtime;
30
31use crate::ecs::{DataSystemRegistration, GlobalTransform, Light, TickPhase, World};
32use crate::{AssetStore, EnvironmentMap, IblBaker};
33
34fn sun_direction(world: &World) -> Vec3 {
41 for (light, transform) in world.query::<(&Light, &GlobalTransform)>() {
42 if !light.enabled {
43 continue;
44 }
45 if let LightType::Directional(dir_light) = &light.light_type {
46 return -(transform.0.rotation() * dir_light.direction);
47 }
48 }
49 Vec3::ZERO
50}
51
52fn ibl_bake_system(world: &mut World, runtime: &Runtime, _deck: &mut OutputDeck) {
53 let Some(baker) = runtime.resources.get::<IblBaker>() else {
54 return;
55 };
56 if baker.is_baked() {
57 return;
58 }
59 let Some(device) = runtime.backends.get::<Arc<dyn GraphicsDevice>>() else {
60 return;
61 };
62 let Some(pipeline_system) = runtime.resources.get::<Arc<dyn PipelineSystem>>() else {
63 return;
64 };
65 let sun = sun_direction(world);
66
67 let env_store = runtime
71 .resources
72 .get::<EnvironmentMap>()
73 .and_then(|env| env.texture)
74 .and_then(|uuid| {
75 let store = runtime.resources.get::<AssetStore>()?.store::<CpuTexture>();
76 Some((uuid, store))
77 });
78 match env_store {
79 Some((uuid, store)) => {
80 let guard = match store.read() {
81 Ok(guard) => guard,
82 Err(_) => {
83 log::error!("ibl_bake: CpuTexture store poisoned; baking procedural sky");
84 baker.ensure_baked(device.as_ref(), pipeline_system.as_ref(), sun, None);
85 return;
86 }
87 };
88 if guard.get(&uuid).is_none() {
89 if baker.wait_for_environment() {
94 return;
95 }
96 log::warn!(
97 "ibl_bake: environment texture {uuid:?} did not load in time; \
98 baking the procedural sky instead"
99 );
100 drop(guard);
101 baker.ensure_baked(device.as_ref(), pipeline_system.as_ref(), sun, None);
102 return;
103 }
104 baker.ensure_baked(
105 device.as_ref(),
106 pipeline_system.as_ref(),
107 sun,
108 guard.get(&uuid).map(|handle| &**handle),
109 );
110 }
111 None => baker.ensure_baked(device.as_ref(), pipeline_system.as_ref(), sun, None),
112 }
113}
114
115inventory::submit! {
116 DataSystemRegistration {
117 name: "ibl_bake",
118 phase: TickPhase::PreExtract,
119 run: ibl_bake_system,
120 order_hint: -10,
121 runs_after: &[],
122 }
123}