@@ -71,9 +71,44 @@ impl VisibleEntities {
7171 }
7272}
7373
74+ #[ derive( Debug , Default , Clone ) ]
75+ pub struct EntityMeshRelationships {
76+ entities_with_mesh : HashMap < Handle < Mesh > , SmallVec < [ Entity ; 1 ] > > ,
77+ mesh_for_entity : HashMap < Entity , Handle < Mesh > > ,
78+ }
79+
80+ impl EntityMeshRelationships {
81+ /// Register the passed `entity` has having the passed `mesh_handle`.
82+ ///
83+ /// Note that this list _could_ have duplicates if an entity is assigned a new mesh and
84+ /// then re-assigned the old mesh. This case should be rare so, for now, we'll risk
85+ /// duplicating `Aabb` cloning+assigning.
86+ fn register ( & mut self , entity : Entity , mesh_handle : & Handle < Mesh > ) {
87+ self . entities_with_mesh
88+ . entry ( mesh_handle. clone_weak ( ) )
89+ . or_default ( )
90+ . push ( entity) ;
91+ self . mesh_for_entity
92+ . insert ( entity, mesh_handle. clone_weak ( ) ) ;
93+ }
94+
95+ /// Deregisters the relationship between an `Entity` and `Mesh`. Used so [`update_bounds`] can
96+ /// track which relationships are still active so `Aabb`s are updated correctly.
97+ fn deregister ( & mut self , entity : Entity ) {
98+ if let Some ( mesh) = self . mesh_for_entity . remove ( & entity) {
99+ if let Some ( entities) = self . entities_with_mesh . get_mut ( & mesh) {
100+ if let Some ( idx) = entities. iter ( ) . position ( |& e| e == entity) {
101+ entities. swap_remove ( idx) ;
102+ }
103+ }
104+ }
105+ }
106+ }
107+
74108#[ derive( Debug , Hash , PartialEq , Eq , Clone , SystemLabel ) ]
75109pub enum VisibilitySystems {
76110 CalculateBounds ,
111+ UpdateBounds ,
77112 UpdateOrthographicFrusta ,
78113 UpdatePerspectiveFrusta ,
79114 UpdateProjectionFrusta ,
@@ -86,80 +121,108 @@ impl Plugin for VisibilityPlugin {
86121 fn build ( & self , app : & mut bevy_app:: App ) {
87122 use VisibilitySystems :: * ;
88123
89- app. add_system_to_stage (
90- CoreStage :: PostUpdate ,
91- calculate_bounds. label ( CalculateBounds ) ,
92- )
93- . add_system_to_stage (
94- CoreStage :: PostUpdate ,
95- update_frusta :: < OrthographicProjection >
96- . label ( UpdateOrthographicFrusta )
97- . after ( TransformSystem :: TransformPropagate ) ,
98- )
99- . add_system_to_stage (
100- CoreStage :: PostUpdate ,
101- update_frusta :: < PerspectiveProjection >
102- . label ( UpdatePerspectiveFrusta )
103- . after ( TransformSystem :: TransformPropagate ) ,
104- )
105- . add_system_to_stage (
106- CoreStage :: PostUpdate ,
107- update_frusta :: < Projection >
108- . label ( UpdateProjectionFrusta )
109- . after ( TransformSystem :: TransformPropagate ) ,
110- )
111- . add_system_to_stage (
112- CoreStage :: PostUpdate ,
113- check_visibility
114- . label ( CheckVisibility )
115- . after ( CalculateBounds )
116- . after ( UpdateOrthographicFrusta )
117- . after ( UpdatePerspectiveFrusta )
118- . after ( UpdateProjectionFrusta )
119- . after ( TransformSystem :: TransformPropagate ) ,
120- ) ;
124+ app. init_resource :: < EntityMeshRelationships > ( )
125+ . add_system_to_stage (
126+ CoreStage :: PostUpdate ,
127+ calculate_bounds. label ( CalculateBounds ) ,
128+ )
129+ . add_system_to_stage ( CoreStage :: PostUpdate , update_bounds. label ( UpdateBounds ) )
130+ . add_system_to_stage (
131+ CoreStage :: PostUpdate ,
132+ update_frusta :: < OrthographicProjection >
133+ . label ( UpdateOrthographicFrusta )
134+ . after ( TransformSystem :: TransformPropagate ) ,
135+ )
136+ . add_system_to_stage (
137+ CoreStage :: PostUpdate ,
138+ update_frusta :: < PerspectiveProjection >
139+ . label ( UpdatePerspectiveFrusta )
140+ . after ( TransformSystem :: TransformPropagate ) ,
141+ )
142+ . add_system_to_stage (
143+ CoreStage :: PostUpdate ,
144+ update_frusta :: < Projection >
145+ . label ( UpdateProjectionFrusta )
146+ . after ( TransformSystem :: TransformPropagate ) ,
147+ )
148+ . add_system_to_stage (
149+ CoreStage :: PostUpdate ,
150+ check_visibility
151+ . label ( CheckVisibility )
152+ . after ( CalculateBounds )
153+ . after ( UpdateOrthographicFrusta )
154+ . after ( UpdatePerspectiveFrusta )
155+ . after ( UpdateProjectionFrusta )
156+ . after ( TransformSystem :: TransformPropagate ) ,
157+ ) ;
121158 }
122159}
123160
124- /// Calculates and updates [`Aabb`]s for [`Entities`](Entity) with [`Mesh`]es.
125- /// To opt out of bound calculation for an `Entity`, give it the [`NoFrustumCulling`] component.
161+ /// Calculates [`Aabb`]s for [`Entities`](Entity) with [`Mesh`]es. To opt out of bound calculation
162+ /// for an `Entity`, give it the [`NoFrustumCulling`] component.
126163pub fn calculate_bounds (
127164 mut commands : Commands ,
128165 meshes : Res < Assets < Mesh > > ,
129- without_aabb_or_with_changed_mesh : Query <
130- ( Entity , & Handle < Mesh > ) ,
131- (
132- Or < ( Without < Aabb > , Changed < Handle < Mesh > > ) > ,
133- Without < NoFrustumCulling > ,
134- ) ,
135- > ,
136- mut entity_mesh_map : Local < HashMap < Handle < Mesh > , SmallVec < [ Entity ; 1 ] > > > ,
137- mut mesh_events : EventReader < AssetEvent < Mesh > > ,
166+ without_aabb : Query < ( Entity , & Handle < Mesh > ) , ( Without < Aabb > , Without < NoFrustumCulling > ) > ,
167+ mut entity_mesh_rel : ResMut < EntityMeshRelationships > ,
138168) {
139- for ( entity, mesh_handle) in without_aabb_or_with_changed_mesh. iter ( ) {
140- // Record entities that have mesh handles. Note that this list _could_ have duplicates if
141- // an entity is assigned a new mesh and then re-assigned the old mesh. This case should be
142- // rare so, for now, we'll risk duplicating `Aabb` cloning+assigning.
143- entity_mesh_map
144- . entry ( mesh_handle. clone_weak ( ) )
145- . or_default ( )
146- . push ( entity) ;
169+ for ( entity, mesh_handle) in without_aabb. iter ( ) {
170+ // Record entities whose Aabb's we're managing.
171+ entity_mesh_rel. register ( entity, mesh_handle) ;
147172
148173 if let Some ( mesh) = meshes. get ( mesh_handle) {
149174 if let Some ( aabb) = mesh. compute_aabb ( ) {
150175 commands. entity ( entity) . insert ( aabb) ;
151176 }
152177 }
153178 }
179+ }
180+
181+ /// Updates [`Aabb`]s for [`Entities`](Entity) with [`Mesh`]es. This includes `Entities` that have
182+ /// been assigned new `Mesh`es as well as `Entities` whose `Mesh` has been directly mutated.
183+ ///
184+ /// To opt out of bound calculation for an `Entity`, give it the [`NoFrustumCulling`] component.
185+ pub fn update_bounds (
186+ mut commands : Commands ,
187+ meshes : Res < Assets < Mesh > > ,
188+ mut mesh_reassigned : Query <
189+ ( Entity , & Handle < Mesh > , & mut Aabb ) ,
190+ ( Changed < Handle < Mesh > > , Without < NoFrustumCulling > ) ,
191+ > ,
192+ mut entity_mesh_rel : ResMut < EntityMeshRelationships > ,
193+ mut mesh_events : EventReader < AssetEvent < Mesh > > ,
194+ entities_lost_mesh : RemovedComponents < Handle < Mesh > > ,
195+ ) {
196+ // If an entity's mesh handle was removed, unlink them.
197+ for entity in entities_lost_mesh. iter ( ) {
198+ entity_mesh_rel. deregister ( entity) ;
199+ }
200+
201+ // If an entity with an Aabb was assigned a new mesh, move it to the new list and update its
202+ // Aabb.
203+ for ( entity, mesh_handle, mut aabb) in mesh_reassigned. iter_mut ( ) {
204+ // Remove it from the previous list
205+ entity_mesh_rel. deregister ( entity) ;
206+
207+ // Add it to the new list.
208+ entity_mesh_rel. register ( entity, mesh_handle) ;
209+
210+ // Update its Aabb
211+ if let Some ( mesh) = meshes. get ( mesh_handle) {
212+ if let Some ( new_aabb) = mesh. compute_aabb ( ) {
213+ * aabb = new_aabb;
214+ }
215+ }
216+ }
154217
155- // Calculate bounds for entities whose meshes have been mutated .
218+ // If an entity's mesh was mutated, update its Aabb .
156219 let to_update = |event : & AssetEvent < Mesh > | {
157220 let handle = match event {
158221 AssetEvent :: Modified { handle } => handle,
159222 _ => return None ,
160223 } ;
161224 let mesh = meshes. get ( handle) ?;
162- let entities_with_handle = entity_mesh_map . get ( handle) ?;
225+ let entities_with_handle = entity_mesh_rel . entities_with_mesh . get ( handle) ?;
163226 let aabb = mesh. compute_aabb ( ) ?;
164227 Some ( ( aabb, entities_with_handle) )
165228 } ;
0 commit comments