@@ -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 ,
@@ -44,7 +45,7 @@ use bevy_platform::collections::{HashMap, HashSet};
44
45
use bevy_reflect:: prelude:: * ;
45
46
use bevy_transform:: components:: GlobalTransform ;
46
47
use bevy_window:: { PrimaryWindow , Window , WindowCreated , WindowResized , WindowScaleFactorChanged } ;
47
- use tracing:: { error , warn} ;
48
+ use tracing:: warn;
48
49
use wgpu:: TextureFormat ;
49
50
50
51
#[ derive( Default ) ]
@@ -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,32 +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
- if let Some ( image) = images. get ( & image_target. handle ) {
236
- Some ( RenderTargetInfo {
237
- physical_size : image. size ( ) ,
238
- scale_factor : image_target. scale_factor . 0 ,
239
- } )
240
- } else {
241
- error ! ( "ImageRenderTarget handle unloaded. Make sure the Image's usages include RenderAssetUsages::MAIN_WORLD" ) ;
242
- None
243
- }
244
- }
245
- NormalizedRenderTarget :: TextureView ( id) => {
246
- manual_texture_views. get ( id) . map ( |tex| RenderTargetInfo {
238
+ NormalizedRenderTarget :: Image ( image_target) => images
239
+ . get ( & image_target. handle )
240
+ . map ( |image| RenderTargetInfo {
241
+ physical_size : image. size ( ) ,
242
+ scale_factor : image_target. scale_factor . 0 ,
243
+ } )
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 {
247
250
physical_size : tex. size ,
248
251
scale_factor : 1.0 ,
249
252
} )
250
- }
253
+ . ok_or ( MissingRenderTargetInfoError :: TextureView { texture_view : * id } ) ,
251
254
}
252
255
}
253
256
@@ -269,6 +272,18 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
269
272
}
270
273
}
271
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
+
272
287
/// System in charge of updating a [`Camera`] when its window or projection changes.
273
288
///
274
289
/// The system detects window creation, resize, and scale factor change events to update the camera
@@ -291,7 +306,7 @@ pub fn camera_system(
291
306
images : Res < Assets < Image > > ,
292
307
manual_texture_views : Res < ManualTextureViews > ,
293
308
mut cameras : Query < ( & mut Camera , & mut Projection ) > ,
294
- ) {
309
+ ) -> Result < ( ) , BevyError > {
295
310
let primary_window = primary_window. iter ( ) . next ( ) ;
296
311
297
312
let mut changed_window_ids = <HashSet < _ > >:: default ( ) ;
@@ -324,25 +339,23 @@ pub fn camera_system(
324
339
|| camera. computed . old_viewport_size != viewport_size
325
340
|| camera. computed . old_sub_camera_view != camera. sub_camera_view )
326
341
{
327
- let new_computed_target_info =
328
- 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
+ ) ?;
329
347
// Check for the scale factor changing, and resize the viewport if needed.
330
348
// This can happen when the window is moved between monitors with different DPIs.
331
349
// Without this, the viewport will take a smaller portion of the window moved to
332
350
// a higher DPI monitor.
333
351
if normalized_target. is_changed ( & scale_factor_changed_window_ids, & HashSet :: default ( ) )
334
- && let ( Some ( new_scale_factor) , Some ( old_scale_factor) ) = (
335
- new_computed_target_info
336
- . as_ref ( )
337
- . map ( |info| info. scale_factor ) ,
338
- camera
339
- . computed
340
- . target_info
341
- . as_ref ( )
342
- . map ( |info| info. scale_factor ) ,
343
- )
352
+ && let Some ( old_scale_factor) = camera
353
+ . computed
354
+ . target_info
355
+ . as_ref ( )
356
+ . map ( |info| info. scale_factor )
344
357
{
345
- let resize_factor = new_scale_factor / old_scale_factor;
358
+ let resize_factor = new_computed_target_info . scale_factor / old_scale_factor;
346
359
if let Some ( ref mut viewport) = camera. viewport {
347
360
let resize = |vec : UVec2 | ( vec. as_vec2 ( ) * resize_factor) . as_uvec2 ( ) ;
348
361
viewport. physical_position = resize ( viewport. physical_position ) ;
@@ -354,12 +367,9 @@ pub fn camera_system(
354
367
// arguments due to a sudden change on the window size to a lower value.
355
368
// If the size of the window is lower, the viewport will match that lower value.
356
369
if let Some ( viewport) = & mut camera. viewport {
357
- let target_info = & new_computed_target_info;
358
- if let Some ( target) = target_info {
359
- viewport. clamp_to_size ( target. physical_size ) ;
360
- }
370
+ viewport. clamp_to_size ( new_computed_target_info. physical_size ) ;
361
371
}
362
- camera. computed . target_info = new_computed_target_info;
372
+ camera. computed . target_info = Some ( new_computed_target_info) ;
363
373
if let Some ( size) = camera. logical_viewport_size ( )
364
374
&& size. x != 0.0
365
375
&& size. y != 0.0
@@ -380,6 +390,7 @@ pub fn camera_system(
380
390
camera. computed . old_sub_camera_view = camera. sub_camera_view ;
381
391
}
382
392
}
393
+ Ok ( ( ) )
383
394
}
384
395
385
396
#[ derive( Component , Debug ) ]
0 commit comments