1use crate::common::{validate_int, IntegerOrSdlError};
32use crate::get_error;
33use crate::pixels;
34use crate::pixels::PixelFormatEnum;
35use crate::rect::FPoint;
36use crate::rect::FRect;
37use crate::rect::Point;
38use crate::rect::Rect;
39use crate::surface;
40use crate::surface::{Surface, SurfaceContext, SurfaceRef};
41use crate::video::{Window, WindowContext};
42use libc::c_void;
43use libc::{c_double, c_int};
44use std::convert::TryFrom;
45use std::error::Error;
46use std::ffi::CStr;
47use std::fmt;
48#[cfg(not(feature = "unsafe_textures"))]
49use std::marker::PhantomData;
50use std::mem;
51use std::mem::{transmute, MaybeUninit};
52use std::ops::Deref;
53use std::ptr;
54use std::rc::Rc;
55
56use crate::sys;
57use crate::sys::SDL_BlendMode;
58use crate::sys::SDL_TextureAccess;
59
60#[derive(Debug, Clone)]
62pub struct SdlError(String);
63
64#[derive(Debug, Clone)]
66pub enum TargetRenderError {
67 SdlError(SdlError),
68 NotSupported,
69}
70
71impl fmt::Display for SdlError {
72 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73 write!(f, "SDL error: {}", self.0)
74 }
75}
76
77impl Error for SdlError {}
78
79impl fmt::Display for TargetRenderError {
80 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81 use self::TargetRenderError::*;
82 match *self {
83 SdlError(ref e) => e.fmt(f),
84 NotSupported => write!(f, "The renderer does not support the use of render targets"),
85 }
86 }
87}
88
89impl Error for TargetRenderError {
90 fn source(&self) -> Option<&(dyn Error + 'static)> {
91 match self {
92 Self::SdlError(err) => Some(err),
93 Self::NotSupported => None,
94 }
95 }
96}
97
98#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
99#[repr(i32)]
100pub enum TextureAccess {
101 Static = SDL_TextureAccess::SDL_TEXTUREACCESS_STATIC as i32,
102 Streaming = SDL_TextureAccess::SDL_TEXTUREACCESS_STREAMING as i32,
103 Target = SDL_TextureAccess::SDL_TEXTUREACCESS_TARGET as i32,
104}
105
106impl TryFrom<u32> for TextureAccess {
107 type Error = ();
108
109 fn try_from(n: u32) -> Result<Self, Self::Error> {
110 use self::TextureAccess::*;
111 use crate::sys::SDL_TextureAccess::*;
112
113 Ok(match unsafe { transmute(n) } {
114 SDL_TEXTUREACCESS_STATIC => Static,
115 SDL_TEXTUREACCESS_STREAMING => Streaming,
116 SDL_TEXTUREACCESS_TARGET => Target,
117 })
118 }
119}
120
121#[derive(Clone, Eq, PartialEq, Hash, Debug)]
124pub struct RendererInfo {
125 pub name: &'static str,
126 pub flags: u32,
127 pub texture_formats: Vec<PixelFormatEnum>,
128 pub max_texture_width: u32,
129 pub max_texture_height: u32,
130}
131
132#[repr(i32)]
134#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
135pub enum BlendMode {
136 None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
138 Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
144 Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
150 Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
154 Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
156 Invalid = SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
158}
159
160impl TryFrom<u32> for BlendMode {
161 type Error = ();
162
163 fn try_from(n: u32) -> Result<Self, Self::Error> {
164 use self::BlendMode::*;
165 use crate::sys::SDL_BlendMode::*;
166
167 Ok(match unsafe { transmute(n) } {
168 SDL_BLENDMODE_NONE => None,
169 SDL_BLENDMODE_BLEND => Blend,
170 SDL_BLENDMODE_ADD => Add,
171 SDL_BLENDMODE_MOD => Mod,
172 SDL_BLENDMODE_MUL => Mul,
173 SDL_BLENDMODE_INVALID => Invalid,
174 })
175 }
176}
177
178impl RendererInfo {
179 pub unsafe fn from_ll(info: &sys::SDL_RendererInfo) -> RendererInfo {
180 let texture_formats: Vec<PixelFormatEnum> = info.texture_formats
181 [0..(info.num_texture_formats as usize)]
182 .iter()
183 .map(|&format| PixelFormatEnum::try_from(format).unwrap_or(PixelFormatEnum::Unknown))
184 .collect();
185
186 let name = CStr::from_ptr(info.name as *const _).to_str().unwrap();
188
189 RendererInfo {
190 name,
191 flags: info.flags,
192 texture_formats,
193 max_texture_width: info.max_texture_width as u32,
194 max_texture_height: info.max_texture_height as u32,
195 }
196 }
197}
198
199pub struct RendererContext<T> {
203 raw: *mut sys::SDL_Renderer,
204 _target: Rc<T>,
205}
206
207impl<T> Drop for RendererContext<T> {
208 #[doc(alias = "SDL_DestroyRenderer")]
209 fn drop(&mut self) {
210 unsafe {
211 sys::SDL_DestroyRenderer(self.raw);
212 };
213 }
214}
215
216impl<T> RendererContext<T> {
217 #[doc(alias = "SDL_GetRendererInfo")]
219 pub fn info(&self) -> RendererInfo {
220 let mut renderer_info_raw = mem::MaybeUninit::uninit();
221 let result =
222 unsafe { sys::SDL_GetRendererInfo(self.raw, renderer_info_raw.as_mut_ptr()) != 0 };
223
224 if result {
225 panic!();
227 } else {
228 unsafe {
229 let renderer_info_raw = renderer_info_raw.assume_init();
230 RendererInfo::from_ll(&renderer_info_raw)
231 }
232 }
233 }
234
235 #[allow(clippy::trivially_copy_pass_by_ref)]
239 pub fn raw(&self) -> *mut sys::SDL_Renderer {
240 self.raw
241 }
242
243 pub unsafe fn from_ll(raw: *mut sys::SDL_Renderer, target: Rc<T>) -> Self {
244 RendererContext {
245 raw,
246 _target: target,
247 }
248 }
249
250 unsafe fn set_raw_target(&self, raw_texture: *mut sys::SDL_Texture) -> Result<(), SdlError> {
251 if sys::SDL_SetRenderTarget(self.raw, raw_texture) == 0 {
252 Ok(())
253 } else {
254 Err(SdlError(get_error()))
255 }
256 }
257
258 unsafe fn get_raw_target(&self) -> *mut sys::SDL_Texture {
259 sys::SDL_GetRenderTarget(self.raw)
260 }
261}
262
263impl<T: RenderTarget> Deref for Canvas<T> {
264 type Target = RendererContext<T::Context>;
265
266 fn deref(&self) -> &RendererContext<T::Context> {
267 self.context.as_ref()
268 }
269}
270
271pub trait RenderTarget {
276 type Context;
277}
278
279impl<'s> RenderTarget for Surface<'s> {
280 type Context = SurfaceContext<'s>;
281}
282
283pub struct Canvas<T: RenderTarget> {
340 target: T,
341 context: Rc<RendererContext<T::Context>>,
342 default_pixel_format: PixelFormatEnum,
343}
344
345pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
347
348impl<'s> Canvas<Surface<'s>> {
350 #[doc(alias = "SDL_CreateSoftwareRenderer")]
355 pub fn from_surface(surface: surface::Surface<'s>) -> Result<Self, String> {
356 let raw_renderer = unsafe { sys::SDL_CreateSoftwareRenderer(surface.raw()) };
357 if !raw_renderer.is_null() {
358 let context =
359 Rc::new(unsafe { RendererContext::from_ll(raw_renderer, surface.context()) });
360 let default_pixel_format = surface.pixel_format_enum();
361 Ok(Canvas {
362 target: surface,
363 context,
364 default_pixel_format,
365 })
366 } else {
367 Err(get_error())
368 }
369 }
370
371 #[inline]
373 pub fn surface(&self) -> &SurfaceRef {
374 &self.target
375 }
376
377 #[inline]
379 pub fn surface_mut(&mut self) -> &mut SurfaceRef {
380 &mut self.target
381 }
382
383 #[inline]
385 pub fn into_surface(self) -> Surface<'s> {
386 self.target
387 }
388
389 pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>> {
396 TextureCreator {
397 context: self.context.clone(),
398 default_pixel_format: self.default_pixel_format,
399 }
400 }
401}
402
403pub type WindowCanvas = Canvas<Window>;
404
405impl RenderTarget for Window {
406 type Context = WindowContext;
407}
408
409impl Canvas<Window> {
411 #[inline]
413 pub fn window(&self) -> &Window {
414 &self.target
415 }
416
417 #[inline]
419 pub fn window_mut(&mut self) -> &mut Window {
420 &mut self.target
421 }
422
423 #[inline]
425 pub fn into_window(self) -> Window {
426 self.target
427 }
428
429 #[inline]
430 pub fn default_pixel_format(&self) -> PixelFormatEnum {
431 self.window().window_pixel_format()
432 }
433
434 pub fn texture_creator(&self) -> TextureCreator<WindowContext> {
441 TextureCreator {
442 context: self.context.clone(),
443 default_pixel_format: self.default_pixel_format(),
444 }
445 }
446}
447
448impl<T: RenderTarget> Canvas<T> {
449 #[doc(alias = "SDL_RenderTargetSupported")]
451 pub fn render_target_supported(&self) -> bool {
452 unsafe { sys::SDL_RenderTargetSupported(self.context.raw) == sys::SDL_bool::SDL_TRUE }
453 }
454
455 pub fn with_texture_canvas<F>(
521 &mut self,
522 texture: &mut Texture,
523 f: F,
524 ) -> Result<(), TargetRenderError>
525 where
526 for<'r> F: FnOnce(&'r mut Canvas<T>),
527 {
528 if self.render_target_supported() {
529 let target = unsafe { self.get_raw_target() };
530 unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
531 f(self);
532 unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
533 Ok(())
534 } else {
535 Err(TargetRenderError::NotSupported)
536 }
537 }
538
539 #[cfg(not(feature = "unsafe_textures"))]
596 pub fn with_multiple_texture_canvas<'t: 'a, 'a: 's, 's, I, F, U: 's>(
597 &mut self,
598 textures: I,
599 mut f: F,
600 ) -> Result<(), TargetRenderError>
601 where
602 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
603 I: Iterator<Item = &'s (&'a mut Texture<'t>, U)>,
604 {
605 if self.render_target_supported() {
606 let target = unsafe { self.get_raw_target() };
607 for (texture, user_context) in textures {
608 unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
609 f(self, user_context);
610 }
611 unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
613 Ok(())
614 } else {
615 Err(TargetRenderError::NotSupported)
616 }
617 }
618
619 #[cfg(feature = "unsafe_textures")]
620 pub fn with_multiple_texture_canvas<'a: 's, 's, I, F, U: 's>(
621 &mut self,
622 textures: I,
623 mut f: F,
624 ) -> Result<(), TargetRenderError>
625 where
626 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
627 I: Iterator<Item = &'s (&'a mut Texture, U)>,
628 {
629 if self.render_target_supported() {
630 for &(ref texture, ref user_context) in textures {
631 unsafe { self.set_raw_target(texture.raw) }
632 .map_err(|e| TargetRenderError::SdlError(e))?;
633 f(self, &user_context);
634 }
635 unsafe { self.set_raw_target(ptr::null_mut()) }
637 .map_err(|e| TargetRenderError::SdlError(e))?;
638 Ok(())
639 } else {
640 Err(TargetRenderError::NotSupported)
641 }
642 }
643}
644
645pub struct TextureCreator<T> {
658 context: Rc<RendererContext<T>>,
659 default_pixel_format: PixelFormatEnum,
660}
661
662pub struct CanvasBuilder {
667 window: Window,
668 index: Option<u32>,
669 renderer_flags: u32,
670}
671
672impl CanvasBuilder {
673 pub fn new(window: Window) -> CanvasBuilder {
675 CanvasBuilder {
676 window,
677 index: None,
680 renderer_flags: 0,
683 }
684 }
685
686 #[doc(alias = "SDL_CreateRenderer")]
688 pub fn build(self) -> Result<WindowCanvas, IntegerOrSdlError> {
689 use crate::common::IntegerOrSdlError::*;
690 let index = match self.index {
691 None => -1,
692 Some(index) => validate_int(index, "index")?,
693 };
694 let raw = unsafe { sys::SDL_CreateRenderer(self.window.raw(), index, self.renderer_flags) };
695
696 if raw.is_null() {
697 Err(SdlError(get_error()))
698 } else {
699 let context = Rc::new(unsafe { RendererContext::from_ll(raw, self.window.context()) });
700 let default_pixel_format = self.window.window_pixel_format();
701 Ok(Canvas {
702 context,
703 target: self.window,
704 default_pixel_format,
705 })
706 }
707 }
708
709 pub fn index(mut self, index: u32) -> CanvasBuilder {
714 self.index = Some(index);
715 self
716 }
717
718 pub fn software(mut self) -> CanvasBuilder {
721 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_SOFTWARE as u32;
722 self
723 }
724
725 pub fn accelerated(mut self) -> CanvasBuilder {
728 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_ACCELERATED as u32;
729 self
730 }
731
732 pub fn present_vsync(mut self) -> CanvasBuilder {
735 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_PRESENTVSYNC as u32;
736 self
737 }
738
739 pub fn target_texture(mut self) -> CanvasBuilder {
742 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_TARGETTEXTURE as u32;
743 self
744 }
745}
746
747#[derive(Debug, Clone)]
748pub enum TextureValueError {
749 WidthOverflows(u32),
750 HeightOverflows(u32),
751 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
752 SdlError(String),
753}
754
755impl fmt::Display for TextureValueError {
756 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
757 use self::TextureValueError::*;
758
759 match *self {
760 WidthOverflows(value) => write!(f, "Integer width overflows ({})", value),
761 HeightOverflows(value) => write!(f, "Integer height overflows ({})", value),
762 WidthMustBeMultipleOfTwoForFormat(value, format) => {
763 write!(
764 f,
765 "Texture width must be multiple of two for pixel format '{:?}' ({})",
766 format, value
767 )
768 }
769 SdlError(ref e) => write!(f, "SDL error: {}", e),
770 }
771 }
772}
773
774impl Error for TextureValueError {}
775
776#[doc(alias = "SDL_CreateTexture")]
777fn ll_create_texture(
778 context: *mut sys::SDL_Renderer,
779 pixel_format: PixelFormatEnum,
780 access: TextureAccess,
781 width: u32,
782 height: u32,
783) -> Result<*mut sys::SDL_Texture, TextureValueError> {
784 use self::TextureValueError::*;
785 let w = match validate_int(width, "width") {
786 Ok(w) => w,
787 Err(_) => return Err(WidthOverflows(width)),
788 };
789 let h = match validate_int(height, "height") {
790 Ok(h) => h,
791 Err(_) => return Err(HeightOverflows(height)),
792 };
793
794 match pixel_format {
797 PixelFormatEnum::YV12
798 | PixelFormatEnum::IYUV
799 | PixelFormatEnum::NV12
800 | PixelFormatEnum::NV21 => {
801 if w % 2 != 0 || h % 2 != 0 {
802 return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format));
803 }
804 }
805 _ => (),
806 };
807
808 Ok(unsafe { sys::SDL_CreateTexture(context, pixel_format as u32, access as c_int, w, h) })
809}
810
811impl<T> TextureCreator<T> {
813 #[allow(clippy::trivially_copy_pass_by_ref)]
816 pub fn raw(&self) -> *mut sys::SDL_Renderer {
817 self.context.raw()
818 }
819
820 pub fn default_pixel_format(&self) -> PixelFormatEnum {
821 self.default_pixel_format
822 }
823
824 pub fn create_texture<F>(
836 &self,
837 format: F,
838 access: TextureAccess,
839 width: u32,
840 height: u32,
841 ) -> Result<Texture, TextureValueError>
842 where
843 F: Into<Option<PixelFormatEnum>>,
844 {
845 use self::TextureValueError::*;
846 let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
847 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
848 if result.is_null() {
849 Err(SdlError(get_error()))
850 } else {
851 unsafe { Ok(self.raw_create_texture(result)) }
852 }
853 }
854
855 #[inline]
856 pub fn create_texture_static<F>(
858 &self,
859 format: F,
860 width: u32,
861 height: u32,
862 ) -> Result<Texture, TextureValueError>
863 where
864 F: Into<Option<PixelFormatEnum>>,
865 {
866 self.create_texture(format, TextureAccess::Static, width, height)
867 }
868
869 #[inline]
870 pub fn create_texture_streaming<F>(
872 &self,
873 format: F,
874 width: u32,
875 height: u32,
876 ) -> Result<Texture, TextureValueError>
877 where
878 F: Into<Option<PixelFormatEnum>>,
879 {
880 self.create_texture(format, TextureAccess::Streaming, width, height)
881 }
882
883 #[inline]
884 pub fn create_texture_target<F>(
886 &self,
887 format: F,
888 width: u32,
889 height: u32,
890 ) -> Result<Texture, TextureValueError>
891 where
892 F: Into<Option<PixelFormatEnum>>,
893 {
894 self.create_texture(format, TextureAccess::Target, width, height)
895 }
896
897 #[doc(alias = "SDL_CreateTextureFromSurface")]
928 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
929 &self,
930 surface: S,
931 ) -> Result<Texture, TextureValueError> {
932 use self::TextureValueError::*;
933 let result =
934 unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
935 if result.is_null() {
936 Err(SdlError(get_error()))
937 } else {
938 unsafe { Ok(self.raw_create_texture(result)) }
939 }
940 }
941
942 #[cfg(not(feature = "unsafe_textures"))]
944 #[inline]
945 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
946 Texture {
947 raw,
948 _marker: PhantomData,
949 }
950 }
951
952 #[cfg(feature = "unsafe_textures")]
954 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
955 Texture { raw }
956 }
957}
958
959impl<T: RenderTarget> Canvas<T> {
961 #[allow(clippy::trivially_copy_pass_by_ref)]
964 pub fn raw(&self) -> *mut sys::SDL_Renderer {
965 self.context.raw()
966 }
967
968 #[doc(alias = "SDL_SetRenderDrawColor")]
970 pub fn set_draw_color<C: Into<pixels::Color>>(&mut self, color: C) {
971 let (r, g, b, a) = color.into().rgba();
972 let ret = unsafe { sys::SDL_SetRenderDrawColor(self.raw, r, g, b, a) };
973 if ret != 0 {
975 panic!("{}", get_error())
976 }
977 }
978
979 #[doc(alias = "SDL_GetRenderDrawColor")]
981 pub fn draw_color(&self) -> pixels::Color {
982 let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
983 let ret = unsafe {
984 sys::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a)
985 };
986 if ret != 0 {
988 panic!("{}", get_error())
989 } else {
990 pixels::Color::RGBA(r, g, b, a)
991 }
992 }
993
994 #[doc(alias = "SDL_SetRenderDrawBlendMode")]
996 pub fn set_blend_mode(&mut self, blend: BlendMode) {
997 let ret =
998 unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32)) };
999 if ret != 0 {
1001 panic!("{}", get_error())
1002 }
1003 }
1004
1005 #[doc(alias = "SDL_GetRenderDrawBlendMode")]
1007 pub fn blend_mode(&self) -> BlendMode {
1008 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
1009 let ret = unsafe { sys::SDL_GetRenderDrawBlendMode(self.context.raw, blend.as_mut_ptr()) };
1010 if ret != 0 {
1012 panic!("{}", get_error())
1013 } else {
1014 let blend = unsafe { blend.assume_init() };
1015 BlendMode::try_from(blend as u32).unwrap()
1016 }
1017 }
1018
1019 #[doc(alias = "SDL_RenderClear")]
1021 pub fn clear(&mut self) {
1022 let ret = unsafe { sys::SDL_RenderClear(self.context.raw) };
1023 if ret != 0 {
1024 panic!("Could not clear: {}", get_error())
1025 }
1026 }
1027
1028 #[doc(alias = "SDL_RenderPresent")]
1036 pub fn present(&mut self) {
1037 unsafe { sys::SDL_RenderPresent(self.context.raw) }
1038 }
1039
1040 #[doc(alias = "SDL_GetRendererOutputSize")]
1042 pub fn output_size(&self) -> Result<(u32, u32), String> {
1043 let mut width = 0;
1044 let mut height = 0;
1045
1046 let result =
1047 unsafe { sys::SDL_GetRendererOutputSize(self.context.raw, &mut width, &mut height) };
1048
1049 if result == 0 {
1050 Ok((width as u32, height as u32))
1051 } else {
1052 Err(get_error())
1053 }
1054 }
1055
1056 #[doc(alias = "SDL_RenderSetLogicalSize")]
1058 pub fn set_logical_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1059 use crate::common::IntegerOrSdlError::*;
1060 let width = validate_int(width, "width")?;
1061 let height = validate_int(height, "height")?;
1062 let result = unsafe { sys::SDL_RenderSetLogicalSize(self.context.raw, width, height) };
1063 match result {
1064 0 => Ok(()),
1065 _ => Err(SdlError(get_error())),
1066 }
1067 }
1068
1069 #[doc(alias = "SDL_RenderGetLogicalSize")]
1071 pub fn logical_size(&self) -> (u32, u32) {
1072 let mut width = 0;
1073 let mut height = 0;
1074
1075 unsafe { sys::SDL_RenderGetLogicalSize(self.context.raw, &mut width, &mut height) };
1076
1077 (width as u32, height as u32)
1078 }
1079
1080 #[doc(alias = "SDL_RenderSetViewport")]
1082 pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
1083 let rect = rect.into();
1084 let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1086 let ret = unsafe { sys::SDL_RenderSetViewport(self.context.raw, ptr) };
1087 if ret != 0 {
1088 panic!("Could not set viewport: {}", get_error())
1089 }
1090 }
1091
1092 #[doc(alias = "SDL_RenderGetViewport")]
1094 pub fn viewport(&self) -> Rect {
1095 let mut rect = mem::MaybeUninit::uninit();
1096 unsafe { sys::SDL_RenderGetViewport(self.context.raw, rect.as_mut_ptr()) };
1097 let rect = unsafe { rect.assume_init() };
1098 Rect::from_ll(rect)
1099 }
1100
1101 #[doc(alias = "SDL_RenderSetClipRect")]
1105 pub fn set_clip_rect<R: Into<Option<Rect>>>(&mut self, rect: R) {
1106 let rect = rect.into();
1107 let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1109 let ret = unsafe { sys::SDL_RenderSetClipRect(self.context.raw, ptr) };
1110 if ret != 0 {
1111 panic!("Could not set clip rect: {}", get_error())
1112 }
1113 }
1114
1115 #[doc(alias = "SDL_RenderGetClipRect")]
1119 pub fn clip_rect(&self) -> Option<Rect> {
1120 let mut raw = mem::MaybeUninit::uninit();
1121 unsafe { sys::SDL_RenderGetClipRect(self.context.raw, raw.as_mut_ptr()) };
1122 let raw = unsafe { raw.assume_init() };
1123 if raw.w == 0 || raw.h == 0 {
1124 None
1125 } else {
1126 Some(Rect::from_ll(raw))
1127 }
1128 }
1129
1130 #[doc(alias = "SDL_RenderSetIntegerScale")]
1132 pub fn set_integer_scale(&mut self, scale: bool) -> Result<(), String> {
1133 let ret = unsafe {
1134 sys::SDL_RenderSetIntegerScale(
1135 self.raw(),
1136 if scale {
1137 sys::SDL_bool::SDL_TRUE
1138 } else {
1139 sys::SDL_bool::SDL_FALSE
1140 },
1141 )
1142 };
1143 if ret != 0 {
1144 Err(get_error())
1145 } else {
1146 Ok(())
1147 }
1148 }
1149
1150 #[doc(alias = "SDL_RenderGetIntegerScale")]
1152 pub fn integer_scale(&self) -> bool {
1153 unsafe { sys::SDL_RenderGetIntegerScale(self.raw()) == sys::SDL_bool::SDL_TRUE }
1154 }
1155
1156 #[doc(alias = "SDL_RenderSetScale")]
1158 pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String> {
1159 let ret = unsafe { sys::SDL_RenderSetScale(self.context.raw, scale_x, scale_y) };
1160 if ret != 0 {
1162 Err(get_error())
1163 } else {
1164 Ok(())
1165 }
1166 }
1167
1168 #[doc(alias = "SDL_RenderGetScale")]
1170 pub fn scale(&self) -> (f32, f32) {
1171 let mut scale_x = 0.0;
1172 let mut scale_y = 0.0;
1173 unsafe { sys::SDL_RenderGetScale(self.context.raw, &mut scale_x, &mut scale_y) };
1174 (scale_x, scale_y)
1175 }
1176
1177 #[doc(alias = "SDL_RenderDrawPoint")]
1180 pub fn draw_point<P: Into<Point>>(&mut self, point: P) -> Result<(), String> {
1181 let point = point.into();
1182 let result = unsafe { sys::SDL_RenderDrawPoint(self.context.raw, point.x(), point.y()) };
1183 if result != 0 {
1184 Err(get_error())
1185 } else {
1186 Ok(())
1187 }
1188 }
1189
1190 #[doc(alias = "SDL_RenderDrawPoints")]
1193 pub fn draw_points<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1194 let points = points.into();
1195 let result = unsafe {
1196 sys::SDL_RenderDrawPoints(
1197 self.context.raw,
1198 Point::raw_slice(points),
1199 points.len() as c_int,
1200 )
1201 };
1202 if result != 0 {
1203 Err(get_error())
1204 } else {
1205 Ok(())
1206 }
1207 }
1208
1209 #[doc(alias = "SDL_RenderDrawLine")]
1212 pub fn draw_line<P1: Into<Point>, P2: Into<Point>>(
1213 &mut self,
1214 start: P1,
1215 end: P2,
1216 ) -> Result<(), String> {
1217 let start = start.into();
1218 let end = end.into();
1219 let result = unsafe {
1220 sys::SDL_RenderDrawLine(self.context.raw, start.x(), start.y(), end.x(), end.y())
1221 };
1222 if result != 0 {
1223 Err(get_error())
1224 } else {
1225 Ok(())
1226 }
1227 }
1228
1229 #[doc(alias = "SDL_RenderDrawLines")]
1232 pub fn draw_lines<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1233 let points = points.into();
1234 let result = unsafe {
1235 sys::SDL_RenderDrawLines(
1236 self.context.raw,
1237 Point::raw_slice(points),
1238 points.len() as c_int,
1239 )
1240 };
1241 if result != 0 {
1242 Err(get_error())
1243 } else {
1244 Ok(())
1245 }
1246 }
1247
1248 #[doc(alias = "SDL_RenderDrawRect")]
1251 pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String> {
1252 let result = unsafe { sys::SDL_RenderDrawRect(self.context.raw, rect.raw()) };
1253 if result != 0 {
1254 Err(get_error())
1255 } else {
1256 Ok(())
1257 }
1258 }
1259
1260 #[doc(alias = "SDL_RenderDrawRects")]
1263 pub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1264 let result = unsafe {
1265 sys::SDL_RenderDrawRects(
1266 self.context.raw,
1267 Rect::raw_slice(rects),
1268 rects.len() as c_int,
1269 )
1270 };
1271 if result != 0 {
1272 Err(get_error())
1273 } else {
1274 Ok(())
1275 }
1276 }
1277
1278 #[doc(alias = "SDL_RenderFillRect")]
1283 pub fn fill_rect<R: Into<Option<Rect>>>(&mut self, rect: R) -> Result<(), String> {
1284 let result = unsafe {
1285 sys::SDL_RenderFillRect(
1286 self.context.raw,
1287 rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1288 )
1289 };
1290 if result != 0 {
1291 Err(get_error())
1292 } else {
1293 Ok(())
1294 }
1295 }
1296
1297 #[doc(alias = "SDL_RenderFillRects")]
1301 pub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1302 let result = unsafe {
1303 sys::SDL_RenderFillRects(
1304 self.context.raw,
1305 Rect::raw_slice(rects),
1306 rects.len() as c_int,
1307 )
1308 };
1309 if result != 0 {
1310 Err(get_error())
1311 } else {
1312 Ok(())
1313 }
1314 }
1315
1316 #[doc(alias = "SDL_RenderDrawPointF")]
1319 pub fn draw_fpoint<P: Into<FPoint>>(&mut self, point: P) -> Result<(), String> {
1320 let point = point.into();
1321 let result = unsafe { sys::SDL_RenderDrawPointF(self.context.raw, point.x(), point.y()) };
1322 if result != 0 {
1323 Err(get_error())
1324 } else {
1325 Ok(())
1326 }
1327 }
1328
1329 #[doc(alias = "SDL_RenderDrawPointsF")]
1332 pub fn draw_fpoints<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1333 let points = points.into();
1334 let result = unsafe {
1335 sys::SDL_RenderDrawPointsF(
1336 self.context.raw,
1337 FPoint::raw_slice(points),
1338 points.len() as c_int,
1339 )
1340 };
1341 if result != 0 {
1342 Err(get_error())
1343 } else {
1344 Ok(())
1345 }
1346 }
1347
1348 #[doc(alias = "SDL_RenderDrawLineF")]
1351 pub fn draw_fline<P1: Into<FPoint>, P2: Into<FPoint>>(
1352 &mut self,
1353 start: P1,
1354 end: P2,
1355 ) -> Result<(), String> {
1356 let start = start.into();
1357 let end = end.into();
1358 let result = unsafe {
1359 sys::SDL_RenderDrawLineF(self.context.raw, start.x(), start.y(), end.x(), end.y())
1360 };
1361 if result != 0 {
1362 Err(get_error())
1363 } else {
1364 Ok(())
1365 }
1366 }
1367
1368 #[doc(alias = "SDL_RenderDrawLinesF")]
1371 pub fn draw_flines<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1372 let points = points.into();
1373 let result = unsafe {
1374 sys::SDL_RenderDrawLinesF(
1375 self.context.raw,
1376 FPoint::raw_slice(points),
1377 points.len() as c_int,
1378 )
1379 };
1380 if result != 0 {
1381 Err(get_error())
1382 } else {
1383 Ok(())
1384 }
1385 }
1386
1387 #[doc(alias = "SDL_RenderDrawRectF")]
1390 pub fn draw_frect(&mut self, rect: FRect) -> Result<(), String> {
1391 let result = unsafe { sys::SDL_RenderDrawRectF(self.context.raw, rect.raw()) };
1392 if result != 0 {
1393 Err(get_error())
1394 } else {
1395 Ok(())
1396 }
1397 }
1398
1399 #[doc(alias = "SDL_RenderDrawRectsF")]
1402 pub fn draw_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1403 let result = unsafe {
1404 sys::SDL_RenderDrawRectsF(
1405 self.context.raw,
1406 FRect::raw_slice(rects),
1407 rects.len() as c_int,
1408 )
1409 };
1410 if result != 0 {
1411 Err(get_error())
1412 } else {
1413 Ok(())
1414 }
1415 }
1416
1417 #[doc(alias = "SDL_RenderFillRectF")]
1422 pub fn fill_frect<R: Into<Option<FRect>>>(&mut self, rect: R) -> Result<(), String> {
1423 let result = unsafe {
1424 sys::SDL_RenderFillRectF(
1425 self.context.raw,
1426 rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1427 )
1428 };
1429 if result != 0 {
1430 Err(get_error())
1431 } else {
1432 Ok(())
1433 }
1434 }
1435
1436 #[doc(alias = "SDL_RenderFillRectsF")]
1440 pub fn fill_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1441 let result = unsafe {
1442 sys::SDL_RenderFillRectsF(
1443 self.context.raw,
1444 FRect::raw_slice(rects),
1445 rects.len() as c_int,
1446 )
1447 };
1448 if result != 0 {
1449 Err(get_error())
1450 } else {
1451 Ok(())
1452 }
1453 }
1454
1455 #[doc(alias = "SDL_RenderCopyF")]
1464 pub fn copy_f<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1465 where
1466 R1: Into<Option<Rect>>,
1467 R2: Into<Option<FRect>>,
1468 {
1469 let ret = unsafe {
1470 sys::SDL_RenderCopyF(
1471 self.context.raw,
1472 texture.raw,
1473 match src.into() {
1474 Some(ref rect) => rect.raw(),
1475 None => ptr::null(),
1476 },
1477 match dst.into() {
1478 Some(ref rect) => rect.raw(),
1479 None => ptr::null(),
1480 },
1481 )
1482 };
1483
1484 if ret != 0 {
1485 Err(get_error())
1486 } else {
1487 Ok(())
1488 }
1489 }
1490
1491 #[doc(alias = "SDL_RenderCopyExF")]
1505 pub fn copy_ex_f<R1, R2, P>(
1506 &mut self,
1507 texture: &Texture,
1508 src: R1,
1509 dst: R2,
1510 angle: f64,
1511 center: P,
1512 flip_horizontal: bool,
1513 flip_vertical: bool,
1514 ) -> Result<(), String>
1515 where
1516 R1: Into<Option<Rect>>,
1517 R2: Into<Option<FRect>>,
1518 P: Into<Option<FPoint>>,
1519 {
1520 use crate::sys::SDL_RendererFlip::*;
1521 let flip = unsafe {
1522 match (flip_horizontal, flip_vertical) {
1523 (false, false) => SDL_FLIP_NONE,
1524 (true, false) => SDL_FLIP_HORIZONTAL,
1525 (false, true) => SDL_FLIP_VERTICAL,
1526 (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1527 transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1528 | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1529 ),
1530 }
1531 };
1532
1533 let ret = unsafe {
1534 sys::SDL_RenderCopyExF(
1535 self.context.raw,
1536 texture.raw,
1537 match src.into() {
1538 Some(ref rect) => rect.raw(),
1539 None => ptr::null(),
1540 },
1541 match dst.into() {
1542 Some(ref rect) => rect.raw(),
1543 None => ptr::null(),
1544 },
1545 angle as c_double,
1546 match center.into() {
1547 Some(ref point) => point.raw(),
1548 None => ptr::null(),
1549 },
1550 flip,
1551 )
1552 };
1553
1554 if ret != 0 {
1555 Err(get_error())
1556 } else {
1557 Ok(())
1558 }
1559 }
1560
1561 #[doc(alias = "SDL_RenderCopy")]
1570 pub fn copy<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1571 where
1572 R1: Into<Option<Rect>>,
1573 R2: Into<Option<Rect>>,
1574 {
1575 let ret = unsafe {
1576 sys::SDL_RenderCopy(
1577 self.context.raw,
1578 texture.raw,
1579 match src.into() {
1580 Some(ref rect) => rect.raw(),
1581 None => ptr::null(),
1582 },
1583 match dst.into() {
1584 Some(ref rect) => rect.raw(),
1585 None => ptr::null(),
1586 },
1587 )
1588 };
1589
1590 if ret != 0 {
1591 Err(get_error())
1592 } else {
1593 Ok(())
1594 }
1595 }
1596
1597 #[doc(alias = "SDL_RenderCopyEx")]
1611 pub fn copy_ex<R1, R2, P>(
1612 &mut self,
1613 texture: &Texture,
1614 src: R1,
1615 dst: R2,
1616 angle: f64,
1617 center: P,
1618 flip_horizontal: bool,
1619 flip_vertical: bool,
1620 ) -> Result<(), String>
1621 where
1622 R1: Into<Option<Rect>>,
1623 R2: Into<Option<Rect>>,
1624 P: Into<Option<Point>>,
1625 {
1626 use crate::sys::SDL_RendererFlip::*;
1627 let flip = unsafe {
1628 match (flip_horizontal, flip_vertical) {
1629 (false, false) => SDL_FLIP_NONE,
1630 (true, false) => SDL_FLIP_HORIZONTAL,
1631 (false, true) => SDL_FLIP_VERTICAL,
1632 (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1633 transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1634 | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1635 ),
1636 }
1637 };
1638
1639 let ret = unsafe {
1640 sys::SDL_RenderCopyEx(
1641 self.context.raw,
1642 texture.raw,
1643 match src.into() {
1644 Some(ref rect) => rect.raw(),
1645 None => ptr::null(),
1646 },
1647 match dst.into() {
1648 Some(ref rect) => rect.raw(),
1649 None => ptr::null(),
1650 },
1651 angle as c_double,
1652 match center.into() {
1653 Some(ref point) => point.raw(),
1654 None => ptr::null(),
1655 },
1656 flip,
1657 )
1658 };
1659
1660 if ret != 0 {
1661 Err(get_error())
1662 } else {
1663 Ok(())
1664 }
1665 }
1666
1667 #[doc(alias = "SDL_RenderReadPixels")]
1671 pub fn read_pixels<R: Into<Option<Rect>>>(
1672 &self,
1673 rect: R,
1674 format: pixels::PixelFormatEnum,
1675 ) -> Result<Vec<u8>, String> {
1676 let rect = rect.into();
1677 let (actual_rect, w, h) = match rect {
1678 Some(ref rect) => (rect.raw(), rect.width() as usize, rect.height() as usize),
1679 None => {
1680 let (w, h) = self.output_size()?;
1681 (ptr::null(), w as usize, h as usize)
1682 }
1683 };
1684
1685 let pitch = w * format.byte_size_per_pixel(); let size = format.byte_size_of_pixels(w * h);
1687 let mut pixels = Vec::with_capacity(size);
1688
1689 let ret = unsafe {
1691 sys::SDL_RenderReadPixels(
1692 self.context.raw,
1693 actual_rect,
1694 format as u32,
1695 pixels.as_mut_ptr() as *mut c_void,
1696 pitch as c_int,
1697 )
1698 };
1699
1700 if ret == 0 {
1701 unsafe { pixels.set_len(size) };
1702 Ok(pixels)
1703 } else {
1704 Err(get_error())
1705 }
1706 }
1707
1708 #[cfg(feature = "unsafe_textures")]
1726 pub fn create_texture<F>(
1727 &self,
1728 format: F,
1729 access: TextureAccess,
1730 width: u32,
1731 height: u32,
1732 ) -> Result<Texture, TextureValueError>
1733 where
1734 F: Into<Option<PixelFormatEnum>>,
1735 {
1736 use self::TextureValueError::*;
1737 let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
1738 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
1739 if result.is_null() {
1740 Err(SdlError(get_error()))
1741 } else {
1742 unsafe { Ok(self.raw_create_texture(result)) }
1743 }
1744 }
1745
1746 #[cfg(feature = "unsafe_textures")]
1752 #[inline]
1753 pub fn create_texture_static<F>(
1754 &self,
1755 format: F,
1756 width: u32,
1757 height: u32,
1758 ) -> Result<Texture, TextureValueError>
1759 where
1760 F: Into<Option<PixelFormatEnum>>,
1761 {
1762 self.create_texture(format, TextureAccess::Static, width, height)
1763 }
1764
1765 #[cfg(feature = "unsafe_textures")]
1771 #[inline]
1772 pub fn create_texture_streaming<F>(
1773 &self,
1774 format: F,
1775 width: u32,
1776 height: u32,
1777 ) -> Result<Texture, TextureValueError>
1778 where
1779 F: Into<Option<PixelFormatEnum>>,
1780 {
1781 self.create_texture(format, TextureAccess::Streaming, width, height)
1782 }
1783
1784 #[cfg(feature = "unsafe_textures")]
1790 #[inline]
1791 pub fn create_texture_target<F>(
1792 &self,
1793 format: F,
1794 width: u32,
1795 height: u32,
1796 ) -> Result<Texture, TextureValueError>
1797 where
1798 F: Into<Option<PixelFormatEnum>>,
1799 {
1800 self.create_texture(format, TextureAccess::Target, width, height)
1801 }
1802
1803 #[cfg(feature = "unsafe_textures")]
1813 #[doc(alias = "SDL_CreateTextureFromSurface")]
1814 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1815 &self,
1816 surface: S,
1817 ) -> Result<Texture, TextureValueError> {
1818 use self::TextureValueError::*;
1819 let result =
1820 unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
1821 if result.is_null() {
1822 Err(SdlError(get_error()))
1823 } else {
1824 unsafe { Ok(self.raw_create_texture(result)) }
1825 }
1826 }
1827
1828 #[cfg(feature = "unsafe_textures")]
1829 pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
1835 Texture { raw }
1836 }
1837
1838 #[doc(alias = "SDL_RenderFlush")]
1839 pub unsafe fn render_flush(&self) {
1840 let ret = sys::SDL_RenderFlush(self.context.raw);
1841
1842 if ret != 0 {
1843 panic!("Error setting blend: {}", get_error())
1844 }
1845 }
1846}
1847
1848#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1849pub struct TextureQuery {
1850 pub format: pixels::PixelFormatEnum,
1851 pub access: TextureAccess,
1852 pub width: u32,
1853 pub height: u32,
1854}
1855
1856#[cfg(feature = "unsafe_textures")]
1883pub struct Texture {
1884 raw: *mut sys::SDL_Texture,
1885}
1886
1887#[cfg(not(feature = "unsafe_textures"))]
1893pub struct Texture<'r> {
1894 raw: *mut sys::SDL_Texture,
1895 _marker: PhantomData<&'r ()>,
1896}
1897
1898#[cfg(not(feature = "unsafe_textures"))]
1899impl<'r> Drop for Texture<'r> {
1900 #[doc(alias = "SDL_DestroyTexture")]
1901 fn drop(&mut self) {
1902 unsafe {
1903 sys::SDL_DestroyTexture(self.raw);
1904 }
1905 }
1906}
1907
1908#[cfg(feature = "unsafe_textures")]
1909impl Texture {
1910 pub unsafe fn destroy(self) {
1927 sys::SDL_DestroyTexture(self.raw)
1928 }
1929}
1930
1931#[derive(Debug, Clone)]
1932pub enum UpdateTextureError {
1933 PitchOverflows(usize),
1934 PitchMustBeMultipleOfTwoForFormat(usize, PixelFormatEnum),
1935 XMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
1936 YMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
1937 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
1938 HeightMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
1939 SdlError(String),
1940}
1941
1942impl fmt::Display for UpdateTextureError {
1943 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1944 use self::UpdateTextureError::*;
1945
1946 match *self {
1947 PitchOverflows(value) => write!(f, "Pitch overflows ({})", value),
1948 PitchMustBeMultipleOfTwoForFormat(value, format) => {
1949 write!(
1950 f,
1951 "Pitch must be multiple of two for pixel format '{:?}' ({})",
1952 format, value
1953 )
1954 }
1955 XMustBeMultipleOfTwoForFormat(value, format) => {
1956 write!(
1957 f,
1958 "X must be multiple of two for pixel format '{:?}' ({})",
1959 format, value
1960 )
1961 }
1962 YMustBeMultipleOfTwoForFormat(value, format) => {
1963 write!(
1964 f,
1965 "Y must be multiple of two for pixel format '{:?}' ({})",
1966 format, value
1967 )
1968 }
1969 WidthMustBeMultipleOfTwoForFormat(value, format) => {
1970 write!(
1971 f,
1972 "Width must be multiple of two for pixel format '{:?}' ({})",
1973 format, value
1974 )
1975 }
1976 HeightMustBeMultipleOfTwoForFormat(value, format) => {
1977 write!(
1978 f,
1979 "Height must be multiple of two for pixel format '{:?}' ({})",
1980 format, value
1981 )
1982 }
1983 SdlError(ref e) => write!(f, "SDL error: {}", e),
1984 }
1985 }
1986}
1987
1988impl Error for UpdateTextureError {}
1989
1990#[derive(Debug, Clone)]
1991pub enum UpdateTextureYUVError {
1992 PitchOverflows {
1993 plane: &'static str,
1994 value: usize,
1995 },
1996 InvalidPlaneLength {
1997 plane: &'static str,
1998 length: usize,
1999 pitch: usize,
2000 height: usize,
2001 },
2002 XMustBeMultipleOfTwoForFormat(i32),
2003 YMustBeMultipleOfTwoForFormat(i32),
2004 WidthMustBeMultipleOfTwoForFormat(u32),
2005 HeightMustBeMultipleOfTwoForFormat(u32),
2006 RectNotInsideTexture(Rect),
2007 SdlError(String),
2008}
2009
2010impl fmt::Display for UpdateTextureYUVError {
2011 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2012 use self::UpdateTextureYUVError::*;
2013
2014 match *self {
2015 PitchOverflows { plane, value } => {
2016 write!(f, "Pitch overflows on {} plane ({})", plane, value)
2017 }
2018 InvalidPlaneLength {
2019 plane,
2020 length,
2021 pitch,
2022 height,
2023 } => {
2024 write!(
2025 f,
2026 "The {} plane is wrong length ({}, should be {} * {})",
2027 plane, length, pitch, height
2028 )
2029 }
2030 XMustBeMultipleOfTwoForFormat(value) => {
2031 write!(f, "X must be multiple of two ({})", value)
2032 }
2033 YMustBeMultipleOfTwoForFormat(value) => {
2034 write!(f, "Y must be multiple of two ({})", value)
2035 }
2036 WidthMustBeMultipleOfTwoForFormat(value) => {
2037 write!(f, "Width must be multiple of two ({})", value)
2038 }
2039 HeightMustBeMultipleOfTwoForFormat(value) => {
2040 write!(f, "Height must be multiple of two ({})", value)
2041 }
2042 RectNotInsideTexture(_) => write!(f, "Rect must be inside texture"),
2043 SdlError(ref e) => write!(f, "SDL error: {}", e),
2044 }
2045 }
2046}
2047
2048impl Error for UpdateTextureYUVError {}
2049
2050struct InternalTexture {
2051 raw: *mut sys::SDL_Texture,
2052}
2053
2054impl InternalTexture {
2055 #[doc(alias = "SDL_QueryTexture")]
2056 pub fn query(&self) -> TextureQuery {
2057 let mut format = 0;
2058 let mut access = 0;
2059 let mut width = 0;
2060 let mut height = 0;
2061
2062 let ret = unsafe {
2063 sys::SDL_QueryTexture(self.raw, &mut format, &mut access, &mut width, &mut height)
2064 };
2065 if ret != 0 {
2067 panic!("{}", get_error())
2068 } else {
2069 TextureQuery {
2070 format: PixelFormatEnum::try_from(format).unwrap(),
2071 access: TextureAccess::try_from(access as u32).unwrap(),
2072 width: width as u32,
2073 height: height as u32,
2074 }
2075 }
2076 }
2077
2078 #[doc(alias = "SDL_SetTextureColorMod")]
2079 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2080 let ret = unsafe { sys::SDL_SetTextureColorMod(self.raw, red, green, blue) };
2081
2082 if ret != 0 {
2083 panic!("Error setting color mod: {}", get_error())
2084 }
2085 }
2086
2087 #[doc(alias = "SDL_GetTextureColorMod")]
2088 pub fn color_mod(&self) -> (u8, u8, u8) {
2089 let (mut r, mut g, mut b) = (0, 0, 0);
2090 let ret = unsafe { sys::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) };
2091
2092 if ret != 0 {
2094 panic!("{}", get_error())
2095 } else {
2096 (r, g, b)
2097 }
2098 }
2099
2100 #[doc(alias = "SDL_SetTextureAlphaMod")]
2101 pub fn set_alpha_mod(&mut self, alpha: u8) {
2102 let ret = unsafe { sys::SDL_SetTextureAlphaMod(self.raw, alpha) };
2103
2104 if ret != 0 {
2105 panic!("Error setting alpha mod: {}", get_error())
2106 }
2107 }
2108
2109 #[doc(alias = "SDL_GetTextureAlphaMod")]
2110 pub fn alpha_mod(&self) -> u8 {
2111 let mut alpha = 0;
2112 let ret = unsafe { sys::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
2113
2114 if ret != 0 {
2116 panic!("{}", get_error())
2117 } else {
2118 alpha
2119 }
2120 }
2121
2122 #[doc(alias = "SDL_SetTextureBlendMode")]
2123 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2124 let ret = unsafe { sys::SDL_SetTextureBlendMode(self.raw, transmute(blend as u32)) };
2125
2126 if ret != 0 {
2127 panic!("Error setting blend: {}", get_error())
2128 }
2129 }
2130
2131 #[doc(alias = "SDL_GetTextureBlendMode")]
2132 pub fn blend_mode(&self) -> BlendMode {
2133 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
2134 let ret = unsafe { sys::SDL_GetTextureBlendMode(self.raw, blend.as_mut_ptr()) };
2135
2136 if ret != 0 {
2138 panic!("{}", get_error())
2139 } else {
2140 let blend = unsafe { blend.assume_init() };
2141 BlendMode::try_from(blend as u32).unwrap()
2142 }
2143 }
2144
2145 #[doc(alias = "SDL_UpdateTexture")]
2146 pub fn update<R>(
2147 &mut self,
2148 rect: R,
2149 pixel_data: &[u8],
2150 pitch: usize,
2151 ) -> Result<(), UpdateTextureError>
2152 where
2153 R: Into<Option<Rect>>,
2154 {
2155 use self::UpdateTextureError::*;
2156 let rect = rect.into();
2157 let rect_raw_ptr = match rect {
2158 Some(ref rect) => rect.raw(),
2159 None => ptr::null(),
2160 };
2161
2162 let TextureQuery { format, .. } = self.query();
2166 match format {
2167 PixelFormatEnum::YV12
2168 | PixelFormatEnum::IYUV
2169 | PixelFormatEnum::NV12
2170 | PixelFormatEnum::NV21 => {
2171 if let Some(r) = rect {
2172 if r.x() % 2 != 0 {
2173 return Err(XMustBeMultipleOfTwoForFormat(r.x(), format));
2174 } else if r.y() % 2 != 0 {
2175 return Err(YMustBeMultipleOfTwoForFormat(r.y(), format));
2176 } else if r.width() % 2 != 0 {
2177 return Err(WidthMustBeMultipleOfTwoForFormat(r.width(), format));
2178 } else if r.height() % 2 != 0 {
2179 return Err(HeightMustBeMultipleOfTwoForFormat(r.height(), format));
2180 }
2181 };
2182 if pitch % 2 != 0 {
2183 return Err(PitchMustBeMultipleOfTwoForFormat(pitch, format));
2184 }
2185 }
2186 _ => {}
2187 }
2188
2189 let pitch = match validate_int(pitch as u32, "pitch") {
2190 Ok(p) => p,
2191 Err(_) => return Err(PitchOverflows(pitch)),
2192 };
2193
2194 let result = unsafe {
2195 sys::SDL_UpdateTexture(
2196 self.raw,
2197 rect_raw_ptr,
2198 pixel_data.as_ptr() as *const _,
2199 pitch,
2200 )
2201 };
2202
2203 if result != 0 {
2204 Err(SdlError(get_error()))
2205 } else {
2206 Ok(())
2207 }
2208 }
2209
2210 #[doc(alias = "SDL_UpdateYUVTexture")]
2211 pub fn update_yuv<R>(
2212 &mut self,
2213 rect: R,
2214 y_plane: &[u8],
2215 y_pitch: usize,
2216 u_plane: &[u8],
2217 u_pitch: usize,
2218 v_plane: &[u8],
2219 v_pitch: usize,
2220 ) -> Result<(), UpdateTextureYUVError>
2221 where
2222 R: Into<Option<Rect>>,
2223 {
2224 use self::UpdateTextureYUVError::*;
2225
2226 let rect = rect.into();
2227
2228 let rect_raw_ptr = match rect {
2229 Some(ref rect) => rect.raw(),
2230 None => ptr::null(),
2231 };
2232
2233 if let Some(ref r) = rect {
2234 if r.x() % 2 != 0 {
2235 return Err(XMustBeMultipleOfTwoForFormat(r.x()));
2236 } else if r.y() % 2 != 0 {
2237 return Err(YMustBeMultipleOfTwoForFormat(r.y()));
2238 } else if r.width() % 2 != 0 {
2239 return Err(WidthMustBeMultipleOfTwoForFormat(r.width()));
2240 } else if r.height() % 2 != 0 {
2241 return Err(HeightMustBeMultipleOfTwoForFormat(r.height()));
2242 }
2243 };
2244
2245 let tex_info = self.query();
2248 if let Some(ref r) = rect {
2249 let tex_rect = Rect::new(0, 0, tex_info.width, tex_info.height);
2250 let inside = match r.intersection(tex_rect) {
2251 Some(intersection) => intersection == *r,
2252 None => false,
2253 };
2254 if !inside {
2256 return Err(RectNotInsideTexture(*r));
2257 }
2258 }
2259
2260 let height = match rect {
2263 Some(ref r) => r.height(),
2264 None => tex_info.height,
2265 } as usize;
2266
2267 if y_plane.len() != (y_pitch * height) {
2269 return Err(InvalidPlaneLength {
2270 plane: "y",
2271 length: y_plane.len(),
2272 pitch: y_pitch,
2273 height,
2274 });
2275 }
2276 if u_plane.len() != (u_pitch * height / 2) {
2277 return Err(InvalidPlaneLength {
2278 plane: "u",
2279 length: u_plane.len(),
2280 pitch: u_pitch,
2281 height: height / 2,
2282 });
2283 }
2284 if v_plane.len() != (v_pitch * height / 2) {
2285 return Err(InvalidPlaneLength {
2286 plane: "v",
2287 length: v_plane.len(),
2288 pitch: v_pitch,
2289 height: height / 2,
2290 });
2291 }
2292
2293 let y_pitch = match validate_int(y_pitch as u32, "y_pitch") {
2294 Ok(p) => p,
2295 Err(_) => {
2296 return Err(PitchOverflows {
2297 plane: "y",
2298 value: y_pitch,
2299 })
2300 }
2301 };
2302 let u_pitch = match validate_int(u_pitch as u32, "u_pitch") {
2303 Ok(p) => p,
2304 Err(_) => {
2305 return Err(PitchOverflows {
2306 plane: "u",
2307 value: u_pitch,
2308 })
2309 }
2310 };
2311 let v_pitch = match validate_int(v_pitch as u32, "v_pitch") {
2312 Ok(p) => p,
2313 Err(_) => {
2314 return Err(PitchOverflows {
2315 plane: "v",
2316 value: v_pitch,
2317 })
2318 }
2319 };
2320
2321 let result = unsafe {
2322 sys::SDL_UpdateYUVTexture(
2323 self.raw,
2324 rect_raw_ptr,
2325 y_plane.as_ptr(),
2326 y_pitch,
2327 u_plane.as_ptr(),
2328 u_pitch,
2329 v_plane.as_ptr(),
2330 v_pitch,
2331 )
2332 };
2333 if result != 0 {
2334 Err(SdlError(get_error()))
2335 } else {
2336 Ok(())
2337 }
2338 }
2339
2340 #[doc(alias = "SDL_LockTexture")]
2341 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2342 where
2343 F: FnOnce(&mut [u8], usize) -> R,
2344 R2: Into<Option<Rect>>,
2345 {
2346 let loaded = unsafe {
2348 let q = self.query();
2349 let mut pixels = ptr::null_mut();
2350 let mut pitch = 0;
2351
2352 let (rect_raw_ptr, height) = match rect.into() {
2353 Some(ref rect) => (rect.raw(), rect.height() as usize),
2354 None => (ptr::null(), q.height as usize),
2355 };
2356
2357 let ret = sys::SDL_LockTexture(self.raw, rect_raw_ptr, &mut pixels, &mut pitch);
2358 if ret == 0 {
2359 let size = q
2360 .format
2361 .byte_size_from_pitch_and_height(pitch as usize, height);
2362 Ok((
2363 ::std::slice::from_raw_parts_mut(pixels as *mut u8, size),
2364 pitch,
2365 ))
2366 } else {
2367 Err(get_error())
2368 }
2369 };
2370
2371 match loaded {
2372 Ok((interior, pitch)) => {
2373 let result;
2374 unsafe {
2375 result = func(interior, pitch as usize);
2376 sys::SDL_UnlockTexture(self.raw);
2377 }
2378 Ok(result)
2379 }
2380 Err(e) => Err(e),
2381 }
2382 }
2383
2384 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2385 let mut texw = 0.0;
2386 let mut texh = 0.0;
2387
2388 if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2389 (texw, texh)
2390 } else {
2391 panic!("OpenGL texture binding not supported");
2392 }
2393 }
2394
2395 pub unsafe fn gl_unbind_texture(&mut self) {
2396 if sys::SDL_GL_UnbindTexture(self.raw) != 0 {
2397 panic!("OpenGL texture unbinding not supported");
2398 }
2399 }
2400
2401 #[doc(alias = "SDL_GL_BindTexture")]
2402 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2403 unsafe {
2404 let mut texw = 0.0;
2405 let mut texh = 0.0;
2406
2407 if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2408 let return_value = f(texw, texh);
2409
2410 if sys::SDL_GL_UnbindTexture(self.raw) == 0 {
2411 return_value
2412 } else {
2413 panic!();
2415 }
2416 } else {
2417 panic!("OpenGL texture binding not supported");
2418 }
2419 }
2420 }
2421}
2422
2423#[cfg(not(feature = "unsafe_textures"))]
2424impl<'r> Texture<'r> {
2425 #[inline]
2427 pub fn query(&self) -> TextureQuery {
2428 InternalTexture { raw: self.raw }.query()
2429 }
2430
2431 #[inline]
2433 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2434 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2435 }
2436
2437 #[inline]
2439 pub fn color_mod(&self) -> (u8, u8, u8) {
2440 InternalTexture { raw: self.raw }.color_mod()
2441 }
2442
2443 #[inline]
2445 pub fn set_alpha_mod(&mut self, alpha: u8) {
2446 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2447 }
2448
2449 #[inline]
2451 pub fn alpha_mod(&self) -> u8 {
2452 InternalTexture { raw: self.raw }.alpha_mod()
2453 }
2454
2455 #[inline]
2457 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2458 InternalTexture { raw: self.raw }.set_blend_mode(blend)
2459 }
2460
2461 #[inline]
2463 pub fn blend_mode(&self) -> BlendMode {
2464 InternalTexture { raw: self.raw }.blend_mode()
2465 }
2466
2467 #[inline]
2474 pub fn update<R>(
2475 &mut self,
2476 rect: R,
2477 pixel_data: &[u8],
2478 pitch: usize,
2479 ) -> Result<(), UpdateTextureError>
2480 where
2481 R: Into<Option<Rect>>,
2482 {
2483 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2484 }
2485
2486 #[inline]
2488 pub fn update_yuv<R>(
2489 &mut self,
2490 rect: R,
2491 y_plane: &[u8],
2492 y_pitch: usize,
2493 u_plane: &[u8],
2494 u_pitch: usize,
2495 v_plane: &[u8],
2496 v_pitch: usize,
2497 ) -> Result<(), UpdateTextureYUVError>
2498 where
2499 R: Into<Option<Rect>>,
2500 {
2501 InternalTexture { raw: self.raw }
2502 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2503 }
2504
2505 #[inline]
2516 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2517 where
2518 F: FnOnce(&mut [u8], usize) -> R,
2519 R2: Into<Option<Rect>>,
2520 {
2521 InternalTexture { raw: self.raw }.with_lock(rect, func)
2522 }
2523
2524 #[inline]
2527 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2528 InternalTexture { raw: self.raw }.gl_bind_texture()
2529 }
2530
2531 #[inline]
2533 pub unsafe fn gl_unbind_texture(&mut self) {
2534 InternalTexture { raw: self.raw }.gl_unbind_texture()
2535 }
2536
2537 #[inline]
2539 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2540 InternalTexture { raw: self.raw }.gl_with_bind(f)
2541 }
2542
2543 #[inline]
2544 #[allow(clippy::trivially_copy_pass_by_ref)]
2547 pub const fn raw(&self) -> *mut sys::SDL_Texture {
2548 self.raw
2549 }
2550
2551 #[cfg(not(feature = "unsafe_textures"))]
2578 pub fn from_surface<'a, T>(
2579 surface: &Surface,
2580 texture_creator: &'a TextureCreator<T>,
2581 ) -> Result<Texture<'a>, TextureValueError> {
2582 texture_creator.create_texture_from_surface(surface)
2583 }
2584
2585 #[cfg(feature = "unsafe_textures")]
2612 pub fn from_surface<T>(
2613 surface: &Surface,
2614 texture_creator: &TextureCreator<T>,
2615 ) -> Result<Texture, TextureValueError> {
2616 texture_creator.create_texture_from_surface(surface)
2617 }
2618}
2619
2620#[cfg(feature = "unsafe_textures")]
2621impl Texture {
2622 #[inline]
2624 pub fn query(&self) -> TextureQuery {
2625 InternalTexture { raw: self.raw }.query()
2626 }
2627
2628 #[inline]
2630 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2631 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2632 }
2633
2634 #[inline]
2636 pub fn color_mod(&self) -> (u8, u8, u8) {
2637 InternalTexture { raw: self.raw }.color_mod()
2638 }
2639
2640 #[inline]
2642 pub fn set_alpha_mod(&mut self, alpha: u8) {
2643 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2644 }
2645
2646 #[inline]
2648 pub fn alpha_mod(&self) -> u8 {
2649 InternalTexture { raw: self.raw }.alpha_mod()
2650 }
2651
2652 #[inline]
2654 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2655 InternalTexture { raw: self.raw }.set_blend_mode(blend)
2656 }
2657
2658 #[inline]
2660 pub fn blend_mode(&self) -> BlendMode {
2661 InternalTexture { raw: self.raw }.blend_mode()
2662 }
2663
2664 #[inline]
2671 pub fn update<R>(
2672 &mut self,
2673 rect: R,
2674 pixel_data: &[u8],
2675 pitch: usize,
2676 ) -> Result<(), UpdateTextureError>
2677 where
2678 R: Into<Option<Rect>>,
2679 {
2680 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2681 }
2682
2683 #[inline]
2685 pub fn update_yuv<R>(
2686 &mut self,
2687 rect: R,
2688 y_plane: &[u8],
2689 y_pitch: usize,
2690 u_plane: &[u8],
2691 u_pitch: usize,
2692 v_plane: &[u8],
2693 v_pitch: usize,
2694 ) -> Result<(), UpdateTextureYUVError>
2695 where
2696 R: Into<Option<Rect>>,
2697 {
2698 InternalTexture { raw: self.raw }
2699 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2700 }
2701
2702 #[inline]
2713 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2714 where
2715 F: FnOnce(&mut [u8], usize) -> R,
2716 R2: Into<Option<Rect>>,
2717 {
2718 InternalTexture { raw: self.raw }.with_lock(rect, func)
2719 }
2720
2721 #[inline]
2724 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2725 InternalTexture { raw: self.raw }.gl_bind_texture()
2726 }
2727
2728 #[inline]
2730 pub unsafe fn gl_unbind_texture(&mut self) {
2731 InternalTexture { raw: self.raw }.gl_unbind_texture()
2732 }
2733
2734 #[inline]
2736 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2737 InternalTexture { raw: self.raw }.gl_with_bind(f)
2738 }
2739
2740 #[inline]
2741 #[allow(clippy::trivially_copy_pass_by_ref)]
2744 pub const fn raw(&self) -> *mut sys::SDL_Texture {
2745 self.raw
2746 }
2747}
2748
2749#[derive(Copy, Clone)]
2750pub struct DriverIterator {
2751 length: i32,
2752 index: i32,
2753}
2754
2755fn get_render_driver_info(index: i32) -> RendererInfo {
2759 let mut out = mem::MaybeUninit::uninit();
2760 let result = unsafe { sys::SDL_GetRenderDriverInfo(index, out.as_mut_ptr()) };
2761 assert_eq!(result, 0);
2762
2763 unsafe { RendererInfo::from_ll(&out.assume_init()) }
2764}
2765
2766impl Iterator for DriverIterator {
2767 type Item = RendererInfo;
2768
2769 #[inline]
2770 #[doc(alias = "SDL_GetRenderDriverInfo")]
2771 fn next(&mut self) -> Option<RendererInfo> {
2772 if self.index >= self.length {
2773 None
2774 } else {
2775 let driver = get_render_driver_info(self.index);
2776 self.index += 1;
2777
2778 Some(driver)
2779 }
2780 }
2781
2782 #[inline]
2783 fn size_hint(&self) -> (usize, Option<usize>) {
2784 let remaining = (self.length - self.index) as usize;
2785 (remaining, Some(remaining))
2786 }
2787
2788 #[inline]
2789 fn nth(&mut self, n: usize) -> Option<RendererInfo> {
2790 use std::convert::TryInto;
2791
2792 self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
2793 Some(index) if index < self.length => index,
2794 _ => self.length,
2795 };
2796
2797 self.next()
2798 }
2799}
2800
2801impl DoubleEndedIterator for DriverIterator {
2802 #[inline]
2803 fn next_back(&mut self) -> Option<RendererInfo> {
2804 if self.index >= self.length {
2805 None
2806 } else {
2807 self.length -= 1;
2808
2809 Some(get_render_driver_info(self.length))
2810 }
2811 }
2812
2813 #[inline]
2814 fn nth_back(&mut self, n: usize) -> Option<RendererInfo> {
2815 use std::convert::TryInto;
2816
2817 self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
2818 Some(length) if length > self.index => length,
2819 _ => self.index,
2820 };
2821
2822 self.next_back()
2823 }
2824}
2825
2826impl ExactSizeIterator for DriverIterator {}
2827
2828impl std::iter::FusedIterator for DriverIterator {}
2829
2830#[inline]
2832#[doc(alias = "SDL_GetNumRenderDrivers")]
2833pub fn drivers() -> DriverIterator {
2834 DriverIterator {
2839 length: unsafe { sys::SDL_GetNumRenderDrivers() },
2840 index: 0,
2841 }
2842}