From 6a218432ec6871edb09ad56253a1f291c78797fc Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Thu, 2 Jan 2025 14:24:08 -0500 Subject: [PATCH 1/8] add ClippingRect type --- src/sdl2/render.rs | 49 ++++++++++++++++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 12 deletions(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index e18e9a06b6..c3abe5a8fd 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -406,6 +406,15 @@ impl RenderTarget for Window { type Context = WindowContext; } +pub enum ClippingRect { + /// a non-zero area clipping rect + Some(Rect), + /// a clipping rect with zero area + Zero, + /// the absence of a clipping rect + None, +} + /// Methods for the `WindowCanvas`. impl Canvas { /// Gets a reference to the associated window of the Canvas @@ -1099,31 +1108,47 @@ impl Canvas { } /// Sets the clip rectangle for rendering on the specified target. - /// - /// If the rectangle is `None`, clipping will be disabled. #[doc(alias = "SDL_RenderSetClipRect")] - pub fn set_clip_rect>>(&mut self, rect: R) { - let rect = rect.into(); - // as_ref is important because we need rect to live until the end of the FFI call, but map_or consumes an Option - let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw()); - let ret = unsafe { sys::SDL_RenderSetClipRect(self.context.raw, ptr) }; + pub fn set_clip_rect(&mut self, arg: ClippingRect) { + let ret = match arg { + ClippingRect::Some(r) => { + unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r.raw()) } + } + ClippingRect::Zero => { + let r = sys::SDL_Rect { + x: 0, + y: 0, + w: 0, + h: 0, + }; + let r: *const sys::SDL_Rect = &r; + unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r) } + } + ClippingRect::None => { + unsafe { sys::SDL_RenderSetClipRect(self.context.raw, ptr::null()) } + } + }; if ret != 0 { panic!("Could not set clip rect: {}", get_error()) } } /// Gets the clip rectangle for the current target. - /// - /// Returns `None` if clipping is disabled. #[doc(alias = "SDL_RenderGetClipRect")] - pub fn clip_rect(&self) -> Option { + pub fn clip_rect(&self) -> ClippingRect { + let clip_enabled = unsafe { sys::SDL_RenderIsClipEnabled(self.context.raw) }; + + if let sys::SDL_bool::SDL_FALSE = clip_enabled { + return ClippingRect::None; + } + let mut raw = mem::MaybeUninit::uninit(); unsafe { sys::SDL_RenderGetClipRect(self.context.raw, raw.as_mut_ptr()) }; let raw = unsafe { raw.assume_init() }; if raw.w == 0 || raw.h == 0 { - None + ClippingRect::Zero } else { - Some(Rect::from_ll(raw)) + ClippingRect::Some(Rect::from_ll(raw)) } } From 13676261eb2f8b547eb86bb04b39fee7c112ebf6 Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Thu, 2 Jan 2025 14:40:35 -0500 Subject: [PATCH 2/8] add derive --- src/sdl2/render.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index c3abe5a8fd..24b146b9d5 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -406,6 +406,7 @@ impl RenderTarget for Window { type Context = WindowContext; } +#[derive(Clone, Copy, Debug)] pub enum ClippingRect { /// a non-zero area clipping rect Some(Rect), From 25b61eb43e3409ae9820ae0b3ef89246588b80d4 Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Sun, 26 Jan 2025 16:50:24 -0500 Subject: [PATCH 3/8] amend previous commit (add eq) --- src/sdl2/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 24b146b9d5..81c1ecaa72 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -406,7 +406,7 @@ impl RenderTarget for Window { type Context = WindowContext; } -#[derive(Clone, Copy, Debug)] +#[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum ClippingRect { /// a non-zero area clipping rect Some(Rect), From 3b8743977e3da625ffabd925b75e850b4c976c0a Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Mon, 27 Jan 2025 09:31:50 -0500 Subject: [PATCH 4/8] cargo fmt --- src/sdl2/render.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 81c1ecaa72..5430763b10 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -1112,9 +1112,9 @@ impl Canvas { #[doc(alias = "SDL_RenderSetClipRect")] pub fn set_clip_rect(&mut self, arg: ClippingRect) { let ret = match arg { - ClippingRect::Some(r) => { - unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r.raw()) } - } + ClippingRect::Some(r) => unsafe { + sys::SDL_RenderSetClipRect(self.context.raw, r.raw()) + }, ClippingRect::Zero => { let r = sys::SDL_Rect { x: 0, @@ -1125,9 +1125,9 @@ impl Canvas { let r: *const sys::SDL_Rect = &r; unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r) } } - ClippingRect::None => { - unsafe { sys::SDL_RenderSetClipRect(self.context.raw, ptr::null()) } - } + ClippingRect::None => unsafe { + sys::SDL_RenderSetClipRect(self.context.raw, ptr::null()) + }, }; if ret != 0 { panic!("Could not set clip rect: {}", get_error()) From acc5d3bc37ebaacb9e2671e7cb321be90c6faf6a Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Mon, 27 Jan 2025 09:35:51 -0500 Subject: [PATCH 5/8] changelog entry --- changelog.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/changelog.md b/changelog.md index 12808ac830..2b4890f912 100644 --- a/changelog.md +++ b/changelog.md @@ -3,6 +3,8 @@ when upgrading from a version of rust-sdl2 to another. ### Next +[PR #1450](https://github.com/Rust-SDL2/rust-sdl2/pull/1450) **BREAKING CHANGE** Create ClippingRect type, to disambiguate between no and zero area clipping rect. + [PR #1416](https://github.com/Rust-SDL2/rust-sdl2/pull/1416) Apply clippy fixes, fix deprecations and other code quality improvements. [PR #1408](https://github.com/Rust-SDL2/rust-sdl2/pull/1408) Allow comparing `Version`s, add constant with the version the bindings were compiled with. From 880632d6f49af6ed21deffab0c1daa0af1f1b90a Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Fri, 7 Feb 2025 22:54:05 -0500 Subject: [PATCH 6/8] improve - settings is now backwards compatible. querying is not --- src/sdl2/render.rs | 65 +++++++++++++++++++++++++++++++++++- tests/render.rs | 82 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 146 insertions(+), 1 deletion(-) create mode 100644 tests/render.rs diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 5430763b10..2ea8630e8d 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -416,6 +416,65 @@ pub enum ClippingRect { None, } +impl Into for Rect { + fn into(self) -> ClippingRect { + ClippingRect::Some(self) + } +} + +impl Into for Option { + fn into(self) -> ClippingRect { + match self { + Some(v) => v.into(), + None => ClippingRect::None, + } + } +} + +impl ClippingRect { + pub fn intersection(&self, other: ClippingRect) -> ClippingRect { + match self { + ClippingRect::Zero => ClippingRect::Zero, + ClippingRect::None => other, + ClippingRect::Some(self_rect) => match other { + ClippingRect::Zero => ClippingRect::Zero, + ClippingRect::None => *self, + ClippingRect::Some(rect) => match self_rect.intersection(rect) { + Some(v) => ClippingRect::Some(v), + None => ClippingRect::Zero, + }, + }, + } + } + + /// shrink the clipping rect to the part which contains the position + pub fn intersect_rect(&self, position: R) -> ClippingRect + where + R: Into>, + { + let position: Option = position.into(); + match position { + Some(position) => { + match self { + ClippingRect::Some(rect) => match rect.intersection(position) { + Some(v) => ClippingRect::Some(v), + None => ClippingRect::Zero, + }, + ClippingRect::Zero => ClippingRect::Zero, + ClippingRect::None => { + // clipping rect has infinite area, so it's just whatever position is + ClippingRect::Some(position) + } + } + } + None => { + // position is zero area so intersection result is zero + ClippingRect::Zero + } + } + } +} + /// Methods for the `WindowCanvas`. impl Canvas { /// Gets a reference to the associated window of the Canvas @@ -1110,7 +1169,11 @@ impl Canvas { /// Sets the clip rectangle for rendering on the specified target. #[doc(alias = "SDL_RenderSetClipRect")] - pub fn set_clip_rect(&mut self, arg: ClippingRect) { + pub fn set_clip_rect(&mut self, arg: R) + where + R: Into, + { + let arg: ClippingRect = arg.into(); let ret = match arg { ClippingRect::Some(r) => unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r.raw()) diff --git a/tests/render.rs b/tests/render.rs new file mode 100644 index 0000000000..f2f7658454 --- /dev/null +++ b/tests/render.rs @@ -0,0 +1,82 @@ +use sdl2::{rect::Rect, render::ClippingRect}; + +extern crate sdl2; + +#[test] +fn clipping_rect_intersection() { + // a zero area clipping rect intersecting with anything else gives zero + assert_eq!( + ClippingRect::Zero.intersection(ClippingRect::Zero), + ClippingRect::Zero + ); + assert_eq!( + ClippingRect::Zero.intersection(ClippingRect::None), + ClippingRect::Zero + ); + assert_eq!( + ClippingRect::Zero.intersection(ClippingRect::Some(Rect::new(0, 0, 1, 1))), + ClippingRect::Zero + ); + + // none gives whatever the arg was + assert_eq!( + ClippingRect::None.intersection(ClippingRect::Zero), + ClippingRect::Zero + ); + assert_eq!( + ClippingRect::None.intersection(ClippingRect::None), + ClippingRect::None + ); + assert_eq!( + ClippingRect::None.intersection(ClippingRect::Some(Rect::new(0, 0, 1, 1))), + ClippingRect::Some(Rect::new(0, 0, 1, 1)) + ); + + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 1, 1)).intersection(ClippingRect::Zero), + ClippingRect::Zero + ); + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 1, 1)).intersection(ClippingRect::None), + ClippingRect::Some(Rect::new(0, 0, 1, 1)) + ); + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 10, 10)) + .intersection(ClippingRect::Some(Rect::new(20, 20, 1, 1))), + ClippingRect::Zero + ); + + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 10, 10)) + .intersection(ClippingRect::Some(Rect::new(5, 5, 10, 10))), + ClippingRect::Some(Rect::new(5, 5, 5, 5)) + ); +} + +#[test] +fn clipping_rect_intersect_rect() { + assert_eq!(ClippingRect::Zero.intersect_rect(None), ClippingRect::Zero); + assert_eq!( + ClippingRect::Zero.intersect_rect(Rect::new(0, 0, 1, 1)), + ClippingRect::Zero + ); + + assert_eq!(ClippingRect::None.intersect_rect(None), ClippingRect::Zero); + assert_eq!( + ClippingRect::None.intersect_rect(Rect::new(0, 0, 1, 1)), + ClippingRect::Some(Rect::new(0, 0, 1, 1)) + ); + + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 1, 1)).intersect_rect(None), + ClippingRect::Zero + ); + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 10, 10)).intersect_rect(Rect::new(5, 5, 10, 10)), + ClippingRect::Some(Rect::new(5, 5, 5, 5)) + ); + assert_eq!( + ClippingRect::Some(Rect::new(0, 0, 10, 10)).intersect_rect(Rect::new(20, 20, 1, 1)), + ClippingRect::Zero + ); +} \ No newline at end of file From 76a697e1a354c904f832cfaceafaef6dcccd8b4f Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Tue, 18 Feb 2025 13:38:38 -0500 Subject: [PATCH 7/8] drop let binding --- src/sdl2/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 2ea8630e8d..fcb35c6f10 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -1202,7 +1202,7 @@ impl Canvas { pub fn clip_rect(&self) -> ClippingRect { let clip_enabled = unsafe { sys::SDL_RenderIsClipEnabled(self.context.raw) }; - if let sys::SDL_bool::SDL_FALSE = clip_enabled { + if sys::SDL_bool::SDL_FALSE == clip_enabled { return ClippingRect::None; } From e7f01849a1274972a14d5c1fb7b17aa53f198f48 Mon Sep 17 00:00:00 2001 From: John Giorshev Date: Tue, 18 Feb 2025 13:43:53 -0500 Subject: [PATCH 8/8] fix fmt --- tests/render.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/render.rs b/tests/render.rs index f2f7658454..d7dcbd8add 100644 --- a/tests/render.rs +++ b/tests/render.rs @@ -79,4 +79,4 @@ fn clipping_rect_intersect_rect() { ClippingRect::Some(Rect::new(0, 0, 10, 10)).intersect_rect(Rect::new(20, 20, 1, 1)), ClippingRect::Zero ); -} \ No newline at end of file +}