rafx_framework/visibility/
view_frustum_arc.rs

1use crate::visibility::{VisibilityConfig, VisibilityResource};
2use crate::RafxResult;
3use crossbeam_channel::Sender;
4use glam::Vec3;
5use parking_lot::{RwLock, RwLockReadGuard};
6use rafx_api::RafxError;
7use rafx_visibility::{AsyncCommand, Projection, ViewFrustumHandle, VisibilityQuery, ZoneHandle};
8use std::sync::Arc;
9
10pub type ViewFrustumId = (Option<ViewFrustumHandle>, Option<ViewFrustumHandle>);
11
12struct ViewFrustumArcInner {
13    visibility_query: RwLock<VisibilityQuery>,
14    static_view_frustum: Option<ViewFrustumRaii>,
15    dynamic_view_frustum: Option<ViewFrustumRaii>,
16}
17
18#[derive(Clone)]
19pub struct ViewFrustumArc {
20    inner: Arc<ViewFrustumArcInner>,
21}
22
23impl ViewFrustumArc {
24    pub fn new(
25        static_view_frustum: Option<ViewFrustumRaii>,
26        dynamic_view_frustum: Option<ViewFrustumRaii>,
27    ) -> Self {
28        Self {
29            inner: Arc::new(ViewFrustumArcInner {
30                visibility_query: Default::default(),
31                static_view_frustum,
32                dynamic_view_frustum,
33            }),
34        }
35    }
36
37    pub fn view_frustum_id(&self) -> ViewFrustumId {
38        (
39            self.inner.static_view_frustum.as_ref().map(|x| x.handle),
40            self.inner.dynamic_view_frustum.as_ref().map(|x| x.handle),
41        )
42    }
43
44    #[allow(dead_code)]
45    pub(super) fn set_zone(
46        &self,
47        static_zone: Option<ZoneHandle>,
48        dynamic_zone: Option<ZoneHandle>,
49    ) -> &Self {
50        if let Some(static_view_frustum) = &self.inner.static_view_frustum {
51            static_view_frustum.set_zone(static_zone);
52        }
53
54        if let Some(dynamic_view_frustum) = &self.inner.dynamic_view_frustum {
55            dynamic_view_frustum.set_zone(dynamic_zone);
56        }
57
58        self
59    }
60
61    pub fn set_transform(
62        &self,
63        eye: Vec3,
64        look_at: Vec3,
65        up: Vec3,
66    ) -> &Self {
67        if let Some(static_view_frustum) = &self.inner.static_view_frustum {
68            static_view_frustum.set_transform(eye, look_at, up);
69        }
70
71        if let Some(dynamic_view_frustum) = &self.inner.dynamic_view_frustum {
72            dynamic_view_frustum.set_transform(eye, look_at, up);
73        }
74
75        self
76    }
77
78    pub fn set_projection(
79        &self,
80        projection: &Projection,
81    ) -> &Self {
82        if let Some(static_view_frustum) = &self.inner.static_view_frustum {
83            static_view_frustum.set_projection(projection);
84        }
85
86        if let Some(dynamic_view_frustum) = &self.inner.dynamic_view_frustum {
87            dynamic_view_frustum.set_projection(projection);
88        }
89
90        self
91    }
92
93    pub fn query_visibility(
94        &self,
95        visibility_resource: &VisibilityResource,
96        visibility_config: &VisibilityConfig,
97    ) -> RafxResult<RwLockReadGuard<VisibilityQuery>> {
98        if visibility_config.enable_visibility_update {
99            let mut results = self.inner.visibility_query.write();
100
101            results.objects.clear();
102            results.volumes.clear();
103            if let Some(static_view_frustum) = &self.inner.static_view_frustum {
104                static_view_frustum.query_visibility(visibility_resource, &mut results)?;
105            }
106
107            if let Some(dynamic_view_frustum) = &self.inner.dynamic_view_frustum {
108                dynamic_view_frustum.query_visibility(visibility_resource, &mut results)?;
109            }
110        }
111
112        Ok(self.inner.visibility_query.read())
113    }
114}
115
116// An RAII object for a ViewFrustumHandle
117pub struct ViewFrustumRaii {
118    commands: Sender<AsyncCommand>,
119    handle: ViewFrustumHandle,
120}
121
122impl Drop for ViewFrustumRaii {
123    fn drop(&mut self) {
124        let _ = self
125            .commands
126            .send(AsyncCommand::DestroyViewFrustum(self.handle));
127    }
128}
129
130impl ViewFrustumRaii {
131    pub fn new(
132        handle: ViewFrustumHandle,
133        commands: Sender<AsyncCommand>,
134    ) -> Self {
135        Self { handle, commands }
136    }
137
138    #[allow(dead_code)]
139    pub(super) fn set_zone(
140        &self,
141        zone: Option<ZoneHandle>,
142    ) -> &Self {
143        self.commands
144            .send(AsyncCommand::SetViewFrustumZone(self.handle, zone))
145            .expect("Unable to send SetViewFrustumZone command.");
146        self
147    }
148
149    pub fn set_transform(
150        &self,
151        eye: Vec3,
152        look_at: Vec3,
153        up: Vec3,
154    ) -> &Self {
155        self.commands
156            .send(AsyncCommand::SetViewFrustumTransforms(
157                self.handle,
158                eye,
159                look_at,
160                up,
161            ))
162            .expect("Unable to send SetViewFrustumTransforms command.");
163        self
164    }
165
166    pub fn set_projection(
167        &self,
168        projection: &Projection,
169    ) -> &Self {
170        self.commands
171            .send(AsyncCommand::SetViewFrustumProjection(
172                self.handle,
173                projection.clone(),
174            ))
175            .expect("Unable to send SetViewFrustumProjection command.");
176        self
177    }
178
179    pub fn query_visibility(
180        &self,
181        visibility_resource: &VisibilityResource,
182        results: &mut VisibilityQuery,
183    ) -> RafxResult<()> {
184        visibility_resource
185            .world()
186            .query_visibility(self.handle, results)
187            .map_err(|_err| RafxError::StringError("Unable to query visibility.".to_string()))?;
188        Ok(())
189    }
190}