Skip to content

Commit 7797f28

Browse files
committed
add proper error enum
1 parent 409b13d commit 7797f28

File tree

1 file changed

+49
-38
lines changed

1 file changed

+49
-38
lines changed

crates/bevy_render/src/camera.rs

Lines changed: 49 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,15 @@ use bevy_camera::{
2020
primitives::Frustum,
2121
visibility::{self, RenderLayers, VisibleEntities},
2222
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,
2525
};
2626
use bevy_derive::{Deref, DerefMut};
2727
use bevy_ecs::{
2828
change_detection::DetectChanges,
2929
component::Component,
3030
entity::{ContainsEntity, Entity},
31+
error::BevyError,
3132
event::EventReader,
3233
lifecycle::HookContext,
3334
prelude::With,
@@ -44,7 +45,7 @@ use bevy_platform::collections::{HashMap, HashSet};
4445
use bevy_reflect::prelude::*;
4546
use bevy_transform::components::GlobalTransform;
4647
use bevy_window::{PrimaryWindow, Window, WindowCreated, WindowResized, WindowScaleFactorChanged};
47-
use tracing::{error, warn};
48+
use tracing::warn;
4849
use wgpu::TextureFormat;
4950

5051
#[derive(Default)]
@@ -167,7 +168,7 @@ pub trait NormalizedRenderTargetExt {
167168
resolutions: impl IntoIterator<Item = (Entity, &'a Window)>,
168169
images: &Assets<Image>,
169170
manual_texture_views: &ManualTextureViews,
170-
) -> Option<RenderTargetInfo>;
171+
) -> Result<RenderTargetInfo, MissingRenderTargetInfoError>;
171172

172173
// Check if this render target is contained in the given changed windows or images.
173174
fn is_changed(
@@ -222,32 +223,34 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
222223
resolutions: impl IntoIterator<Item = (Entity, &'a Window)>,
223224
images: &Assets<Image>,
224225
manual_texture_views: &ManualTextureViews,
225-
) -> Option<RenderTargetInfo> {
226+
) -> Result<RenderTargetInfo, MissingRenderTargetInfoError> {
226227
match self {
227228
NormalizedRenderTarget::Window(window_ref) => resolutions
228229
.into_iter()
229230
.find(|(entity, _)| *entity == window_ref.entity())
230231
.map(|(_, window)| RenderTargetInfo {
231232
physical_size: window.physical_size(),
232233
scale_factor: window.resolution.scale_factor(),
234+
})
235+
.ok_or(MissingRenderTargetInfoError::Window {
236+
window: window_ref.entity(),
233237
}),
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 {
247250
physical_size: tex.size,
248251
scale_factor: 1.0,
249252
})
250-
}
253+
.ok_or(MissingRenderTargetInfoError::TextureView { texture_view: *id }),
251254
}
252255
}
253256

@@ -269,6 +272,18 @@ impl NormalizedRenderTargetExt for NormalizedRenderTarget {
269272
}
270273
}
271274

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+
272287
/// System in charge of updating a [`Camera`] when its window or projection changes.
273288
///
274289
/// The system detects window creation, resize, and scale factor change events to update the camera
@@ -291,7 +306,7 @@ pub fn camera_system(
291306
images: Res<Assets<Image>>,
292307
manual_texture_views: Res<ManualTextureViews>,
293308
mut cameras: Query<(&mut Camera, &mut Projection)>,
294-
) {
309+
) -> Result<(), BevyError> {
295310
let primary_window = primary_window.iter().next();
296311

297312
let mut changed_window_ids = <HashSet<_>>::default();
@@ -324,25 +339,23 @@ pub fn camera_system(
324339
|| camera.computed.old_viewport_size != viewport_size
325340
|| camera.computed.old_sub_camera_view != camera.sub_camera_view)
326341
{
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+
)?;
329347
// Check for the scale factor changing, and resize the viewport if needed.
330348
// This can happen when the window is moved between monitors with different DPIs.
331349
// Without this, the viewport will take a smaller portion of the window moved to
332350
// a higher DPI monitor.
333351
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)
344357
{
345-
let resize_factor = new_scale_factor / old_scale_factor;
358+
let resize_factor = new_computed_target_info.scale_factor / old_scale_factor;
346359
if let Some(ref mut viewport) = camera.viewport {
347360
let resize = |vec: UVec2| (vec.as_vec2() * resize_factor).as_uvec2();
348361
viewport.physical_position = resize(viewport.physical_position);
@@ -354,12 +367,9 @@ pub fn camera_system(
354367
// arguments due to a sudden change on the window size to a lower value.
355368
// If the size of the window is lower, the viewport will match that lower value.
356369
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);
361371
}
362-
camera.computed.target_info = new_computed_target_info;
372+
camera.computed.target_info = Some(new_computed_target_info);
363373
if let Some(size) = camera.logical_viewport_size()
364374
&& size.x != 0.0
365375
&& size.y != 0.0
@@ -380,6 +390,7 @@ pub fn camera_system(
380390
camera.computed.old_sub_camera_view = camera.sub_camera_view;
381391
}
382392
}
393+
Ok(())
383394
}
384395

385396
#[derive(Component, Debug)]

0 commit comments

Comments
 (0)