rafx_framework/visibility/
visibility_object_allocator.rs

1use 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        // We don't currently use the ID
116        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}