use super::super::asset::{SceneAsset, with_serialized_object};
use super::super::configuration::{DefaultSimulationConfiguration, SimulationConfiguration};
use super::super::simulation::Simulation;
use super::instanced_mesh::{InstancedMesh, SpawnedInstancedMesh, SubSceneOf};
use super::static_mesh::SpawnedStaticMesh;
use crate::callback::{CustomRayTracingCallbacks, ProgressCallback};
use crate::context::Context;
use crate::device::{EmbreeDevice, RadeonRaysDevice};
use crate::error::SteamAudioError;
use crate::ray_tracing::{CustomRayTracer, DefaultRayTracer, Embree, RadeonRays};
use crate::serialized_object::SerializedObject;
use bevy::prelude::{
Add, ChildOf, Commands, Component, Entity, Local, On, Query, Reflect, ReflectComponent, Remove,
ResMut, With, Without,
};
use std::ops::{Deref, DerefMut};
#[derive(Component, Reflect, Debug)]
#[reflect(Component, opaque)]
#[require(SceneStatus)]
pub struct Scene<C: SimulationConfiguration = DefaultSimulationConfiguration>(
pub crate::geometry::Scene<C::RayTracer>,
);
impl<C: SimulationConfiguration> Clone for Scene<C> {
fn clone(&self) -> Self {
Self(self.0.clone())
}
}
impl<C> Scene<C>
where
C: SimulationConfiguration<RayTracer = DefaultRayTracer>,
{
pub fn try_new(context: &Context) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<DefaultRayTracer>::try_new(context).map(Self)
}
pub fn load(
context: &Context,
serialized_object: &SerializedObject,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<DefaultRayTracer>::load(context, serialized_object).map(Self)
}
pub fn from_asset(context: &Context, asset: &SceneAsset) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load(context, serialized_object)
})
}
pub fn load_with_progress(
context: &Context,
serialized_object: &SerializedObject,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<DefaultRayTracer>::load_with_progress(
context,
serialized_object,
progress_callback,
)
.map(Self)
}
pub fn from_asset_with_progress(
context: &Context,
asset: &SceneAsset,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_with_progress(context, serialized_object, progress_callback)
})
}
}
impl<C> Scene<C>
where
C: SimulationConfiguration<RayTracer = Embree>,
{
pub fn try_with_embree(
context: &Context,
device: EmbreeDevice,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<Embree>::try_with_embree(context, device).map(Self)
}
pub fn load_embree(
context: &Context,
device: EmbreeDevice,
serialized_object: &SerializedObject,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<Embree>::load_embree(context, device, serialized_object).map(Self)
}
pub fn from_asset_with_embree(
context: &Context,
device: EmbreeDevice,
asset: &SceneAsset,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_embree(context, device, serialized_object)
})
}
pub fn load_embree_with_progress(
context: &Context,
device: EmbreeDevice,
serialized_object: &SerializedObject,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<Embree>::load_embree_with_progress(
context,
device,
serialized_object,
progress_callback,
)
.map(Self)
}
pub fn from_asset_with_embree_progress(
context: &Context,
device: EmbreeDevice,
asset: &SceneAsset,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_embree_with_progress(context, device, serialized_object, progress_callback)
})
}
}
impl<C> Scene<C>
where
C: SimulationConfiguration<RayTracer = RadeonRays>,
{
pub fn try_with_radeon_rays(
context: &Context,
device: RadeonRaysDevice,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<RadeonRays>::try_with_radeon_rays(context, device).map(Self)
}
pub fn load_radeon_rays(
context: &Context,
device: RadeonRaysDevice,
serialized_object: &SerializedObject,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<RadeonRays>::load_radeon_rays(context, device, serialized_object)
.map(Self)
}
pub fn from_asset_with_radeon_rays(
context: &Context,
device: RadeonRaysDevice,
asset: &SceneAsset,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_radeon_rays(context, device, serialized_object)
})
}
pub fn load_radeon_rays_with_progress(
context: &Context,
device: RadeonRaysDevice,
serialized_object: &SerializedObject,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<RadeonRays>::load_radeon_rays_with_progress(
context,
device,
serialized_object,
progress_callback,
)
.map(Self)
}
pub fn from_asset_with_radeon_rays_progress(
context: &Context,
device: RadeonRaysDevice,
asset: &SceneAsset,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_radeon_rays_with_progress(
context,
device,
serialized_object,
progress_callback,
)
})
}
}
impl<C> Scene<C>
where
C: SimulationConfiguration<RayTracer = CustomRayTracer>,
{
pub fn try_with_custom(
context: &Context,
callbacks: CustomRayTracingCallbacks,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<CustomRayTracer>::try_with_custom(context, callbacks).map(Self)
}
pub fn load_custom(
context: &Context,
callbacks: CustomRayTracingCallbacks,
serialized_object: &SerializedObject,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<CustomRayTracer>::load_custom(
context,
callbacks,
serialized_object,
)
.map(Self)
}
pub fn from_asset_with_custom(
context: &Context,
callbacks: CustomRayTracingCallbacks,
asset: &SceneAsset,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_custom(context, callbacks, serialized_object)
})
}
pub fn load_custom_with_progress(
context: &Context,
callbacks: CustomRayTracingCallbacks,
serialized_object: &SerializedObject,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
crate::geometry::Scene::<CustomRayTracer>::load_custom_with_progress(
context,
callbacks,
serialized_object,
progress_callback,
)
.map(Self)
}
pub fn from_asset_with_custom_progress(
context: &Context,
callbacks: CustomRayTracingCallbacks,
asset: &SceneAsset,
progress_callback: ProgressCallback,
) -> Result<Self, SteamAudioError> {
with_serialized_object(context, asset.bytes().to_vec(), |serialized_object| {
Self::load_custom_with_progress(
context,
callbacks,
serialized_object,
progress_callback,
)
})
}
}
impl<C: SimulationConfiguration> Deref for Scene<C> {
type Target = crate::geometry::Scene<C::RayTracer>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl<C: SimulationConfiguration> DerefMut for Scene<C> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl<C: SimulationConfiguration> From<crate::geometry::Scene<C::RayTracer>> for Scene<C> {
fn from(scene: crate::geometry::Scene<C::RayTracer>) -> Self {
Self(scene)
}
}
#[derive(Component, Default, Copy, Clone, Debug)]
pub(crate) struct SceneStatus {
pub commit_needed: bool,
}
#[derive(Component, Reflect, Debug)]
#[reflect(Component)]
#[component(storage = "SparseSet")]
pub struct MainScene;
pub(crate) fn commit_scenes<C: SimulationConfiguration>(
simulation: ResMut<Simulation<C>>,
mut scenes: Query<(&mut Scene<C>, &mut SceneStatus)>,
) {
let scenes_iter = scenes.iter_mut();
let mut scenes_pending_commit = Vec::with_capacity(scenes_iter.len());
for (scene, mut scene_status) in scenes_iter {
if scene_status.commit_needed {
scenes_pending_commit.push(scene.0.clone());
scene_status.commit_needed = false;
}
}
simulation
.0
.request_scene_commits(scenes_pending_commit.as_slice());
}
#[cfg(debug_assertions)]
pub(crate) fn warn_missing_main_scene<C: SimulationConfiguration>(
scenes: Query<Entity, (With<Scene<C>>, Without<SubSceneOf>)>,
main_scenes: Query<Entity, With<MainScene>>,
mut warned: Local<bool>,
) {
if *warned || scenes.is_empty() || !main_scenes.is_empty() {
return;
}
*warned = true;
bevy::log::warn!(
"found Scene entities but no MainScene; add MainScene to the scene entity that should be used by the simulator."
);
}
pub(crate) fn on_main_scene_added<C: SimulationConfiguration>(
event: On<Add, MainScene>,
main_scenes: Query<Entity, With<MainScene>>,
mut commands: Commands,
mut simulation: ResMut<Simulation<C>>,
scenes: Query<&Scene<C>>,
) {
for entity in &main_scenes {
if entity != event.entity {
commands.entity(entity).remove::<MainScene>();
}
}
if let Ok(scene) = scenes.get(event.entity) {
simulation.0.simulator.set_scene(&scene.0);
simulation.0.request_simulator_commit();
}
}
pub(crate) fn on_scene_removed<C: SimulationConfiguration>(
event: On<Remove, Scene<C>>,
static_meshes: Query<(Entity, &SpawnedStaticMesh)>,
instanced_meshes: Query<(Entity, &InstancedMesh, Option<&SpawnedInstancedMesh>)>,
mut scenes: Query<(&mut Scene<C>, &mut SceneStatus)>,
main_scenes: Query<(), With<MainScene>>,
mut commands: Commands,
) {
let removed_scene_entity = event.entity;
if main_scenes.contains(removed_scene_entity)
&& let Ok(mut removed_scene_commands) = commands.get_entity(removed_scene_entity)
{
removed_scene_commands.remove::<MainScene>();
}
for (entity, spawned_static_mesh) in &static_meshes {
if spawned_static_mesh.scene_entity == removed_scene_entity {
commands.entity(entity).remove::<SpawnedStaticMesh>();
}
}
for (entity, instanced_mesh, spawned_instanced_mesh_option) in &instanced_meshes {
let references_removed_scene = instanced_mesh.0 == removed_scene_entity
|| spawned_instanced_mesh_option.is_some_and(|spawned_instanced_mesh| {
spawned_instanced_mesh.scene_entity == removed_scene_entity
|| spawned_instanced_mesh.sub_scene_entity == removed_scene_entity
});
if !references_removed_scene {
continue;
}
if let Some(spawned_instanced_mesh) = spawned_instanced_mesh_option
&& spawned_instanced_mesh.scene_entity != removed_scene_entity
&& let Ok((mut scene, mut scene_status)) =
scenes.get_mut(spawned_instanced_mesh.scene_entity)
{
scene.0.remove_instanced_mesh(spawned_instanced_mesh.handle);
scene_status.commit_needed = true;
}
commands.entity(entity).remove::<SpawnedInstancedMesh>();
}
}
pub(super) fn find_scene_ancestor<C: SimulationConfiguration>(
entity: Entity,
parents: &Query<&ChildOf>,
scenes: &Query<(&mut Scene<C>, &mut SceneStatus)>,
) -> Option<Entity> {
if scenes.contains(entity) {
return Some(entity);
}
parents
.iter_ancestors(entity)
.find(|&ancestor| scenes.contains(ancestor))
}