@@ -20,14 +20,15 @@ use bevy_camera::{
20
20
primitives:: Frustum ,
21
21
visibility:: { self , RenderLayers , VisibleEntities } ,
22
22
Camera , Camera2d , Camera3d , CameraMainTextureUsages , CameraOutputMode , CameraUpdateSystems ,
23
- ClearColor , ClearColorConfig , Exposure , NormalizedRenderTarget , Projection , RenderTargetInfo ,
24
- Viewport ,
23
+ ClearColor , ClearColorConfig , Exposure , ManualTextureViewHandle , NormalizedRenderTarget ,
24
+ Projection , RenderTargetInfo , Viewport ,
25
25
} ;
26
26
use bevy_derive:: { Deref , DerefMut } ;
27
27
use bevy_ecs:: {
28
28
change_detection:: DetectChanges ,
29
29
component:: Component ,
30
30
entity:: { ContainsEntity , Entity } ,
31
+ error:: BevyError ,
31
32
event:: EventReader ,
32
33
lifecycle:: HookContext ,
33
34
prelude:: With ,
@@ -167,7 +168,7 @@ pub trait NormalizedRenderTargetExt {
167
168
resolutions : impl IntoIterator < Item = ( Entity , & ' a Window ) > ,
168
169
images : & Assets < Image > ,
169
170
manual_texture_views : & ManualTextureViews ,
170
- ) -> Option < RenderTargetInfo > ;
171
+ ) -> Result < RenderTargetInfo , MissingRenderTargetInfoError > ;
171
172
172
173
// Check if this render target is contained in the given changed windows or images.
173
174
fn is_changed (
@@ -222,28 +223,34 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
222
223
resolutions : impl IntoIterator < Item = ( Entity , & ' a Window ) > ,
223
224
images : & Assets < Image > ,
224
225
manual_texture_views : & ManualTextureViews ,
225
- ) -> Option < RenderTargetInfo > {
226
+ ) -> Result < RenderTargetInfo , MissingRenderTargetInfoError > {
226
227
match self {
227
228
NormalizedRenderTarget :: Window ( window_ref) => resolutions
228
229
. into_iter ( )
229
230
. find ( |( entity, _) | * entity == window_ref. entity ( ) )
230
231
. map ( |( _, window) | RenderTargetInfo {
231
232
physical_size : window. physical_size ( ) ,
232
233
scale_factor : window. resolution . scale_factor ( ) ,
234
+ } )
235
+ . ok_or ( MissingRenderTargetInfoError :: Window {
236
+ window : window_ref. entity ( ) ,
233
237
} ) ,
234
- NormalizedRenderTarget :: Image ( image_target) => {
235
- let image = images . get ( & image_target. handle ) ? ;
236
- Some ( RenderTargetInfo {
238
+ NormalizedRenderTarget :: Image ( image_target) => images
239
+ . get ( & image_target. handle )
240
+ . map ( |image| RenderTargetInfo {
237
241
physical_size : image. size ( ) ,
238
242
scale_factor : image_target. scale_factor . 0 ,
239
243
} )
240
- }
241
- NormalizedRenderTarget :: TextureView ( id) => {
242
- manual_texture_views. get ( id) . map ( |tex| RenderTargetInfo {
244
+ . ok_or ( MissingRenderTargetInfoError :: Image {
245
+ image : image_target. handle . id ( ) ,
246
+ } ) ,
247
+ NormalizedRenderTarget :: TextureView ( id) => manual_texture_views
248
+ . get ( id)
249
+ . map ( |tex| RenderTargetInfo {
243
250
physical_size : tex. size ,
244
251
scale_factor : 1.0 ,
245
252
} )
246
- }
253
+ . ok_or ( MissingRenderTargetInfoError :: TextureView { texture_view : * id } ) ,
247
254
}
248
255
}
249
256
@@ -265,6 +272,18 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
265
272
}
266
273
}
267
274
275
+ #[ derive( Debug , thiserror:: Error ) ]
276
+ pub enum MissingRenderTargetInfoError {
277
+ #[ error( "RenderTarget::Window missing ({window:?}): Make sure the provided entity has a Window component." ) ]
278
+ Window { window : Entity } ,
279
+ #[ error( "RenderTarget::Image missing ({image:?}): Make sure the Image's usages include RenderAssetUsages::MAIN_WORLD." ) ]
280
+ Image { image : AssetId < Image > } ,
281
+ #[ error( "RenderTarget::TextureView missing ({texture_view:?}): make sure the texture view handle was not removed." ) ]
282
+ TextureView {
283
+ texture_view : ManualTextureViewHandle ,
284
+ } ,
285
+ }
286
+
268
287
/// System in charge of updating a [`Camera`] when its window or projection changes.
269
288
///
270
289
/// The system detects window creation, resize, and scale factor change events to update the camera
@@ -287,7 +306,7 @@ pub fn camera_system(
287
306
images : Res < Assets < Image > > ,
288
307
manual_texture_views : Res < ManualTextureViews > ,
289
308
mut cameras : Query < ( & mut Camera , & mut Projection ) > ,
290
- ) {
309
+ ) -> Result < ( ) , BevyError > {
291
310
let primary_window = primary_window. iter ( ) . next ( ) ;
292
311
293
312
let mut changed_window_ids = <HashSet < _ > >:: default ( ) ;
@@ -320,25 +339,23 @@ pub fn camera_system(
320
339
|| camera. computed . old_viewport_size != viewport_size
321
340
|| camera. computed . old_sub_camera_view != camera. sub_camera_view )
322
341
{
323
- let new_computed_target_info =
324
- normalized_target. get_render_target_info ( windows, & images, & manual_texture_views) ;
342
+ let new_computed_target_info = normalized_target. get_render_target_info (
343
+ windows,
344
+ & images,
345
+ & manual_texture_views,
346
+ ) ?;
325
347
// Check for the scale factor changing, and resize the viewport if needed.
326
348
// This can happen when the window is moved between monitors with different DPIs.
327
349
// Without this, the viewport will take a smaller portion of the window moved to
328
350
// a higher DPI monitor.
329
351
if normalized_target. is_changed ( & scale_factor_changed_window_ids, & HashSet :: default ( ) )
330
- && let ( Some ( new_scale_factor) , Some ( old_scale_factor) ) = (
331
- new_computed_target_info
332
- . as_ref ( )
333
- . map ( |info| info. scale_factor ) ,
334
- camera
335
- . computed
336
- . target_info
337
- . as_ref ( )
338
- . map ( |info| info. scale_factor ) ,
339
- )
352
+ && let Some ( old_scale_factor) = camera
353
+ . computed
354
+ . target_info
355
+ . as_ref ( )
356
+ . map ( |info| info. scale_factor )
340
357
{
341
- let resize_factor = new_scale_factor / old_scale_factor;
358
+ let resize_factor = new_computed_target_info . scale_factor / old_scale_factor;
342
359
if let Some ( ref mut viewport) = camera. viewport {
343
360
let resize = |vec : UVec2 | ( vec. as_vec2 ( ) * resize_factor) . as_uvec2 ( ) ;
344
361
viewport. physical_position = resize ( viewport. physical_position ) ;
@@ -350,12 +367,9 @@ pub fn camera_system(
350
367
// arguments due to a sudden change on the window size to a lower value.
351
368
// If the size of the window is lower, the viewport will match that lower value.
352
369
if let Some ( viewport) = & mut camera. viewport {
353
- let target_info = & new_computed_target_info;
354
- if let Some ( target) = target_info {
355
- viewport. clamp_to_size ( target. physical_size ) ;
356
- }
370
+ viewport. clamp_to_size ( new_computed_target_info. physical_size ) ;
357
371
}
358
- camera. computed . target_info = new_computed_target_info;
372
+ camera. computed . target_info = Some ( new_computed_target_info) ;
359
373
if let Some ( size) = camera. logical_viewport_size ( )
360
374
&& size. x != 0.0
361
375
&& size. y != 0.0
@@ -376,6 +390,7 @@ pub fn camera_system(
376
390
camera. computed . old_sub_camera_view = camera. sub_camera_view ;
377
391
}
378
392
}
393
+ Ok ( ( ) )
379
394
}
380
395
381
396
#[ derive( Component , Debug ) ]
0 commit comments