From a6748e70f4780a2c6d6d325c79e9c9029228ce03 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9l=C3=A8ne=20Amanita?= Date: Fri, 7 Jun 2024 05:50:57 +0200 Subject: [PATCH] Migrate to Bevu 0.14.0-rc2 --- Cargo.toml | 29 +++++----- README.md | 5 +- examples/cube/main.rs | 111 +++++++++++++++++++------------------- examples/cube/scenes.rs | 18 +++---- examples/mirror/main.rs | 2 +- examples/moving/main.rs | 2 +- examples/shapes/main.rs | 2 +- src/portals/api.rs | 3 +- src/portals/create.rs | 28 ++++++---- src/portals/despawn.rs | 7 +-- src/portals/material.rs | 4 +- src/portals/projection.rs | 37 +++++++------ src/portals/update.rs | 42 ++++++++------- 13 files changed, 156 insertions(+), 134 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 583a3d8..635e872 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "bevy_basic_portals" -version = "0.5.0" +version = "0.6.0-dev" edition = "2021" categories = ["game-engines", "graphics", "rendering"] keywords = ["bevy", "portal", "mirror", "gamedev"] @@ -11,23 +11,24 @@ repository = "https://github.com/Selene-Amanita/bevy_basic_portals" authors = ["Selene Amanita"] [dependencies] -bevy_app = "0.13" -bevy_asset = "0.13" -bevy_core_pipeline = "0.13" -bevy_ecs = "0.13" -bevy_hierarchy = "0.13" -bevy_math = "0.13" -bevy_pbr = "0.13" -bevy_reflect = "0.13" # Could potentially be under a feature? -bevy_render = "0.13" -bevy_transform = "0.13" -bevy_window = "0.13" +bevy_app = "0.14.0-rc.2" +bevy_asset = "0.14.0-rc.2" +bevy_color = "0.14.0-rc.2" +bevy_core_pipeline = "0.14.0-rc.2" +bevy_ecs = "0.14.0-rc.2" +bevy_hierarchy = "0.14.0-rc.2" +bevy_math = "0.14.0-rc.2" +bevy_pbr = "0.14.0-rc.2" +bevy_reflect = "0.14.0-rc.2" # Could potentially be under a feature? +bevy_render = "0.14.0-rc.2" +bevy_transform = "0.14.0-rc.2" +bevy_window = "0.14.0-rc.2" tracing = { version = "0.1", default-features = false, features = ["std"] } # From bevy_utils # All of the above can be replaced by: -# bevy = { version = "0.13", default-features = false, features = ["bevy_asset", "bevy_core_pipeline", "bevy_pbr", "bevy_render", ] } +# bevy = { version = "0.14.0-rc.2", default-features = false, features = ["bevy_asset", "bevy_core_pipeline", "bevy_pbr", "bevy_render", ] } [dev-dependencies] -bevy = { version = "0.13", default-features = false, features = [ +bevy = { version = "0.14.0-rc.2", default-features = false, features = [ "bevy_asset", "bevy_core_pipeline", "bevy_pbr", diff --git a/README.md b/README.md index 59476a4..9a7d32e 100644 --- a/README.md +++ b/README.md @@ -2,8 +2,8 @@ [![crates.io](https://img.shields.io/crates/v/bevy_basic_portals)](https://crates.io/crates/bevy_basic_portals) [![docs.rs](https://img.shields.io/docsrs/bevy_basic_portals)](https://docs.rs/bevy_basic_portals/latest/bevy_basic_portals/) -[![MIT/Apache 2.0](https://img.shields.io/badge/license-EUPL-blue.svg)](https://commission.europa.eu/content/european-union-public-licence_en) -[![Bevy tracking](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://github.com/bevyengine/bevy/blob/main/docs/plugins_guidelines.md#main-branch-tracking) +[![NVPLv7+](https://img.shields.io/badge/license-NPLv7+-blue.svg)](https://git.pixie.town/thufie/npl-builder/src/branch/main/nvpl.md) +[![Following released Bevy versions](https://img.shields.io/badge/Bevy%20tracking-released%20version-lightblue)](https://bevyengine.org/learn/quick-start/plugin-development/#main-branch-tracking) Bevy Basic Portals is a Bevy game engine plugin aimed to create portals. @@ -78,6 +78,7 @@ if you want a bidirectional portal you can crate two portals manually ## Bevy versions | Bevy version | Bevy Basic Portals recommended version | |--------------|----------------------------------------| +| 0.14.0-rc2 | 0.6.0-dev (not released on crates.io) | | 0.13.* | 0.5.0 | | 0.12.* | 0.4.0 | | 0.11.1 | 0.3.0 | diff --git a/examples/cube/main.rs b/examples/cube/main.rs index b077968..96c6861 100644 --- a/examples/cube/main.rs +++ b/examples/cube/main.rs @@ -3,6 +3,7 @@ //! (This is what this crate was created for originally) use bevy::{ + color::palettes::basic::*, prelude::*, render::{render_resource::Face, view::RenderLayers}, }; @@ -55,7 +56,7 @@ fn setup( brightness: 10., }); - commands.insert_resource(ClearColor(Color::rgb(0., 0., 0.))); + commands.insert_resource(ClearColor(Color::srgb(0., 0., 0.))); // Scenes let portal_mesh = meshes.add(Mesh::from(Rectangle::new( @@ -72,26 +73,26 @@ fn setup( let spawn_portal_up = Vec3::Y; let render_layer = RenderLayers::layer(1); let shape = meshes.add(Cuboid::new(5., 5., 5.)); - let color = Color::YELLOW; - scenes::setup_portal_cube_face( + let color = YELLOW.into(); + scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - main_camera, - render_layer, + &render_layer, portal_mesh.clone(), - true, + wall_material.clone(), + shape.clone(), + debug_material.clone(), + color, ); - scenes::setup_scene_test( + scenes::setup_portal_cube_face( &mut commands, spawn_portal_dir, spawn_portal_up, + main_camera, render_layer, portal_mesh.clone(), - wall_material.clone(), - shape.clone(), - debug_material.clone(), - color, + true, ); // Back scene @@ -102,34 +103,18 @@ fn setup( Vec3::new(1., 4., 1.), Vec3::new(-1., -1., -2.), )); - let color = Color::BLUE; - scenes::setup_portal_cube_face( - &mut commands, - spawn_portal_dir, - spawn_portal_up, - main_camera, - render_layer, - portal_mesh.clone(), - true, - ); + let color = BLUE.into(); scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - render_layer, + &render_layer, portal_mesh.clone(), wall_material.clone(), shape.clone(), debug_material.clone(), color, ); - - // Right scene - let spawn_portal_dir = Vec3::X; - let spawn_portal_up = Vec3::Y; - let render_layer = RenderLayers::layer(3); - let shape = meshes.add(Capsule3d::new(3., 3.)); - let color = Color::GREEN; scenes::setup_portal_cube_face( &mut commands, spawn_portal_dir, @@ -139,24 +124,24 @@ fn setup( portal_mesh.clone(), true, ); + + // Right scene + let spawn_portal_dir = Vec3::X; + let spawn_portal_up = Vec3::Y; + let render_layer = RenderLayers::layer(3); + let shape = meshes.add(Capsule3d::new(3., 3.)); + let color = GREEN.into(); scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - render_layer, + &render_layer, portal_mesh.clone(), wall_material.clone(), shape.clone(), debug_material.clone(), color, ); - - // Left scene - let spawn_portal_dir = -Vec3::X; - let spawn_portal_up = Vec3::Y; - let render_layer = RenderLayers::layer(4); - let shape = meshes.add(Capsule3d::new(3., 3.)); - let color = Color::FUCHSIA; scenes::setup_portal_cube_face( &mut commands, spawn_portal_dir, @@ -164,26 +149,26 @@ fn setup( main_camera, render_layer, portal_mesh.clone(), - false, + true, ); + + // Left scene + let spawn_portal_dir = -Vec3::X; + let spawn_portal_up = Vec3::Y; + let render_layer = RenderLayers::layer(4); + let shape = meshes.add(Capsule3d::new(3., 3.)); + let color = FUCHSIA.into(); scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - render_layer, + &render_layer, portal_mesh.clone(), wall_material.clone(), shape.clone(), debug_material.clone(), color, ); - - // Up scene - let spawn_portal_dir = Vec3::Y; - let spawn_portal_up = -Vec3::Z; - let render_layer = RenderLayers::layer(5); - let shape = meshes.add(Cuboid::new(5., 5., 5.)); - let color = Color::RED; scenes::setup_portal_cube_face( &mut commands, spawn_portal_dir, @@ -193,24 +178,24 @@ fn setup( portal_mesh.clone(), false, ); + + // Up scene + let spawn_portal_dir = Vec3::Y; + let spawn_portal_up = -Vec3::Z; + let render_layer = RenderLayers::layer(5); + let shape = meshes.add(Cuboid::new(5., 5., 5.)); + let color = RED.into(); scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - render_layer, + &render_layer, portal_mesh.clone(), wall_material.clone(), shape.clone(), debug_material.clone(), color, ); - - // Down scene - let spawn_portal_dir = -Vec3::Y; - let spawn_portal_up = -Vec3::Z; - let render_layer = RenderLayers::layer(6); - let shape = meshes.add(Torus::new(2.5, 3.5)); - let color = Color::CYAN; scenes::setup_portal_cube_face( &mut commands, spawn_portal_dir, @@ -220,15 +205,31 @@ fn setup( portal_mesh.clone(), false, ); + + // Down scene + let spawn_portal_dir = -Vec3::Y; + let spawn_portal_up = -Vec3::Z; + let render_layer = RenderLayers::layer(6); + let shape = meshes.add(Torus::new(2.5, 3.5)); + let color = AQUA.into(); scenes::setup_scene_test( &mut commands, spawn_portal_dir, spawn_portal_up, - render_layer, + &render_layer, portal_mesh.clone(), wall_material.clone(), shape.clone(), debug_material.clone(), color, ); + scenes::setup_portal_cube_face( + &mut commands, + spawn_portal_dir, + spawn_portal_up, + main_camera, + render_layer, + portal_mesh.clone(), + false, + ); } diff --git a/examples/cube/scenes.rs b/examples/cube/scenes.rs index 5534477..3a2d13d 100644 --- a/examples/cube/scenes.rs +++ b/examples/cube/scenes.rs @@ -56,7 +56,7 @@ pub fn setup_scene_test( commands: &mut Commands, spawn_portal_dir: Vec3, spawn_portal_up: Vec3, - render_layer: RenderLayers, + render_layer: &RenderLayers, wall_mesh: Handle, wall_material: Handle, shape: Handle, @@ -84,7 +84,7 @@ pub fn setup_scene_test( transform: shape_transform, ..default() }, - render_layer, + render_layer.clone(), )); // Light @@ -102,35 +102,35 @@ pub fn setup_scene_test( transform: light_transform, ..default() }, - render_layer, + render_layer.clone(), )); // Walls let walls_center_rotation = vec![ // back - (Vec3::new(0., 0., -PORTAL_SIZE), Vec3::Y, 0.), + (Vec3::new(0., 0., -PORTAL_SIZE), Dir3::Y, 0.), // left ( Vec3::new(-PORTAL_SIZE / 2., 0., -PORTAL_SIZE / 2.), - Vec3::Y, + Dir3::Y, PI / 2., ), // right ( Vec3::new(PORTAL_SIZE / 2., 0., -PORTAL_SIZE / 2.), - Vec3::Y, + Dir3::Y, -PI / 2., ), // up ( Vec3::new(0., PORTAL_SIZE / 2., -PORTAL_SIZE / 2.), - Vec3::X, + Dir3::X, PI / 2., ), // down ( Vec3::new(0., -PORTAL_SIZE / 2., -PORTAL_SIZE / 2.), - Vec3::X, + Dir3::X, -PI / 2., ), ]; @@ -144,7 +144,7 @@ pub fn setup_scene_test( material: wall_material.clone(), ..default() }, - render_layer, + render_layer.clone(), )); } }); diff --git a/examples/mirror/main.rs b/examples/mirror/main.rs index 7042ab6..ea80b72 100644 --- a/examples/mirror/main.rs +++ b/examples/mirror/main.rs @@ -30,7 +30,7 @@ fn setup( color: Color::WHITE, brightness: 400., }); - commands.insert_resource(ClearColor(Color::rgb(0.1, 0.1, 0.2))); + commands.insert_resource(ClearColor(Color::srgb(0.1, 0.1, 0.2))); // Camera let pivot = Vec3::ZERO; diff --git a/examples/moving/main.rs b/examples/moving/main.rs index 48d723f..6ba0f8a 100644 --- a/examples/moving/main.rs +++ b/examples/moving/main.rs @@ -112,7 +112,7 @@ fn move_portal_and_destination( let mut camera_transform = camera_query.get_single_mut().unwrap(); let time = time.elapsed().as_millis() % TIME_STOP; - let (portal_translation, portal_rotation, destination_translation, destination_rotation, camera_scale) = + let (portal_translation, portal_rotation, destination_translation, destination_rotation, camera_scale) = // Portal translation if (TIME0..TIME1).contains(&time) { ( diff --git a/examples/shapes/main.rs b/examples/shapes/main.rs index 29a3bad..0f9e288 100644 --- a/examples/shapes/main.rs +++ b/examples/shapes/main.rs @@ -50,7 +50,7 @@ fn setup( brightness: 300., }); - commands.insert_resource(ClearColor(Color::rgb(0., 0., 0.))); + commands.insert_resource(ClearColor(Color::srgb(0., 0., 0.))); // Sphere let debug_material = materials.add(textures::debug_material(&mut images, 3, Some(Face::Back))); diff --git a/src/portals/api.rs b/src/portals/api.rs index 7c196eb..1dfd7b4 100644 --- a/src/portals/api.rs +++ b/src/portals/api.rs @@ -2,6 +2,7 @@ use bevy_app::prelude::*; use bevy_asset::Handle; +use bevy_color::{palettes::basic::GRAY, Color}; use bevy_ecs::prelude::*; use bevy_reflect::Reflect; use bevy_render::{prelude::*, primitives::HalfSpace, render_resource::Face, view::RenderLayers}; @@ -298,7 +299,7 @@ impl Default for DebugPortal { fn default() -> Self { DebugPortal { name: Default::default(), - color: Color::GRAY, + color: GRAY.into(), show_window: true, show_destination_point: true, show_portal_copy: true, diff --git a/src/portals/create.rs b/src/portals/create.rs index 0711fdb..dd589e4 100644 --- a/src/portals/create.rs +++ b/src/portals/create.rs @@ -2,6 +2,7 @@ use bevy_app::prelude::*; use bevy_asset::prelude::*; +use bevy_color::Alpha; use bevy_core_pipeline::{ prelude::*, tonemapping::{DebandDither, Tonemapping}, @@ -25,6 +26,7 @@ use bevy_render::{ use bevy_transform::{prelude::*, TransformSystem}; use bevy_window::{Window, WindowLevel, WindowRef, WindowResolution}; use std::f32::consts::PI; +use tracing::error; use super::*; @@ -178,7 +180,7 @@ fn create_portal( main_camera_projection, main_camera_camera3d, main_camera_tonemapping, - main_camera_dither, + main_camera_deband_dither, main_camera_color_grading, ) = if let Some(camera_entity) = create_portal.main_camera { main_camera_query.get(camera_entity).unwrap() @@ -186,7 +188,11 @@ fn create_portal( main_camera_query.iter().next().unwrap() }; - let main_camera_viewport_size = get_viewport_size(main_camera, size_params); + let main_camera_viewport_size = + get_viewport_size(main_camera, size_params).unwrap_or_else(|| { + error!("Viewport size not found, creating portal with default sized image"); + UVec2::new(100, 100) + }); let size = Extent3d { width: main_camera_viewport_size.x, @@ -267,8 +273,10 @@ fn create_portal( .unwrap_or(&camera_bundle.camera_3d) .clone(), *main_camera_tonemapping.unwrap_or(&camera_bundle.tonemapping), - *main_camera_dither.unwrap_or(&camera_bundle.dither), - *main_camera_color_grading.unwrap_or(&camera_bundle.color_grading), + *main_camera_deband_dither.unwrap_or(&camera_bundle.deband_dither), + main_camera_color_grading + .cloned() + .unwrap_or_else(|| camera_bundle.color_grading.clone()), // TOFIX set the exact value of Transform and GlobalTransform to avoid black screen at spawn // let portal_camera_transform = get_portal_camera_transform(main_camera_transform, portal_transform, &destination_transform); // This requires an extra Query to get destination_transform when AsPortalDestination::Entity/CreateMirror @@ -279,7 +287,7 @@ fn create_portal( visibility: Visibility::Hidden, ..SpatialBundle::default() }, - create_portal.render_layer, + create_portal.render_layer.clone(), camera_bundle.exposure, camera_bundle.main_texture_usages, )) @@ -314,7 +322,7 @@ fn create_portal( if let Some(debug) = &create_portal.debug { let debug_color = debug.color; let mut debug_transparent_color = debug.color; - debug_transparent_color.set_a(0.3); + debug_transparent_color.set_alpha(0.3); // Create the debug camera as a child of the portal camera in a new window if debug.show_window { @@ -343,7 +351,7 @@ fn create_portal( ..Camera3dBundle::default() }, PortalDebugCamera {}, - create_portal.render_layer, + create_portal.render_layer.clone(), )); }); } @@ -357,7 +365,7 @@ fn create_portal( material: materials.add(debug_color), ..PbrBundle::default() }, - create_portal.render_layer, + create_portal.render_layer.clone(), )); }); } @@ -377,7 +385,7 @@ fn create_portal( transform: Transform::from_xyz(0., 0., -0.001), ..PbrBundle::default() }, - create_portal.render_layer, + create_portal.render_layer.clone(), )); }); } @@ -394,7 +402,7 @@ fn create_portal( visibility: Visibility::Visible, ..PbrBundle::default() }, - create_portal.render_layer, + create_portal.render_layer.clone(), )); }); } diff --git a/src/portals/despawn.rs b/src/portals/despawn.rs index 8c6ed43..48c96d5 100644 --- a/src/portals/despawn.rs +++ b/src/portals/despawn.rs @@ -4,7 +4,8 @@ use bevy_app::prelude::*; use bevy_ecs::{ prelude::*, query::QueryEntityError, - system::{Command, EntityCommand, SystemState}, + system::{EntityCommand, SystemState}, + world::Command, }; use bevy_hierarchy::DespawnRecursiveExt; use bevy_render::camera::Camera; @@ -53,7 +54,7 @@ impl Command for DespawnPortalPartsCommand { #[derive(Default)] pub struct DespawnPortalPartsEntityCommand(PortalPartsDespawnStrategy); -impl EntityCommand for DespawnPortalPartsCommand { +impl EntityCommand for DespawnPortalPartsEntityCommand { fn apply(self, entity: Entity, world: &mut World) { let mut system_state = SystemState::<( Commands, @@ -79,7 +80,7 @@ impl EntityCommand for DespawnPortalPartsCommand { ); if let Some(portal_parts) = portal_parts { - despawn_portal_parts(&mut commands, portal_parts, &self.strategy); + despawn_portal_parts(&mut commands, portal_parts, &self.0); } else { warn!( "DespawnPortalPartsEntityCommand called on entity {} which is not a portal part", diff --git a/src/portals/material.rs b/src/portals/material.rs index 10b34e5..80e2a12 100644 --- a/src/portals/material.rs +++ b/src/portals/material.rs @@ -6,7 +6,7 @@ use bevy_pbr::prelude::*; use bevy_pbr::{MaterialPipeline, MaterialPipelineKey}; use bevy_reflect::TypePath; use bevy_render::{ - mesh::MeshVertexBufferLayout, + mesh::MeshVertexBufferLayoutRef, prelude::*, render_resource::{ AsBindGroup, Face, RenderPipelineDescriptor, ShaderRef, SpecializedMeshPipelineError, @@ -46,7 +46,7 @@ impl Material for PortalMaterial { fn specialize( _: &MaterialPipeline, descriptor: &mut RenderPipelineDescriptor, - _: &MeshVertexBufferLayout, + _: &MeshVertexBufferLayoutRef, key: MaterialPipelineKey, ) -> Result<(), SpecializedMeshPipelineError> { descriptor.primitive.cull_mode = key.bind_group_data.cull_mode; diff --git a/src/portals/projection.rs b/src/portals/projection.rs index d531344..e962aba 100644 --- a/src/portals/projection.rs +++ b/src/portals/projection.rs @@ -1,26 +1,33 @@ //! Projection logic for portals. -use bevy_app::{App, PostUpdate}; +use bevy_app::{App, PostStartup, PostUpdate}; use bevy_ecs::prelude::*; use bevy_math::{Mat4, Vec3A}; -use bevy_pbr::{ - build_directional_light_cascades, clear_directional_light_cascades, SimulationLightSystems, -}; +use bevy_pbr::PbrProjectionPlugin; use bevy_reflect::{std_traits::ReflectDefault, Reflect}; use bevy_render::{ - camera::{CameraProjection, CameraProjectionPlugin}, + camera::{camera_system, CameraProjection, CameraUpdateSystem}, prelude::*, }; /// Add the projection logic to [PortalsPlugin](super::PortalsPlugin) pub(super) fn build_projection(app: &mut App) { - app.add_plugins(CameraProjectionPlugin::::default()); - app.add_systems( - PostUpdate, - build_directional_light_cascades:: - .in_set(SimulationLightSystems::UpdateDirectionalLightCascades) - .after(clear_directional_light_cascades), - ); + // Copy of CameraProjectionPlugin's code but without update_frusta + app.register_type::() + .add_systems( + PostStartup, + camera_system:: + .in_set(CameraUpdateSystem) + .ambiguous_with(CameraUpdateSystem), + ) + .add_systems( + PostUpdate, + camera_system:: + .in_set(CameraUpdateSystem) + .ambiguous_with(CameraUpdateSystem), + ); + + app.add_plugins(PbrProjectionPlugin::::default()); } /// For now, almost a copy of Bevy's Projection, to avoid frustum being calculated @@ -63,10 +70,10 @@ impl From for PortalProjection { } impl CameraProjection for PortalProjection { - fn get_projection_matrix(&self) -> Mat4 { + fn get_clip_from_view(&self) -> Mat4 { match self { - Self::Perspective(projection) => projection.get_projection_matrix(), - Self::Orthographic(projection) => projection.get_projection_matrix(), + Self::Perspective(projection) => projection.get_clip_from_view(), + Self::Orthographic(projection) => projection.get_clip_from_view(), } } diff --git a/src/portals/update.rs b/src/portals/update.rs index ad548ee..964e297 100644 --- a/src/portals/update.rs +++ b/src/portals/update.rs @@ -157,11 +157,14 @@ fn resize_image_if_needed( ) -> bool { let portal_image = size_params.images.get(&portal_camera.image).unwrap(); let portal_image_size = portal_image.size(); - let main_camera_viewport_size = get_viewport_size(main_camera, size_params); + let Some(main_camera_viewport_size) = get_viewport_size(main_camera, size_params) else { + warn!("Viewport size not found, skipping portal resize"); + return false; + }; - if portal_image_size.x != main_camera_viewport_size.x - || portal_image_size.y != main_camera_viewport_size.y - { + let resize = portal_image_size.x != main_camera_viewport_size.x + || portal_image_size.y != main_camera_viewport_size.y; + if resize { let size = Extent3d { width: main_camera_viewport_size.x, height: main_camera_viewport_size.y, @@ -178,10 +181,9 @@ fn resize_image_if_needed( } else { warn!("No portal image or material."); } - true - } else { - false } + + resize } /// Get the [Frustum] for the [PortalCamera] from the [PortalProjection] and @@ -193,9 +195,9 @@ fn get_frustum( projection: &PortalProjection, ) -> Frustum { let view_projection = - projection.get_projection_matrix() * portal_camera_transform.compute_matrix().inverse(); + projection.get_clip_from_view() * portal_camera_transform.compute_matrix().inverse(); - let mut frustum = Frustum::from_view_projection_custom_far( + let mut frustum = Frustum::from_clip_from_world_custom_far( &view_projection, &portal_camera_transform.translation, &portal_camera_transform.back(), @@ -241,19 +243,19 @@ pub(super) fn get_viewport_size( windows_query, texture_views, }: &PortalImageSizeParams, -) -> UVec2 { +) -> Option { match main_camera.viewport.as_ref() { - Some(viewport) => viewport.physical_size, + Some(viewport) => Some(viewport.physical_size), None => match &main_camera.target { - RenderTarget::Window(window_ref) => { - let window = match window_ref { - WindowRef::Primary => primary_window_query.get_single().unwrap(), - WindowRef::Entity(entity) => windows_query.get(*entity).unwrap(), - }; - UVec2::new(window.physical_width(), window.physical_height()) - } - RenderTarget::Image(handle) => images.get(handle).unwrap().size(), - RenderTarget::TextureView(handle) => texture_views.get(handle).unwrap().size, + RenderTarget::Window(window_ref) => (match window_ref { + WindowRef::Primary => primary_window_query.get_single().ok(), + WindowRef::Entity(entity) => windows_query.get(*entity).ok(), + }) + .map(|window| UVec2::new(window.physical_width(), window.physical_height())), + RenderTarget::Image(handle) => images.get(handle).map(|image| image.size()), + RenderTarget::TextureView(handle) => texture_views + .get(handle) + .map(|texture_view| texture_view.size), }, } }