rafx_framework/visibility/
view_frustum_arc.rs1use 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
116pub 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}