rafx_framework/visibility/
visibility_object_arc.rs

1use crate::render_features::RenderObjectHandle;
2use crate::visibility::visibility_object_allocator::VisibilityObjectId;
3use crate::visibility::ObjectId;
4use crossbeam_channel::Sender;
5use glam::{Quat, Vec3};
6use rafx_visibility::geometry::Transform;
7use rafx_visibility::{
8    AsyncCommand, ModelHandle, PolygonSoup, VisibilityObjectHandle, VisibleBounds, ZoneHandle,
9};
10use slotmap::Key;
11use std::sync::atomic::{AtomicU64, Ordering};
12use std::sync::{Arc, Weak};
13
14pub enum CullModel {
15    Mesh(PolygonSoup),
16    VisibleBounds(VisibleBounds),
17    Sphere(f32),
18    Quad(f32, f32),
19    None,
20}
21
22impl CullModel {
23    pub fn mesh(polygon_soup: PolygonSoup) -> CullModel {
24        CullModel::Mesh(polygon_soup)
25    }
26
27    pub fn visible_bounds(model: VisibleBounds) -> CullModel {
28        CullModel::VisibleBounds(model)
29    }
30
31    pub fn sphere(radius: f32) -> CullModel {
32        CullModel::Sphere(radius)
33    }
34
35    pub fn quad(
36        width: f32,
37        height: f32,
38    ) -> CullModel {
39        CullModel::Quad(width, height)
40    }
41
42    pub fn none() -> CullModel {
43        CullModel::None
44    }
45}
46
47pub struct VisibilityObjectArcInner {
48    object: VisibilityObjectRaii,
49    // This corresponds to the key in VisibilityObjectAllocator::visibility_objects. It's set after
50    // we insert VisibilityObjectArc into the slot map
51    visibility_object_id: AtomicU64,
52    drop_tx: Sender<VisibilityObjectId>,
53}
54
55impl Drop for VisibilityObjectArcInner {
56    fn drop(&mut self) {
57        let _ = self
58            .drop_tx
59            .send(VisibilityObjectId::from(slotmap::KeyData::from_ffi(
60                self.visibility_object_id.load(Ordering::Relaxed),
61            )));
62    }
63}
64
65pub struct VisibilityObjectWeakArcInner {
66    inner: Weak<VisibilityObjectArcInner>,
67}
68
69impl VisibilityObjectWeakArcInner {
70    pub fn upgrade(&self) -> Option<VisibilityObjectArc> {
71        self.inner
72            .upgrade()
73            .map(|inner| VisibilityObjectArc { inner })
74    }
75}
76
77#[derive(Clone)]
78pub struct VisibilityObjectArc {
79    inner: Arc<VisibilityObjectArcInner>,
80}
81
82impl VisibilityObjectArc {
83    pub(crate) fn new(
84        object: VisibilityObjectRaii,
85        drop_tx: Sender<VisibilityObjectId>,
86    ) -> Self {
87        Self {
88            inner: Arc::new(VisibilityObjectArcInner {
89                object,
90                visibility_object_id: AtomicU64::default(),
91                drop_tx,
92            }),
93        }
94    }
95
96    pub fn downgrade(&self) -> VisibilityObjectWeakArcInner {
97        VisibilityObjectWeakArcInner {
98            inner: Arc::downgrade(&self.inner),
99        }
100    }
101
102    pub(super) fn set_visibility_object_id(
103        &self,
104        visibility_object_id: VisibilityObjectId,
105    ) {
106        self.inner
107            .visibility_object_id
108            .store(visibility_object_id.data().as_ffi(), Ordering::Relaxed);
109    }
110
111    #[allow(dead_code)]
112    pub(super) fn set_zone(
113        &self,
114        zone: Option<ZoneHandle>,
115    ) -> &Self {
116        self.inner.object.set_zone(zone);
117        self
118    }
119
120    pub fn object_id(&self) -> ObjectId {
121        self.inner.object.object_id()
122    }
123
124    // This is
125    pub fn visibility_object_handle(&self) -> VisibilityObjectHandle {
126        self.inner.object.handle
127    }
128
129    pub fn render_objects(&self) -> &[RenderObjectHandle] {
130        &self.inner.object.render_objects()
131    }
132
133    pub fn set_cull_model(
134        &self,
135        cull_model: Option<ModelHandle>,
136    ) -> &Self {
137        self.inner.object.set_cull_model(cull_model);
138        self
139    }
140
141    pub fn set_transform(
142        &self,
143        translation: Vec3,
144        rotation: Quat,
145        scale: Vec3,
146    ) -> &Self {
147        self.inner
148            .object
149            .set_transform(translation, rotation, scale);
150        self
151    }
152}
153
154// An RAII object for a visibility VisibilityObjectHandle
155pub struct VisibilityObjectRaii {
156    commands: Sender<AsyncCommand>,
157    handle: VisibilityObjectHandle,
158    object_id: ObjectId,
159    render_objects: Vec<RenderObjectHandle>, // TODO(dvd): This might be better as a SmallVec.
160}
161
162impl Drop for VisibilityObjectRaii {
163    fn drop(&mut self) {
164        // NOTE(dvd): Destroy the associated Object in the visibility world.
165        let _ = self.commands.send(AsyncCommand::DestroyObject(self.handle));
166    }
167}
168
169impl VisibilityObjectRaii {
170    pub fn new(
171        object_id: ObjectId,
172        render_objects: Vec<RenderObjectHandle>,
173        handle: VisibilityObjectHandle,
174        commands: Sender<AsyncCommand>,
175    ) -> Self {
176        Self {
177            commands,
178            handle,
179            object_id,
180            render_objects,
181        }
182    }
183
184    #[allow(dead_code)]
185    pub(super) fn set_zone(
186        &self,
187        zone: Option<ZoneHandle>,
188    ) -> &Self {
189        self.commands
190            .send(AsyncCommand::SetObjectZone(self.handle, zone))
191            .expect("Unable to send SetObjectZone command.");
192        self
193    }
194
195    pub fn object_id(&self) -> ObjectId {
196        self.object_id
197    }
198
199    pub fn render_objects(&self) -> &[RenderObjectHandle] {
200        &self.render_objects
201    }
202
203    pub fn set_cull_model(
204        &self,
205        cull_model: Option<ModelHandle>,
206    ) -> &Self {
207        self.commands
208            .send(AsyncCommand::SetObjectCullModel(self.handle, cull_model))
209            .expect("Unable to send SetObjectCullModel command.");
210        self
211    }
212
213    pub fn set_transform(
214        &self,
215        translation: Vec3,
216        rotation: Quat,
217        scale: Vec3,
218    ) -> &Self {
219        self.commands
220            .send(AsyncCommand::SetObjectTransform(
221                self.handle,
222                Transform {
223                    translation,
224                    rotation,
225                    scale,
226                },
227            ))
228            .expect("Unable to send SetObjectPosition command.");
229        self
230    }
231}