1use crate::common::{validate_int, IntegerOrSdlError};
32use crate::get_error;
33use crate::pixels;
34use crate::rect::Point;
35use crate::rect::Rect;
36use crate::surface::{Surface, SurfaceContext, SurfaceRef};
37use crate::sys;
38use crate::video::{Window, WindowContext};
39use crate::Error;
40use libc::{c_double, c_int};
41use pixels::PixelFormat;
42use std::convert::{Into, TryFrom, TryInto};
43use std::error;
44use std::ffi::CStr;
45use std::fmt;
46#[cfg(not(feature = "unsafe_textures"))]
47use std::marker::PhantomData;
48use std::mem;
49use std::mem::{transmute, MaybeUninit};
50use std::ops::Deref;
51use std::ptr;
52use std::rc::Rc;
53use std::sync::Arc;
54use sys::blendmode::SDL_BlendMode;
55use sys::everything::SDL_PropertiesID;
56use sys::render::{SDL_GetTextureProperties, SDL_TextureAccess};
57use sys::stdinc::Sint64;
58use sys::surface::{SDL_FLIP_HORIZONTAL, SDL_FLIP_NONE, SDL_FLIP_VERTICAL};
59
60#[derive(Debug, Clone)]
62pub enum TargetRenderError {
63 SdlError(Error),
64}
65
66impl fmt::Display for TargetRenderError {
67 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
68 use self::TargetRenderError::*;
69 match *self {
70 SdlError(ref e) => write!(f, "SDL error: {}", e),
71 }
72 }
73}
74
75impl error::Error for TargetRenderError {
76 fn description(&self) -> &str {
77 use self::TargetRenderError::*;
78 match self {
79 SdlError(e) => &e.0,
80 }
81 }
82}
83
84#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
85#[repr(i32)]
86pub enum TextureAccess {
87 Static = sys::render::SDL_TEXTUREACCESS_STATIC.0,
88 Streaming = sys::render::SDL_TEXTUREACCESS_STREAMING.0,
89 Target = sys::render::SDL_TEXTUREACCESS_TARGET.0,
90}
91
92impl From<TextureAccess> for sys::render::SDL_TextureAccess {
93 fn from(access: TextureAccess) -> sys::render::SDL_TextureAccess {
94 sys::render::SDL_TextureAccess(access as i32)
95 }
96}
97
98impl From<SDL_TextureAccess> for TextureAccess {
99 fn from(access: SDL_TextureAccess) -> TextureAccess {
100 match access {
101 sys::render::SDL_TEXTUREACCESS_STATIC => TextureAccess::Static,
102 sys::render::SDL_TEXTUREACCESS_STREAMING => TextureAccess::Streaming,
103 sys::render::SDL_TEXTUREACCESS_TARGET => TextureAccess::Target,
104 _ => panic!("Unknown texture access value: {}", access.0),
105 }
106 }
107}
108
109impl From<i64> for TextureAccess {
110 fn from(n: i64) -> TextureAccess {
111 let texture_access_c_int: std::ffi::c_int = n
112 .try_into()
113 .expect("Pixel format value out of range for c_int");
114 let texture_access = SDL_TextureAccess(texture_access_c_int);
115 texture_access.into()
116 }
117}
118
119#[derive(Copy, Clone, PartialEq, Debug)]
121pub struct FPoint {
122 pub x: f32,
123 pub y: f32,
124}
125impl FPoint {
126 pub fn new(x: f32, y: f32) -> FPoint {
127 FPoint { x, y }
128 }
129 pub fn to_ll(&self) -> sys::rect::SDL_FPoint {
130 sys::rect::SDL_FPoint {
131 x: self.x,
132 y: self.y,
133 }
134 }
135}
136
137impl From<Point> for FPoint {
138 fn from(point: Point) -> Self {
139 FPoint::new(point.x as f32, point.y as f32)
140 }
141}
142
143#[derive(Copy, Clone, PartialEq, Debug)]
145pub struct FRect {
146 pub x: f32,
147 pub y: f32,
148 pub w: f32,
149 pub h: f32,
150}
151impl FRect {
152 pub fn new(x: f32, y: f32, w: f32, h: f32) -> FRect {
153 FRect { x, y, w, h }
154 }
155 pub fn to_ll(&self) -> sys::rect::SDL_FRect {
156 sys::rect::SDL_FRect {
157 x: self.x,
158 y: self.y,
159 w: self.w,
160 h: self.h,
161 }
162 }
163 pub fn set_x(&mut self, update: f32) {
164 self.x = update;
165 }
166 pub fn set_y(&mut self, update: f32) {
167 self.y = update;
168 }
169 pub fn set_w(&mut self, update: f32) {
170 self.w = update;
171 }
172 pub fn set_h(&mut self, update: f32) {
173 self.h = update;
174 }
175 pub fn set_xy(&mut self, update: FPoint) {
176 self.x = update.x;
177 self.y = update.y;
178 }
179}
180
181impl From<Rect> for FRect {
182 fn from(rect: Rect) -> Self {
183 FRect::new(rect.x as f32, rect.y as f32, rect.w as f32, rect.h as f32)
184 }
185}
186
187#[derive(Debug)]
188pub struct InvalidTextureAccess(u32);
189
190impl std::fmt::Display for InvalidTextureAccess {
191 fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
192 write!(f, "Invalid texture access value: {}", self.0)
193 }
194}
195
196impl std::error::Error for InvalidTextureAccess {}
197
198impl TryFrom<u32> for TextureAccess {
199 type Error = InvalidTextureAccess;
200
201 fn try_from(n: u32) -> Result<Self, Self::Error> {
202 let sdl_access = SDL_TextureAccess(n as i32);
204
205 if sdl_access == SDL_TextureAccess::STATIC {
207 Ok(TextureAccess::Static)
208 } else if sdl_access == SDL_TextureAccess::STREAMING {
209 Ok(TextureAccess::Streaming)
210 } else if sdl_access == SDL_TextureAccess::TARGET {
211 Ok(TextureAccess::Target)
212 } else {
213 Err(InvalidTextureAccess(n))
214 }
215 }
216}
217
218#[derive(Clone, Eq, PartialEq, Hash, Debug)]
221pub struct RendererInfo {
222 pub name: &'static str,
223 pub flags: u32,
224 pub texture_formats: Vec<PixelFormat>,
225 pub max_texture_width: u32,
226 pub max_texture_height: u32,
227}
228
229#[repr(i32)]
231#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
232pub enum BlendMode {
233 None = sys::blendmode::SDL_BLENDMODE_NONE as i32,
235 Blend = sys::blendmode::SDL_BLENDMODE_BLEND as i32,
241 Add = sys::blendmode::SDL_BLENDMODE_ADD as i32,
247 Mod = sys::blendmode::SDL_BLENDMODE_MOD as i32,
251 Mul = sys::blendmode::SDL_BLENDMODE_MUL as i32,
253 Invalid = sys::blendmode::SDL_BLENDMODE_INVALID as i32,
255}
256
257impl TryFrom<u32> for BlendMode {
258 type Error = ();
259
260 fn try_from(n: u32) -> Result<Self, Self::Error> {
261 use self::BlendMode::*;
262
263 Ok(match n {
264 sys::blendmode::SDL_BLENDMODE_NONE => None,
265 sys::blendmode::SDL_BLENDMODE_BLEND => Blend,
266 sys::blendmode::SDL_BLENDMODE_ADD => Add,
267 sys::blendmode::SDL_BLENDMODE_MOD => Mod,
268 sys::blendmode::SDL_BLENDMODE_MUL => Mul,
269 sys::blendmode::SDL_BLENDMODE_INVALID => Invalid,
270 _ => return Err(()),
271 })
272 }
273}
274
275#[derive(Clone, Copy, Debug, PartialEq, Eq)]
276pub enum ClippingRect {
277 Some(Rect),
279 Zero,
281 None,
283}
284
285impl Into<ClippingRect> for Rect {
286 fn into(self) -> ClippingRect {
287 ClippingRect::Some(self)
288 }
289}
290
291impl Into<ClippingRect> for Option<Rect> {
292 fn into(self) -> ClippingRect {
293 match self {
294 Some(v) => v.into(),
295 None => ClippingRect::None,
296 }
297 }
298}
299
300impl ClippingRect {
301 pub fn intersection(&self, other: ClippingRect) -> ClippingRect {
302 match self {
303 ClippingRect::Zero => ClippingRect::Zero,
304 ClippingRect::None => other,
305 ClippingRect::Some(self_rect) => match other {
306 ClippingRect::Zero => ClippingRect::Zero,
307 ClippingRect::None => *self,
308 ClippingRect::Some(rect) => match self_rect.intersection(rect) {
309 Some(v) => ClippingRect::Some(v),
310 None => ClippingRect::Zero,
311 },
312 },
313 }
314 }
315
316 pub fn intersect_rect<R>(&self, position: R) -> ClippingRect
318 where
319 R: Into<Option<Rect>>,
320 {
321 let position: Option<Rect> = position.into();
322 match position {
323 Some(position) => {
324 match self {
325 ClippingRect::Some(rect) => match rect.intersection(position) {
326 Some(v) => ClippingRect::Some(v),
327 None => ClippingRect::Zero,
328 },
329 ClippingRect::Zero => ClippingRect::Zero,
330 ClippingRect::None => {
331 ClippingRect::Some(position)
333 }
334 }
335 }
336 None => {
337 ClippingRect::Zero
339 }
340 }
341 }
342}
343
344pub struct RendererContext<T> {
348 raw: *mut sys::render::SDL_Renderer,
349 _target: Arc<T>,
350}
351
352impl<T> Drop for RendererContext<T> {
353 #[doc(alias = "SDL_DestroyRenderer")]
354 fn drop(&mut self) {
355 unsafe {
356 sys::render::SDL_DestroyRenderer(self.raw);
357 };
358 }
359}
360
361impl<T> RendererContext<T> {
362 #[allow(clippy::trivially_copy_pass_by_ref)]
366 pub fn raw(&self) -> *mut sys::render::SDL_Renderer {
367 self.raw
368 }
369
370 pub unsafe fn from_ll(raw: *mut sys::render::SDL_Renderer, target: Arc<T>) -> Self {
371 RendererContext {
372 raw,
373 _target: target,
374 }
375 }
376
377 unsafe fn set_raw_target(
378 &self,
379 raw_texture: *mut sys::render::SDL_Texture,
380 ) -> Result<(), Error> {
381 if sys::render::SDL_SetRenderTarget(self.raw, raw_texture) {
382 Ok(())
383 } else {
384 Err(get_error())
385 }
386 }
387
388 unsafe fn get_raw_target(&self) -> *mut sys::render::SDL_Texture {
389 sys::render::SDL_GetRenderTarget(self.raw)
390 }
391}
392
393impl<T: RenderTarget> Deref for Canvas<T> {
394 type Target = RendererContext<T::Context>;
395
396 fn deref(&self) -> &RendererContext<T::Context> {
397 self.context.as_ref()
398 }
399}
400
401pub trait RenderTarget {
406 type Context;
407}
408
409impl<'s> RenderTarget for Surface<'s> {
410 type Context = SurfaceContext<'s>;
411}
412
413pub struct Canvas<T: RenderTarget> {
467 target: T,
468 context: Rc<RendererContext<T::Context>>,
469 default_pixel_format: PixelFormat,
470 pub renderer_name: String,
471}
472
473pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
475
476impl<'s> Canvas<Surface<'s>> {
478 #[doc(alias = "SDL_CreateSoftwareRenderer")]
483 pub fn from_surface(surface: Surface<'s>) -> Result<Self, Error> {
484 let raw_renderer = unsafe { sys::render::SDL_CreateSoftwareRenderer(surface.raw()) };
485 if !raw_renderer.is_null() {
486 let context =
487 Rc::new(unsafe { RendererContext::from_ll(raw_renderer, surface.context()) });
488 let default_pixel_format = surface.pixel_format_enum();
489 Ok(Canvas {
490 target: surface,
491 context,
492 default_pixel_format,
493 renderer_name: unsafe {
494 CStr::from_ptr(sys::render::SDL_GetRendererName(raw_renderer))
495 .to_string_lossy()
496 .into_owned()
497 },
498 })
499 } else {
500 Err(get_error())
501 }
502 }
503
504 #[inline]
506 pub fn surface(&self) -> &SurfaceRef {
507 &self.target
508 }
509
510 #[inline]
512 pub fn surface_mut(&mut self) -> &mut SurfaceRef {
513 &mut self.target
514 }
515
516 #[inline]
518 pub fn into_surface(self) -> Surface<'s> {
519 self.target
520 }
521
522 pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>> {
529 TextureCreator {
530 context: self.context.clone(),
531 default_pixel_format: self.default_pixel_format,
532 }
533 }
534}
535
536pub type WindowCanvas = Canvas<Window>;
537
538impl RenderTarget for Window {
539 type Context = WindowContext;
540}
541
542impl Canvas<Window> {
544 #[inline]
546 pub fn window(&self) -> &Window {
547 &self.target
548 }
549
550 #[inline]
552 pub fn window_mut(&mut self) -> &mut Window {
553 &mut self.target
554 }
555
556 #[inline]
558 pub fn into_window(self) -> Window {
559 self.target
560 }
561
562 #[inline]
563 pub fn default_pixel_format(&self) -> PixelFormat {
564 self.window().window_pixel_format()
565 }
566
567 pub fn from_window_and_renderer(
568 window: Window,
569 renderer: *mut sys::render::SDL_Renderer,
570 ) -> Self {
571 let context = Rc::new(unsafe { RendererContext::from_ll(renderer, window.context()) });
572 let default_pixel_format = window.window_pixel_format();
573 Canvas::<Window> {
574 context,
575 target: window,
576 default_pixel_format,
577 renderer_name: unsafe {
578 CStr::from_ptr(sys::render::SDL_GetRendererName(renderer))
579 .to_string_lossy()
580 .into_owned()
581 },
582 }
583 }
584
585 pub fn texture_creator(&self) -> TextureCreator<WindowContext> {
592 TextureCreator {
593 context: self.context.clone(),
594 default_pixel_format: self.default_pixel_format(),
595 }
596 }
597}
598
599impl<T: RenderTarget> Canvas<T> {
600 pub fn with_texture_canvas<F>(&mut self, texture: &mut Texture, f: F)
665 where
666 for<'r> F: FnOnce(&'r mut Canvas<T>),
667 {
668 let target = unsafe { self.get_raw_target() };
669 unsafe { self.set_raw_target(texture.raw) };
670 f(self);
671 unsafe { self.set_raw_target(target) };
672 }
673
674 #[cfg(not(feature = "unsafe_textures"))]
731 pub fn with_multiple_texture_canvas<'t: 'a, 'a: 's, 's, I, F, U: 's>(
732 &mut self,
733 textures: I,
734 mut f: F,
735 ) where
736 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
737 I: Iterator<Item = &'s (&'a mut Texture<'t>, U)>,
738 {
739 let target = unsafe { self.get_raw_target() };
740 for (texture, user_context) in textures {
741 unsafe { self.set_raw_target(texture.raw) };
742 f(self, user_context);
743 }
744 unsafe { self.set_raw_target(target) };
746 }
747
748 #[cfg(feature = "unsafe_textures")]
749 pub fn with_multiple_texture_canvas<'a: 's, 's, I, F, U: 's>(
750 &mut self,
751 textures: I,
752 mut f: F,
753 ) -> Result<(), TargetRenderError>
754 where
755 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
756 I: Iterator<Item = &'s (&'a mut Texture, U)>,
757 {
758 for &(ref texture, ref user_context) in textures {
759 unsafe { self.set_raw_target(texture.raw) }
760 .map_err(|e| TargetRenderError::SdlError(e))?;
761 f(self, &user_context);
762 }
763 unsafe { self.set_raw_target(ptr::null_mut()) }
765 .map_err(|e| TargetRenderError::SdlError(e))?;
766 Ok(())
767 }
768}
769
770pub struct TextureCreator<T> {
783 context: Rc<RendererContext<T>>,
784 default_pixel_format: PixelFormat,
785}
786
787#[doc(alias = "SDL_CreateRenderer")]
789pub fn create_renderer(
790 window: Window,
791 renderer_name: Option<&str>,
792) -> Result<WindowCanvas, IntegerOrSdlError> {
793 use crate::common::IntegerOrSdlError::*;
794 let raw = unsafe {
795 sys::render::SDL_CreateRenderer(
796 window.raw(),
797 if let Some(renderer_name) = renderer_name {
798 renderer_name.as_ptr() as *const _
799 } else {
800 std::ptr::null()
801 },
802 )
803 };
804
805 if raw.is_null() {
806 Err(SdlError(get_error()))
807 } else {
808 Ok(Canvas::from_window_and_renderer(window, raw))
809 }
810}
811
812#[derive(Debug, Clone)]
813pub enum TextureValueError {
814 WidthOverflows(u32),
815 HeightOverflows(u32),
816 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormat),
817 SdlError(Error),
818}
819
820impl fmt::Display for TextureValueError {
821 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
822 use self::TextureValueError::*;
823
824 match *self {
825 WidthOverflows(value) => write!(f, "Integer width overflows ({})", value),
826 HeightOverflows(value) => write!(f, "Integer height overflows ({})", value),
827 WidthMustBeMultipleOfTwoForFormat(value, format) => {
828 write!(
829 f,
830 "Texture width must be multiple of two for pixel format '{:?}' ({})",
831 format, value
832 )
833 }
834 SdlError(ref e) => write!(f, "SDL error: {}", e),
835 }
836 }
837}
838
839impl error::Error for TextureValueError {
840 fn description(&self) -> &str {
841 use self::TextureValueError::*;
842
843 match *self {
844 WidthOverflows(_) => "texture width overflow",
845 HeightOverflows(_) => "texture height overflow",
846 WidthMustBeMultipleOfTwoForFormat(..) => "texture width must be multiple of two",
847 SdlError(ref e) => &e.0,
848 }
849 }
850}
851
852#[doc(alias = "SDL_CreateTexture")]
853fn ll_create_texture(
854 context: *mut sys::render::SDL_Renderer,
855 pixel_format: PixelFormat,
856 access: TextureAccess,
857 width: u32,
858 height: u32,
859) -> Result<*mut sys::render::SDL_Texture, TextureValueError> {
860 use self::TextureValueError::*;
861 let w = match validate_int(width, "width") {
862 Ok(w) => w,
863 Err(_) => return Err(WidthOverflows(width)),
864 };
865 let h = match validate_int(height, "height") {
866 Ok(h) => h,
867 Err(_) => return Err(HeightOverflows(height)),
868 };
869
870 unsafe {
873 match pixel_format.raw() {
874 sys::pixels::SDL_PIXELFORMAT_YV12 | sys::pixels::SDL_PIXELFORMAT_IYUV => {
875 if w % 2 != 0 || h % 2 != 0 {
876 return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format));
877 }
878 }
879 _ => (),
880 };
881 }
882
883 Ok(
884 unsafe {
885 sys::render::SDL_CreateTexture(context, pixel_format.into(), access.into(), w, h)
886 },
887 )
888}
889
890#[repr(i32)]
891#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
892pub enum ScaleMode {
893 Nearest = sdl3_sys::everything::SDL_ScaleMode::NEAREST.0,
895 Linear = sdl3_sys::everything::SDL_ScaleMode::LINEAR.0,
897}
898
899impl Into<sdl3_sys::everything::SDL_ScaleMode> for ScaleMode {
900 fn into(self) -> sdl3_sys::everything::SDL_ScaleMode {
901 match self {
902 ScaleMode::Nearest => sdl3_sys::everything::SDL_ScaleMode::NEAREST,
903 ScaleMode::Linear => sdl3_sys::everything::SDL_ScaleMode::LINEAR,
904 }
905 }
906}
907
908impl TryFrom<sdl3_sys::everything::SDL_ScaleMode> for ScaleMode {
909 type Error = ();
910
911 fn try_from(n: sdl3_sys::everything::SDL_ScaleMode) -> Result<Self, Self::Error> {
912 Ok(match n {
913 sdl3_sys::everything::SDL_ScaleMode::NEAREST => Self::Nearest,
914 sdl3_sys::everything::SDL_ScaleMode::LINEAR => Self::Linear,
915 _ => return Err(()),
916 })
917 }
918}
919
920impl<T> TextureCreator<T> {
922 #[allow(clippy::trivially_copy_pass_by_ref)]
925 pub fn raw(&self) -> *mut sys::render::SDL_Renderer {
926 self.context.raw()
927 }
928
929 pub fn default_pixel_format(&self) -> PixelFormat {
930 self.default_pixel_format
931 }
932
933 pub fn create_texture<F>(
945 &self,
946 format: F,
947 access: TextureAccess,
948 width: u32,
949 height: u32,
950 ) -> Result<Texture, TextureValueError>
951 where
952 F: Into<Option<PixelFormat>>,
953 {
954 use self::TextureValueError::*;
955 let format: PixelFormat = format.into().unwrap_or(self.default_pixel_format);
956 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
957 if result.is_null() {
958 Err(SdlError(get_error()))
959 } else {
960 unsafe { Ok(self.raw_create_texture(result)) }
961 }
962 }
963
964 #[inline]
965 pub fn create_texture_static<F>(
967 &self,
968 format: F,
969 width: u32,
970 height: u32,
971 ) -> Result<Texture, TextureValueError>
972 where
973 F: Into<Option<PixelFormat>>,
974 {
975 self.create_texture(format, TextureAccess::Static, width, height)
976 }
977
978 #[inline]
979 pub fn create_texture_streaming<F>(
981 &self,
982 format: F,
983 width: u32,
984 height: u32,
985 ) -> Result<Texture, TextureValueError>
986 where
987 F: Into<Option<PixelFormat>>,
988 {
989 self.create_texture(format, TextureAccess::Streaming, width, height)
990 }
991
992 #[inline]
993 pub fn create_texture_target<F>(
995 &self,
996 format: F,
997 width: u32,
998 height: u32,
999 ) -> Result<Texture, TextureValueError>
1000 where
1001 F: Into<Option<PixelFormat>>,
1002 {
1003 self.create_texture(format, TextureAccess::Target, width, height)
1004 }
1005
1006 #[doc(alias = "SDL_CreateTextureFromSurface")]
1035 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1036 &self,
1037 surface: S,
1038 ) -> Result<Texture, TextureValueError> {
1039 use self::TextureValueError::*;
1040 let result = unsafe {
1041 sys::render::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw())
1042 };
1043 if result.is_null() {
1044 Err(SdlError(get_error()))
1045 } else {
1046 unsafe { Ok(self.raw_create_texture(result)) }
1047 }
1048 }
1049
1050 #[cfg(not(feature = "unsafe_textures"))]
1052 #[inline]
1053 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::render::SDL_Texture) -> Texture {
1054 Texture {
1055 raw,
1056 _marker: PhantomData,
1057 }
1058 }
1059
1060 #[cfg(feature = "unsafe_textures")]
1062 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::render::SDL_Texture) -> Texture {
1063 Texture { raw }
1064 }
1065}
1066
1067impl<T: RenderTarget> Canvas<T> {
1069 #[allow(clippy::trivially_copy_pass_by_ref)]
1072 pub fn raw(&self) -> *mut sys::render::SDL_Renderer {
1073 self.context.raw()
1074 }
1075
1076 #[doc(alias = "SDL_SetRenderDrawColor")]
1078 pub fn set_draw_color<C: Into<pixels::Color>>(&mut self, color: C) {
1079 let (r, g, b, a) = color.into().rgba();
1080 let ret = unsafe { sys::render::SDL_SetRenderDrawColor(self.raw, r, g, b, a) };
1081 if !ret {
1083 panic!("{}", get_error())
1084 }
1085 }
1086
1087 #[doc(alias = "SDL_GetRenderDrawColor")]
1089 pub fn draw_color(&self) -> pixels::Color {
1090 let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
1091 let ret = unsafe {
1092 sys::render::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a)
1093 };
1094 if !ret {
1096 panic!("{}", get_error())
1097 } else {
1098 pixels::Color::RGBA(r, g, b, a)
1099 }
1100 }
1101
1102 #[doc(alias = "SDL_SetRenderDrawBlendMode")]
1104 pub fn set_blend_mode(&mut self, blend: BlendMode) {
1105 let ret =
1106 unsafe { sys::render::SDL_SetRenderDrawBlendMode(self.context.raw, blend as u32) };
1107 if !ret {
1109 panic!("{}", get_error())
1110 }
1111 }
1112
1113 #[doc(alias = "SDL_GetRenderDrawBlendMode")]
1115 pub fn blend_mode(&self) -> BlendMode {
1116 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
1117 let ret = unsafe {
1118 sys::render::SDL_GetRenderDrawBlendMode(self.context.raw, blend.as_mut_ptr())
1119 };
1120 if !ret {
1122 panic!("{}", get_error())
1123 } else {
1124 let blend = unsafe { blend.assume_init() };
1125 BlendMode::try_from(blend).unwrap()
1126 }
1127 }
1128
1129 #[doc(alias = "SDL_RenderClear")]
1131 pub fn clear(&mut self) {
1132 let ret = unsafe { sys::render::SDL_RenderClear(self.context.raw) };
1133 if !ret {
1134 panic!("Could not clear: {}", get_error())
1135 }
1136 }
1137
1138 #[doc(alias = "SDL_RenderPresent")]
1148 pub fn present(&mut self) -> bool {
1149 unsafe { sys::render::SDL_RenderPresent(self.context.raw) }
1150 }
1151
1152 #[doc(alias = "SDL_GetCurrentRenderOutputSize")]
1154 pub fn output_size(&self) -> Result<(u32, u32), Error> {
1155 let mut width = 0;
1156 let mut height = 0;
1157
1158 let result = unsafe {
1159 sys::render::SDL_GetCurrentRenderOutputSize(self.context.raw, &mut width, &mut height)
1160 };
1161
1162 if result {
1163 Ok((width as u32, height as u32))
1164 } else {
1165 Err(get_error())
1166 }
1167 }
1168
1169 #[doc(alias = "SDL_SetRenderLogicalPresentation")]
1171 pub fn set_logical_size(
1172 &mut self,
1173 width: u32,
1174 height: u32,
1175 mode: sys::render::SDL_RendererLogicalPresentation,
1176 ) -> Result<(), IntegerOrSdlError> {
1177 use crate::common::IntegerOrSdlError::*;
1178 let width = validate_int(width, "width")?;
1179 let height = validate_int(height, "height")?;
1180 let result = unsafe {
1181 sys::render::SDL_SetRenderLogicalPresentation(self.context.raw, width, height, mode)
1182 };
1183 match result {
1184 true => Ok(()),
1185 false => Err(SdlError(get_error())),
1186 }
1187 }
1188
1189 #[doc(alias = "SDL_GetRenderLogicalPresentation")]
1191 pub fn logical_size(&self) -> (u32, u32, sys::render::SDL_RendererLogicalPresentation) {
1192 let mut width = 0;
1193 let mut height = 0;
1194 let mut mode: sys::render::SDL_RendererLogicalPresentation =
1195 sys::render::SDL_LOGICAL_PRESENTATION_DISABLED;
1196
1197 unsafe {
1198 sys::render::SDL_GetRenderLogicalPresentation(
1199 self.context.raw,
1200 &mut width,
1201 &mut height,
1202 &mut mode,
1203 )
1204 };
1205
1206 (width as u32, height as u32, mode)
1207 }
1208
1209 #[doc(alias = "SDL_SetRenderViewport")]
1211 pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
1212 let rect = rect.into();
1213 let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1215 let ret = unsafe { sys::render::SDL_SetRenderViewport(self.context.raw, ptr) };
1216 if !ret {
1217 panic!("Could not set viewport: {}", get_error())
1218 }
1219 }
1220
1221 #[doc(alias = "SDL_GetRenderViewport")]
1223 pub fn viewport(&self) -> Rect {
1224 let mut rect = mem::MaybeUninit::uninit();
1225 unsafe { sys::render::SDL_GetRenderViewport(self.context.raw, rect.as_mut_ptr()) };
1226 let rect = unsafe { rect.assume_init() };
1227 Rect::from_ll(rect)
1228 }
1229
1230 #[doc(alias = "SDL_SetRenderClipRect")]
1232 pub fn set_clip_rect<R>(&mut self, arg: R)
1233 where
1234 R: Into<ClippingRect>,
1235 {
1236 let arg: ClippingRect = arg.into();
1237 let ret = match arg {
1238 ClippingRect::Some(r) => unsafe {
1239 sdl3_sys::everything::SDL_SetRenderClipRect(self.context.raw, r.raw())
1240 },
1241 ClippingRect::Zero => {
1242 let r = sdl3_sys::everything::SDL_Rect {
1243 x: 0,
1244 y: 0,
1245 w: 0,
1246 h: 0,
1247 };
1248 let r: *const sdl3_sys::everything::SDL_Rect = &r;
1249 unsafe { sdl3_sys::everything::SDL_SetRenderClipRect(self.context.raw, r) }
1250 }
1251 ClippingRect::None => unsafe {
1252 sdl3_sys::everything::SDL_SetRenderClipRect(self.context.raw, ptr::null())
1253 },
1254 };
1255 if !ret {
1256 panic!("Could not set clip rect: {}", get_error())
1257 }
1258 }
1259
1260 #[doc(alias = "SDL_GetRenderClipRect")]
1262 pub fn clip_rect(&self) -> ClippingRect {
1263 let clip_enabled = unsafe { sdl3_sys::everything::SDL_RenderClipEnabled(self.context.raw) };
1264
1265 if !clip_enabled {
1266 return ClippingRect::None;
1267 }
1268
1269 let mut raw = mem::MaybeUninit::uninit();
1270 unsafe { sdl3_sys::everything::SDL_GetRenderClipRect(self.context.raw, raw.as_mut_ptr()) };
1271 let raw = unsafe { raw.assume_init() };
1272 if raw.w == 0 || raw.h == 0 {
1273 ClippingRect::Zero
1274 } else {
1275 ClippingRect::Some(Rect::from_ll(raw))
1276 }
1277 }
1278
1279 #[doc(alias = "SDL_SetRenderScale")]
1281 pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), Error> {
1282 let ret = unsafe { sys::render::SDL_SetRenderScale(self.context.raw, scale_x, scale_y) };
1283 if !ret {
1285 Err(get_error())
1286 } else {
1287 Ok(())
1288 }
1289 }
1290
1291 #[doc(alias = "SDL_GetRenderScale")]
1293 pub fn scale(&self) -> (f32, f32) {
1294 let mut scale_x = 0.0;
1295 let mut scale_y = 0.0;
1296 unsafe { sys::render::SDL_GetRenderScale(self.context.raw, &mut scale_x, &mut scale_y) };
1297 (scale_x, scale_y)
1298 }
1299
1300 #[doc(alias = "SDL_RenderPoint")]
1303 pub fn draw_point<P: Into<FPoint>>(&mut self, point: P) -> Result<(), Error> {
1304 let point = point.into();
1305 let result = unsafe { sys::render::SDL_RenderPoint(self.context.raw, point.x, point.y) };
1306 if !result {
1307 Err(get_error())
1308 } else {
1309 Ok(())
1310 }
1311 }
1312
1313 #[doc(alias = "SDL_RenderPoints")]
1316 pub fn draw_points<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), Error> {
1317 let points = points.into();
1318 let result = unsafe {
1319 sys::render::SDL_RenderPoints(
1320 self.context.raw,
1321 points.as_ptr() as *const sys::rect::SDL_FPoint,
1322 points.len() as c_int,
1323 )
1324 };
1325 if !result {
1326 Err(get_error())
1327 } else {
1328 Ok(())
1329 }
1330 }
1331
1332 #[doc(alias = "SDL_RenderLine")]
1335 pub fn draw_line<P1: Into<FPoint>, P2: Into<FPoint>>(
1336 &mut self,
1337 start: P1,
1338 end: P2,
1339 ) -> Result<(), Error> {
1340 let start = start.into();
1341 let end = end.into();
1342 let result = unsafe {
1343 sys::render::SDL_RenderLine(self.context.raw, start.x, start.y, end.x, end.y)
1344 };
1345 if !result {
1346 Err(get_error())
1347 } else {
1348 Ok(())
1349 }
1350 }
1351
1352 #[doc(alias = "SDL_RenderLines")]
1355 pub fn draw_lines<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), Error> {
1356 let points = points.into();
1357 let result = unsafe {
1358 sys::render::SDL_RenderLines(
1359 self.context.raw,
1360 points
1361 .iter()
1362 .map(|p| p.to_ll())
1363 .collect::<Vec<_>>()
1364 .as_ptr(),
1365 points.len() as c_int,
1366 )
1367 };
1368 if !result {
1369 Err(get_error())
1370 } else {
1371 Ok(())
1372 }
1373 }
1374
1375 #[doc(alias = "SDL_RenderRect")]
1378 pub fn draw_rect(&mut self, rect: FRect) -> Result<(), Error> {
1379 let rect = rect.to_ll();
1380
1381 let result = unsafe { sys::render::SDL_RenderRect(self.context.raw, &rect) };
1382 if !result {
1383 Err(get_error())
1384 } else {
1385 Ok(())
1386 }
1387 }
1388
1389 #[doc(alias = "SDL_RenderRects")]
1392 pub fn draw_rects(&mut self, rects: &[FRect]) -> Result<(), Error> {
1393 let result = unsafe {
1394 sys::render::SDL_RenderRects(
1395 self.context.raw,
1396 rects.iter().map(|r| r.to_ll()).collect::<Vec<_>>().as_ptr(),
1397 rects.len() as c_int,
1398 )
1399 };
1400 if !result {
1401 Err(get_error())
1402 } else {
1403 Ok(())
1404 }
1405 }
1406
1407 #[doc(alias = "SDL_RenderFillRect")]
1412 pub fn fill_rect<R: Into<Option<FRect>>>(&mut self, rect: R) -> Result<(), Error> {
1413 let rect_ll = rect.into().map(|r| r.to_ll());
1414 let result = unsafe {
1415 sys::render::SDL_RenderFillRect(
1416 self.context.raw,
1417 rect_ll.as_ref().map_or(ptr::null(), |r| r),
1418 )
1419 };
1420 if !result {
1421 Err(get_error())
1422 } else {
1423 Ok(())
1424 }
1425 }
1426
1427 #[doc(alias = "SDL_RenderFillRects")]
1431 pub fn fill_rects(&mut self, rects: &[FRect]) -> Result<(), Error> {
1432 let result = unsafe {
1433 sys::render::SDL_RenderFillRects(
1434 self.context.raw,
1435 rects.iter().map(|r| r.to_ll()).collect::<Vec<_>>().as_ptr(),
1436 rects.len() as c_int,
1437 )
1438 };
1439 if !result {
1440 Err(get_error())
1441 } else {
1442 Ok(())
1443 }
1444 }
1445
1446 #[doc(alias = "SDL_RenderTexture")]
1455 pub fn copy<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), Error>
1456 where
1457 R1: Into<Option<FRect>>,
1458 R2: Into<Option<FRect>>,
1459 {
1460 let src = src.into().map(|rect| rect.to_ll());
1461 let dst = dst.into().map(|rect| rect.to_ll());
1462
1463 let ret = unsafe {
1464 sys::render::SDL_RenderTexture(
1465 self.context.raw,
1466 texture.raw,
1467 match src {
1468 Some(ref rect) => rect,
1469 None => ptr::null(),
1470 },
1471 match dst {
1472 Some(ref rect) => rect,
1473 None => ptr::null(),
1474 },
1475 )
1476 };
1477
1478 if !ret {
1479 Err(get_error())
1480 } else {
1481 Ok(())
1482 }
1483 }
1484
1485 #[doc(alias = "SDL_RenderTextureRotated")]
1499 pub fn copy_ex<R1, R2, P>(
1500 &mut self,
1501 texture: &Texture,
1502 src: R1,
1503 dst: R2,
1504 angle: f64,
1505 center: P,
1506 flip_horizontal: bool,
1507 flip_vertical: bool,
1508 ) -> Result<(), Error>
1509 where
1510 R1: Into<Option<FRect>>,
1511 R2: Into<Option<FRect>>,
1512 P: Into<Option<FPoint>>,
1513 {
1514 let flip = unsafe {
1515 match (flip_horizontal, flip_vertical) {
1516 (false, false) => SDL_FLIP_NONE,
1517 (true, false) => SDL_FLIP_HORIZONTAL,
1518 (false, true) => SDL_FLIP_VERTICAL,
1519 (true, true) => transmute::<u32, sys::surface::SDL_FlipMode>(
1520 transmute::<sys::surface::SDL_FlipMode, u32>(SDL_FLIP_HORIZONTAL)
1521 | transmute::<sys::surface::SDL_FlipMode, u32>(SDL_FLIP_VERTICAL),
1522 ),
1523 }
1524 };
1525
1526 let src = src.into().map(|rect| rect.to_ll());
1527 let dst = dst.into().map(|rect| rect.to_ll());
1528 let center = center.into().map(|point| point.to_ll());
1529
1530 let ret = unsafe {
1531 sys::render::SDL_RenderTextureRotated(
1532 self.context.raw,
1533 texture.raw,
1534 match src {
1535 Some(ref rect) => rect,
1536 None => ptr::null(),
1537 },
1538 match dst {
1539 Some(ref rect) => rect,
1540 None => ptr::null(),
1541 },
1542 angle as c_double,
1543 match center {
1544 Some(ref point) => point,
1545 None => ptr::null(),
1546 },
1547 flip,
1548 )
1549 };
1550
1551 if !ret {
1552 Err(get_error())
1553 } else {
1554 Ok(())
1555 }
1556 }
1557
1558 #[doc(alias = "SDL_RenderReadPixels")]
1562 pub fn read_pixels<R: Into<Option<Rect>>>(
1563 &self,
1564 rect: R,
1565 ) -> Result<Surface, Error> {
1567 unsafe {
1568 let rect = rect.into();
1569 let (actual_rect, _w, _h) = match rect {
1570 Some(ref rect) => (rect.raw(), rect.width() as usize, rect.height() as usize),
1571 None => {
1572 let (w, h) = self.output_size()?;
1573 (ptr::null(), w as usize, h as usize)
1574 }
1575 };
1576
1577 let surface_ptr = sys::render::SDL_RenderReadPixels(self.context.raw, actual_rect);
1578 if surface_ptr.is_null() {
1579 return Err(get_error());
1580 }
1581
1582 let surface = Surface::from_ll(surface_ptr);
1583 Ok(surface)
1584 }
1585 }
1586
1587 #[cfg(feature = "unsafe_textures")]
1605 pub fn create_texture<F>(
1606 &self,
1607 format: F,
1608 access: TextureAccess,
1609 width: u32,
1610 height: u32,
1611 ) -> Result<Texture, TextureValueError>
1612 where
1613 F: Into<Option<PixelFormat>>,
1614 {
1615 use self::TextureValueError::*;
1616 let format: PixelFormat = format.into().unwrap_or(self.default_pixel_format);
1617 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
1618 if result.is_null() {
1619 Err(SdlError(get_error()))
1620 } else {
1621 unsafe { Ok(self.raw_create_texture(result)) }
1622 }
1623 }
1624
1625 #[cfg(feature = "unsafe_textures")]
1631 #[inline]
1632 pub fn create_texture_static<F>(
1633 &self,
1634 format: F,
1635 width: u32,
1636 height: u32,
1637 ) -> Result<Texture, TextureValueError>
1638 where
1639 F: Into<Option<PixelFormat>>,
1640 {
1641 self.create_texture(format, TextureAccess::Static, width, height)
1642 }
1643
1644 #[cfg(feature = "unsafe_textures")]
1650 #[inline]
1651 pub fn create_texture_streaming<F>(
1652 &self,
1653 format: F,
1654 width: u32,
1655 height: u32,
1656 ) -> Result<Texture, TextureValueError>
1657 where
1658 F: Into<Option<PixelFormat>>,
1659 {
1660 self.create_texture(format, TextureAccess::Streaming, width, height)
1661 }
1662
1663 #[cfg(feature = "unsafe_textures")]
1669 #[inline]
1670 pub fn create_texture_target<F>(
1671 &self,
1672 format: F,
1673 width: u32,
1674 height: u32,
1675 ) -> Result<Texture, TextureValueError>
1676 where
1677 F: Into<Option<PixelFormat>>,
1678 {
1679 self.create_texture(format, TextureAccess::Target, width, height)
1680 }
1681
1682 #[cfg(feature = "unsafe_textures")]
1692 #[doc(alias = "SDL_CreateTextureFromSurface")]
1693 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1694 &self,
1695 surface: S,
1696 ) -> Result<Texture, TextureValueError> {
1697 use self::TextureValueError::*;
1698 let result = unsafe {
1699 sys::render::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw())
1700 };
1701 if result.is_null() {
1702 Err(SdlError(get_error()))
1703 } else {
1704 unsafe { Ok(self.raw_create_texture(result)) }
1705 }
1706 }
1707
1708 #[cfg(feature = "unsafe_textures")]
1709 pub unsafe fn raw_create_texture(&self, raw: *mut sys::render::SDL_Texture) -> Texture {
1715 Texture { raw }
1716 }
1717
1718 #[doc(alias = "SDL_FlushRenderer")]
1719 pub unsafe fn flush_renderer(&self) {
1720 let ret = sys::render::SDL_FlushRenderer(self.context.raw);
1721
1722 if !ret {
1723 panic!("Error flushing renderer: {}", get_error())
1724 }
1725 }
1726}
1727
1728#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1729pub struct TextureQuery {
1730 pub format: pixels::PixelFormat,
1731 pub access: TextureAccess,
1732 pub width: u32,
1733 pub height: u32,
1734}
1735
1736#[cfg(feature = "unsafe_textures")]
1763pub struct Texture {
1764 raw: *mut sys::render::SDL_Texture,
1765}
1766
1767#[cfg(not(feature = "unsafe_textures"))]
1773pub struct Texture<'r> {
1774 raw: *mut sys::render::SDL_Texture,
1775 _marker: PhantomData<&'r ()>,
1776}
1777
1778#[cfg(not(feature = "unsafe_textures"))]
1779impl Drop for Texture<'_> {
1780 #[doc(alias = "SDL_DestroyTexture")]
1781 fn drop(&mut self) {
1782 unsafe {
1783 sys::render::SDL_DestroyTexture(self.raw);
1784 }
1785 }
1786}
1787
1788#[cfg(feature = "unsafe_textures")]
1789impl Texture {
1790 pub unsafe fn destroy(self) {
1807 sys::render::SDL_DestroyTexture(self.raw)
1808 }
1809}
1810
1811#[derive(Debug, Clone)]
1812pub enum UpdateTextureError {
1813 PitchOverflows(usize),
1814 PitchMustBeMultipleOfTwoForFormat(usize, PixelFormat),
1815 XMustBeMultipleOfTwoForFormat(i32, PixelFormat),
1816 YMustBeMultipleOfTwoForFormat(i32, PixelFormat),
1817 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormat),
1818 HeightMustBeMultipleOfTwoForFormat(u32, PixelFormat),
1819 SdlError(Error),
1820}
1821
1822impl fmt::Display for UpdateTextureError {
1823 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1824 use self::UpdateTextureError::*;
1825
1826 match *self {
1827 PitchOverflows(value) => write!(f, "Pitch overflows ({})", value),
1828 PitchMustBeMultipleOfTwoForFormat(value, format) => {
1829 write!(
1830 f,
1831 "Pitch must be multiple of two for pixel format '{:?}' ({})",
1832 format, value
1833 )
1834 }
1835 XMustBeMultipleOfTwoForFormat(value, format) => {
1836 write!(
1837 f,
1838 "X must be multiple of two for pixel format '{:?}' ({})",
1839 format, value
1840 )
1841 }
1842 YMustBeMultipleOfTwoForFormat(value, format) => {
1843 write!(
1844 f,
1845 "Y must be multiple of two for pixel format '{:?}' ({})",
1846 format, value
1847 )
1848 }
1849 WidthMustBeMultipleOfTwoForFormat(value, format) => {
1850 write!(
1851 f,
1852 "Width must be multiple of two for pixel format '{:?}' ({})",
1853 format, value
1854 )
1855 }
1856 HeightMustBeMultipleOfTwoForFormat(value, format) => {
1857 write!(
1858 f,
1859 "Height must be multiple of two for pixel format '{:?}' ({})",
1860 format, value
1861 )
1862 }
1863 SdlError(ref e) => write!(f, "SDL error: {}", e),
1864 }
1865 }
1866}
1867
1868impl error::Error for UpdateTextureError {
1869 fn description(&self) -> &str {
1870 use self::UpdateTextureError::*;
1871
1872 match *self {
1873 PitchOverflows(_) => "pitch overflow",
1874 PitchMustBeMultipleOfTwoForFormat(..) => "pitch must be multiple of two",
1875 XMustBeMultipleOfTwoForFormat(..) => "x must be multiple of two",
1876 YMustBeMultipleOfTwoForFormat(..) => "y must be multiple of two",
1877 WidthMustBeMultipleOfTwoForFormat(..) => "width must be multiple of two",
1878 HeightMustBeMultipleOfTwoForFormat(..) => "height must be multiple of two",
1879 SdlError(ref e) => &e.0,
1880 }
1881 }
1882}
1883
1884#[derive(Debug, Clone)]
1885pub enum UpdateTextureYUVError {
1886 PitchOverflows {
1887 plane: &'static str,
1888 value: usize,
1889 },
1890 InvalidPlaneLength {
1891 plane: &'static str,
1892 length: usize,
1893 pitch: usize,
1894 height: usize,
1895 },
1896 XMustBeMultipleOfTwoForFormat(i32),
1897 YMustBeMultipleOfTwoForFormat(i32),
1898 WidthMustBeMultipleOfTwoForFormat(u32),
1899 HeightMustBeMultipleOfTwoForFormat(u32),
1900 RectNotInsideTexture(Rect),
1901 SdlError(Error),
1902}
1903
1904impl fmt::Display for UpdateTextureYUVError {
1905 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1906 use self::UpdateTextureYUVError::*;
1907
1908 match *self {
1909 PitchOverflows { plane, value } => {
1910 write!(f, "Pitch overflows on {} plane ({})", plane, value)
1911 }
1912 InvalidPlaneLength {
1913 plane,
1914 length,
1915 pitch,
1916 height,
1917 } => {
1918 write!(
1919 f,
1920 "The {} plane is wrong length ({}, should be {} * {})",
1921 plane, length, pitch, height
1922 )
1923 }
1924 XMustBeMultipleOfTwoForFormat(value) => {
1925 write!(f, "X must be multiple of two ({})", value)
1926 }
1927 YMustBeMultipleOfTwoForFormat(value) => {
1928 write!(f, "Y must be multiple of two ({})", value)
1929 }
1930 WidthMustBeMultipleOfTwoForFormat(value) => {
1931 write!(f, "Width must be multiple of two ({})", value)
1932 }
1933 HeightMustBeMultipleOfTwoForFormat(value) => {
1934 write!(f, "Height must be multiple of two ({})", value)
1935 }
1936 RectNotInsideTexture(_) => write!(f, "Rect must be inside texture"),
1937 SdlError(ref e) => write!(f, "SDL error: {}", e),
1938 }
1939 }
1940}
1941
1942impl error::Error for UpdateTextureYUVError {
1943 fn description(&self) -> &str {
1944 use self::UpdateTextureYUVError::*;
1945
1946 match *self {
1947 PitchOverflows { .. } => "pitch overflow",
1948 InvalidPlaneLength { .. } => "invalid plane length",
1949 XMustBeMultipleOfTwoForFormat(_) => "x must be multiple of two",
1950 YMustBeMultipleOfTwoForFormat(_) => "y must be multiple of two",
1951 WidthMustBeMultipleOfTwoForFormat(_) => "width must be multiple of two",
1952 HeightMustBeMultipleOfTwoForFormat(_) => "height must be multiple of two",
1953 RectNotInsideTexture(_) => "rect must be inside texture",
1954 SdlError(ref e) => &e.0,
1955 }
1956 }
1957}
1958
1959struct InternalTexture {
1960 raw: *mut sys::render::SDL_Texture,
1961}
1962
1963impl InternalTexture {
1964 #[doc(alias = "SDL_GetTextureProperties")]
1965 pub fn get_properties(&self) -> SDL_PropertiesID {
1966 unsafe { SDL_GetTextureProperties(self.raw) }
1967 }
1968
1969 pub fn get_format(&self) -> PixelFormat {
1970 let format = unsafe {
1971 sys::properties::SDL_GetNumberProperty(
1972 self.get_properties(),
1973 sys::render::SDL_PROP_TEXTURE_FORMAT_NUMBER,
1974 0,
1975 )
1976 };
1977
1978 PixelFormat::from(format)
1979 }
1980
1981 pub fn get_access(&self) -> TextureAccess {
1982 let access = unsafe {
1983 sys::properties::SDL_GetNumberProperty(
1984 self.get_properties(),
1985 sys::render::SDL_PROP_TEXTURE_ACCESS_NUMBER,
1986 0,
1987 )
1988 };
1989 TextureAccess::from(access)
1990 }
1991
1992 pub fn get_width(&self) -> u32 {
1993 unsafe {
1994 sys::properties::SDL_GetNumberProperty(
1995 self.get_properties(),
1996 sys::render::SDL_PROP_TEXTURE_WIDTH_NUMBER,
1997 0,
1998 ) as u32
1999 }
2000 }
2001
2002 pub fn get_height(&self) -> u32 {
2003 unsafe {
2004 sys::properties::SDL_GetNumberProperty(
2005 self.get_properties(),
2006 sys::render::SDL_PROP_TEXTURE_HEIGHT_NUMBER,
2007 0,
2008 ) as u32
2009 }
2010 }
2011
2012 #[doc(alias = "SDL_SetTextureColorMod")]
2013 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2014 let ret = unsafe { sys::render::SDL_SetTextureColorMod(self.raw, red, green, blue) };
2015
2016 if !ret {
2017 panic!("Error setting color mod: {}", get_error())
2018 }
2019 }
2020
2021 #[doc(alias = "SDL_GetTextureColorMod")]
2022 pub fn color_mod(&self) -> (u8, u8, u8) {
2023 let (mut r, mut g, mut b) = (0, 0, 0);
2024 let ret = unsafe { sys::render::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) };
2025
2026 if !ret {
2028 panic!("{}", get_error())
2029 } else {
2030 (r, g, b)
2031 }
2032 }
2033
2034 #[doc(alias = "SDL_SetTextureAlphaMod")]
2035 pub fn set_alpha_mod(&mut self, alpha: u8) {
2036 let ret = unsafe { sys::render::SDL_SetTextureAlphaMod(self.raw, alpha) };
2037
2038 if !ret {
2039 panic!("Error setting alpha mod: {}", get_error())
2040 }
2041 }
2042
2043 #[doc(alias = "SDL_GetTextureAlphaMod")]
2044 pub fn alpha_mod(&self) -> u8 {
2045 let mut alpha = 0;
2046 let ret = unsafe { sys::render::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
2047
2048 if !ret {
2050 panic!("{}", get_error())
2051 } else {
2052 alpha
2053 }
2054 }
2055
2056 #[doc(alias = "SDL_SetTextureBlendMode")]
2057 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2058 let ret = unsafe { sys::render::SDL_SetTextureBlendMode(self.raw, blend as u32) };
2059
2060 if !ret {
2061 panic!("Error setting blend: {}", get_error())
2062 }
2063 }
2064
2065 #[doc(alias = "SDL_GetTextureBlendMode")]
2066 pub fn blend_mode(&self) -> BlendMode {
2067 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
2068 let ret = unsafe { sys::render::SDL_GetTextureBlendMode(self.raw, blend.as_mut_ptr()) };
2069
2070 if !ret {
2072 panic!("{}", get_error())
2073 } else {
2074 let blend = unsafe { blend.assume_init() };
2075 BlendMode::try_from(blend).unwrap()
2076 }
2077 }
2078
2079 #[doc(alias = "SDL_SetTextureScaleMode")]
2080 pub fn set_scale_mode(&mut self, scale: ScaleMode) {
2081 let ret = unsafe { sdl3_sys::everything::SDL_SetTextureScaleMode(self.raw, scale.into()) };
2082
2083 if !ret {
2084 panic!("Error setting scale mode: {}", get_error())
2085 }
2086 }
2087
2088 #[doc(alias = "SDL_GetTextureScaleMode")]
2089 pub fn scale_mode(&self) -> ScaleMode {
2090 let mut scale: MaybeUninit<sdl3_sys::everything::SDL_ScaleMode> =
2091 mem::MaybeUninit::uninit();
2092 let ret =
2093 unsafe { sdl3_sys::everything::SDL_GetTextureScaleMode(self.raw, scale.as_mut_ptr()) };
2094 if !ret {
2095 panic!("{}", get_error())
2096 } else {
2097 let scale = unsafe { scale.assume_init() };
2098 ScaleMode::try_from(scale).unwrap()
2099 }
2100 }
2101
2102 #[doc(alias = "SDL_UpdateTexture")]
2103 pub fn update<R>(
2104 &mut self,
2105 rect: R,
2106 pixel_data: &[u8],
2107 pitch: usize,
2108 ) -> Result<(), UpdateTextureError>
2109 where
2110 R: Into<Option<Rect>>,
2111 {
2112 use self::UpdateTextureError::*;
2113 let rect = rect.into();
2114 let rect_raw_ptr = match rect {
2115 Some(ref rect) => rect.raw(),
2116 None => ptr::null(),
2117 };
2118
2119 let format = self.get_format();
2123 unsafe {
2124 match format.raw() {
2125 sys::pixels::SDL_PIXELFORMAT_YV12 | sys::pixels::SDL_PIXELFORMAT_IYUV => {
2126 if let Some(r) = rect {
2127 if r.x() % 2 != 0 {
2128 return Err(XMustBeMultipleOfTwoForFormat(r.x(), format));
2129 } else if r.y() % 2 != 0 {
2130 return Err(YMustBeMultipleOfTwoForFormat(r.y(), format));
2131 } else if r.width() % 2 != 0 {
2132 return Err(WidthMustBeMultipleOfTwoForFormat(r.width(), format));
2133 } else if r.height() % 2 != 0 {
2134 return Err(HeightMustBeMultipleOfTwoForFormat(r.height(), format));
2135 }
2136 };
2137 if pitch % 2 != 0 {
2138 return Err(PitchMustBeMultipleOfTwoForFormat(pitch, format));
2139 }
2140 }
2141 _ => {}
2142 }
2143 }
2144
2145 let pitch = match validate_int(pitch as u32, "pitch") {
2146 Ok(p) => p,
2147 Err(_) => return Err(PitchOverflows(pitch)),
2148 };
2149
2150 let result = unsafe {
2151 sys::render::SDL_UpdateTexture(
2152 self.raw,
2153 rect_raw_ptr,
2154 pixel_data.as_ptr() as *const _,
2155 pitch,
2156 )
2157 };
2158
2159 if !result {
2160 Err(SdlError(get_error()))
2161 } else {
2162 Ok(())
2163 }
2164 }
2165
2166 #[doc(alias = "SDL_UpdateYUVTexture")]
2167 pub fn update_yuv<R>(
2168 &mut self,
2169 rect: R,
2170 y_plane: &[u8],
2171 y_pitch: usize,
2172 u_plane: &[u8],
2173 u_pitch: usize,
2174 v_plane: &[u8],
2175 v_pitch: usize,
2176 ) -> Result<(), UpdateTextureYUVError>
2177 where
2178 R: Into<Option<Rect>>,
2179 {
2180 use self::UpdateTextureYUVError::*;
2181
2182 let rect = rect.into();
2183
2184 let rect_raw_ptr = match rect {
2185 Some(ref rect) => rect.raw(),
2186 None => ptr::null(),
2187 };
2188
2189 if let Some(ref r) = rect {
2190 if r.x() % 2 != 0 {
2191 return Err(XMustBeMultipleOfTwoForFormat(r.x()));
2192 } else if r.y() % 2 != 0 {
2193 return Err(YMustBeMultipleOfTwoForFormat(r.y()));
2194 } else if r.width() % 2 != 0 {
2195 return Err(WidthMustBeMultipleOfTwoForFormat(r.width()));
2196 } else if r.height() % 2 != 0 {
2197 return Err(HeightMustBeMultipleOfTwoForFormat(r.height()));
2198 }
2199 };
2200
2201 let width_ = self.get_width();
2204 let height_ = self.get_height();
2205 if let Some(ref r) = rect {
2206 let tex_rect = Rect::new(0, 0, width_, height_);
2207 let inside = match r.intersection(tex_rect) {
2208 Some(intersection) => intersection == *r,
2209 None => false,
2210 };
2211 if !inside {
2213 return Err(RectNotInsideTexture(*r));
2214 }
2215 }
2216
2217 let height = match rect {
2220 Some(ref r) => r.height(),
2221 None => height_,
2222 } as usize;
2223
2224 if y_plane.len() != (y_pitch * height) {
2226 return Err(InvalidPlaneLength {
2227 plane: "y",
2228 length: y_plane.len(),
2229 pitch: y_pitch,
2230 height,
2231 });
2232 }
2233 if u_plane.len() != (u_pitch * height / 2) {
2234 return Err(InvalidPlaneLength {
2235 plane: "u",
2236 length: u_plane.len(),
2237 pitch: u_pitch,
2238 height: height / 2,
2239 });
2240 }
2241 if v_plane.len() != (v_pitch * height / 2) {
2242 return Err(InvalidPlaneLength {
2243 plane: "v",
2244 length: v_plane.len(),
2245 pitch: v_pitch,
2246 height: height / 2,
2247 });
2248 }
2249
2250 let y_pitch = match validate_int(y_pitch as u32, "y_pitch") {
2251 Ok(p) => p,
2252 Err(_) => {
2253 return Err(PitchOverflows {
2254 plane: "y",
2255 value: y_pitch,
2256 })
2257 }
2258 };
2259 let u_pitch = match validate_int(u_pitch as u32, "u_pitch") {
2260 Ok(p) => p,
2261 Err(_) => {
2262 return Err(PitchOverflows {
2263 plane: "u",
2264 value: u_pitch,
2265 })
2266 }
2267 };
2268 let v_pitch = match validate_int(v_pitch as u32, "v_pitch") {
2269 Ok(p) => p,
2270 Err(_) => {
2271 return Err(PitchOverflows {
2272 plane: "v",
2273 value: v_pitch,
2274 })
2275 }
2276 };
2277
2278 let result = unsafe {
2279 sys::render::SDL_UpdateYUVTexture(
2280 self.raw,
2281 rect_raw_ptr,
2282 y_plane.as_ptr(),
2283 y_pitch,
2284 u_plane.as_ptr(),
2285 u_pitch,
2286 v_plane.as_ptr(),
2287 v_pitch,
2288 )
2289 };
2290 if !result {
2291 Err(SdlError(get_error()))
2292 } else {
2293 Ok(())
2294 }
2295 }
2296
2297 #[doc(alias = "SDL_LockTexture")]
2298 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, Error>
2299 where
2300 F: FnOnce(&mut [u8], usize) -> R,
2301 R2: Into<Option<Rect>>,
2302 {
2303 let loaded = unsafe {
2305 let mut pixels = ptr::null_mut();
2306 let mut pitch = 0;
2307 let height = self.get_height();
2308 let format = self.get_format();
2309
2310 let (rect_raw_ptr, height) = match rect.into() {
2311 Some(ref rect) => (rect.raw(), rect.height() as usize),
2312 None => (ptr::null(), height as usize),
2313 };
2314
2315 let ret = sys::render::SDL_LockTexture(self.raw, rect_raw_ptr, &mut pixels, &mut pitch);
2316 if ret {
2317 let size = format.byte_size_from_pitch_and_height(pitch as usize, height);
2318 Ok((
2319 ::std::slice::from_raw_parts_mut(pixels as *mut u8, size),
2320 pitch,
2321 ))
2322 } else {
2323 Err(get_error())
2324 }
2325 };
2326
2327 match loaded {
2328 Ok((interior, pitch)) => {
2329 let result;
2330 unsafe {
2331 result = func(interior, pitch as usize);
2332 sys::render::SDL_UnlockTexture(self.raw);
2333 }
2334 Ok(result)
2335 }
2336 Err(e) => Err(e),
2337 }
2338 }
2339
2340 unsafe fn get_gl_texture_id(&self) -> Sint64 {
2342 let props_id = unsafe { SDL_GetTextureProperties(self.raw) };
2343 unsafe {
2344 sys::properties::SDL_GetNumberProperty(
2345 props_id,
2346 sys::render::SDL_PROP_TEXTURE_OPENGL_TEXTURE_NUMBER,
2347 0,
2348 )
2349 }
2350 }
2351
2352 }
2394
2395#[cfg(not(feature = "unsafe_textures"))]
2396impl Texture<'_> {
2397 #[inline]
2399 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2400 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2401 }
2402
2403 #[inline]
2405 pub fn color_mod(&self) -> (u8, u8, u8) {
2406 InternalTexture { raw: self.raw }.color_mod()
2407 }
2408
2409 #[inline]
2411 pub fn set_alpha_mod(&mut self, alpha: u8) {
2412 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2413 }
2414
2415 #[inline]
2417 pub fn alpha_mod(&self) -> u8 {
2418 InternalTexture { raw: self.raw }.alpha_mod()
2419 }
2420
2421 #[inline]
2423 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2424 InternalTexture { raw: self.raw }.set_blend_mode(blend)
2425 }
2426
2427 #[inline]
2429 pub fn blend_mode(&self) -> BlendMode {
2430 InternalTexture { raw: self.raw }.blend_mode()
2431 }
2432
2433 #[inline]
2435 pub fn set_scale_mode(&mut self, scale: ScaleMode) {
2436 InternalTexture { raw: self.raw }.set_scale_mode(scale)
2437 }
2438
2439 #[inline]
2441 pub fn scale_mode(&self) -> ScaleMode {
2442 InternalTexture { raw: self.raw }.scale_mode()
2443 }
2444
2445 #[inline]
2452 pub fn update<R>(
2453 &mut self,
2454 rect: R,
2455 pixel_data: &[u8],
2456 pitch: usize,
2457 ) -> Result<(), UpdateTextureError>
2458 where
2459 R: Into<Option<Rect>>,
2460 {
2461 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2462 }
2463
2464 #[inline]
2466 pub fn update_yuv<R>(
2467 &mut self,
2468 rect: R,
2469 y_plane: &[u8],
2470 y_pitch: usize,
2471 u_plane: &[u8],
2472 u_pitch: usize,
2473 v_plane: &[u8],
2474 v_pitch: usize,
2475 ) -> Result<(), UpdateTextureYUVError>
2476 where
2477 R: Into<Option<Rect>>,
2478 {
2479 InternalTexture { raw: self.raw }
2480 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2481 }
2482
2483 #[inline]
2494 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, Error>
2495 where
2496 F: FnOnce(&mut [u8], usize) -> R,
2497 R2: Into<Option<Rect>>,
2498 {
2499 InternalTexture { raw: self.raw }.with_lock(rect, func)
2500 }
2501
2502 #[inline]
2522 #[allow(clippy::trivially_copy_pass_by_ref)]
2525 pub const fn raw(&self) -> *mut sys::render::SDL_Texture {
2526 self.raw
2527 }
2528
2529 #[cfg(not(feature = "unsafe_textures"))]
2554 pub fn from_surface<'a, T>(
2555 surface: &Surface,
2556 texture_creator: &'a TextureCreator<T>,
2557 ) -> Result<Texture<'a>, TextureValueError> {
2558 texture_creator.create_texture_from_surface(surface)
2559 }
2560
2561 #[cfg(feature = "unsafe_textures")]
2586 pub fn from_surface<T>(
2587 surface: &Surface,
2588 texture_creator: &TextureCreator<T>,
2589 ) -> Result<Texture, TextureValueError> {
2590 texture_creator.create_texture_from_surface(surface)
2591 }
2592}
2593
2594#[cfg(feature = "unsafe_textures")]
2595impl Texture {
2596 #[inline]
2598 pub fn format(&self) -> PixelFormat {
2599 InternalTexture { raw: self.raw }.get_format()
2600 }
2601
2602 #[inline]
2604 pub fn access(&self) -> TextureAccess {
2605 InternalTexture { raw: self.raw }.get_access()
2606 }
2607
2608 #[inline]
2610 pub fn width(&self) -> u32 {
2611 InternalTexture { raw: self.raw }.get_width()
2612 }
2613
2614 #[inline]
2616 pub fn height(&self) -> u32 {
2617 InternalTexture { raw: self.raw }.get_height()
2618 }
2619
2620 #[inline]
2622 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2623 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2624 }
2625
2626 #[inline]
2628 pub fn color_mod(&self) -> (u8, u8, u8) {
2629 InternalTexture { raw: self.raw }.color_mod()
2630 }
2631
2632 #[inline]
2634 pub fn set_alpha_mod(&mut self, alpha: u8) {
2635 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2636 }
2637
2638 #[inline]
2640 pub fn alpha_mod(&self) -> u8 {
2641 InternalTexture { raw: self.raw }.alpha_mod()
2642 }
2643
2644 #[inline]
2646 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2647 InternalTexture { raw: self.raw }.set_blend_mode(blend)
2648 }
2649
2650 #[inline]
2652 pub fn blend_mode(&self) -> BlendMode {
2653 InternalTexture { raw: self.raw }.blend_mode()
2654 }
2655
2656 #[inline]
2663 pub fn update<R>(
2664 &mut self,
2665 rect: R,
2666 pixel_data: &[u8],
2667 pitch: usize,
2668 ) -> Result<(), UpdateTextureError>
2669 where
2670 R: Into<Option<Rect>>,
2671 {
2672 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2673 }
2674
2675 #[inline]
2677 pub fn update_yuv<R>(
2678 &mut self,
2679 rect: R,
2680 y_plane: &[u8],
2681 y_pitch: usize,
2682 u_plane: &[u8],
2683 u_pitch: usize,
2684 v_plane: &[u8],
2685 v_pitch: usize,
2686 ) -> Result<(), UpdateTextureYUVError>
2687 where
2688 R: Into<Option<Rect>>,
2689 {
2690 InternalTexture { raw: self.raw }
2691 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2692 }
2693
2694 #[inline]
2705 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, Error>
2706 where
2707 F: FnOnce(&mut [u8], usize) -> R,
2708 R2: Into<Option<Rect>>,
2709 {
2710 InternalTexture { raw: self.raw }.with_lock(rect, func)
2711 }
2712
2713 #[inline]
2735 #[allow(clippy::trivially_copy_pass_by_ref)]
2738 pub const fn raw(&self) -> *mut sys::render::SDL_Texture {
2739 self.raw
2740 }
2741}
2742
2743#[derive(Copy, Clone)]
2744pub struct DriverIterator {
2745 length: i32,
2746 index: i32,
2747}
2748
2749impl Iterator for DriverIterator {
2750 type Item = String;
2751
2752 #[inline]
2753 #[doc(alias = "SDL_GetRenderDriver")]
2754 fn next(&mut self) -> Option<String> {
2755 if self.index >= self.length {
2756 None
2757 } else {
2758 let result = unsafe { sys::render::SDL_GetRenderDriver(self.index) };
2759 self.index += 1;
2760
2761 Some(
2762 unsafe { CStr::from_ptr(result) }
2763 .to_string_lossy()
2764 .into_owned(),
2765 )
2766 }
2767 }
2768
2769 #[inline]
2770 fn size_hint(&self) -> (usize, Option<usize>) {
2771 let l = self.length as usize;
2772 (l, Some(l))
2773 }
2774}
2775
2776impl ExactSizeIterator for DriverIterator {}
2777
2778#[inline]
2780#[doc(alias = "SDL_GetNumRenderDrivers")]
2781pub fn drivers() -> DriverIterator {
2782 DriverIterator {
2787 length: unsafe { sys::render::SDL_GetNumRenderDrivers() },
2788 index: 0,
2789 }
2790}