From 5195fb042be6785ab436a8905dd0d18d37c7ecb4 Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Mon, 7 Mar 2022 11:49:15 +0800 Subject: [PATCH 1/7] Implement some more renderer functions --- src/sdl2/render.rs | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index e88c90cf36..ed153eacc4 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -1189,6 +1189,40 @@ impl Canvas { (scale_x, scale_y) } + /// Get logical coordinates of point in renderer when given real coordinates of point in window. + #[doc(alias = "SDL_RenderWindowToLogical")] + pub fn window_to_logical(&self, window_x: i32, window_y: i32) -> (f32, f32) { + let mut logical_x = 0.0; + let mut logical_y = 0.0; + unsafe { + sys::SDL_RenderWindowToLogical( + self.context.raw, + window_x, + window_y, + &mut logical_x, + &mut logical_y, + ) + }; + (logical_x, logical_y) + } + + /// Get real coordinates of point in window when given logical coordinates of point in renderer. + #[doc(alias = "SDL_RenderLogicalToWindow")] + pub fn logical_to_window(&self, logical_x: f32, logical_y: f32) -> (i32, i32) { + let mut window_x = 0; + let mut window_y = 0; + unsafe { + sys::SDL_RenderLogicalToWindow( + self.context.raw, + logical_x, + logical_y, + &mut window_x, + &mut window_y, + ) + }; + (window_x, window_y) + } + /// Draws a point on the current rendering target. /// Errors if drawing fails for any reason (e.g. driver failure) #[doc(alias = "SDL_RenderDrawPoint")] @@ -1615,6 +1649,18 @@ impl Canvas { panic!("Error setting blend: {}", get_error()) } } + + /// Toggle VSync. + #[doc(alias = "SDL_RenderSetVSync")] + pub unsafe fn set_vsync(&self, vsync: i32) -> Result<(), String> { + let ret = sys::SDL_RenderSetVSync(self.context.raw, vsync); + + if ret != 0 { + Err(get_error()) + } else { + Ok(()) + } + } } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] From 5ec5ea7c0efd2a647a5db0a9cfbff820252c678d Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Mon, 7 Mar 2022 12:30:49 +0800 Subject: [PATCH 2/7] Implement SDL_FPoint --- src/sdl2/rect.rs | 205 ++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/src/sdl2/rect.rs b/src/sdl2/rect.rs index efe8e06289..cfc15edbce 100644 --- a/src/sdl2/rect.rs +++ b/src/sdl2/rect.rs @@ -662,7 +662,7 @@ impl BitOr for Rect { } } -/// Immutable point type, consisting of x and y. +/// Immutable point type, consisting of integer x and y. #[derive(Copy, Clone)] pub struct Point { raw: sys::SDL_Point, @@ -897,6 +897,209 @@ impl std::iter::Sum for Point { } } +/// Immutable point type, consisting of floating point x and y. +#[derive(Copy, Clone)] +pub struct FPoint { + raw: sys::SDL_FPoint, +} + +impl ::std::fmt::Debug for FPoint { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + return write!(fmt, "FPoint {{ x: {}, y: {} }}", self.raw.x, self.raw.y); + } +} + +impl PartialEq for FPoint { + fn eq(&self, other: &FPoint) -> bool { + self.raw.x == other.raw.x && self.raw.y == other.raw.y + } +} + +impl Deref for FPoint { + type Target = sys::SDL_FPoint; + + /// # Example + /// + /// ```rust + /// use sdl2::rect::FPoint; + /// let point = FPoint::new(2.0, 3.0); + /// assert_eq!(2.0, point.x); + /// ``` + fn deref(&self) -> &sys::SDL_FPoint { + &self.raw + } +} + +impl DerefMut for FPoint { + /// # Example + /// + /// ```rust + /// use sdl2::rect::FPoint; + /// let mut point = FPoint::new(2.0, 3.0); + /// point.x = 4.0; + /// assert_eq!(4.0, point.x); + /// ``` + fn deref_mut(&mut self) -> &mut sys::SDL_FPoint { + &mut self.raw + } +} + +impl AsRef for FPoint { + fn as_ref(&self) -> &sys::SDL_FPoint { + &self.raw + } +} + +impl AsMut for FPoint { + fn as_mut(&mut self) -> &mut sys::SDL_FPoint { + &mut self.raw + } +} + +impl From for FPoint { + fn from(prim: sys::SDL_FPoint) -> FPoint { + FPoint { raw: prim } + } +} + +impl From<(f32, f32)> for FPoint { + fn from((x, y): (f32, f32)) -> FPoint { + FPoint::new(x, y) + } +} + +impl Into for FPoint { + fn into(self) -> sys::SDL_FPoint { + self.raw + } +} + +impl Into<(f32, f32)> for FPoint { + fn into(self) -> (f32, f32) { + (self.x(), self.y()) + } +} + +impl FPoint { + /// Creates a new FPoint from the given coordinates. + pub fn new(x: f32, y: f32) -> FPoint { + FPoint { + raw: sys::SDL_FPoint { x, y }, + } + } + + pub fn from_ll(raw: sys::SDL_FPoint) -> FPoint { + FPoint::new(raw.x, raw.y) + } + + #[doc(alias = "SDL_FPoint")] + pub fn raw_slice(slice: &[FPoint]) -> *const sys::SDL_FPoint { + slice.as_ptr() as *const sys::SDL_FPoint + } + // this can prevent introducing UB until + // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn raw(&self) -> *const sys::SDL_FPoint { + &self.raw + } + + /// Returns a new FPoint by shifting this point's coordinates by the given + /// x and y values. + pub fn offset(self, x: f32, y: f32) -> FPoint { + FPoint::new(self.raw.x + x, self.raw.y + y) + } + + /// Returns a new point by multiplying this point's coordinates by the + /// given scale factor. + pub fn scale(self, f: f32) -> FPoint { + FPoint::new(self.raw.x * f, self.raw.y * f) + } + + /// Returns the x-coordinate of this point. + pub fn x(self) -> f32 { + self.raw.x + } + + /// Returns the y-coordinate of this point. + pub fn y(self) -> f32 { + self.raw.y + } +} + +impl Add for FPoint { + type Output = FPoint; + + fn add(self, rhs: FPoint) -> FPoint { + self.offset(rhs.x(), rhs.y()) + } +} + +impl AddAssign for FPoint { + fn add_assign(&mut self, rhs: FPoint) { + self.raw.x = self.x() + rhs.x(); + self.raw.y = self.y() + rhs.y(); + } +} + +impl Neg for FPoint { + type Output = FPoint; + + fn neg(self) -> FPoint { + FPoint::new(-self.x(), -self.y()) + } +} + +impl Sub for FPoint { + type Output = FPoint; + + fn sub(self, rhs: FPoint) -> FPoint { + self.offset(-rhs.x(), -rhs.y()) + } +} + +impl SubAssign for FPoint { + fn sub_assign(&mut self, rhs: FPoint) { + self.raw.x = self.x() - rhs.x(); + self.raw.y = self.y() - rhs.y(); + } +} + +impl Mul for FPoint { + type Output = FPoint; + + fn mul(self, rhs: f32) -> FPoint { + self.scale(rhs) + } +} + +impl MulAssign for FPoint { + fn mul_assign(&mut self, rhs: f32) { + self.raw.x = self.x() * rhs; + self.raw.y = self.y() * rhs; + } +} + +impl Div for FPoint { + type Output = FPoint; + + fn div(self, rhs: f32) -> FPoint { + FPoint::new(self.x() / rhs, self.y() / rhs) + } +} + +impl DivAssign for FPoint { + fn div_assign(&mut self, rhs: f32) { + self.raw.x /= rhs; + self.raw.y /= rhs; + } +} + +impl std::iter::Sum for FPoint { + fn sum>(iter: I) -> Self { + iter.fold(FPoint::new(0.0, 0.0), FPoint::add) + } +} + #[cfg(test)] mod test { use super::{max_int_value, min_int_value, Point, Rect}; From 02e5ec8f52a98a136658694b08ba2c6b22a3c7ad Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Mon, 7 Mar 2022 12:48:29 +0800 Subject: [PATCH 3/7] Implement SDL_UpdateNVTexture --- src/sdl2/render.rs | 141 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 141 insertions(+) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index ed153eacc4..953f8d3622 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -2181,6 +2181,115 @@ impl InternalTexture { } } + #[doc(alias = "SDL_UpdateNVTexture")] + pub fn update_nv( + &mut self, + rect: R, + y_plane: &[u8], + y_pitch: usize, + uv_plane: &[u8], + uv_pitch: usize, + ) -> Result<(), UpdateTextureYUVError> + where + R: Into>, + { + use self::UpdateTextureYUVError::*; + + let rect = rect.into(); + + let rect_raw_ptr = match rect { + Some(ref rect) => rect.raw(), + None => ptr::null(), + }; + + if let Some(ref r) = rect { + if r.x() % 2 != 0 { + return Err(XMustBeMultipleOfTwoForFormat(r.x())); + } else if r.y() % 2 != 0 { + return Err(YMustBeMultipleOfTwoForFormat(r.y())); + } else if r.width() % 2 != 0 { + return Err(WidthMustBeMultipleOfTwoForFormat(r.width())); + } else if r.height() % 2 != 0 { + return Err(HeightMustBeMultipleOfTwoForFormat(r.height())); + } + }; + + // If the destination rectangle lies outside the texture boundaries, + // SDL_UpdateNVTexture will write outside allocated texture memory. + let tex_info = self.query(); + if let Some(ref r) = rect { + let tex_rect = Rect::new(0, 0, tex_info.width, tex_info.height); + let inside = match r.intersection(tex_rect) { + Some(intersection) => intersection == *r, + None => false, + }; + // The destination rectangle cannot lie outside the texture boundaries + if !inside { + return Err(RectNotInsideTexture(*r)); + } + } + + // We need the height in order to check the array slice lengths. + // Checking the lengths can prevent buffer overruns in SDL_UpdateNVTexture. + let height = match rect { + Some(ref r) => r.height(), + None => tex_info.height, + } as usize; + + //let wrong_length = + if y_plane.len() != (y_pitch * height) { + return Err(InvalidPlaneLength { + plane: "y", + length: y_plane.len(), + pitch: y_pitch, + height, + }); + } + if uv_plane.len() != (uv_pitch * height) { + return Err(InvalidPlaneLength { + plane: "uv", + length: uv_plane.len(), + pitch: uv_pitch, + height: height, + }); + } + + let y_pitch = match validate_int(y_pitch as u32, "y_pitch") { + Ok(p) => p, + Err(_) => { + return Err(PitchOverflows { + plane: "y", + value: y_pitch, + }) + } + }; + let uv_pitch = match validate_int(uv_pitch as u32, "uv_pitch") { + Ok(p) => p, + Err(_) => { + return Err(PitchOverflows { + plane: "uv", + value: uv_pitch, + }) + } + }; + + let result = unsafe { + sys::SDL_UpdateNVTexture( + self.raw, + rect_raw_ptr, + y_plane.as_ptr(), + y_pitch, + uv_plane.as_ptr(), + uv_pitch, + ) + }; + if result != 0 { + Err(SdlError(get_error())) + } else { + Ok(()) + } + } + #[doc(alias = "SDL_LockTexture")] pub fn with_lock(&mut self, rect: R2, func: F) -> Result where @@ -2346,6 +2455,22 @@ impl<'r> Texture<'r> { .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch) } + /// Update a rectangle within a planar NV12 or NV21 texture with new pixel data. + #[inline] + pub fn update_nv( + &mut self, + rect: R, + y_plane: &[u8], + y_pitch: usize, + uv_plane: &[u8], + uv_pitch: usize, + ) -> Result<(), UpdateTextureYUVError> + where + R: Into>, + { + InternalTexture { raw: self.raw }.update_nv(rect, y_plane, y_pitch, uv_plane, uv_pitch) + } + /// Locks the texture for **write-only** pixel access. /// The texture must have been created with streaming access. /// @@ -2543,6 +2668,22 @@ impl Texture { .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch) } + /// Update a rectangle within a planar NV12 or NV21 texture with new pixel data. + #[inline] + pub fn update_nv( + &mut self, + rect: R, + y_plane: &[u8], + y_pitch: usize, + uv_plane: &[u8], + uv_pitch: usize, + ) -> Result<(), UpdateTextureYUVError> + where + R: Into>, + { + InternalTexture { raw: self.raw }.update_nv(rect, y_plane, y_pitch, uv_plane, uv_pitch) + } + /// Locks the texture for **write-only** pixel access. /// The texture must have been created with streaming access. /// From d19671ddc83c5ca2de2295bfd4a5404732662341 Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Tue, 8 Mar 2022 00:40:52 +0800 Subject: [PATCH 4/7] Implement SDL_Vertex and SDL_RenderGeometry --- src/sdl2/render.rs | 167 ++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 166 insertions(+), 1 deletion(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 953f8d3622..21d47be437 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -32,6 +32,7 @@ use crate::common::{validate_int, IntegerOrSdlError}; use crate::get_error; use crate::pixels; use crate::pixels::PixelFormatEnum; +use crate::rect::FPoint; use crate::rect::Point; use crate::rect::Rect; use crate::surface; @@ -47,7 +48,7 @@ use std::fmt; use std::marker::PhantomData; use std::mem; use std::mem::{transmute, MaybeUninit}; -use std::ops::Deref; +use std::ops::{Deref, DerefMut}; use std::ptr; use std::rc::Rc; @@ -100,6 +101,106 @@ impl Error for TargetRenderError { } } +#[derive(Copy, Clone)] +pub struct Vertex { + raw: sys::SDL_Vertex, +} + +pub trait VertexIndex {} + +impl VertexIndex for u8 {} +impl VertexIndex for u16 {} +impl VertexIndex for u32 {} + +impl ::std::fmt::Debug for Vertex { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + return write!( + fmt, + "Vertex {{ position: {:?}, color: {:?}, tex_coord: {:?} }}", + self.position(), + self.color(), + self.tex_coord(), + ); + } +} + +impl Deref for Vertex { + type Target = sys::SDL_Vertex; + + fn deref(&self) -> &sys::SDL_Vertex { + &self.raw + } +} + +impl DerefMut for Vertex { + fn deref_mut(&mut self) -> &mut sys::SDL_Vertex { + &mut self.raw + } +} + +impl AsRef for Vertex { + fn as_ref(&self) -> &sys::SDL_Vertex { + &self.raw + } +} + +impl AsMut for Vertex { + fn as_mut(&mut self) -> &mut sys::SDL_Vertex { + &mut self.raw + } +} + +impl From for Vertex { + fn from(prim: sys::SDL_Vertex) -> Vertex { + Vertex { raw: prim } + } +} + +impl Into for Vertex { + fn into(self) -> sys::SDL_Vertex { + self.raw + } +} + +impl Vertex { + pub fn new(position: FPoint, color: pixels::Color, tex_coord: FPoint) -> Vertex { + Vertex { + raw: sys::SDL_Vertex { + position: position.into(), + color: color.into(), + tex_coord: tex_coord.into(), + }, + } + } + + pub fn from_ll(raw: sys::SDL_Vertex) -> Vertex { + Vertex::new(raw.position.into(), raw.color.into(), raw.tex_coord.into()) + } + + #[doc(alias = "SDL_Vertex")] + pub fn raw_slice(slice: &[Vertex]) -> *const sys::SDL_Vertex { + slice.as_ptr() as *const sys::SDL_Vertex + } + // this can prevent introducing UB until + // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed + #[allow(clippy::trivially_copy_pass_by_ref)] + pub fn raw(&self) -> *const sys::SDL_Vertex { + &self.raw + } + + pub fn position(self) -> FPoint { + self.raw.position.into() + } + + pub fn color(self) -> pixels::Color { + self.raw.color.into() + } + + pub fn tex_coord(self) -> FPoint { + self.raw.tex_coord.into() + } +} + #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] #[repr(i32)] pub enum TextureAccess { @@ -1468,6 +1569,70 @@ impl Canvas { } } + /// Render a list of triangles, optionally using a texture and indices into the vertex array. + #[doc(alias = "SDL_RenderGeometry")] + pub fn geometry( + &mut self, + texture: &Texture, + vertices: &[Vertex], + indices: &[u32], + ) -> Result<(), String> { + let result = unsafe { + sys::SDL_RenderGeometry( + self.context.raw, + texture.raw, + Vertex::raw_slice(vertices), + vertices.len() as c_int, + indices.as_ptr() as *const i32, + indices.len() as c_int, + ) + }; + + if result != 0 { + Err(get_error()) + } else { + Ok(()) + } + } + + /// Render a list of triangles, optionally using a texture and indices into the vertex arrays. + #[doc(alias = "SDL_RenderGeometryRaw")] + pub fn geometry_raw( + &mut self, + texture: &Texture, + xy: &[f32], + xy_stride: i32, + color: &[sys::SDL_Color], + color_stride: i32, + uv: &[f32], + uv_stride: i32, + num_vertices: i32, + indices: &[I], + ) -> Result<(), String> { + let result = unsafe { + sys::SDL_RenderGeometryRaw( + self.context.raw, + texture.raw, + xy.as_ptr(), + xy_stride as c_int, + color.as_ptr(), + color_stride as c_int, + uv.as_ptr(), + uv_stride as c_int, + num_vertices as c_int, + indices.as_ptr() as *const c_void, + indices.len() as c_int, + std::mem::size_of::() as i32, + ) + }; + + if result != 0 { + Err(get_error()) + } else { + Ok(()) + } + } + /// Reads pixels from the current rendering target. /// # Remarks /// WARNING: This is a very slow operation, and should not be used frequently. From d519ffc043594cb3b31fd91edca94c63f8bdeb08 Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Wed, 9 Mar 2022 20:51:10 +0800 Subject: [PATCH 5/7] Create RColor type to directly wrap SDL_Color --- examples/animation.rs | 2 +- src/sdl2/gfx/primitives.rs | 7 ++ src/sdl2/pixels.rs | 172 ++++++++++++++++++++++++++++++++++++- src/sdl2/render.rs | 39 +++++---- src/sdl2/surface.rs | 32 ++++--- 5 files changed, 218 insertions(+), 34 deletions(-) diff --git a/examples/animation.rs b/examples/animation.rs index 44024156ac..583cafeb2c 100644 --- a/examples/animation.rs +++ b/examples/animation.rs @@ -24,7 +24,7 @@ fn main() -> Result<(), String> { .map_err(|e| e.to_string())?; let texture_creator = canvas.texture_creator(); - canvas.set_draw_color(sdl2::pixels::Color::RGBA(0, 0, 0, 255)); + canvas.set_draw_color(sdl2::pixels::RColor::RGBA(0, 0, 0, 255)); let timer = sdl_context.timer()?; diff --git a/src/sdl2/gfx/primitives.rs b/src/sdl2/gfx/primitives.rs index b3e634a64c..ccd2d66997 100644 --- a/src/sdl2/gfx/primitives.rs +++ b/src/sdl2/gfx/primitives.rs @@ -29,6 +29,13 @@ impl ToColor for pixels::Color { } } +impl ToColor for pixels::RColor { + #[inline] + fn as_rgba(&self) -> (u8, u8, u8, u8) { + self.rgba() + } +} + impl ToColor for (u8, u8, u8, u8) { #[inline] fn as_rgba(&self) -> (u8, u8, u8, u8) { diff --git a/src/sdl2/pixels.rs b/src/sdl2/pixels.rs index 9e55f874c4..1a8bba2e26 100644 --- a/src/sdl2/pixels.rs +++ b/src/sdl2/pixels.rs @@ -1,6 +1,8 @@ use crate::sys; -use std::convert::TryFrom; +use std::convert::{AsMut, AsRef, TryFrom}; +use std::hash::{Hash, Hasher}; use std::mem::transmute; +use std::ops::{Deref, DerefMut}; use crate::get_error; @@ -41,7 +43,10 @@ impl Palette { /// Creates a palette from the provided colors #[doc(alias = "SDL_SetPaletteColors")] - pub fn with_colors(colors: &[Color]) -> Result { + pub fn with_colors(colors: &[C]) -> Result + where + C: Copy + Into, + { let pal = Self::new(colors.len())?; // Already validated, so don't check again @@ -49,7 +54,7 @@ impl Palette { let result = unsafe { let mut raw_colors: Vec = - colors.iter().map(|color| color.raw()).collect(); + colors.iter().map(|color| (*color).into().raw).collect(); let pal_ptr = (&mut raw_colors[0]) as *mut sys::SDL_Color; @@ -85,7 +90,7 @@ impl_raw_accessors!((Palette, *mut sys::SDL_Palette)); #[test] fn create_palette() { - let colors: Vec<_> = (0..0xff).map(|u| Color::RGB(u, 0, 0xff - u)).collect(); + let colors: Vec<_> = (0..0xff).map(|u| RColor::RGB(u, 0, 0xff - u)).collect(); let palette = Palette::with_colors(&colors).unwrap(); @@ -93,6 +98,7 @@ fn create_palette() { } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] +#[deprecated(since = "0.35.3", note = "Users should instead use RColor")] pub struct Color { pub r: u8, pub g: u8, @@ -100,6 +106,7 @@ pub struct Color { pub a: u8, } +#[allow(deprecated)] impl Color { #[inline] #[allow(non_snake_case)] @@ -163,30 +170,187 @@ impl Color { pub const CYAN: Color = Color::RGBA(0, 255, 255, 255); } +#[allow(deprecated)] impl Into for Color { fn into(self) -> sys::SDL_Color { self.raw() } } +#[allow(deprecated)] impl From for Color { fn from(raw: sys::SDL_Color) -> Color { Color::RGBA(raw.r, raw.g, raw.b, raw.a) } } +#[allow(deprecated)] impl From<(u8, u8, u8)> for Color { fn from((r, g, b): (u8, u8, u8)) -> Color { Color::RGB(r, g, b) } } +#[allow(deprecated)] impl From<(u8, u8, u8, u8)> for Color { fn from((r, g, b, a): (u8, u8, u8, u8)) -> Color { Color::RGBA(r, g, b, a) } } +#[allow(deprecated)] +impl Into for Color { + fn into(self) -> RColor { + RColor::RGBA(self.r, self.g, self.b, self.a) + } +} + +#[derive(Copy, Clone)] +pub struct RColor { + raw: sys::SDL_Color, +} + +impl RColor { + #[inline] + #[allow(non_snake_case)] + pub const fn RGB(r: u8, g: u8, b: u8) -> RColor { + RColor { + raw: sys::SDL_Color { r, g, b, a: 0xff }, + } + } + + #[inline] + #[allow(non_snake_case)] + pub const fn RGBA(r: u8, g: u8, b: u8, a: u8) -> RColor { + RColor { + raw: sys::SDL_Color { r, g, b, a }, + } + } + + #[doc(alias = "SDL_MapRGBA")] + pub fn to_u32(self, format: &PixelFormat) -> u32 { + unsafe { sys::SDL_MapRGBA(format.raw, self.raw.r, self.raw.g, self.raw.b, self.raw.a) } + } + + #[doc(alias = "SDL_GetRGBA")] + pub fn from_u32(format: &PixelFormat, pixel: u32) -> RColor { + let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0); + + unsafe { sys::SDL_GetRGBA(pixel, format.raw, &mut r, &mut g, &mut b, &mut a) }; + RColor::RGBA(r, g, b, a) + } + + pub fn invert(self) -> RColor { + RColor::RGBA( + 255 - self.raw.r, + 255 - self.raw.g, + 255 - self.raw.b, + 255 - self.raw.a, + ) + } + + #[inline] + pub const fn rgb(self) -> (u8, u8, u8) { + (self.raw.r, self.raw.g, self.raw.b) + } + + #[inline] + pub const fn rgba(self) -> (u8, u8, u8, u8) { + (self.raw.r, self.raw.g, self.raw.b, self.raw.a) + } + + #[inline] + pub const fn raw(self) -> sys::SDL_Color { + self.raw + } + + pub const WHITE: RColor = RColor::RGBA(255, 255, 255, 255); + pub const BLACK: RColor = RColor::RGBA(0, 0, 0, 255); + pub const GRAY: RColor = RColor::RGBA(128, 128, 128, 255); + pub const GREY: RColor = RColor::GRAY; + pub const RED: RColor = RColor::RGBA(255, 0, 0, 255); + pub const GREEN: RColor = RColor::RGBA(0, 255, 0, 255); + pub const BLUE: RColor = RColor::RGBA(0, 0, 255, 255); + pub const MAGENTA: RColor = RColor::RGBA(255, 0, 255, 255); + pub const YELLOW: RColor = RColor::RGBA(255, 255, 0, 255); + pub const CYAN: RColor = RColor::RGBA(0, 255, 255, 255); +} + +impl ::std::fmt::Debug for RColor { + fn fmt(&self, fmt: &mut ::std::fmt::Formatter) -> Result<(), ::std::fmt::Error> { + return write!( + fmt, + "RColor {{ r: {}, g: {}, b: {}, a: {} }}", + self.raw.r, self.raw.g, self.raw.b, self.raw.a + ); + } +} + +impl PartialEq for RColor { + fn eq(&self, other: &RColor) -> bool { + self.raw.r == other.raw.r + && self.raw.g == other.raw.g + && self.raw.b == other.raw.b + && self.raw.a == other.raw.a + } +} + +impl Eq for RColor {} + +impl Hash for RColor { + fn hash(&self, state: &mut H) { + self.raw.r.hash(state); + self.raw.g.hash(state); + self.raw.b.hash(state); + self.raw.a.hash(state); + } +} + +impl Deref for RColor { + type Target = sys::SDL_Color; + + fn deref(&self) -> &sys::SDL_Color { + &self.raw + } +} + +impl DerefMut for RColor { + fn deref_mut(&mut self) -> &mut sys::SDL_Color { + &mut self.raw + } +} + +impl AsRef for RColor { + fn as_ref(&self) -> &sys::SDL_Color { + &self.raw + } +} + +impl AsMut for RColor { + fn as_mut(&mut self) -> &mut sys::SDL_Color { + &mut self.raw + } +} + +impl Into for RColor { + fn into(self) -> sys::SDL_Color { + self.raw + } +} + +impl From for RColor { + fn from(raw: sys::SDL_Color) -> RColor { + RColor { raw } + } +} + +#[allow(deprecated)] +impl Into for RColor { + fn into(self) -> Color { + Color::RGBA(self.raw.r, self.raw.g, self.raw.b, self.raw.a) + } +} + pub struct PixelMasks { /// Bits per pixel; usually 15, 16, or 32 pub bpp: u8, diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 21d47be437..b9cc865b8b 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -163,18 +163,21 @@ impl Into for Vertex { } impl Vertex { - pub fn new(position: FPoint, color: pixels::Color, tex_coord: FPoint) -> Vertex { + pub fn new(position: FPoint, color: C, tex_coord: FPoint) -> Vertex + where + C: Copy + Into, + { Vertex { raw: sys::SDL_Vertex { position: position.into(), - color: color.into(), + color: color.into().raw(), tex_coord: tex_coord.into(), }, } } pub fn from_ll(raw: sys::SDL_Vertex) -> Vertex { - Vertex::new(raw.position.into(), raw.color.into(), raw.tex_coord.into()) + Vertex::new(raw.position.into(), raw.color, raw.tex_coord.into()) } #[doc(alias = "SDL_Vertex")] @@ -192,7 +195,7 @@ impl Vertex { self.raw.position.into() } - pub fn color(self) -> pixels::Color { + pub fn color(self) -> pixels::RColor { self.raw.color.into() } @@ -408,7 +411,7 @@ impl<'s> RenderTarget for Surface<'s> { /// ```rust,no_run /// # use sdl2::render::Canvas; /// # use sdl2::video::Window; -/// # use sdl2::pixels::Color; +/// # use sdl2::pixels::RColor; /// # use sdl2::rect::Rect; /// # let sdl_context = sdl2::init().unwrap(); /// # let video_subsystem = sdl_context.video().unwrap(); @@ -420,12 +423,12 @@ impl<'s> RenderTarget for Surface<'s> { /// // render faster than your display rate (usually 60Hz or 144Hz) /// .build().unwrap(); /// -/// canvas.set_draw_color(Color::RGB(0, 0, 0)); +/// canvas.set_draw_color(RColor::RGB(0, 0, 0)); /// // fills the canvas with the color we set in `set_draw_color`. /// canvas.clear(); /// /// // change the color of our drawing with a gold-color ... -/// canvas.set_draw_color(Color::RGB(255, 210, 0)); +/// canvas.set_draw_color(RColor::RGB(255, 210, 0)); /// // A draw a rectangle which almost fills our window with it ! /// canvas.fill_rect(Rect::new(10, 10, 780, 580)); /// @@ -609,7 +612,7 @@ impl Canvas { /// ```rust,no_run /// # use sdl2::render::{Canvas, Texture}; /// # use sdl2::video::Window; - /// # use sdl2::pixels::Color; + /// # use sdl2::pixels::RColor; /// # use sdl2::rect::Rect; /// # let mut canvas : Canvas = unimplemented!(); /// let texture_creator = canvas.texture_creator(); @@ -617,9 +620,9 @@ impl Canvas { /// .create_texture_target(texture_creator.default_pixel_format(), 150, 150) /// .unwrap(); /// let result = canvas.with_texture_canvas(&mut texture, |texture_canvas| { - /// texture_canvas.set_draw_color(Color::RGBA(0, 0, 0, 255)); + /// texture_canvas.set_draw_color(RColor::RGBA(0, 0, 0, 255)); /// texture_canvas.clear(); - /// texture_canvas.set_draw_color(Color::RGBA(255, 0, 0, 255)); + /// texture_canvas.set_draw_color(RColor::RGBA(255, 0, 0, 255)); /// texture_canvas.fill_rect(Rect::new(50, 50, 50, 50)).unwrap(); /// }); /// ``` @@ -665,7 +668,7 @@ impl Canvas { /// Let's create two textures, one which will be yellow, and the other will be white /// /// ```rust,no_run - /// # use sdl2::pixels::Color; + /// # use sdl2::pixels::RColor; /// # use sdl2::rect::Rect; /// # use sdl2::video::Window; /// # use sdl2::render::{Canvas, Texture}; @@ -688,10 +691,10 @@ impl Canvas { /// canvas.with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| { /// match *user_context { /// TextureColor::White => { - /// texture_canvas.set_draw_color(Color::RGB(255, 255, 255)); + /// texture_canvas.set_draw_color(RColor::RGB(255, 255, 255)); /// }, /// TextureColor::Yellow => { - /// texture_canvas.set_draw_color(Color::RGB(255, 255, 0)); + /// texture_canvas.set_draw_color(RColor::RGB(255, 255, 0)); /// } /// }; /// texture_canvas.clear(); @@ -1083,7 +1086,7 @@ impl Canvas { /// Sets the color used for drawing operations (Rect, Line and Clear). #[doc(alias = "SDL_SetRenderDrawColor")] - pub fn set_draw_color>(&mut self, color: C) { + pub fn set_draw_color>(&mut self, color: C) { let (r, g, b, a) = color.into().rgba(); let ret = unsafe { sys::SDL_SetRenderDrawColor(self.raw, r, g, b, a) }; // Should only fail on an invalid renderer @@ -1094,7 +1097,7 @@ impl Canvas { /// Gets the color used for drawing operations (Rect, Line and Clear). #[doc(alias = "SDL_GetRenderDrawColor")] - pub fn draw_color(&self) -> pixels::Color { + pub fn draw_color(&self) -> pixels::RColor { let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0); let ret = unsafe { sys::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a) @@ -1103,7 +1106,7 @@ impl Canvas { if ret != 0 { panic!("{}", get_error()) } else { - pixels::Color::RGBA(r, g, b, a) + pixels::RColor::RGBA(r, g, b, a) } } @@ -1602,7 +1605,7 @@ impl Canvas { texture: &Texture, xy: &[f32], xy_stride: i32, - color: &[sys::SDL_Color], + color: &[pixels::RColor], color_stride: i32, uv: &[f32], uv_stride: i32, @@ -1615,7 +1618,7 @@ impl Canvas { texture.raw, xy.as_ptr(), xy_stride as c_int, - color.as_ptr(), + color.as_ptr() as *const sys::SDL_Color, color_stride as c_int, uv.as_ptr(), uv_stride as c_int, diff --git a/src/sdl2/surface.rs b/src/sdl2/surface.rs index bb92e182f9..1ed22eadfc 100644 --- a/src/sdl2/surface.rs +++ b/src/sdl2/surface.rs @@ -487,8 +487,11 @@ impl SurfaceRef { } #[doc(alias = "SDL_SetColorKey")] - pub fn set_color_key(&mut self, enable: bool, color: pixels::Color) -> Result<(), String> { - let key = color.to_u32(&self.pixel_format()); + pub fn set_color_key(&mut self, enable: bool, color: C) -> Result<(), String> + where + C: Copy + Into, + { + let key = color.into().to_u32(&self.pixel_format()); let result = unsafe { sys::SDL_SetColorKey(self.raw(), if enable { 1 } else { 0 }, key) }; if result == 0 { Ok(()) @@ -499,7 +502,7 @@ impl SurfaceRef { /// The function will fail if the surface doesn't have color key enabled. #[doc(alias = "SDL_GetColorKey")] - pub fn color_key(&self) -> Result { + pub fn color_key(&self) -> Result { let mut key = 0; // SDL_GetColorKey does not mutate, but requires a non-const pointer anyway. @@ -507,15 +510,18 @@ impl SurfaceRef { let result = unsafe { sys::SDL_GetColorKey(self.raw(), &mut key) }; if result == 0 { - Ok(pixels::Color::from_u32(&self.pixel_format(), key)) + Ok(pixels::RColor::from_u32(&self.pixel_format(), key)) } else { Err(get_error()) } } #[doc(alias = "SDL_SetSurfaceColorMod")] - pub fn set_color_mod(&mut self, color: pixels::Color) { - let (r, g, b) = color.rgb(); + pub fn set_color_mod(&mut self, color: C) + where + C: Copy + Into, + { + let (r, g, b) = color.into().rgb(); let result = unsafe { sys::SDL_SetSurfaceColorMod(self.raw(), r, g, b) }; if result != 0 { @@ -525,7 +531,7 @@ impl SurfaceRef { } #[doc(alias = "SDL_GetSurfaceColorMod")] - pub fn color_mod(&self) -> pixels::Color { + pub fn color_mod(&self) -> pixels::RColor { let mut r = 0; let mut g = 0; let mut b = 0; @@ -536,7 +542,7 @@ impl SurfaceRef { unsafe { sys::SDL_GetSurfaceColorMod(self.raw(), &mut r, &mut g, &mut b) == 0 }; if result { - pixels::Color::RGB(r, g, b) + pixels::RColor::RGB(r, g, b) } else { // Should only fail on a null Surface panic!("{}", get_error()) @@ -544,16 +550,17 @@ impl SurfaceRef { } #[doc(alias = "SDL_FillRect")] - pub fn fill_rect(&mut self, rect: R, color: pixels::Color) -> Result<(), String> + pub fn fill_rect(&mut self, rect: R, color: C) -> Result<(), String> where R: Into>, + C: Into, { unsafe { let rect = rect.into(); let rect_ptr = mem::transmute(rect.as_ref()); // TODO find a better way to transform // Option<&...> into a *const _ let format = self.pixel_format(); - let result = sys::SDL_FillRect(self.raw(), rect_ptr, color.to_u32(&format)); + let result = sys::SDL_FillRect(self.raw(), rect_ptr, color.into().to_u32(&format)); match result { 0 => Ok(()), _ => Err(get_error()), @@ -562,7 +569,10 @@ impl SurfaceRef { } #[allow(clippy::clone_on_copy)] - pub fn fill_rects(&mut self, rects: &[Rect], color: pixels::Color) -> Result<(), String> { + pub fn fill_rects(&mut self, rects: &[Rect], color: C) -> Result<(), String> + where + C: Copy + Into, + { for rect in rects.iter() { if let Err(e) = self.fill_rect(rect.clone(), color) { return Err(e); From 1d3e11410c1f78ac11687f8dc11c4a8846959ac1 Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Wed, 9 Mar 2022 21:19:57 +0800 Subject: [PATCH 6/7] Replace Color in example code with RColor --- examples/cursor.rs | 4 ++-- examples/demo.rs | 4 ++-- examples/events.rs | 4 ++-- examples/game-of-life-unsafe-textures.rs | 20 ++++++++++---------- examples/game-of-life.rs | 20 ++++++++++---------- examples/message-box.rs | 4 ++-- examples/no-renderer.rs | 12 ++++++------ examples/renderer-target.rs | 6 +++--- examples/window-properties.rs | 4 ++-- 9 files changed, 39 insertions(+), 39 deletions(-) diff --git a/examples/cursor.rs b/examples/cursor.rs index 4399acc86c..7fba9fe787 100644 --- a/examples/cursor.rs +++ b/examples/cursor.rs @@ -4,7 +4,7 @@ use sdl2::event::Event; use sdl2::image::{InitFlag, LoadSurface}; use sdl2::keyboard::Keycode; use sdl2::mouse::Cursor; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; use sdl2::rect::Rect; use sdl2::surface::Surface; use std::env; @@ -35,7 +35,7 @@ pub fn run(png: &Path) -> Result<(), String> { canvas.clear(); canvas.present(); - canvas.set_draw_color(Color::RGBA(255, 255, 255, 255)); + canvas.set_draw_color(RColor::RGBA(255, 255, 255, 255)); let mut events = sdl_context.event_pump()?; diff --git a/examples/demo.rs b/examples/demo.rs index 7521fa9b4a..8b58388f3c 100644 --- a/examples/demo.rs +++ b/examples/demo.rs @@ -2,7 +2,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; use std::time::Duration; pub fn main() -> Result<(), String> { @@ -18,7 +18,7 @@ pub fn main() -> Result<(), String> { let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; - canvas.set_draw_color(Color::RGB(255, 0, 0)); + canvas.set_draw_color(RColor::RGB(255, 0, 0)); canvas.clear(); canvas.present(); let mut event_pump = sdl_context.event_pump()?; diff --git a/examples/events.rs b/examples/events.rs index 5fb42dfb3e..987c4ccae1 100644 --- a/examples/events.rs +++ b/examples/events.rs @@ -2,7 +2,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; use std::time::Duration; pub fn main() -> Result<(), String> { @@ -18,7 +18,7 @@ pub fn main() -> Result<(), String> { let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; - canvas.set_draw_color(Color::RGB(255, 0, 0)); + canvas.set_draw_color(RColor::RGB(255, 0, 0)); canvas.clear(); canvas.present(); let mut event_pump = sdl_context.event_pump()?; diff --git a/examples/game-of-life-unsafe-textures.rs b/examples/game-of-life-unsafe-textures.rs index 9ee3e27959..df01b75b12 100644 --- a/examples/game-of-life-unsafe-textures.rs +++ b/examples/game-of-life-unsafe-textures.rs @@ -9,7 +9,7 @@ use sdl2::keyboard::Keycode; #[cfg(feature = "unsafe_textures")] use sdl2::mouse::MouseButton; #[cfg(feature = "unsafe_textures")] -use sdl2::pixels::Color; +use sdl2::pixels::RColor; #[cfg(feature = "unsafe_textures")] use sdl2::rect::{Point, Rect}; #[cfg(feature = "unsafe_textures")] @@ -140,20 +140,20 @@ fn dummy_texture<'a>(canvas: &mut Canvas) -> Result<(Texture, Texture), ]; canvas .with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| { - texture_canvas.set_draw_color(Color::RGB(0, 0, 0)); + texture_canvas.set_draw_color(RColor::RGB(0, 0, 0)); texture_canvas.clear(); match *user_context { TextureColor::Yellow => { for i in 0..SQUARE_SIZE { for j in 0..SQUARE_SIZE { if (i + j) % 4 == 0 { - texture_canvas.set_draw_color(Color::RGB(255, 255, 0)); + texture_canvas.set_draw_color(RColor::RGB(255, 255, 0)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 9 == 0 { - texture_canvas.set_draw_color(Color::RGB(200, 200, 0)); + texture_canvas.set_draw_color(RColor::RGB(200, 200, 0)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -169,13 +169,13 @@ fn dummy_texture<'a>(canvas: &mut Canvas) -> Result<(Texture, Texture), if (i + j) % 7 == 0 { // this doesn't mean anything, there was some trial and error to find // something that wasn't too ugly - texture_canvas.set_draw_color(Color::RGB(192, 192, 192)); + texture_canvas.set_draw_color(RColor::RGB(192, 192, 192)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 5 == 0 { - texture_canvas.set_draw_color(Color::RGB(64, 64, 64)); + texture_canvas.set_draw_color(RColor::RGB(64, 64, 64)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -191,13 +191,13 @@ fn dummy_texture<'a>(canvas: &mut Canvas) -> Result<(Texture, Texture), if (i + j) % 7 == 0 { // this doesn't mean anything, there was some trial and serror to find // something that wasn't too ugly - texture_canvas.set_draw_color(Color::RGB(192, 192, 192)); + texture_canvas.set_draw_color(RColor::RGB(192, 192, 192)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 5 == 0 { - texture_canvas.set_draw_color(Color::RGB(64, 64, 64)); + texture_canvas.set_draw_color(RColor::RGB(64, 64, 64)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -239,7 +239,7 @@ pub fn main() -> Result<(), String> { .map_err(|e| e.to_string())?; println!("Using SDL_Renderer \"{}\"", canvas.info().name); - canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.set_draw_color(RColor::RGB(0, 0, 0)); // clears the canvas with the color we set in `set_draw_color`. canvas.clear(); // However the canvas has not been updated to the window yet, everything has been processed to @@ -294,7 +294,7 @@ pub fn main() -> Result<(), String> { frame = 0; } - canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.set_draw_color(RColor::RGB(0, 0, 0)); canvas.clear(); for (i, unit) in (&game).into_iter().enumerate() { let i = i as u32; diff --git a/examples/game-of-life.rs b/examples/game-of-life.rs index 22cc873eaa..6bcbc67585 100644 --- a/examples/game-of-life.rs +++ b/examples/game-of-life.rs @@ -4,7 +4,7 @@ use crate::game_of_life::{PLAYGROUND_HEIGHT, PLAYGROUND_WIDTH, SQUARE_SIZE}; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::mouse::MouseButton; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; use sdl2::rect::{Point, Rect}; use sdl2::render::{Canvas, Texture, TextureCreator}; use sdl2::video::{Window, WindowContext}; @@ -133,20 +133,20 @@ fn dummy_texture<'a>( ]; canvas .with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| { - texture_canvas.set_draw_color(Color::RGB(0, 0, 0)); + texture_canvas.set_draw_color(RColor::RGB(0, 0, 0)); texture_canvas.clear(); match *user_context { TextureColor::Yellow => { for i in 0..SQUARE_SIZE { for j in 0..SQUARE_SIZE { if (i + j) % 4 == 0 { - texture_canvas.set_draw_color(Color::RGB(255, 255, 0)); + texture_canvas.set_draw_color(RColor::RGB(255, 255, 0)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 9 == 0 { - texture_canvas.set_draw_color(Color::RGB(200, 200, 0)); + texture_canvas.set_draw_color(RColor::RGB(200, 200, 0)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -162,13 +162,13 @@ fn dummy_texture<'a>( if (i + j) % 7 == 0 { // this doesn't mean anything, there was some trial and error to find // something that wasn't too ugly - texture_canvas.set_draw_color(Color::RGB(192, 192, 192)); + texture_canvas.set_draw_color(RColor::RGB(192, 192, 192)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 5 == 0 { - texture_canvas.set_draw_color(Color::RGB(64, 64, 64)); + texture_canvas.set_draw_color(RColor::RGB(64, 64, 64)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -184,13 +184,13 @@ fn dummy_texture<'a>( if (i + j) % 7 == 0 { // this doesn't mean anything, there was some trial and serror to find // something that wasn't too ugly - texture_canvas.set_draw_color(Color::RGB(192, 192, 192)); + texture_canvas.set_draw_color(RColor::RGB(192, 192, 192)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); } if (i + j * 2) % 5 == 0 { - texture_canvas.set_draw_color(Color::RGB(64, 64, 64)); + texture_canvas.set_draw_color(RColor::RGB(64, 64, 64)); texture_canvas .draw_point(Point::new(i as i32, j as i32)) .expect("could not draw point"); @@ -231,7 +231,7 @@ pub fn main() -> Result<(), String> { .map_err(|e| e.to_string())?; println!("Using SDL_Renderer \"{}\"", canvas.info().name); - canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.set_draw_color(RColor::RGB(0, 0, 0)); // clears the canvas with the color we set in `set_draw_color`. canvas.clear(); // However the canvas has not been updated to the window yet, everything has been processed to @@ -290,7 +290,7 @@ pub fn main() -> Result<(), String> { frame = 0; } - canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.set_draw_color(RColor::RGB(0, 0, 0)); canvas.clear(); for (i, unit) in (&game).into_iter().enumerate() { let i = i as u32; diff --git a/examples/message-box.rs b/examples/message-box.rs index 9e725c8d4b..075470569b 100644 --- a/examples/message-box.rs +++ b/examples/message-box.rs @@ -3,7 +3,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; use sdl2::messagebox::*; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; pub fn main() -> Result<(), String> { let sdl_context = sdl2::init()?; @@ -18,7 +18,7 @@ pub fn main() -> Result<(), String> { let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; - canvas.set_draw_color(Color::RGB(255, 0, 0)); + canvas.set_draw_color(RColor::RGB(255, 0, 0)); canvas.clear(); canvas.present(); let mut event_pump = sdl_context.event_pump()?; diff --git a/examples/no-renderer.rs b/examples/no-renderer.rs index 2deac1fded..e0b6ddb38c 100644 --- a/examples/no-renderer.rs +++ b/examples/no-renderer.rs @@ -2,7 +2,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; use sdl2::rect::Rect; use sdl2::video::Window; use std::time::Duration; @@ -29,11 +29,11 @@ fn set_window_gradient( let c: u8 = 255 - (i as u8); let i = i as i32; let color = match gradient { - Gradient::Red => Color::RGB(c, 0, 0), - Gradient::Cyan => Color::RGB(0, c, c), - Gradient::Green => Color::RGB(0, c, 0), - Gradient::Blue => Color::RGB(0, 0, c), - Gradient::White => Color::RGB(c, c, c), + Gradient::Red => RColor::RGB(c, 0, 0), + Gradient::Cyan => RColor::RGB(0, c, c), + Gradient::Green => RColor::RGB(0, c, 0), + Gradient::Blue => RColor::RGB(0, 0, c), + Gradient::White => RColor::RGB(c, c, c), }; surface.fill_rect(Rect::new(i * 4, 0, 4, WINDOW_HEIGHT), color)?; } diff --git a/examples/renderer-target.rs b/examples/renderer-target.rs index b48fd285be..cfeb04d677 100644 --- a/examples/renderer-target.rs +++ b/examples/renderer-target.rs @@ -2,7 +2,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::{Color, PixelFormatEnum}; +use sdl2::pixels::{PixelFormatEnum, RColor}; use sdl2::rect::{Point, Rect}; fn main() -> Result<(), String> { @@ -40,13 +40,13 @@ fn main() -> Result<(), String> { canvas .with_texture_canvas(&mut texture, |texture_canvas| { texture_canvas.clear(); - texture_canvas.set_draw_color(Color::RGBA(255, 0, 0, 255)); + texture_canvas.set_draw_color(RColor::RGBA(255, 0, 0, 255)); texture_canvas .fill_rect(Rect::new(0, 0, 400, 300)) .expect("could not fill rect"); }) .map_err(|e| e.to_string())?; - canvas.set_draw_color(Color::RGBA(0, 0, 0, 255)); + canvas.set_draw_color(RColor::RGBA(0, 0, 0, 255)); let dst = Some(Rect::new(0, 0, 400, 300)); canvas.clear(); canvas.copy_ex( diff --git a/examples/window-properties.rs b/examples/window-properties.rs index d2509a24b6..5d9072fb09 100644 --- a/examples/window-properties.rs +++ b/examples/window-properties.rs @@ -2,7 +2,7 @@ extern crate sdl2; use sdl2::event::Event; use sdl2::keyboard::Keycode; -use sdl2::pixels::Color; +use sdl2::pixels::RColor; pub fn main() -> Result<(), String> { let sdl_context = sdl2::init()?; @@ -51,7 +51,7 @@ pub fn main() -> Result<(), String> { tick += 1; } - canvas.set_draw_color(Color::RGB(0, 0, 0)); + canvas.set_draw_color(RColor::RGB(0, 0, 0)); canvas.clear(); canvas.present(); } From 503d18c761ab565a57eef24455d1b7eb902470bb Mon Sep 17 00:00:00 2001 From: Scott Percival Date: Tue, 5 Apr 2022 01:23:20 +0800 Subject: [PATCH 7/7] Add geometry raw functions --- src/sdl2/render.rs | 88 +++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 79 insertions(+), 9 deletions(-) diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index b9cc865b8b..d7b314302c 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -1578,16 +1578,25 @@ impl Canvas { &mut self, texture: &Texture, vertices: &[Vertex], - indices: &[u32], + indices: Option<&[u32]>, ) -> Result<(), String> { + // API expects i32, however the underlying SDL_RenderGeometryRaw call casts to u32 + let indices_ptr: *const c_int = match indices { + Some(i) => i.as_ptr() as *const c_int, + None => std::ptr::null(), + }; + let indices_count: c_int = match indices { + Some(i) => i.len() as c_int, + None => 0, + }; let result = unsafe { sys::SDL_RenderGeometry( self.context.raw, texture.raw, Vertex::raw_slice(vertices), vertices.len() as c_int, - indices.as_ptr() as *const i32, - indices.len() as c_int, + indices_ptr, + indices_count, ) }; @@ -1598,9 +1607,9 @@ impl Canvas { } } - /// Render a list of triangles, optionally using a texture and indices into the vertex arrays. + /// Render a list of triangles, using separate arrays for position, color and UV. #[doc(alias = "SDL_RenderGeometryRaw")] - pub fn geometry_raw( + pub fn geometry_split( &mut self, texture: &Texture, xy: &[f32], @@ -1610,8 +1619,20 @@ impl Canvas { uv: &[f32], uv_stride: i32, num_vertices: i32, - indices: &[I], + indices: Option<&[I]>, ) -> Result<(), String> { + let indices_ptr: *const c_void = match indices { + Some(i) => i.as_ptr() as *const c_void, + None => std::ptr::null(), + }; + let indices_count: c_int = match indices { + Some(i) => i.len() as c_int, + None => 0, + }; + let indices_size: c_int = match indices { + Some(_) => std::mem::size_of::() as c_int, + None => 0, + }; let result = unsafe { sys::SDL_RenderGeometryRaw( self.context.raw, @@ -1623,9 +1644,58 @@ impl Canvas { uv.as_ptr(), uv_stride as c_int, num_vertices as c_int, - indices.as_ptr() as *const c_void, - indices.len() as c_int, - std::mem::size_of::() as i32, + indices_ptr, + indices_count, + indices_size, + ) + }; + + if result != 0 { + Err(get_error()) + } else { + Ok(()) + } + } + + /// Render a list of triangles, optionally using a texture and indices into the vertex arrays. + /// It is recommended that you use the "memoffset" crate to determine the offsets of fields in your struct. + #[doc(alias = "SDL_RenderGeometryRaw")] + pub fn geometry_struct( + &mut self, + texture: &Texture, + vertices: &[V], + xy_offset: usize, + color_offset: usize, + uv_offset: usize, + indices: Option<&[I]>, + ) -> Result<(), String> { + let stride = std::mem::size_of::() as c_int; + let indices_ptr: *const c_void = match indices { + Some(i) => i.as_ptr() as *const c_void, + None => std::ptr::null(), + }; + let indices_count: c_int = match indices { + Some(i) => i.len() as c_int, + None => 0, + }; + let indices_size: c_int = match indices { + Some(_) => std::mem::size_of::() as c_int, + None => 0, + }; + let result = unsafe { + sys::SDL_RenderGeometryRaw( + self.context.raw, + texture.raw, + (vertices.as_ptr() as *const u8).add(xy_offset) as *const f32, + stride, + (vertices.as_ptr() as *const u8).add(color_offset) as *const sys::SDL_Color, + stride, + (vertices.as_ptr() as *const u8).add(uv_offset) as *const f32, + stride, + vertices.len() as c_int, + indices_ptr, + indices_count, + indices_size, ) };