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, TryInto};
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;
55use std::slice;
56
57use crate::sys;
58use crate::sys::SDL_BlendMode;
59use crate::sys::SDL_ScaleMode;
60use crate::sys::SDL_TextureAccess;
61
62#[derive(Debug, Clone)]
64pub struct SdlError(String);
65
66#[derive(Debug, Clone)]
68pub enum TargetRenderError {
69 SdlError(SdlError),
70 NotSupported,
71}
72
73impl fmt::Display for SdlError {
74 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
75 write!(f, "SDL error: {}", self.0)
76 }
77}
78
79impl Error for SdlError {}
80
81impl fmt::Display for TargetRenderError {
82 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
83 use self::TargetRenderError::*;
84 match *self {
85 SdlError(ref e) => e.fmt(f),
86 NotSupported => write!(f, "The renderer does not support the use of render targets"),
87 }
88 }
89}
90
91impl Error for TargetRenderError {
92 fn source(&self) -> Option<&(dyn Error + 'static)> {
93 match self {
94 Self::SdlError(err) => Some(err),
95 Self::NotSupported => None,
96 }
97 }
98}
99
100#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
101#[repr(i32)]
102pub enum TextureAccess {
103 Static = SDL_TextureAccess::SDL_TEXTUREACCESS_STATIC as i32,
104 Streaming = SDL_TextureAccess::SDL_TEXTUREACCESS_STREAMING as i32,
105 Target = SDL_TextureAccess::SDL_TEXTUREACCESS_TARGET as i32,
106}
107
108impl TryFrom<u32> for TextureAccess {
109 type Error = ();
110
111 fn try_from(n: u32) -> Result<Self, Self::Error> {
112 use self::TextureAccess::*;
113 use crate::sys::SDL_TextureAccess::*;
114
115 match n {
116 x if x == SDL_TEXTUREACCESS_STATIC as u32 => Ok(Static),
117 x if x == SDL_TEXTUREACCESS_STREAMING as u32 => Ok(Streaming),
118 x if x == SDL_TEXTUREACCESS_TARGET as u32 => Ok(Target),
119 _ => Err(()),
120 }
121 }
122}
123
124#[derive(Clone, Eq, PartialEq, Hash, Debug)]
127pub struct RendererInfo {
128 pub name: &'static str,
129 pub flags: u32,
130 pub texture_formats: Vec<PixelFormatEnum>,
131 pub max_texture_width: u32,
132 pub max_texture_height: u32,
133}
134
135#[repr(i32)]
137#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
138pub enum BlendMode {
139 None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
141 Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
147 Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
153 Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
157 Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
159 Invalid = SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
161}
162
163impl TryFrom<u32> for BlendMode {
164 type Error = ();
165
166 fn try_from(n: u32) -> Result<Self, Self::Error> {
167 use self::BlendMode::*;
168 use crate::sys::SDL_BlendMode::*;
169
170 match n {
171 x if x == SDL_BLENDMODE_NONE as u32 => Ok(None),
172 x if x == SDL_BLENDMODE_BLEND as u32 => Ok(Blend),
173 x if x == SDL_BLENDMODE_ADD as u32 => Ok(Add),
174 x if x == SDL_BLENDMODE_MOD as u32 => Ok(Mod),
175 x if x == SDL_BLENDMODE_MUL as u32 => Ok(Mul),
176 x if x == SDL_BLENDMODE_INVALID as u32 => Ok(Invalid),
177 _ => Err(()),
178 }
179 }
180}
181
182#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
183pub enum ScaleMode {
184 Nearest = SDL_ScaleMode::SDL_ScaleModeNearest as isize,
186 Linear = SDL_ScaleMode::SDL_ScaleModeLinear as isize,
188 Best = SDL_ScaleMode::SDL_ScaleModeBest as isize,
190}
191
192impl TryFrom<u32> for ScaleMode {
193 type Error = ();
194
195 fn try_from(n: u32) -> Result<Self, Self::Error> {
196 match n {
197 x if x == crate::sys::SDL_ScaleMode::SDL_ScaleModeNearest as u32 => {
198 Ok(ScaleMode::Nearest)
199 }
200 x if x == crate::sys::SDL_ScaleMode::SDL_ScaleModeLinear as u32 => {
201 Ok(ScaleMode::Linear)
202 }
203 x if x == crate::sys::SDL_ScaleMode::SDL_ScaleModeBest as u32 => Ok(ScaleMode::Best),
204 _ => Err(()),
205 }
206 }
207}
208
209impl RendererInfo {
210 pub unsafe fn from_ll(info: &sys::SDL_RendererInfo) -> RendererInfo {
211 let texture_formats: Vec<PixelFormatEnum> = info.texture_formats
212 [0..(info.num_texture_formats as usize)]
213 .iter()
214 .map(|&format| PixelFormatEnum::try_from(format).unwrap_or(PixelFormatEnum::Unknown))
215 .collect();
216
217 let name = CStr::from_ptr(info.name as *const _).to_str().unwrap();
219
220 RendererInfo {
221 name,
222 flags: info.flags,
223 texture_formats,
224 max_texture_width: info.max_texture_width as u32,
225 max_texture_height: info.max_texture_height as u32,
226 }
227 }
228}
229
230pub struct RendererContext<T> {
234 raw: *mut sys::SDL_Renderer,
235 _target: Rc<T>,
236}
237
238impl<T> Drop for RendererContext<T> {
239 #[doc(alias = "SDL_DestroyRenderer")]
240 fn drop(&mut self) {
241 unsafe {
242 sys::SDL_DestroyRenderer(self.raw);
243 };
244 }
245}
246
247impl<T> RendererContext<T> {
248 #[doc(alias = "SDL_GetRendererInfo")]
250 pub fn info(&self) -> RendererInfo {
251 let mut renderer_info_raw = mem::MaybeUninit::uninit();
252 let result =
253 unsafe { sys::SDL_GetRendererInfo(self.raw, renderer_info_raw.as_mut_ptr()) != 0 };
254
255 if result {
256 panic!();
258 } else {
259 unsafe {
260 let renderer_info_raw = renderer_info_raw.assume_init();
261 RendererInfo::from_ll(&renderer_info_raw)
262 }
263 }
264 }
265
266 #[allow(clippy::trivially_copy_pass_by_ref)]
270 pub fn raw(&self) -> *mut sys::SDL_Renderer {
271 self.raw
272 }
273
274 pub unsafe fn from_ll(raw: *mut sys::SDL_Renderer, target: Rc<T>) -> Self {
275 RendererContext {
276 raw,
277 _target: target,
278 }
279 }
280
281 unsafe fn set_raw_target(&self, raw_texture: *mut sys::SDL_Texture) -> Result<(), SdlError> {
282 if sys::SDL_SetRenderTarget(self.raw, raw_texture) == 0 {
283 Ok(())
284 } else {
285 Err(SdlError(get_error()))
286 }
287 }
288
289 unsafe fn get_raw_target(&self) -> *mut sys::SDL_Texture {
290 sys::SDL_GetRenderTarget(self.raw)
291 }
292}
293
294impl<T: RenderTarget> Deref for Canvas<T> {
295 type Target = RendererContext<T::Context>;
296
297 fn deref(&self) -> &RendererContext<T::Context> {
298 self.context.as_ref()
299 }
300}
301
302pub trait RenderTarget {
307 type Context;
308}
309
310impl<'s> RenderTarget for Surface<'s> {
311 type Context = SurfaceContext<'s>;
312}
313
314pub struct Canvas<T: RenderTarget> {
371 target: T,
372 context: Rc<RendererContext<T::Context>>,
373 default_pixel_format: PixelFormatEnum,
374}
375
376pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
378
379impl<'s> Canvas<Surface<'s>> {
381 #[doc(alias = "SDL_CreateSoftwareRenderer")]
386 pub fn from_surface(surface: surface::Surface<'s>) -> Result<Self, String> {
387 let raw_renderer = unsafe { sys::SDL_CreateSoftwareRenderer(surface.raw()) };
388 if !raw_renderer.is_null() {
389 let context =
390 Rc::new(unsafe { RendererContext::from_ll(raw_renderer, surface.context()) });
391 let default_pixel_format = surface.pixel_format_enum();
392 Ok(Canvas {
393 target: surface,
394 context,
395 default_pixel_format,
396 })
397 } else {
398 Err(get_error())
399 }
400 }
401
402 #[inline]
404 pub fn surface(&self) -> &SurfaceRef {
405 &self.target
406 }
407
408 #[inline]
410 pub fn surface_mut(&mut self) -> &mut SurfaceRef {
411 &mut self.target
412 }
413
414 #[inline]
416 pub fn into_surface(self) -> Surface<'s> {
417 self.target
418 }
419
420 pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>> {
427 TextureCreator {
428 context: self.context.clone(),
429 default_pixel_format: self.default_pixel_format,
430 }
431 }
432}
433
434pub type WindowCanvas = Canvas<Window>;
435
436impl RenderTarget for Window {
437 type Context = WindowContext;
438}
439
440#[derive(Clone, Copy, Debug, PartialEq, Eq)]
441pub enum ClippingRect {
442 Some(Rect),
444 Zero,
446 None,
448}
449
450impl Into<ClippingRect> for Rect {
451 fn into(self) -> ClippingRect {
452 ClippingRect::Some(self)
453 }
454}
455
456impl Into<ClippingRect> for Option<Rect> {
457 fn into(self) -> ClippingRect {
458 match self {
459 Some(v) => v.into(),
460 None => ClippingRect::None,
461 }
462 }
463}
464
465impl ClippingRect {
466 pub fn intersection(&self, other: ClippingRect) -> ClippingRect {
467 match self {
468 ClippingRect::Zero => ClippingRect::Zero,
469 ClippingRect::None => other,
470 ClippingRect::Some(self_rect) => match other {
471 ClippingRect::Zero => ClippingRect::Zero,
472 ClippingRect::None => *self,
473 ClippingRect::Some(rect) => match self_rect.intersection(rect) {
474 Some(v) => ClippingRect::Some(v),
475 None => ClippingRect::Zero,
476 },
477 },
478 }
479 }
480
481 pub fn intersect_rect<R>(&self, position: R) -> ClippingRect
483 where
484 R: Into<Option<Rect>>,
485 {
486 let position: Option<Rect> = position.into();
487 match position {
488 Some(position) => {
489 match self {
490 ClippingRect::Some(rect) => match rect.intersection(position) {
491 Some(v) => ClippingRect::Some(v),
492 None => ClippingRect::Zero,
493 },
494 ClippingRect::Zero => ClippingRect::Zero,
495 ClippingRect::None => {
496 ClippingRect::Some(position)
498 }
499 }
500 }
501 None => {
502 ClippingRect::Zero
504 }
505 }
506 }
507}
508
509impl Canvas<Window> {
511 #[inline]
513 pub fn window(&self) -> &Window {
514 &self.target
515 }
516
517 #[inline]
519 pub fn window_mut(&mut self) -> &mut Window {
520 &mut self.target
521 }
522
523 #[inline]
525 pub fn into_window(self) -> Window {
526 self.target
527 }
528
529 #[inline]
530 pub fn default_pixel_format(&self) -> PixelFormatEnum {
531 self.window().window_pixel_format()
532 }
533
534 pub fn texture_creator(&self) -> TextureCreator<WindowContext> {
541 TextureCreator {
542 context: self.context.clone(),
543 default_pixel_format: self.default_pixel_format(),
544 }
545 }
546}
547
548impl<T: RenderTarget> Canvas<T> {
549 #[doc(alias = "SDL_RenderTargetSupported")]
551 pub fn render_target_supported(&self) -> bool {
552 unsafe { sys::SDL_RenderTargetSupported(self.context.raw) == sys::SDL_bool::SDL_TRUE }
553 }
554
555 pub fn with_texture_canvas<F>(
621 &mut self,
622 texture: &mut Texture,
623 f: F,
624 ) -> Result<(), TargetRenderError>
625 where
626 for<'r> F: FnOnce(&'r mut Canvas<T>),
627 {
628 if self.render_target_supported() {
629 let target = unsafe { self.get_raw_target() };
630 unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
631 f(self);
632 unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
633 Ok(())
634 } else {
635 Err(TargetRenderError::NotSupported)
636 }
637 }
638
639 #[cfg(not(feature = "unsafe_textures"))]
696 pub fn with_multiple_texture_canvas<'t: 'a, 'a: 's, 's, I, F, U: 's>(
697 &mut self,
698 textures: I,
699 mut f: F,
700 ) -> Result<(), TargetRenderError>
701 where
702 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
703 I: Iterator<Item = &'s (&'a mut Texture<'t>, U)>,
704 {
705 if self.render_target_supported() {
706 let target = unsafe { self.get_raw_target() };
707 for (texture, user_context) in textures {
708 unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
709 f(self, user_context);
710 }
711 unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
713 Ok(())
714 } else {
715 Err(TargetRenderError::NotSupported)
716 }
717 }
718
719 #[cfg(feature = "unsafe_textures")]
720 pub fn with_multiple_texture_canvas<'a: 's, 's, I, F, U: 's>(
721 &mut self,
722 textures: I,
723 mut f: F,
724 ) -> Result<(), TargetRenderError>
725 where
726 for<'r> F: FnMut(&'r mut Canvas<T>, &U),
727 I: Iterator<Item = &'s (&'a mut Texture, U)>,
728 {
729 if self.render_target_supported() {
730 for &(ref texture, ref user_context) in textures {
731 unsafe { self.set_raw_target(texture.raw) }
732 .map_err(|e| TargetRenderError::SdlError(e))?;
733 f(self, &user_context);
734 }
735 unsafe { self.set_raw_target(ptr::null_mut()) }
737 .map_err(|e| TargetRenderError::SdlError(e))?;
738 Ok(())
739 } else {
740 Err(TargetRenderError::NotSupported)
741 }
742 }
743}
744
745pub struct TextureCreator<T> {
758 context: Rc<RendererContext<T>>,
759 default_pixel_format: PixelFormatEnum,
760}
761
762pub struct CanvasBuilder {
767 window: Window,
768 index: Option<u32>,
769 renderer_flags: u32,
770}
771
772impl CanvasBuilder {
773 pub fn new(window: Window) -> CanvasBuilder {
775 CanvasBuilder {
776 window,
777 index: None,
780 renderer_flags: 0,
783 }
784 }
785
786 #[doc(alias = "SDL_CreateRenderer")]
788 pub fn build(self) -> Result<WindowCanvas, IntegerOrSdlError> {
789 use crate::common::IntegerOrSdlError::*;
790 let index = match self.index {
791 None => -1,
792 Some(index) => validate_int(index, "index")?,
793 };
794 let raw = unsafe { sys::SDL_CreateRenderer(self.window.raw(), index, self.renderer_flags) };
795
796 if raw.is_null() {
797 Err(SdlError(get_error()))
798 } else {
799 let context = Rc::new(unsafe { RendererContext::from_ll(raw, self.window.context()) });
800 let default_pixel_format = self.window.window_pixel_format();
801 Ok(Canvas {
802 context,
803 target: self.window,
804 default_pixel_format,
805 })
806 }
807 }
808
809 pub fn index(mut self, index: u32) -> CanvasBuilder {
814 self.index = Some(index);
815 self
816 }
817
818 pub fn software(mut self) -> CanvasBuilder {
821 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_SOFTWARE as u32;
822 self
823 }
824
825 pub fn accelerated(mut self) -> CanvasBuilder {
828 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_ACCELERATED as u32;
829 self
830 }
831
832 pub fn present_vsync(mut self) -> CanvasBuilder {
835 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_PRESENTVSYNC as u32;
836 self
837 }
838
839 pub fn target_texture(mut self) -> CanvasBuilder {
842 self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_TARGETTEXTURE as u32;
843 self
844 }
845}
846
847#[derive(Debug, Clone)]
848pub enum TextureValueError {
849 WidthOverflows(u32),
850 HeightOverflows(u32),
851 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
852 SdlError(String),
853}
854
855impl fmt::Display for TextureValueError {
856 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
857 use self::TextureValueError::*;
858
859 match *self {
860 WidthOverflows(value) => write!(f, "Integer width overflows ({})", value),
861 HeightOverflows(value) => write!(f, "Integer height overflows ({})", value),
862 WidthMustBeMultipleOfTwoForFormat(value, format) => {
863 write!(
864 f,
865 "Texture width must be multiple of two for pixel format '{:?}' ({})",
866 format, value
867 )
868 }
869 SdlError(ref e) => write!(f, "SDL error: {}", e),
870 }
871 }
872}
873
874impl Error for TextureValueError {}
875
876#[doc(alias = "SDL_CreateTexture")]
877fn ll_create_texture(
878 context: *mut sys::SDL_Renderer,
879 pixel_format: PixelFormatEnum,
880 access: TextureAccess,
881 width: u32,
882 height: u32,
883) -> Result<*mut sys::SDL_Texture, TextureValueError> {
884 use self::TextureValueError::*;
885 let w = match validate_int(width, "width") {
886 Ok(w) => w,
887 Err(_) => return Err(WidthOverflows(width)),
888 };
889 let h = match validate_int(height, "height") {
890 Ok(h) => h,
891 Err(_) => return Err(HeightOverflows(height)),
892 };
893
894 match pixel_format {
897 PixelFormatEnum::YV12
898 | PixelFormatEnum::IYUV
899 | PixelFormatEnum::NV12
900 | PixelFormatEnum::NV21 => {
901 if w % 2 != 0 || h % 2 != 0 {
902 return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format));
903 }
904 }
905 _ => (),
906 };
907
908 Ok(unsafe { sys::SDL_CreateTexture(context, pixel_format as u32, access as c_int, w, h) })
909}
910
911impl<T> TextureCreator<T> {
913 #[allow(clippy::trivially_copy_pass_by_ref)]
916 pub fn raw(&self) -> *mut sys::SDL_Renderer {
917 self.context.raw()
918 }
919
920 pub fn default_pixel_format(&self) -> PixelFormatEnum {
921 self.default_pixel_format
922 }
923
924 pub fn create_texture<F>(
936 &self,
937 format: F,
938 access: TextureAccess,
939 width: u32,
940 height: u32,
941 ) -> Result<Texture, TextureValueError>
942 where
943 F: Into<Option<PixelFormatEnum>>,
944 {
945 use self::TextureValueError::*;
946 let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
947 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
948 if result.is_null() {
949 Err(SdlError(get_error()))
950 } else {
951 unsafe { Ok(self.raw_create_texture(result)) }
952 }
953 }
954
955 #[inline]
956 pub fn create_texture_static<F>(
958 &self,
959 format: F,
960 width: u32,
961 height: u32,
962 ) -> Result<Texture, TextureValueError>
963 where
964 F: Into<Option<PixelFormatEnum>>,
965 {
966 self.create_texture(format, TextureAccess::Static, width, height)
967 }
968
969 #[inline]
970 pub fn create_texture_streaming<F>(
972 &self,
973 format: F,
974 width: u32,
975 height: u32,
976 ) -> Result<Texture, TextureValueError>
977 where
978 F: Into<Option<PixelFormatEnum>>,
979 {
980 self.create_texture(format, TextureAccess::Streaming, width, height)
981 }
982
983 #[inline]
984 pub fn create_texture_target<F>(
986 &self,
987 format: F,
988 width: u32,
989 height: u32,
990 ) -> Result<Texture, TextureValueError>
991 where
992 F: Into<Option<PixelFormatEnum>>,
993 {
994 self.create_texture(format, TextureAccess::Target, width, height)
995 }
996
997 #[doc(alias = "SDL_CreateTextureFromSurface")]
1028 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1029 &self,
1030 surface: S,
1031 ) -> Result<Texture, TextureValueError> {
1032 use self::TextureValueError::*;
1033 let result =
1034 unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
1035 if result.is_null() {
1036 Err(SdlError(get_error()))
1037 } else {
1038 unsafe { Ok(self.raw_create_texture(result)) }
1039 }
1040 }
1041
1042 #[cfg(not(feature = "unsafe_textures"))]
1044 #[inline]
1045 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
1046 Texture {
1047 raw,
1048 _marker: PhantomData,
1049 }
1050 }
1051
1052 #[cfg(feature = "unsafe_textures")]
1054 pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
1055 Texture { raw }
1056 }
1057}
1058
1059impl<T: RenderTarget> Canvas<T> {
1061 #[allow(clippy::trivially_copy_pass_by_ref)]
1064 pub fn raw(&self) -> *mut sys::SDL_Renderer {
1065 self.context.raw()
1066 }
1067
1068 #[doc(alias = "SDL_SetRenderDrawColor")]
1070 pub fn set_draw_color<C: Into<pixels::Color>>(&mut self, color: C) {
1071 let (r, g, b, a) = color.into().rgba();
1072 let ret = unsafe { sys::SDL_SetRenderDrawColor(self.raw, r, g, b, a) };
1073 if ret != 0 {
1075 panic!("{}", get_error())
1076 }
1077 }
1078
1079 #[doc(alias = "SDL_GetRenderDrawColor")]
1081 pub fn draw_color(&self) -> pixels::Color {
1082 let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
1083 let ret = unsafe {
1084 sys::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a)
1085 };
1086 if ret != 0 {
1088 panic!("{}", get_error())
1089 } else {
1090 pixels::Color::RGBA(r, g, b, a)
1091 }
1092 }
1093
1094 #[doc(alias = "SDL_SetRenderDrawBlendMode")]
1096 pub fn set_blend_mode(&mut self, blend: BlendMode) {
1097 let ret =
1098 unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32)) };
1099 if ret != 0 {
1101 panic!("{}", get_error())
1102 }
1103 }
1104
1105 #[doc(alias = "SDL_GetRenderDrawBlendMode")]
1107 pub fn blend_mode(&self) -> BlendMode {
1108 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
1109 let ret = unsafe { sys::SDL_GetRenderDrawBlendMode(self.context.raw, blend.as_mut_ptr()) };
1110 if ret != 0 {
1112 panic!("{}", get_error())
1113 } else {
1114 let blend = unsafe { blend.assume_init() };
1115 BlendMode::try_from(blend as u32).unwrap()
1116 }
1117 }
1118
1119 #[doc(alias = "SDL_RenderClear")]
1121 pub fn clear(&mut self) {
1122 let ret = unsafe { sys::SDL_RenderClear(self.context.raw) };
1123 if ret != 0 {
1124 panic!("Could not clear: {}", get_error())
1125 }
1126 }
1127
1128 #[doc(alias = "SDL_RenderPresent")]
1136 pub fn present(&mut self) {
1137 unsafe { sys::SDL_RenderPresent(self.context.raw) }
1138 }
1139
1140 #[doc(alias = "SDL_GetRendererOutputSize")]
1142 pub fn output_size(&self) -> Result<(u32, u32), String> {
1143 let mut width = 0;
1144 let mut height = 0;
1145
1146 let result =
1147 unsafe { sys::SDL_GetRendererOutputSize(self.context.raw, &mut width, &mut height) };
1148
1149 if result == 0 {
1150 Ok((width as u32, height as u32))
1151 } else {
1152 Err(get_error())
1153 }
1154 }
1155
1156 #[doc(alias = "SDL_RenderSetLogicalSize")]
1158 pub fn set_logical_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1159 use crate::common::IntegerOrSdlError::*;
1160 let width = validate_int(width, "width")?;
1161 let height = validate_int(height, "height")?;
1162 let result = unsafe { sys::SDL_RenderSetLogicalSize(self.context.raw, width, height) };
1163 match result {
1164 0 => Ok(()),
1165 _ => Err(SdlError(get_error())),
1166 }
1167 }
1168
1169 #[doc(alias = "SDL_RenderGetLogicalSize")]
1171 pub fn logical_size(&self) -> (u32, u32) {
1172 let mut width = 0;
1173 let mut height = 0;
1174
1175 unsafe { sys::SDL_RenderGetLogicalSize(self.context.raw, &mut width, &mut height) };
1176
1177 (width as u32, height as u32)
1178 }
1179
1180 #[doc(alias = "SDL_RenderSetViewport")]
1182 pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
1183 let rect = rect.into();
1184 let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1186 let ret = unsafe { sys::SDL_RenderSetViewport(self.context.raw, ptr) };
1187 if ret != 0 {
1188 panic!("Could not set viewport: {}", get_error())
1189 }
1190 }
1191
1192 #[doc(alias = "SDL_RenderGetViewport")]
1194 pub fn viewport(&self) -> Rect {
1195 let mut rect = mem::MaybeUninit::uninit();
1196 unsafe { sys::SDL_RenderGetViewport(self.context.raw, rect.as_mut_ptr()) };
1197 let rect = unsafe { rect.assume_init() };
1198 Rect::from_ll(rect)
1199 }
1200
1201 #[doc(alias = "SDL_RenderSetClipRect")]
1203 pub fn set_clip_rect<R>(&mut self, arg: R)
1204 where
1205 R: Into<ClippingRect>,
1206 {
1207 let arg: ClippingRect = arg.into();
1208 let ret = match arg {
1209 ClippingRect::Some(r) => unsafe {
1210 sys::SDL_RenderSetClipRect(self.context.raw, r.raw())
1211 },
1212 ClippingRect::Zero => {
1213 let r = sys::SDL_Rect {
1214 x: 0,
1215 y: 0,
1216 w: 0,
1217 h: 0,
1218 };
1219 let r: *const sys::SDL_Rect = &r;
1220 unsafe { sys::SDL_RenderSetClipRect(self.context.raw, r) }
1221 }
1222 ClippingRect::None => unsafe {
1223 sys::SDL_RenderSetClipRect(self.context.raw, ptr::null())
1224 },
1225 };
1226 if ret != 0 {
1227 panic!("Could not set clip rect: {}", get_error())
1228 }
1229 }
1230
1231 #[doc(alias = "SDL_RenderGetClipRect")]
1233 pub fn clip_rect(&self) -> ClippingRect {
1234 let clip_enabled = unsafe { sys::SDL_RenderIsClipEnabled(self.context.raw) };
1235
1236 if sys::SDL_bool::SDL_FALSE == clip_enabled {
1237 return ClippingRect::None;
1238 }
1239
1240 let mut raw = mem::MaybeUninit::uninit();
1241 unsafe { sys::SDL_RenderGetClipRect(self.context.raw, raw.as_mut_ptr()) };
1242 let raw = unsafe { raw.assume_init() };
1243 if raw.w == 0 || raw.h == 0 {
1244 ClippingRect::Zero
1245 } else {
1246 ClippingRect::Some(Rect::from_ll(raw))
1247 }
1248 }
1249
1250 #[doc(alias = "SDL_RenderSetIntegerScale")]
1252 pub fn set_integer_scale(&mut self, scale: bool) -> Result<(), String> {
1253 let ret = unsafe {
1254 sys::SDL_RenderSetIntegerScale(
1255 self.raw(),
1256 if scale {
1257 sys::SDL_bool::SDL_TRUE
1258 } else {
1259 sys::SDL_bool::SDL_FALSE
1260 },
1261 )
1262 };
1263 if ret != 0 {
1264 Err(get_error())
1265 } else {
1266 Ok(())
1267 }
1268 }
1269
1270 #[doc(alias = "SDL_RenderGetIntegerScale")]
1272 pub fn integer_scale(&self) -> bool {
1273 unsafe { sys::SDL_RenderGetIntegerScale(self.raw()) == sys::SDL_bool::SDL_TRUE }
1274 }
1275
1276 #[doc(alias = "SDL_RenderSetScale")]
1278 pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String> {
1279 let ret = unsafe { sys::SDL_RenderSetScale(self.context.raw, scale_x, scale_y) };
1280 if ret != 0 {
1282 Err(get_error())
1283 } else {
1284 Ok(())
1285 }
1286 }
1287
1288 #[doc(alias = "SDL_RenderGetScale")]
1290 pub fn scale(&self) -> (f32, f32) {
1291 let mut scale_x = 0.0;
1292 let mut scale_y = 0.0;
1293 unsafe { sys::SDL_RenderGetScale(self.context.raw, &mut scale_x, &mut scale_y) };
1294 (scale_x, scale_y)
1295 }
1296
1297 #[doc(alias = "SDL_RenderDrawPoint")]
1300 pub fn draw_point<P: Into<Point>>(&mut self, point: P) -> Result<(), String> {
1301 let point = point.into();
1302 let result = unsafe { sys::SDL_RenderDrawPoint(self.context.raw, point.x(), point.y()) };
1303 if result != 0 {
1304 Err(get_error())
1305 } else {
1306 Ok(())
1307 }
1308 }
1309
1310 #[doc(alias = "SDL_RenderDrawPoints")]
1313 pub fn draw_points<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1314 let points = points.into();
1315 let result = unsafe {
1316 sys::SDL_RenderDrawPoints(
1317 self.context.raw,
1318 Point::raw_slice(points),
1319 points.len() as c_int,
1320 )
1321 };
1322 if result != 0 {
1323 Err(get_error())
1324 } else {
1325 Ok(())
1326 }
1327 }
1328
1329 #[doc(alias = "SDL_RenderDrawLine")]
1332 pub fn draw_line<P1: Into<Point>, P2: Into<Point>>(
1333 &mut self,
1334 start: P1,
1335 end: P2,
1336 ) -> Result<(), String> {
1337 let start = start.into();
1338 let end = end.into();
1339 let result = unsafe {
1340 sys::SDL_RenderDrawLine(self.context.raw, start.x(), start.y(), end.x(), end.y())
1341 };
1342 if result != 0 {
1343 Err(get_error())
1344 } else {
1345 Ok(())
1346 }
1347 }
1348
1349 #[doc(alias = "SDL_RenderDrawLines")]
1352 pub fn draw_lines<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1353 let points = points.into();
1354 let result = unsafe {
1355 sys::SDL_RenderDrawLines(
1356 self.context.raw,
1357 Point::raw_slice(points),
1358 points.len() as c_int,
1359 )
1360 };
1361 if result != 0 {
1362 Err(get_error())
1363 } else {
1364 Ok(())
1365 }
1366 }
1367
1368 #[doc(alias = "SDL_RenderDrawRect")]
1371 pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String> {
1372 let result = unsafe { sys::SDL_RenderDrawRect(self.context.raw, rect.raw()) };
1373 if result != 0 {
1374 Err(get_error())
1375 } else {
1376 Ok(())
1377 }
1378 }
1379
1380 #[doc(alias = "SDL_RenderDrawRects")]
1383 pub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1384 let result = unsafe {
1385 sys::SDL_RenderDrawRects(
1386 self.context.raw,
1387 Rect::raw_slice(rects),
1388 rects.len() as c_int,
1389 )
1390 };
1391 if result != 0 {
1392 Err(get_error())
1393 } else {
1394 Ok(())
1395 }
1396 }
1397
1398 #[doc(alias = "SDL_RenderFillRect")]
1403 pub fn fill_rect<R: Into<Option<Rect>>>(&mut self, rect: R) -> Result<(), String> {
1404 let result = unsafe {
1405 sys::SDL_RenderFillRect(
1406 self.context.raw,
1407 rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1408 )
1409 };
1410 if result != 0 {
1411 Err(get_error())
1412 } else {
1413 Ok(())
1414 }
1415 }
1416
1417 #[doc(alias = "SDL_RenderFillRects")]
1421 pub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1422 let result = unsafe {
1423 sys::SDL_RenderFillRects(
1424 self.context.raw,
1425 Rect::raw_slice(rects),
1426 rects.len() as c_int,
1427 )
1428 };
1429 if result != 0 {
1430 Err(get_error())
1431 } else {
1432 Ok(())
1433 }
1434 }
1435
1436 #[doc(alias = "SDL_RenderDrawPointF")]
1439 pub fn draw_fpoint<P: Into<FPoint>>(&mut self, point: P) -> Result<(), String> {
1440 let point = point.into();
1441 let result = unsafe { sys::SDL_RenderDrawPointF(self.context.raw, point.x(), point.y()) };
1442 if result != 0 {
1443 Err(get_error())
1444 } else {
1445 Ok(())
1446 }
1447 }
1448
1449 #[doc(alias = "SDL_RenderDrawPointsF")]
1452 pub fn draw_fpoints<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1453 let points = points.into();
1454 let result = unsafe {
1455 sys::SDL_RenderDrawPointsF(
1456 self.context.raw,
1457 FPoint::raw_slice(points),
1458 points.len() as c_int,
1459 )
1460 };
1461 if result != 0 {
1462 Err(get_error())
1463 } else {
1464 Ok(())
1465 }
1466 }
1467
1468 #[doc(alias = "SDL_RenderDrawLineF")]
1471 pub fn draw_fline<P1: Into<FPoint>, P2: Into<FPoint>>(
1472 &mut self,
1473 start: P1,
1474 end: P2,
1475 ) -> Result<(), String> {
1476 let start = start.into();
1477 let end = end.into();
1478 let result = unsafe {
1479 sys::SDL_RenderDrawLineF(self.context.raw, start.x(), start.y(), end.x(), end.y())
1480 };
1481 if result != 0 {
1482 Err(get_error())
1483 } else {
1484 Ok(())
1485 }
1486 }
1487
1488 #[doc(alias = "SDL_RenderDrawLinesF")]
1491 pub fn draw_flines<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1492 let points = points.into();
1493 let result = unsafe {
1494 sys::SDL_RenderDrawLinesF(
1495 self.context.raw,
1496 FPoint::raw_slice(points),
1497 points.len() as c_int,
1498 )
1499 };
1500 if result != 0 {
1501 Err(get_error())
1502 } else {
1503 Ok(())
1504 }
1505 }
1506
1507 #[doc(alias = "SDL_RenderDrawRectF")]
1510 pub fn draw_frect(&mut self, rect: FRect) -> Result<(), String> {
1511 let result = unsafe { sys::SDL_RenderDrawRectF(self.context.raw, rect.raw()) };
1512 if result != 0 {
1513 Err(get_error())
1514 } else {
1515 Ok(())
1516 }
1517 }
1518
1519 #[doc(alias = "SDL_RenderDrawRectsF")]
1522 pub fn draw_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1523 let result = unsafe {
1524 sys::SDL_RenderDrawRectsF(
1525 self.context.raw,
1526 FRect::raw_slice(rects),
1527 rects.len() as c_int,
1528 )
1529 };
1530 if result != 0 {
1531 Err(get_error())
1532 } else {
1533 Ok(())
1534 }
1535 }
1536
1537 #[doc(alias = "SDL_RenderFillRectF")]
1542 pub fn fill_frect<R: Into<Option<FRect>>>(&mut self, rect: R) -> Result<(), String> {
1543 let result = unsafe {
1544 sys::SDL_RenderFillRectF(
1545 self.context.raw,
1546 rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1547 )
1548 };
1549 if result != 0 {
1550 Err(get_error())
1551 } else {
1552 Ok(())
1553 }
1554 }
1555
1556 #[doc(alias = "SDL_RenderFillRectsF")]
1560 pub fn fill_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1561 let result = unsafe {
1562 sys::SDL_RenderFillRectsF(
1563 self.context.raw,
1564 FRect::raw_slice(rects),
1565 rects.len() as c_int,
1566 )
1567 };
1568 if result != 0 {
1569 Err(get_error())
1570 } else {
1571 Ok(())
1572 }
1573 }
1574
1575 #[doc(alias = "SDL_RenderCopyF")]
1584 pub fn copy_f<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1585 where
1586 R1: Into<Option<Rect>>,
1587 R2: Into<Option<FRect>>,
1588 {
1589 let ret = unsafe {
1590 sys::SDL_RenderCopyF(
1591 self.context.raw,
1592 texture.raw,
1593 match src.into() {
1594 Some(ref rect) => rect.raw(),
1595 None => ptr::null(),
1596 },
1597 match dst.into() {
1598 Some(ref rect) => rect.raw(),
1599 None => ptr::null(),
1600 },
1601 )
1602 };
1603
1604 if ret != 0 {
1605 Err(get_error())
1606 } else {
1607 Ok(())
1608 }
1609 }
1610
1611 #[doc(alias = "SDL_RenderCopyExF")]
1625 pub fn copy_ex_f<R1, R2, P>(
1626 &mut self,
1627 texture: &Texture,
1628 src: R1,
1629 dst: R2,
1630 angle: f64,
1631 center: P,
1632 flip_horizontal: bool,
1633 flip_vertical: bool,
1634 ) -> Result<(), String>
1635 where
1636 R1: Into<Option<Rect>>,
1637 R2: Into<Option<FRect>>,
1638 P: Into<Option<FPoint>>,
1639 {
1640 use crate::sys::SDL_RendererFlip::*;
1641 let flip = unsafe {
1642 match (flip_horizontal, flip_vertical) {
1643 (false, false) => SDL_FLIP_NONE,
1644 (true, false) => SDL_FLIP_HORIZONTAL,
1645 (false, true) => SDL_FLIP_VERTICAL,
1646 (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1647 transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1648 | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1649 ),
1650 }
1651 };
1652
1653 let ret = unsafe {
1654 sys::SDL_RenderCopyExF(
1655 self.context.raw,
1656 texture.raw,
1657 match src.into() {
1658 Some(ref rect) => rect.raw(),
1659 None => ptr::null(),
1660 },
1661 match dst.into() {
1662 Some(ref rect) => rect.raw(),
1663 None => ptr::null(),
1664 },
1665 angle as c_double,
1666 match center.into() {
1667 Some(ref point) => point.raw(),
1668 None => ptr::null(),
1669 },
1670 flip,
1671 )
1672 };
1673
1674 if ret != 0 {
1675 Err(get_error())
1676 } else {
1677 Ok(())
1678 }
1679 }
1680
1681 #[doc(alias = "SDL_RenderCopy")]
1690 pub fn copy<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1691 where
1692 R1: Into<Option<Rect>>,
1693 R2: Into<Option<Rect>>,
1694 {
1695 let ret = unsafe {
1696 sys::SDL_RenderCopy(
1697 self.context.raw,
1698 texture.raw,
1699 match src.into() {
1700 Some(ref rect) => rect.raw(),
1701 None => ptr::null(),
1702 },
1703 match dst.into() {
1704 Some(ref rect) => rect.raw(),
1705 None => ptr::null(),
1706 },
1707 )
1708 };
1709
1710 if ret != 0 {
1711 Err(get_error())
1712 } else {
1713 Ok(())
1714 }
1715 }
1716
1717 #[doc(alias = "SDL_RenderCopyEx")]
1731 pub fn copy_ex<R1, R2, P>(
1732 &mut self,
1733 texture: &Texture,
1734 src: R1,
1735 dst: R2,
1736 angle: f64,
1737 center: P,
1738 flip_horizontal: bool,
1739 flip_vertical: bool,
1740 ) -> Result<(), String>
1741 where
1742 R1: Into<Option<Rect>>,
1743 R2: Into<Option<Rect>>,
1744 P: Into<Option<Point>>,
1745 {
1746 use crate::sys::SDL_RendererFlip::*;
1747 let flip = unsafe {
1748 match (flip_horizontal, flip_vertical) {
1749 (false, false) => SDL_FLIP_NONE,
1750 (true, false) => SDL_FLIP_HORIZONTAL,
1751 (false, true) => SDL_FLIP_VERTICAL,
1752 (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1753 transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1754 | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1755 ),
1756 }
1757 };
1758
1759 let ret = unsafe {
1760 sys::SDL_RenderCopyEx(
1761 self.context.raw,
1762 texture.raw,
1763 match src.into() {
1764 Some(ref rect) => rect.raw(),
1765 None => ptr::null(),
1766 },
1767 match dst.into() {
1768 Some(ref rect) => rect.raw(),
1769 None => ptr::null(),
1770 },
1771 angle as c_double,
1772 match center.into() {
1773 Some(ref point) => point.raw(),
1774 None => ptr::null(),
1775 },
1776 flip,
1777 )
1778 };
1779
1780 if ret != 0 {
1781 Err(get_error())
1782 } else {
1783 Ok(())
1784 }
1785 }
1786
1787 #[doc(alias = "SDL_RenderReadPixels")]
1791 pub fn read_pixels<R: Into<Option<Rect>>>(
1792 &self,
1793 rect: R,
1794 format: pixels::PixelFormatEnum,
1795 ) -> Result<Vec<u8>, String> {
1796 let rect = rect.into();
1797 let (actual_rect, w, h) = match rect {
1798 Some(ref rect) => (rect.raw(), rect.width() as usize, rect.height() as usize),
1799 None => {
1800 let (w, h) = self.output_size()?;
1801 (ptr::null(), w as usize, h as usize)
1802 }
1803 };
1804
1805 let pitch = w * format.byte_size_per_pixel(); let size = format.byte_size_of_pixels(w * h);
1807 let mut pixels = Vec::with_capacity(size);
1808
1809 let ret = unsafe {
1811 sys::SDL_RenderReadPixels(
1812 self.context.raw,
1813 actual_rect,
1814 format as u32,
1815 pixels.as_mut_ptr() as *mut c_void,
1816 pitch as c_int,
1817 )
1818 };
1819
1820 if ret == 0 {
1821 unsafe { pixels.set_len(size) };
1822 Ok(pixels)
1823 } else {
1824 Err(get_error())
1825 }
1826 }
1827
1828 #[cfg(feature = "unsafe_textures")]
1846 pub fn create_texture<F>(
1847 &self,
1848 format: F,
1849 access: TextureAccess,
1850 width: u32,
1851 height: u32,
1852 ) -> Result<Texture, TextureValueError>
1853 where
1854 F: Into<Option<PixelFormatEnum>>,
1855 {
1856 use self::TextureValueError::*;
1857 let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
1858 let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
1859 if result.is_null() {
1860 Err(SdlError(get_error()))
1861 } else {
1862 unsafe { Ok(self.raw_create_texture(result)) }
1863 }
1864 }
1865
1866 #[cfg(feature = "unsafe_textures")]
1872 #[inline]
1873 pub fn create_texture_static<F>(
1874 &self,
1875 format: F,
1876 width: u32,
1877 height: u32,
1878 ) -> Result<Texture, TextureValueError>
1879 where
1880 F: Into<Option<PixelFormatEnum>>,
1881 {
1882 self.create_texture(format, TextureAccess::Static, width, height)
1883 }
1884
1885 #[cfg(feature = "unsafe_textures")]
1891 #[inline]
1892 pub fn create_texture_streaming<F>(
1893 &self,
1894 format: F,
1895 width: u32,
1896 height: u32,
1897 ) -> Result<Texture, TextureValueError>
1898 where
1899 F: Into<Option<PixelFormatEnum>>,
1900 {
1901 self.create_texture(format, TextureAccess::Streaming, width, height)
1902 }
1903
1904 #[cfg(feature = "unsafe_textures")]
1910 #[inline]
1911 pub fn create_texture_target<F>(
1912 &self,
1913 format: F,
1914 width: u32,
1915 height: u32,
1916 ) -> Result<Texture, TextureValueError>
1917 where
1918 F: Into<Option<PixelFormatEnum>>,
1919 {
1920 self.create_texture(format, TextureAccess::Target, width, height)
1921 }
1922
1923 #[cfg(feature = "unsafe_textures")]
1933 #[doc(alias = "SDL_CreateTextureFromSurface")]
1934 pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1935 &self,
1936 surface: S,
1937 ) -> Result<Texture, TextureValueError> {
1938 use self::TextureValueError::*;
1939 let result =
1940 unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
1941 if result.is_null() {
1942 Err(SdlError(get_error()))
1943 } else {
1944 unsafe { Ok(self.raw_create_texture(result)) }
1945 }
1946 }
1947
1948 #[cfg(feature = "unsafe_textures")]
1949 pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
1955 Texture { raw }
1956 }
1957
1958 #[doc(alias = "SDL_RenderFlush")]
1959 pub unsafe fn render_flush(&self) {
1960 let ret = sys::SDL_RenderFlush(self.context.raw);
1961
1962 if ret != 0 {
1963 panic!("Error setting blend: {}", get_error())
1964 }
1965 }
1966}
1967
1968#[repr(C)]
1971#[derive(Debug, Clone, Copy)]
1972pub struct Vertex {
1973 pub position: FPoint,
1974 pub color: pixels::Color,
1975 pub tex_coord: FPoint,
1976}
1977
1978#[derive(Debug, Clone, Copy)]
1979pub enum VertexIndices<'a> {
1980 Sequential,
1982 U8(&'a [u8]),
1984 U16(&'a [u16]),
1986 U32(&'a [u32]),
1988}
1989
1990impl VertexIndices<'_> {
1991 fn into_raw(self) -> (*const c_void, c_int, c_int) {
1993 match self {
1994 Self::Sequential => (ptr::null(), 0, 0),
1995 Self::U8(indices) => (indices.as_ptr().cast::<c_void>(), indices.len() as c_int, 1),
1996 Self::U16(indices) => (indices.as_ptr().cast::<c_void>(), indices.len() as c_int, 2),
1997 Self::U32(indices) => (indices.as_ptr().cast::<c_void>(), indices.len() as c_int, 4),
1998 }
1999 }
2000}
2001
2002impl<'a> From<&'a [u8]> for VertexIndices<'a> {
2003 fn from(value: &'a [u8]) -> Self {
2004 Self::U8(value)
2005 }
2006}
2007
2008impl<'a> From<&'a [u16]> for VertexIndices<'a> {
2009 fn from(value: &'a [u16]) -> Self {
2010 Self::U16(value)
2011 }
2012}
2013
2014impl<'a> From<&'a [u32]> for VertexIndices<'a> {
2015 fn from(value: &'a [u32]) -> Self {
2016 Self::U32(value)
2017 }
2018}
2019
2020impl<'a> From<&'a [i32]> for VertexIndices<'a> {
2021 fn from(value: &'a [i32]) -> Self {
2022 Self::U32(unsafe { slice::from_raw_parts(value.as_ptr().cast::<u32>(), value.len()) })
2023 }
2024}
2025
2026impl<'a> From<&'a [[u8; 3]]> for VertexIndices<'a> {
2027 fn from(value: &'a [[u8; 3]]) -> Self {
2028 Self::U8(unsafe { slice::from_raw_parts(value.as_ptr().cast::<u8>(), value.len() * 3) })
2029 }
2030}
2031
2032impl<'a> From<&'a [[u16; 3]]> for VertexIndices<'a> {
2033 fn from(value: &'a [[u16; 3]]) -> Self {
2034 Self::U16(unsafe { slice::from_raw_parts(value.as_ptr().cast::<u16>(), value.len() * 3) })
2035 }
2036}
2037
2038impl<'a> From<&'a [[u32; 3]]> for VertexIndices<'a> {
2039 fn from(value: &'a [[u32; 3]]) -> Self {
2040 Self::U32(unsafe { slice::from_raw_parts(value.as_ptr().cast::<u32>(), value.len() * 3) })
2041 }
2042}
2043
2044impl<'a> From<&'a [[i32; 3]]> for VertexIndices<'a> {
2045 fn from(value: &'a [[i32; 3]]) -> Self {
2046 Self::U32(unsafe { slice::from_raw_parts(value.as_ptr().cast::<u32>(), value.len() * 3) })
2047 }
2048}
2049
2050macro_rules! impl_into_vertex_indices_forward {
2051 ($($ty:ty)*) => {
2052 $(
2053 impl<'a> From<&'a Vec<$ty>> for VertexIndices<'a> {
2054 fn from(value: &'a Vec<$ty>) -> Self {
2055 Self::from(value.as_slice())
2056 }
2057 }
2058
2059 impl<'a, const N: usize> From<&'a [$ty; N]> for VertexIndices<'a> {
2060 fn from(value: &'a [$ty; N]) -> Self {
2061 Self::from(value.as_slice())
2062 }
2063 }
2064 )*
2065 };
2066}
2067
2068impl_into_vertex_indices_forward!(u8 u16 u32 i32 [u8; 3] [u16; 3] [u32; 3] [i32; 3]);
2069
2070#[derive(Clone, Copy)]
2071pub struct RenderGeometryTextureParams<'a, TexCoordVertex> {
2072 #[cfg(not(feature = "unsafe_textures"))]
2073 pub texture: &'a Texture<'a>,
2074 #[cfg(feature = "unsafe_textures")]
2075 pub texture: &'a Texture,
2076 pub tex_coords: &'a [TexCoordVertex],
2077 pub tex_coord_offset: usize,
2078}
2079
2080impl<T: RenderTarget> Canvas<T> {
2081 #[doc(alias = "SDL_RenderGeometry")]
2103 pub fn render_geometry<'a>(
2104 &mut self,
2105 vertices: &[Vertex],
2106 texture: Option<&Texture>,
2107 indices: impl Into<VertexIndices<'a>>,
2108 ) -> Result<(), String> {
2109 unsafe {
2110 self.render_geometry_raw(
2111 vertices,
2112 mem::offset_of!(Vertex, position),
2113 vertices,
2114 mem::offset_of!(Vertex, color),
2115 texture.map(|texture| RenderGeometryTextureParams {
2116 texture,
2117 tex_coords: vertices,
2118 tex_coord_offset: mem::offset_of!(Vertex, tex_coord),
2119 }),
2120 indices,
2121 )
2122 }
2123 }
2124
2125 #[inline]
2176 #[doc(alias = "SDL_RenderGeometryRaw")]
2177 pub unsafe fn render_geometry_raw<'a, PosVertex, ColorVertex, TexCoordVertex>(
2178 &mut self,
2179 positions: &[PosVertex],
2180 position_offset: usize,
2181 colors: &[ColorVertex],
2182 color_offset: usize,
2183 texture_params: Option<RenderGeometryTextureParams<TexCoordVertex>>,
2184 indices: impl Into<VertexIndices<'a>>,
2185 ) -> Result<(), String> {
2186 let num_vertices = positions.len();
2187 assert_eq!(num_vertices, colors.len());
2188
2189 assert!(position_offset + size_of::<FPoint>() <= size_of::<PosVertex>());
2190 assert!(color_offset + size_of::<pixels::Color>() <= size_of::<ColorVertex>());
2191 let (texture, uv, uv_stride) = if let Some(texture_params) = texture_params {
2192 assert_eq!(num_vertices, texture_params.tex_coords.len());
2193 assert!(
2194 texture_params.tex_coord_offset + size_of::<FPoint>()
2195 <= size_of::<TexCoordVertex>(),
2196 );
2197
2198 (
2199 texture_params.texture.raw,
2200 texture_params
2201 .tex_coords
2202 .as_ptr()
2203 .cast::<f32>()
2204 .byte_offset(texture_params.tex_coord_offset.try_into().unwrap()),
2205 size_of::<TexCoordVertex>().try_into().unwrap(),
2206 )
2207 } else {
2208 (ptr::null_mut(), ptr::null(), 0)
2209 };
2210
2211 let xy = positions
2212 .as_ptr()
2213 .cast::<f32>()
2214 .byte_offset(position_offset.try_into().unwrap());
2215 let xy_stride = size_of::<PosVertex>().try_into().unwrap();
2216
2217 let color = colors
2218 .as_ptr()
2219 .cast::<sys::SDL_Color>()
2220 .byte_offset(color_offset.try_into().unwrap());
2221 let color_stride = size_of::<ColorVertex>().try_into().unwrap();
2222
2223 let (indices, num_indices, size_indices) = indices.into().into_raw();
2224
2225 let ret = unsafe {
2226 sys::SDL_RenderGeometryRaw(
2227 self.context.raw,
2228 texture,
2229 xy,
2230 xy_stride,
2231 color,
2232 color_stride,
2233 uv,
2234 uv_stride,
2235 num_vertices.try_into().unwrap(),
2236 indices,
2237 num_indices,
2238 size_indices,
2239 )
2240 };
2241
2242 if ret == 0 {
2243 Ok(())
2244 } else {
2245 Err(get_error())
2246 }
2247 }
2248}
2249
2250#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
2251pub struct TextureQuery {
2252 pub format: pixels::PixelFormatEnum,
2253 pub access: TextureAccess,
2254 pub width: u32,
2255 pub height: u32,
2256}
2257
2258#[cfg(feature = "unsafe_textures")]
2285pub struct Texture {
2286 raw: *mut sys::SDL_Texture,
2287}
2288
2289#[cfg(not(feature = "unsafe_textures"))]
2295pub struct Texture<'r> {
2296 raw: *mut sys::SDL_Texture,
2297 _marker: PhantomData<&'r ()>,
2298}
2299
2300#[cfg(not(feature = "unsafe_textures"))]
2301impl<'r> Drop for Texture<'r> {
2302 #[doc(alias = "SDL_DestroyTexture")]
2303 fn drop(&mut self) {
2304 unsafe {
2305 sys::SDL_DestroyTexture(self.raw);
2306 }
2307 }
2308}
2309
2310#[cfg(feature = "unsafe_textures")]
2311impl Texture {
2312 pub unsafe fn destroy(self) {
2329 sys::SDL_DestroyTexture(self.raw)
2330 }
2331}
2332
2333#[derive(Debug, Clone)]
2334pub enum UpdateTextureError {
2335 PitchOverflows(usize),
2336 PitchMustBeMultipleOfTwoForFormat(usize, PixelFormatEnum),
2337 XMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
2338 YMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
2339 WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
2340 HeightMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
2341 SdlError(String),
2342}
2343
2344impl fmt::Display for UpdateTextureError {
2345 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2346 use self::UpdateTextureError::*;
2347
2348 match *self {
2349 PitchOverflows(value) => write!(f, "Pitch overflows ({})", value),
2350 PitchMustBeMultipleOfTwoForFormat(value, format) => {
2351 write!(
2352 f,
2353 "Pitch must be multiple of two for pixel format '{:?}' ({})",
2354 format, value
2355 )
2356 }
2357 XMustBeMultipleOfTwoForFormat(value, format) => {
2358 write!(
2359 f,
2360 "X must be multiple of two for pixel format '{:?}' ({})",
2361 format, value
2362 )
2363 }
2364 YMustBeMultipleOfTwoForFormat(value, format) => {
2365 write!(
2366 f,
2367 "Y must be multiple of two for pixel format '{:?}' ({})",
2368 format, value
2369 )
2370 }
2371 WidthMustBeMultipleOfTwoForFormat(value, format) => {
2372 write!(
2373 f,
2374 "Width must be multiple of two for pixel format '{:?}' ({})",
2375 format, value
2376 )
2377 }
2378 HeightMustBeMultipleOfTwoForFormat(value, format) => {
2379 write!(
2380 f,
2381 "Height must be multiple of two for pixel format '{:?}' ({})",
2382 format, value
2383 )
2384 }
2385 SdlError(ref e) => write!(f, "SDL error: {}", e),
2386 }
2387 }
2388}
2389
2390impl Error for UpdateTextureError {}
2391
2392#[derive(Debug, Clone)]
2393pub enum UpdateTextureYUVError {
2394 PitchOverflows {
2395 plane: &'static str,
2396 value: usize,
2397 },
2398 InvalidPlaneLength {
2399 plane: &'static str,
2400 length: usize,
2401 pitch: usize,
2402 height: usize,
2403 },
2404 XMustBeMultipleOfTwoForFormat(i32),
2405 YMustBeMultipleOfTwoForFormat(i32),
2406 WidthMustBeMultipleOfTwoForFormat(u32),
2407 HeightMustBeMultipleOfTwoForFormat(u32),
2408 RectNotInsideTexture(Rect),
2409 SdlError(String),
2410}
2411
2412impl fmt::Display for UpdateTextureYUVError {
2413 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2414 use self::UpdateTextureYUVError::*;
2415
2416 match *self {
2417 PitchOverflows { plane, value } => {
2418 write!(f, "Pitch overflows on {} plane ({})", plane, value)
2419 }
2420 InvalidPlaneLength {
2421 plane,
2422 length,
2423 pitch,
2424 height,
2425 } => {
2426 write!(
2427 f,
2428 "The {} plane is wrong length ({}, should be {} * {})",
2429 plane, length, pitch, height
2430 )
2431 }
2432 XMustBeMultipleOfTwoForFormat(value) => {
2433 write!(f, "X must be multiple of two ({})", value)
2434 }
2435 YMustBeMultipleOfTwoForFormat(value) => {
2436 write!(f, "Y must be multiple of two ({})", value)
2437 }
2438 WidthMustBeMultipleOfTwoForFormat(value) => {
2439 write!(f, "Width must be multiple of two ({})", value)
2440 }
2441 HeightMustBeMultipleOfTwoForFormat(value) => {
2442 write!(f, "Height must be multiple of two ({})", value)
2443 }
2444 RectNotInsideTexture(_) => write!(f, "Rect must be inside texture"),
2445 SdlError(ref e) => write!(f, "SDL error: {}", e),
2446 }
2447 }
2448}
2449
2450impl Error for UpdateTextureYUVError {}
2451
2452struct InternalTexture {
2453 raw: *mut sys::SDL_Texture,
2454}
2455
2456impl InternalTexture {
2457 #[doc(alias = "SDL_QueryTexture")]
2458 pub fn query(&self) -> TextureQuery {
2459 let mut format = 0;
2460 let mut access = 0;
2461 let mut width = 0;
2462 let mut height = 0;
2463
2464 let ret = unsafe {
2465 sys::SDL_QueryTexture(self.raw, &mut format, &mut access, &mut width, &mut height)
2466 };
2467 if ret != 0 {
2469 panic!("{}", get_error())
2470 } else {
2471 TextureQuery {
2472 format: PixelFormatEnum::try_from(format).unwrap(),
2473 access: TextureAccess::try_from(access as u32).unwrap(),
2474 width: width as u32,
2475 height: height as u32,
2476 }
2477 }
2478 }
2479
2480 #[doc(alias = "SDL_SetTextureColorMod")]
2481 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2482 let ret = unsafe { sys::SDL_SetTextureColorMod(self.raw, red, green, blue) };
2483
2484 if ret != 0 {
2485 panic!("Error setting color mod: {}", get_error())
2486 }
2487 }
2488
2489 #[doc(alias = "SDL_GetTextureColorMod")]
2490 pub fn color_mod(&self) -> (u8, u8, u8) {
2491 let (mut r, mut g, mut b) = (0, 0, 0);
2492 let ret = unsafe { sys::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) };
2493
2494 if ret != 0 {
2496 panic!("{}", get_error())
2497 } else {
2498 (r, g, b)
2499 }
2500 }
2501
2502 #[doc(alias = "SDL_SetTextureScaleMode")]
2503 pub fn set_scale_mode(&mut self, scale: ScaleMode) {
2504 let ret = unsafe { sys::SDL_SetTextureScaleMode(self.raw, transmute(scale as u32)) };
2505 if ret != 0 {
2506 panic!("Error setting scale mode: {}", get_error())
2507 }
2508 }
2509
2510 #[doc(alias = "SDL_GetTextureScaleMode")]
2511 pub fn scale_mode(&self) -> ScaleMode {
2512 let mut scale: MaybeUninit<SDL_ScaleMode> = mem::MaybeUninit::uninit();
2513 let ret = unsafe { sys::SDL_GetTextureScaleMode(self.raw, scale.as_mut_ptr()) };
2514 if ret != 0 {
2515 panic!("{}", get_error())
2516 } else {
2517 let scale = unsafe { scale.assume_init() };
2518 ScaleMode::try_from(scale as u32).unwrap()
2519 }
2520 }
2521
2522 #[doc(alias = "SDL_SetTextureAlphaMod")]
2523 pub fn set_alpha_mod(&mut self, alpha: u8) {
2524 let ret = unsafe { sys::SDL_SetTextureAlphaMod(self.raw, alpha) };
2525
2526 if ret != 0 {
2527 panic!("Error setting alpha mod: {}", get_error())
2528 }
2529 }
2530
2531 #[doc(alias = "SDL_GetTextureAlphaMod")]
2532 pub fn alpha_mod(&self) -> u8 {
2533 let mut alpha = 0;
2534 let ret = unsafe { sys::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
2535
2536 if ret != 0 {
2538 panic!("{}", get_error())
2539 } else {
2540 alpha
2541 }
2542 }
2543
2544 #[doc(alias = "SDL_SetTextureBlendMode")]
2545 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2546 let ret = unsafe { sys::SDL_SetTextureBlendMode(self.raw, transmute(blend as u32)) };
2547
2548 if ret != 0 {
2549 panic!("Error setting blend: {}", get_error())
2550 }
2551 }
2552
2553 #[doc(alias = "SDL_GetTextureBlendMode")]
2554 pub fn blend_mode(&self) -> BlendMode {
2555 let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
2556 let ret = unsafe { sys::SDL_GetTextureBlendMode(self.raw, blend.as_mut_ptr()) };
2557
2558 if ret != 0 {
2560 panic!("{}", get_error())
2561 } else {
2562 let blend = unsafe { blend.assume_init() };
2563 BlendMode::try_from(blend as u32).unwrap()
2564 }
2565 }
2566
2567 #[doc(alias = "SDL_UpdateTexture")]
2568 pub fn update<R>(
2569 &mut self,
2570 rect: R,
2571 pixel_data: &[u8],
2572 pitch: usize,
2573 ) -> Result<(), UpdateTextureError>
2574 where
2575 R: Into<Option<Rect>>,
2576 {
2577 use self::UpdateTextureError::*;
2578 let rect = rect.into();
2579 let rect_raw_ptr = match rect {
2580 Some(ref rect) => rect.raw(),
2581 None => ptr::null(),
2582 };
2583
2584 let TextureQuery { format, .. } = self.query();
2588 match format {
2589 PixelFormatEnum::YV12
2590 | PixelFormatEnum::IYUV
2591 | PixelFormatEnum::NV12
2592 | PixelFormatEnum::NV21 => {
2593 if let Some(r) = rect {
2594 if r.x() % 2 != 0 {
2595 return Err(XMustBeMultipleOfTwoForFormat(r.x(), format));
2596 } else if r.y() % 2 != 0 {
2597 return Err(YMustBeMultipleOfTwoForFormat(r.y(), format));
2598 } else if r.width() % 2 != 0 {
2599 return Err(WidthMustBeMultipleOfTwoForFormat(r.width(), format));
2600 } else if r.height() % 2 != 0 {
2601 return Err(HeightMustBeMultipleOfTwoForFormat(r.height(), format));
2602 }
2603 };
2604 if pitch % 2 != 0 {
2605 return Err(PitchMustBeMultipleOfTwoForFormat(pitch, format));
2606 }
2607 }
2608 _ => {}
2609 }
2610
2611 let pitch = match validate_int(pitch as u32, "pitch") {
2612 Ok(p) => p,
2613 Err(_) => return Err(PitchOverflows(pitch)),
2614 };
2615
2616 let result = unsafe {
2617 sys::SDL_UpdateTexture(
2618 self.raw,
2619 rect_raw_ptr,
2620 pixel_data.as_ptr() as *const _,
2621 pitch,
2622 )
2623 };
2624
2625 if result != 0 {
2626 Err(SdlError(get_error()))
2627 } else {
2628 Ok(())
2629 }
2630 }
2631
2632 #[doc(alias = "SDL_UpdateYUVTexture")]
2633 pub fn update_yuv<R>(
2634 &mut self,
2635 rect: R,
2636 y_plane: &[u8],
2637 y_pitch: usize,
2638 u_plane: &[u8],
2639 u_pitch: usize,
2640 v_plane: &[u8],
2641 v_pitch: usize,
2642 ) -> Result<(), UpdateTextureYUVError>
2643 where
2644 R: Into<Option<Rect>>,
2645 {
2646 use self::UpdateTextureYUVError::*;
2647
2648 let rect = rect.into();
2649
2650 let rect_raw_ptr = match rect {
2651 Some(ref rect) => rect.raw(),
2652 None => ptr::null(),
2653 };
2654
2655 if let Some(ref r) = rect {
2656 if r.x() % 2 != 0 {
2657 return Err(XMustBeMultipleOfTwoForFormat(r.x()));
2658 } else if r.y() % 2 != 0 {
2659 return Err(YMustBeMultipleOfTwoForFormat(r.y()));
2660 } else if r.width() % 2 != 0 {
2661 return Err(WidthMustBeMultipleOfTwoForFormat(r.width()));
2662 } else if r.height() % 2 != 0 {
2663 return Err(HeightMustBeMultipleOfTwoForFormat(r.height()));
2664 }
2665 };
2666
2667 let tex_info = self.query();
2670 if let Some(ref r) = rect {
2671 let tex_rect = Rect::new(0, 0, tex_info.width, tex_info.height);
2672 let inside = match r.intersection(tex_rect) {
2673 Some(intersection) => intersection == *r,
2674 None => false,
2675 };
2676 if !inside {
2678 return Err(RectNotInsideTexture(*r));
2679 }
2680 }
2681
2682 let height = match rect {
2685 Some(ref r) => r.height(),
2686 None => tex_info.height,
2687 } as usize;
2688
2689 if y_plane.len() != (y_pitch * height) {
2691 return Err(InvalidPlaneLength {
2692 plane: "y",
2693 length: y_plane.len(),
2694 pitch: y_pitch,
2695 height,
2696 });
2697 }
2698 if u_plane.len() != (u_pitch * height / 2) {
2699 return Err(InvalidPlaneLength {
2700 plane: "u",
2701 length: u_plane.len(),
2702 pitch: u_pitch,
2703 height: height / 2,
2704 });
2705 }
2706 if v_plane.len() != (v_pitch * height / 2) {
2707 return Err(InvalidPlaneLength {
2708 plane: "v",
2709 length: v_plane.len(),
2710 pitch: v_pitch,
2711 height: height / 2,
2712 });
2713 }
2714
2715 let y_pitch = match validate_int(y_pitch as u32, "y_pitch") {
2716 Ok(p) => p,
2717 Err(_) => {
2718 return Err(PitchOverflows {
2719 plane: "y",
2720 value: y_pitch,
2721 })
2722 }
2723 };
2724 let u_pitch = match validate_int(u_pitch as u32, "u_pitch") {
2725 Ok(p) => p,
2726 Err(_) => {
2727 return Err(PitchOverflows {
2728 plane: "u",
2729 value: u_pitch,
2730 })
2731 }
2732 };
2733 let v_pitch = match validate_int(v_pitch as u32, "v_pitch") {
2734 Ok(p) => p,
2735 Err(_) => {
2736 return Err(PitchOverflows {
2737 plane: "v",
2738 value: v_pitch,
2739 })
2740 }
2741 };
2742
2743 let result = unsafe {
2744 sys::SDL_UpdateYUVTexture(
2745 self.raw,
2746 rect_raw_ptr,
2747 y_plane.as_ptr(),
2748 y_pitch,
2749 u_plane.as_ptr(),
2750 u_pitch,
2751 v_plane.as_ptr(),
2752 v_pitch,
2753 )
2754 };
2755 if result != 0 {
2756 Err(SdlError(get_error()))
2757 } else {
2758 Ok(())
2759 }
2760 }
2761
2762 #[doc(alias = "SDL_LockTexture")]
2763 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2764 where
2765 F: FnOnce(&mut [u8], usize) -> R,
2766 R2: Into<Option<Rect>>,
2767 {
2768 let loaded = unsafe {
2770 let q = self.query();
2771 let mut pixels = ptr::null_mut();
2772 let mut pitch = 0;
2773
2774 let (rect_raw_ptr, height) = match rect.into() {
2775 Some(ref rect) => (rect.raw(), rect.height() as usize),
2776 None => (ptr::null(), q.height as usize),
2777 };
2778
2779 let ret = sys::SDL_LockTexture(self.raw, rect_raw_ptr, &mut pixels, &mut pitch);
2780 if ret == 0 {
2781 let size = q
2782 .format
2783 .byte_size_from_pitch_and_height(pitch as usize, height);
2784 Ok((
2785 ::std::slice::from_raw_parts_mut(pixels as *mut u8, size),
2786 pitch,
2787 ))
2788 } else {
2789 Err(get_error())
2790 }
2791 };
2792
2793 match loaded {
2794 Ok((interior, pitch)) => {
2795 let result;
2796 unsafe {
2797 result = func(interior, pitch as usize);
2798 sys::SDL_UnlockTexture(self.raw);
2799 }
2800 Ok(result)
2801 }
2802 Err(e) => Err(e),
2803 }
2804 }
2805
2806 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2807 let mut texw = 0.0;
2808 let mut texh = 0.0;
2809
2810 if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2811 (texw, texh)
2812 } else {
2813 panic!("OpenGL texture binding not supported");
2814 }
2815 }
2816
2817 pub unsafe fn gl_unbind_texture(&mut self) {
2818 if sys::SDL_GL_UnbindTexture(self.raw) != 0 {
2819 panic!("OpenGL texture unbinding not supported");
2820 }
2821 }
2822
2823 #[doc(alias = "SDL_GL_BindTexture")]
2824 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2825 unsafe {
2826 let mut texw = 0.0;
2827 let mut texh = 0.0;
2828
2829 if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2830 let return_value = f(texw, texh);
2831
2832 if sys::SDL_GL_UnbindTexture(self.raw) == 0 {
2833 return_value
2834 } else {
2835 panic!();
2837 }
2838 } else {
2839 panic!("OpenGL texture binding not supported");
2840 }
2841 }
2842 }
2843}
2844
2845#[cfg(not(feature = "unsafe_textures"))]
2846impl<'r> Texture<'r> {
2847 #[inline]
2849 pub fn query(&self) -> TextureQuery {
2850 InternalTexture { raw: self.raw }.query()
2851 }
2852
2853 #[inline]
2855 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2856 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2857 }
2858
2859 #[inline]
2861 pub fn color_mod(&self) -> (u8, u8, u8) {
2862 InternalTexture { raw: self.raw }.color_mod()
2863 }
2864
2865 #[inline]
2867 pub fn set_scale_mode(&mut self, scale: ScaleMode) {
2868 InternalTexture { raw: self.raw }.set_scale_mode(scale)
2869 }
2870
2871 #[inline]
2873 pub fn scale_mode(&self) -> ScaleMode {
2874 InternalTexture { raw: self.raw }.scale_mode()
2875 }
2876
2877 #[inline]
2879 pub fn set_alpha_mod(&mut self, alpha: u8) {
2880 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2881 }
2882
2883 #[inline]
2885 pub fn alpha_mod(&self) -> u8 {
2886 InternalTexture { raw: self.raw }.alpha_mod()
2887 }
2888
2889 #[inline]
2891 pub fn set_blend_mode(&mut self, blend: BlendMode) {
2892 InternalTexture { raw: self.raw }.set_blend_mode(blend)
2893 }
2894
2895 #[inline]
2897 pub fn blend_mode(&self) -> BlendMode {
2898 InternalTexture { raw: self.raw }.blend_mode()
2899 }
2900
2901 #[inline]
2908 pub fn update<R>(
2909 &mut self,
2910 rect: R,
2911 pixel_data: &[u8],
2912 pitch: usize,
2913 ) -> Result<(), UpdateTextureError>
2914 where
2915 R: Into<Option<Rect>>,
2916 {
2917 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2918 }
2919
2920 #[inline]
2922 pub fn update_yuv<R>(
2923 &mut self,
2924 rect: R,
2925 y_plane: &[u8],
2926 y_pitch: usize,
2927 u_plane: &[u8],
2928 u_pitch: usize,
2929 v_plane: &[u8],
2930 v_pitch: usize,
2931 ) -> Result<(), UpdateTextureYUVError>
2932 where
2933 R: Into<Option<Rect>>,
2934 {
2935 InternalTexture { raw: self.raw }
2936 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2937 }
2938
2939 #[inline]
2950 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2951 where
2952 F: FnOnce(&mut [u8], usize) -> R,
2953 R2: Into<Option<Rect>>,
2954 {
2955 InternalTexture { raw: self.raw }.with_lock(rect, func)
2956 }
2957
2958 #[inline]
2961 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2962 InternalTexture { raw: self.raw }.gl_bind_texture()
2963 }
2964
2965 #[inline]
2967 pub unsafe fn gl_unbind_texture(&mut self) {
2968 InternalTexture { raw: self.raw }.gl_unbind_texture()
2969 }
2970
2971 #[inline]
2973 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2974 InternalTexture { raw: self.raw }.gl_with_bind(f)
2975 }
2976
2977 #[inline]
2978 #[allow(clippy::trivially_copy_pass_by_ref)]
2981 pub const fn raw(&self) -> *mut sys::SDL_Texture {
2982 self.raw
2983 }
2984
2985 #[cfg(not(feature = "unsafe_textures"))]
3012 pub fn from_surface<'a, T>(
3013 surface: &Surface,
3014 texture_creator: &'a TextureCreator<T>,
3015 ) -> Result<Texture<'a>, TextureValueError> {
3016 texture_creator.create_texture_from_surface(surface)
3017 }
3018
3019 #[cfg(feature = "unsafe_textures")]
3046 pub fn from_surface<T>(
3047 surface: &Surface,
3048 texture_creator: &TextureCreator<T>,
3049 ) -> Result<Texture, TextureValueError> {
3050 texture_creator.create_texture_from_surface(surface)
3051 }
3052}
3053
3054#[cfg(feature = "unsafe_textures")]
3055impl Texture {
3056 #[inline]
3058 pub fn query(&self) -> TextureQuery {
3059 InternalTexture { raw: self.raw }.query()
3060 }
3061
3062 #[inline]
3064 pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
3065 InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
3066 }
3067
3068 #[inline]
3070 pub fn color_mod(&self) -> (u8, u8, u8) {
3071 InternalTexture { raw: self.raw }.color_mod()
3072 }
3073
3074 #[inline]
3076 pub fn set_scale_mode(&mut self, scale: ScaleMode) {
3077 InternalTexture { raw: self.raw }.set_scale_mode(scale)
3078 }
3079
3080 #[inline]
3082 pub fn scale_mode(&self) -> ScaleMode {
3083 InternalTexture { raw: self.raw }.scale_mode()
3084 }
3085
3086 #[inline]
3088 pub fn set_alpha_mod(&mut self, alpha: u8) {
3089 InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
3090 }
3091
3092 #[inline]
3094 pub fn alpha_mod(&self) -> u8 {
3095 InternalTexture { raw: self.raw }.alpha_mod()
3096 }
3097
3098 #[inline]
3100 pub fn set_blend_mode(&mut self, blend: BlendMode) {
3101 InternalTexture { raw: self.raw }.set_blend_mode(blend)
3102 }
3103
3104 #[inline]
3106 pub fn blend_mode(&self) -> BlendMode {
3107 InternalTexture { raw: self.raw }.blend_mode()
3108 }
3109
3110 #[inline]
3117 pub fn update<R>(
3118 &mut self,
3119 rect: R,
3120 pixel_data: &[u8],
3121 pitch: usize,
3122 ) -> Result<(), UpdateTextureError>
3123 where
3124 R: Into<Option<Rect>>,
3125 {
3126 InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
3127 }
3128
3129 #[inline]
3131 pub fn update_yuv<R>(
3132 &mut self,
3133 rect: R,
3134 y_plane: &[u8],
3135 y_pitch: usize,
3136 u_plane: &[u8],
3137 u_pitch: usize,
3138 v_plane: &[u8],
3139 v_pitch: usize,
3140 ) -> Result<(), UpdateTextureYUVError>
3141 where
3142 R: Into<Option<Rect>>,
3143 {
3144 InternalTexture { raw: self.raw }
3145 .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
3146 }
3147
3148 #[inline]
3159 pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
3160 where
3161 F: FnOnce(&mut [u8], usize) -> R,
3162 R2: Into<Option<Rect>>,
3163 {
3164 InternalTexture { raw: self.raw }.with_lock(rect, func)
3165 }
3166
3167 #[inline]
3170 pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
3171 InternalTexture { raw: self.raw }.gl_bind_texture()
3172 }
3173
3174 #[inline]
3176 pub unsafe fn gl_unbind_texture(&mut self) {
3177 InternalTexture { raw: self.raw }.gl_unbind_texture()
3178 }
3179
3180 #[inline]
3182 pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
3183 InternalTexture { raw: self.raw }.gl_with_bind(f)
3184 }
3185
3186 #[inline]
3187 #[allow(clippy::trivially_copy_pass_by_ref)]
3190 pub const fn raw(&self) -> *mut sys::SDL_Texture {
3191 self.raw
3192 }
3193}
3194
3195#[derive(Copy, Clone)]
3196pub struct DriverIterator {
3197 length: i32,
3198 index: i32,
3199}
3200
3201fn get_render_driver_info(index: i32) -> RendererInfo {
3205 let mut out = mem::MaybeUninit::uninit();
3206 let result = unsafe { sys::SDL_GetRenderDriverInfo(index, out.as_mut_ptr()) };
3207 assert_eq!(result, 0);
3208
3209 unsafe { RendererInfo::from_ll(&out.assume_init()) }
3210}
3211
3212impl Iterator for DriverIterator {
3213 type Item = RendererInfo;
3214
3215 #[inline]
3216 #[doc(alias = "SDL_GetRenderDriverInfo")]
3217 fn next(&mut self) -> Option<RendererInfo> {
3218 if self.index >= self.length {
3219 None
3220 } else {
3221 let driver = get_render_driver_info(self.index);
3222 self.index += 1;
3223
3224 Some(driver)
3225 }
3226 }
3227
3228 #[inline]
3229 fn size_hint(&self) -> (usize, Option<usize>) {
3230 let remaining = (self.length - self.index) as usize;
3231 (remaining, Some(remaining))
3232 }
3233
3234 #[inline]
3235 fn nth(&mut self, n: usize) -> Option<RendererInfo> {
3236 use std::convert::TryInto;
3237
3238 self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
3239 Some(index) if index < self.length => index,
3240 _ => self.length,
3241 };
3242
3243 self.next()
3244 }
3245}
3246
3247impl DoubleEndedIterator for DriverIterator {
3248 #[inline]
3249 fn next_back(&mut self) -> Option<RendererInfo> {
3250 if self.index >= self.length {
3251 None
3252 } else {
3253 self.length -= 1;
3254
3255 Some(get_render_driver_info(self.length))
3256 }
3257 }
3258
3259 #[inline]
3260 fn nth_back(&mut self, n: usize) -> Option<RendererInfo> {
3261 use std::convert::TryInto;
3262
3263 self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
3264 Some(length) if length > self.index => length,
3265 _ => self.index,
3266 };
3267
3268 self.next_back()
3269 }
3270}
3271
3272impl ExactSizeIterator for DriverIterator {}
3273
3274impl std::iter::FusedIterator for DriverIterator {}
3275
3276#[inline]
3278#[doc(alias = "SDL_GetNumRenderDrivers")]
3279pub fn drivers() -> DriverIterator {
3280 DriverIterator {
3285 length: unsafe { sys::SDL_GetNumRenderDrivers() },
3286 index: 0,
3287 }
3288}