1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
use crate::visibility::view_frustum_arc::{ViewFrustumArc, ViewFrustumObject}; use crate::visibility::visibility_object_arc::{CullModel, VisibilityObject, VisibilityObjectArc}; use crate::visibility::EntityId; use parking_lot::{RwLock, RwLockReadGuard}; use rafx_visibility::{ModelHandle, VisibilityWorldArc, ZoneHandle}; use slotmap::SlotMap; use slotmap::{new_key_type, Key}; use std::ops::Deref; use std::sync::Arc; new_key_type! { pub struct VisibilityObjectId; } new_key_type! { pub struct ViewFrustumObjectId; } pub(super) type SlotMapArc<K, V> = Arc<RwLock<SlotMap<K, V>>>; pub struct VisibilityObjectRef<'a>( RwLockReadGuard<'a, SlotMap<VisibilityObjectId, VisibilityObject>>, VisibilityObjectId, ); impl<'a> Deref for VisibilityObjectRef<'a> { type Target = VisibilityObject; fn deref(&self) -> &Self::Target { self.0.get(self.1).unwrap() } } #[derive(Clone)] pub struct VisibilityObjectAllocator { view_frustums: SlotMapArc<ViewFrustumObjectId, ViewFrustumObject>, objects: SlotMapArc<VisibilityObjectId, VisibilityObject>, visibility_world: VisibilityWorldArc, } impl VisibilityObjectAllocator { pub(super) fn new(visibility_world: VisibilityWorldArc) -> Self { VisibilityObjectAllocator { visibility_world, view_frustums: Default::default(), objects: Default::default(), } } pub fn try_destroy_model( &self, model: ModelHandle, ) -> bool { let mut inner = self.visibility_world.inner.lock(); inner.destroy_model(model) } pub fn new_cull_model( &self, cull_model: CullModel, ) -> Option<ModelHandle> { let mut inner = self.visibility_world.inner.lock(); match cull_model { CullModel::Mesh(polygons) => Some(inner.new_model(polygons)), CullModel::Sphere(radius) => Some(inner.new_bounding_sphere(radius)), CullModel::Quad(width, height) => Some(inner.new_quad(width, height)), CullModel::VisibleBounds(bounds) => Some(inner.new_visible_bounds(bounds)), CullModel::None => None, } } pub fn new_object( &self, entity_id: EntityId, cull_model: CullModel, zone: Option<ZoneHandle>, ) -> VisibilityObjectArc { let cull_model = self.new_cull_model(cull_model); let mut inner = self.visibility_world.inner.lock(); let handle = inner.new_object(); let id = self.objects.write().insert(VisibilityObject::new( entity_id, handle.clone(), self.visibility_world.new_async_command_sender(), )); inner.set_object_id(handle, id.data().as_ffi()); inner.set_object_cull_model(handle, cull_model); inner.set_object_zone(handle, zone); VisibilityObjectArc::new(id, self.objects.clone()) } pub fn object_ref( &self, id: VisibilityObjectId, ) -> VisibilityObjectRef { let guard = self.objects.read(); VisibilityObjectRef(guard, id) } pub fn new_view_frustum( &self, static_zone: Option<ZoneHandle>, dynamic_zone: Option<ZoneHandle>, ) -> ViewFrustumArc { assert!( static_zone.is_some() || dynamic_zone.is_some(), "A ViewFrustumObject requires at least one defined Zone." ); let mut inner = self.visibility_world.inner.lock(); let mut view_frustums = self.view_frustums.write(); let static_view_frustum = static_zone.map(|region| { let handle = inner.new_view_frustum(); inner.set_view_frustum_zone(handle, Some(region)); let id = view_frustums.insert(ViewFrustumObject::new( handle, self.visibility_world.new_async_command_sender(), self.visibility_world.clone(), )); inner.set_view_frustum_id(handle, id.data().as_ffi()); id }); let dynamic_view_frustum = dynamic_zone.map(|region| { let handle = inner.new_view_frustum(); inner.set_view_frustum_zone(handle, Some(region)); let id = view_frustums.insert(ViewFrustumObject::new( handle, self.visibility_world.new_async_command_sender(), self.visibility_world.clone(), )); inner.set_view_frustum_id(handle, id.data().as_ffi()); id }); ViewFrustumArc::new( static_view_frustum, dynamic_view_frustum, self.view_frustums.clone(), self.visibility_world.clone(), ) } }