rafx_framework/visibility/
visibility_object_allocator.rs1use crate::render_features::RenderObjectHandle;
2use crate::visibility::view_frustum_arc::{ViewFrustumArc, ViewFrustumRaii};
3use crate::visibility::visibility_object_arc::{
4 CullModel, VisibilityObjectArc, VisibilityObjectRaii, VisibilityObjectWeakArcInner,
5};
6use crate::visibility::ObjectId;
7use crossbeam_channel::{Receiver, Sender};
8use rafx_visibility::{ModelHandle, VisibilityWorld, ZoneHandle};
9use slotmap::SlotMap;
10use slotmap::{new_key_type, Key};
11
12new_key_type! { pub struct VisibilityObjectId; }
13new_key_type! { pub struct ViewFrustumObjectId; }
14
15pub struct VisibilityObjectAllocator {
16 visibility_objects: SlotMap<VisibilityObjectId, VisibilityObjectWeakArcInner>,
17 visibility_world: VisibilityWorld,
18 visibility_object_drop_tx: Sender<VisibilityObjectId>,
19 visibility_object_drop_rx: Receiver<VisibilityObjectId>,
20}
21
22impl VisibilityObjectAllocator {
23 pub(super) fn new(visibility_world: VisibilityWorld) -> Self {
24 let (visibility_object_drop_tx, visibility_object_drop_rx) = crossbeam_channel::unbounded();
25
26 VisibilityObjectAllocator {
27 visibility_world,
28 visibility_object_drop_tx,
29 visibility_object_drop_rx,
30 visibility_objects: Default::default(),
31 }
32 }
33
34 pub(super) fn world(&self) -> &VisibilityWorld {
35 &self.visibility_world
36 }
37
38 pub fn update(&mut self) {
39 for id in self.visibility_object_drop_rx.try_iter() {
40 self.visibility_objects.remove(id);
41 }
42 self.visibility_world.update();
43 }
44
45 pub fn try_destroy_model(
46 &mut self,
47 model: ModelHandle,
48 ) -> bool {
49 self.visibility_world.inner.destroy_model(model)
50 }
51
52 pub fn new_cull_model(
53 &mut self,
54 cull_model: CullModel,
55 ) -> Option<ModelHandle> {
56 let inner = &mut self.visibility_world.inner;
57 match cull_model {
58 CullModel::Mesh(polygons) => Some(inner.new_model(polygons)),
59 CullModel::Sphere(radius) => Some(inner.new_bounding_sphere(radius)),
60 CullModel::Quad(width, height) => Some(inner.new_quad(width, height)),
61 CullModel::VisibleBounds(bounds) => Some(inner.new_visible_bounds(bounds)),
62 CullModel::None => None,
63 }
64 }
65
66 pub fn new_object(
67 &mut self,
68 object_id: ObjectId,
69 cull_model: CullModel,
70 render_objects: Vec<RenderObjectHandle>,
71 zone: Option<ZoneHandle>,
72 ) -> VisibilityObjectArc {
73 let cull_model = self.new_cull_model(cull_model);
74 let handle = self.visibility_world.inner.new_object();
75
76 let object = VisibilityObjectArc::new(
77 VisibilityObjectRaii::new(
78 object_id,
79 render_objects,
80 handle.clone(),
81 self.visibility_world.new_async_command_sender(),
82 ),
83 self.visibility_object_drop_tx.clone(),
84 );
85 let id = self.visibility_objects.insert(object.downgrade());
86 object.set_visibility_object_id(id);
87
88 let inner = &mut self.visibility_world.inner;
89 inner.set_object_id(handle, id.data().as_ffi());
90 inner.set_object_cull_model(handle, cull_model);
91 inner.set_object_zone(handle, zone);
92 object
93 }
94
95 pub fn object_ref(
96 &self,
97 id: VisibilityObjectId,
98 ) -> Option<VisibilityObjectArc> {
99 self.visibility_objects
100 .get(id)
101 .map(|x| x.upgrade())
102 .flatten()
103 }
104
105 pub fn new_view_frustum(
106 &mut self,
107 static_zone: Option<ZoneHandle>,
108 dynamic_zone: Option<ZoneHandle>,
109 ) -> ViewFrustumArc {
110 assert!(
111 static_zone.is_some() || dynamic_zone.is_some(),
112 "A ViewFrustumObject requires at least one defined Zone."
113 );
114
115 const UNUSED_ID: u64 = u64::MAX;
117
118 let async_command_sender = self.visibility_world.new_async_command_sender();
119 let inner = &mut self.visibility_world.inner;
120 let static_view_frustum = static_zone.map(|region| {
121 let handle = inner.new_view_frustum();
122 inner.set_view_frustum_zone(handle, Some(region));
123 inner.set_view_frustum_id(handle, UNUSED_ID);
124 let static_object = ViewFrustumRaii::new(handle, async_command_sender);
125
126 static_object
127 });
128
129 let async_command_sender = self.visibility_world.new_async_command_sender();
130 let inner = &mut self.visibility_world.inner;
131 let dynamic_view_frustum = dynamic_zone.map(|region| {
132 let handle = inner.new_view_frustum();
133 inner.set_view_frustum_zone(handle, Some(region));
134 inner.set_view_frustum_id(handle, UNUSED_ID);
135 let dynamic_object = ViewFrustumRaii::new(handle, async_command_sender);
136 dynamic_object
137 });
138
139 ViewFrustumArc::new(static_view_frustum, dynamic_view_frustum)
140 }
141}