Skip to content

Commit 1503371

Browse files
mgi388mrchantey
authored andcommitted
Fix cursor hotspot out of bounds when flipping (bevyengine#17571)
# Objective - Fix off by one error introduced in bevyengine#17540 causing: ``` Cursor image StrongHandle<Image>{ id: Index(AssetIndex { generation: 0, index: 3 }), path: Some(cursors/kenney_crosshairPack/Tilesheet/crosshairs_tilesheet_white.png) } is invalid: The specified hotspot (64, 64) is outside the image bounds (64x64). ``` - First PR commit and run shows the bug: https://github.com/bevyengine/bevy/actions/runs/13009405866/job/36283507530?pr=17571 - Second PR commit fixes it. ## Solution - Hotspot coordinates are 0-indexed, so we need to subtract 1 from the width and height. ## Testing - Fix the tests which included the off-by-one error in their expected values. - Consolidate the tests into a single test for brevity. - Test round trip transform to ensure we can "undo" to get back to the original value. - Add a specific bounds test. - Ran the example again and observed there are no more error logs: `cargo run --example custom_cursor_image --features=custom_cursor`.
1 parent 3fa245a commit 1503371

File tree

1 file changed

+22
-37
lines changed

1 file changed

+22
-37
lines changed

crates/bevy_winit/src/custom_cursor.rs

Lines changed: 22 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -204,11 +204,16 @@ pub(crate) fn transform_hotspot(
204204
) -> (u16, u16) {
205205
let hotspot_x = hotspot.0 as f32;
206206
let hotspot_y = hotspot.1 as f32;
207+
207208
let (width, height) = (rect.width(), rect.height());
208209

209-
let hotspot_x = if flip_x { width - hotspot_x } else { hotspot_x };
210+
let hotspot_x = if flip_x {
211+
(width - 1.0).max(0.0) - hotspot_x
212+
} else {
213+
hotspot_x
214+
};
210215
let hotspot_y = if flip_y {
211-
height - hotspot_y
216+
(height - 1.0).max(0.0) - hotspot_y
212217
} else {
213218
hotspot_y
214219
};
@@ -576,46 +581,26 @@ mod tests {
576581
);
577582

578583
#[test]
579-
fn test_transform_hotspot_no_flip() {
580-
let hotspot = (10, 20);
581-
let rect = Rect {
582-
min: Vec2::ZERO,
583-
max: Vec2::new(100.0, 200.0),
584-
};
585-
let transformed = transform_hotspot(hotspot, false, false, rect);
586-
assert_eq!(transformed, (10, 20));
587-
}
588-
589-
#[test]
590-
fn test_transform_hotspot_flip_x() {
591-
let hotspot = (10, 20);
592-
let rect = Rect {
593-
min: Vec2::ZERO,
594-
max: Vec2::new(100.0, 200.0),
595-
};
596-
let transformed = transform_hotspot(hotspot, true, false, rect);
597-
assert_eq!(transformed, (90, 20));
598-
}
584+
fn test_transform_hotspot() {
585+
fn test(hotspot: (u16, u16), flip_x: bool, flip_y: bool, rect: Rect, expected: (u16, u16)) {
586+
let transformed = transform_hotspot(hotspot, flip_x, flip_y, rect);
587+
assert_eq!(transformed, expected);
588+
589+
// Round-trip test: Applying the same transformation again should
590+
// reverse it.
591+
let transformed = transform_hotspot(transformed, flip_x, flip_y, rect);
592+
assert_eq!(transformed, hotspot);
593+
}
599594

600-
#[test]
601-
fn test_transform_hotspot_flip_y() {
602-
let hotspot = (10, 20);
603595
let rect = Rect {
604596
min: Vec2::ZERO,
605597
max: Vec2::new(100.0, 200.0),
606598
};
607-
let transformed = transform_hotspot(hotspot, false, true, rect);
608-
assert_eq!(transformed, (10, 180));
609-
}
610599

611-
#[test]
612-
fn test_transform_hotspot_flip_both() {
613-
let hotspot = (10, 20);
614-
let rect = Rect {
615-
min: Vec2::ZERO,
616-
max: Vec2::new(100.0, 200.0),
617-
};
618-
let transformed = transform_hotspot(hotspot, true, true, rect);
619-
assert_eq!(transformed, (90, 180));
600+
test((10, 20), false, false, rect, (10, 20)); // no flip
601+
test((10, 20), true, false, rect, (89, 20)); // flip X
602+
test((10, 20), false, true, rect, (10, 179)); // flip Y
603+
test((10, 20), true, true, rect, (89, 179)); // flip both
604+
test((0, 0), true, true, rect, (99, 199)); // flip both (bounds check)
620605
}
621606
}

0 commit comments

Comments
 (0)