@@ -13,6 +13,7 @@ use bevy_ecs::{
13
13
component:: Component ,
14
14
entity:: Entity ,
15
15
event:: EventReader ,
16
+ prelude:: With ,
16
17
reflect:: ReflectComponent ,
17
18
system:: { Commands , Query , Res } ,
18
19
} ;
@@ -21,7 +22,10 @@ use bevy_reflect::prelude::*;
21
22
use bevy_reflect:: FromReflect ;
22
23
use bevy_transform:: components:: GlobalTransform ;
23
24
use bevy_utils:: HashSet ;
24
- use bevy_window:: { WindowCreated , WindowId , WindowResized , Windows } ;
25
+ use bevy_window:: {
26
+ NormalizedWindowRef , PrimaryWindow , Window , WindowCreated , WindowRef , WindowResized ,
27
+ } ;
28
+
25
29
use std:: { borrow:: Cow , ops:: Range } ;
26
30
use wgpu:: { Extent3d , TextureFormat } ;
27
31
@@ -325,10 +329,21 @@ impl CameraRenderGraph {
325
329
326
330
/// The "target" that a [`Camera`] will render to. For example, this could be a [`Window`](bevy_window::Window)
327
331
/// swapchain or an [`Image`].
328
- #[ derive( Debug , Clone , Reflect , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
332
+ #[ derive( Debug , Clone , Reflect ) ]
329
333
pub enum RenderTarget {
330
334
/// Window to which the camera's view is rendered.
331
- Window ( WindowId ) ,
335
+ Window ( WindowRef ) ,
336
+ /// Image to which the camera's view is rendered.
337
+ Image ( Handle < Image > ) ,
338
+ }
339
+
340
+ /// Normalized version of the render target.
341
+ ///
342
+ /// Once we have this we shouldn't need to resolve it down anymore.
343
+ #[ derive( Debug , Clone , Reflect , PartialEq , Eq , Hash , PartialOrd , Ord ) ]
344
+ pub enum NormalizedRenderTarget {
345
+ /// Window to which the camera's view is rendered.
346
+ Window ( NormalizedWindowRef ) ,
332
347
/// Image to which the camera's view is rendered.
333
348
Image ( Handle < Image > ) ,
334
349
}
@@ -340,16 +355,28 @@ impl Default for RenderTarget {
340
355
}
341
356
342
357
impl RenderTarget {
358
+ /// Normalize the render target down to a more concrete value, mostly used for equality comparisons.
359
+ pub fn normalize ( & self , primary_window : Option < Entity > ) -> Option < NormalizedRenderTarget > {
360
+ match self {
361
+ RenderTarget :: Window ( window_ref) => window_ref
362
+ . normalize ( primary_window)
363
+ . map ( NormalizedRenderTarget :: Window ) ,
364
+ RenderTarget :: Image ( handle) => Some ( NormalizedRenderTarget :: Image ( handle. clone ( ) ) ) ,
365
+ }
366
+ }
367
+ }
368
+
369
+ impl NormalizedRenderTarget {
343
370
pub fn get_texture_view < ' a > (
344
371
& self ,
345
372
windows : & ' a ExtractedWindows ,
346
373
images : & ' a RenderAssets < Image > ,
347
374
) -> Option < & ' a TextureView > {
348
375
match self {
349
- RenderTarget :: Window ( window_id ) => windows
350
- . get ( window_id )
376
+ NormalizedRenderTarget :: Window ( window_ref ) => windows
377
+ . get ( & window_ref . entity ( ) )
351
378
. and_then ( |window| window. swap_chain_texture . as_ref ( ) ) ,
352
- RenderTarget :: Image ( image_handle) => {
379
+ NormalizedRenderTarget :: Image ( image_handle) => {
353
380
images. get ( image_handle) . map ( |image| & image. texture_view )
354
381
}
355
382
}
@@ -362,47 +389,55 @@ impl RenderTarget {
362
389
images : & ' a RenderAssets < Image > ,
363
390
) -> Option < TextureFormat > {
364
391
match self {
365
- RenderTarget :: Window ( window_id ) => windows
366
- . get ( window_id )
392
+ NormalizedRenderTarget :: Window ( window_ref ) => windows
393
+ . get ( & window_ref . entity ( ) )
367
394
. and_then ( |window| window. swap_chain_texture_format ) ,
368
- RenderTarget :: Image ( image_handle) => {
395
+ NormalizedRenderTarget :: Image ( image_handle) => {
369
396
images. get ( image_handle) . map ( |image| image. texture_format )
370
397
}
371
398
}
372
399
}
373
400
374
- pub fn get_render_target_info (
401
+ pub fn get_render_target_info < ' a > (
375
402
& self ,
376
- windows : & Windows ,
403
+ resolutions : impl IntoIterator < Item = ( Entity , & ' a Window ) > ,
377
404
images : & Assets < Image > ,
378
405
) -> Option < RenderTargetInfo > {
379
- Some ( match self {
380
- RenderTarget :: Window ( window_id) => {
381
- let window = windows. get ( * window_id) ?;
382
- RenderTargetInfo {
383
- physical_size : UVec2 :: new ( window. physical_width ( ) , window. physical_height ( ) ) ,
384
- scale_factor : window. scale_factor ( ) ,
385
- }
386
- }
387
- RenderTarget :: Image ( image_handle) => {
406
+ match self {
407
+ NormalizedRenderTarget :: Window ( window_ref) => resolutions
408
+ . into_iter ( )
409
+ . find ( |( entity, _) | * entity == window_ref. entity ( ) )
410
+ . map ( |( _, window) | RenderTargetInfo {
411
+ physical_size : UVec2 :: new (
412
+ window. resolution . physical_width ( ) ,
413
+ window. resolution . physical_height ( ) ,
414
+ ) ,
415
+ scale_factor : window. resolution . scale_factor ( ) ,
416
+ } ) ,
417
+ NormalizedRenderTarget :: Image ( image_handle) => {
388
418
let image = images. get ( image_handle) ?;
389
419
let Extent3d { width, height, .. } = image. texture_descriptor . size ;
390
- RenderTargetInfo {
420
+ Some ( RenderTargetInfo {
391
421
physical_size : UVec2 :: new ( width, height) ,
392
422
scale_factor : 1.0 ,
393
- }
423
+ } )
394
424
}
395
- } )
425
+ }
396
426
}
427
+
397
428
// Check if this render target is contained in the given changed windows or images.
398
429
fn is_changed (
399
430
& self ,
400
- changed_window_ids : & [ WindowId ] ,
431
+ changed_window_ids : & HashSet < Entity > ,
401
432
changed_image_handles : & HashSet < & Handle < Image > > ,
402
433
) -> bool {
403
434
match self {
404
- RenderTarget :: Window ( window_id) => changed_window_ids. contains ( window_id) ,
405
- RenderTarget :: Image ( image_handle) => changed_image_handles. contains ( & image_handle) ,
435
+ NormalizedRenderTarget :: Window ( window_ref) => {
436
+ changed_window_ids. contains ( & window_ref. entity ( ) )
437
+ }
438
+ NormalizedRenderTarget :: Image ( image_handle) => {
439
+ changed_image_handles. contains ( & image_handle)
440
+ }
406
441
}
407
442
}
408
443
}
@@ -431,29 +466,16 @@ pub fn camera_system<T: CameraProjection + Component>(
431
466
mut window_resized_events : EventReader < WindowResized > ,
432
467
mut window_created_events : EventReader < WindowCreated > ,
433
468
mut image_asset_events : EventReader < AssetEvent < Image > > ,
434
- windows : Res < Windows > ,
469
+ primary_window : Query < Entity , With < PrimaryWindow > > ,
470
+ windows : Query < ( Entity , & Window ) > ,
435
471
images : Res < Assets < Image > > ,
436
472
mut cameras : Query < ( & mut Camera , & mut T ) > ,
437
473
) {
438
- let mut changed_window_ids = Vec :: new ( ) ;
439
-
440
- // Collect all unique window IDs of changed windows by inspecting created windows
441
- for event in window_created_events. iter ( ) {
442
- if changed_window_ids. contains ( & event. id ) {
443
- continue ;
444
- }
445
-
446
- changed_window_ids. push ( event. id ) ;
447
- }
474
+ let primary_window = primary_window. iter ( ) . next ( ) ;
448
475
449
- // Collect all unique window IDs of changed windows by inspecting resized windows
450
- for event in window_resized_events. iter ( ) {
451
- if changed_window_ids. contains ( & event. id ) {
452
- continue ;
453
- }
454
-
455
- changed_window_ids. push ( event. id ) ;
456
- }
476
+ let mut changed_window_ids = HashSet :: new ( ) ;
477
+ changed_window_ids. extend ( window_created_events. iter ( ) . map ( |event| event. window ) ) ;
478
+ changed_window_ids. extend ( window_resized_events. iter ( ) . map ( |event| event. window ) ) ;
457
479
458
480
let changed_image_handles: HashSet < & Handle < Image > > = image_asset_events
459
481
. iter ( )
@@ -472,26 +494,26 @@ pub fn camera_system<T: CameraProjection + Component>(
472
494
. as_ref ( )
473
495
. map ( |viewport| viewport. physical_size ) ;
474
496
475
- if camera
476
- . target
477
- . is_changed ( & changed_window_ids , & changed_image_handles )
478
- || camera . is_added ( )
479
- || camera_projection . is_changed ( )
480
- || camera . computed . old_viewport_size != viewport_size
481
- {
482
- camera . computed . target_info = camera . target . get_render_target_info ( & windows, & images) ;
483
- camera . computed . old_viewport_size = viewport_size ;
484
- if let Some ( size ) = camera . logical_viewport_size ( ) {
485
- camera_projection . update ( size . x , size . y ) ;
486
- camera . computed . projection_matrix = camera_projection . get_projection_matrix ( ) ;
497
+ if let Some ( normalized_target ) = camera. target . normalize ( primary_window ) {
498
+ if normalized_target . is_changed ( & changed_window_ids , & changed_image_handles )
499
+ || camera . is_added ( )
500
+ || camera_projection . is_changed ( )
501
+ || camera . computed . old_viewport_size != viewport_size
502
+ {
503
+ camera . computed . target_info =
504
+ normalized_target . get_render_target_info ( & windows, & images) ;
505
+ if let Some ( size ) = camera . logical_viewport_size ( ) {
506
+ camera_projection . update ( size . x , size . y ) ;
507
+ camera . computed . projection_matrix = camera_projection . get_projection_matrix ( ) ;
508
+ }
487
509
}
488
510
}
489
511
}
490
512
}
491
513
492
514
#[ derive( Component , Debug ) ]
493
515
pub struct ExtractedCamera {
494
- pub target : RenderTarget ,
516
+ pub target : Option < NormalizedRenderTarget > ,
495
517
pub physical_viewport_size : Option < UVec2 > ,
496
518
pub physical_target_size : Option < UVec2 > ,
497
519
pub viewport : Option < Viewport > ,
@@ -510,7 +532,9 @@ pub fn extract_cameras(
510
532
& VisibleEntities ,
511
533
) > ,
512
534
> ,
535
+ primary_window : Extract < Query < Entity , With < PrimaryWindow > > > ,
513
536
) {
537
+ let primary_window = primary_window. iter ( ) . next ( ) ;
514
538
for ( entity, camera, camera_render_graph, transform, visible_entities) in query. iter ( ) {
515
539
if !camera. is_active {
516
540
continue ;
@@ -525,7 +549,7 @@ pub fn extract_cameras(
525
549
}
526
550
commands. get_or_spawn ( entity) . insert ( (
527
551
ExtractedCamera {
528
- target : camera. target . clone ( ) ,
552
+ target : camera. target . normalize ( primary_window ) ,
529
553
viewport : camera. viewport . clone ( ) ,
530
554
physical_viewport_size : Some ( viewport_size) ,
531
555
physical_target_size : Some ( target_size) ,
0 commit comments