sdl2/
render.rs

1//! 2D accelerated rendering
2//!
3//! Official C documentation: https://wiki.libsdl.org/CategoryRender
4//! # Introduction
5//!
6//! This module contains functions for 2D accelerated rendering.
7//!
8//! This API supports the following features:
9//!
10//! * single pixel points
11//! * single pixel lines
12//! * filled rectangles
13//! * texture images
14//! * All of these may be drawn in opaque, blended, or additive modes.
15//!
16//! The texture images can have an additional color tint or alpha modulation
17//! applied to them, and may also be stretched with linear interpolation,
18//! rotated or flipped/mirrored.
19//!
20//! For advanced functionality like particle effects or actual 3D you should use
21//! SDL's OpenGL/Direct3D support or one of the many available 3D engines.
22//!
23//! This API is not designed to be used from multiple threads, see
24//! [this bug](http://bugzilla.libsdl.org/show_bug.cgi?id=1995) for details.
25//!
26//! ---
27//!
28//! None of the draw methods in `Canvas` are expected to fail.
29//! If they do, a panic is raised and the program is aborted.
30
31use 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/// Contains the description of an error returned by SDL
63#[derive(Debug, Clone)]
64pub struct SdlError(String);
65
66/// Possible errors returned by targeting a `Canvas` to render to a `Texture`
67#[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/// A structure that contains information on the capabilities of a render driver
125/// or the current render context.
126#[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/// Blend mode for `Canvas`, `Texture` or `Surface`.
136#[repr(i32)]
137#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
138pub enum BlendMode {
139    /// no blending (replace destination with source).
140    None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
141    /// Alpha blending
142    ///
143    /// dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
144    ///
145    /// dstA = srcA + (dstA * (1-srcA))
146    Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
147    /// Additive blending
148    ///
149    /// dstRGB = (srcRGB * srcA) + dstRGB
150    ///
151    /// dstA = dstA (keep original alpha)
152    Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
153    /// Color modulate
154    ///
155    /// dstRGB = srcRGB * dstRGB
156    Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
157    /// Color multiply
158    Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
159    /// Invalid blending mode (indicates error)
160    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 pixel sampling. default
185    Nearest = SDL_ScaleMode::SDL_ScaleModeNearest as isize,
186    /// linear filtering
187    Linear = SDL_ScaleMode::SDL_ScaleModeLinear as isize,
188    /// anisotropic filtering
189    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        // The driver name is always a static string, compiled into SDL2.
218        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
230/// Manages what keeps a `SDL_Renderer` alive
231///
232/// When the `RendererContext` is dropped, it destroys the `SDL_Renderer`
233pub 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    /// Gets information about the rendering context.
249    #[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            // Should only fail on an invalid renderer
257            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    /// Gets the raw pointer to the SDL_Renderer
267    // this can prevent introducing UB until
268    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
269    #[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
302/// Represents structs which can be the target of a `SDL_Renderer` (or Canvas).
303///
304/// This is intended for internal use only. It should not be used outside of this crate,
305/// but is still visible for documentation reasons.
306pub trait RenderTarget {
307    type Context;
308}
309
310impl<'s> RenderTarget for Surface<'s> {
311    type Context = SurfaceContext<'s>;
312}
313
314/// Manages and owns a target (`Surface` or `Window`) and allows drawing in it.
315///
316/// If the `Window` manipulates the shell of the Window, `Canvas<Window>` allows you to
317/// manipulate both the shell and the inside of the window;
318/// you can manipulate pixel by pixel (*not recommended*), lines, colored rectangles, or paste
319/// `Texture`s to this `Canvas`.
320///
321/// Drawing to the `Canvas` does not take effect immediately, it draws to a buffer until you
322/// call `present()`, where all the operations you did until the last `present()`
323/// are updated to your target
324///
325/// Its context may be shared with the `TextureCreator`.
326///
327/// The context will not be dropped until all references of it are out of scope.
328///
329/// # Examples
330///
331/// ```rust,no_run
332/// # use sdl2::render::Canvas;
333/// # use sdl2::video::Window;
334/// # use sdl2::pixels::Color;
335/// # use sdl2::rect::Rect;
336/// # let sdl_context = sdl2::init().unwrap();
337/// # let video_subsystem = sdl_context.video().unwrap();
338/// let window = video_subsystem.window("Example", 800, 600).build().unwrap();
339///
340/// // Let's create a Canvas which we will use to draw in our Window
341/// let mut canvas : Canvas<Window> = window.into_canvas()
342///     .present_vsync() //< this means the screen cannot
343///     // render faster than your display rate (usually 60Hz or 144Hz)
344///     .build().unwrap();
345///
346/// canvas.set_draw_color(Color::RGB(0, 0, 0));
347/// // fills the canvas with the color we set in `set_draw_color`.
348/// canvas.clear();
349///
350/// // change the color of our drawing with a gold-color ...
351/// canvas.set_draw_color(Color::RGB(255, 210, 0));
352/// // A draw a rectangle which almost fills our window with it !
353/// canvas.fill_rect(Rect::new(10, 10, 780, 580));
354///
355/// // However the canvas has not been updated to the window yet,
356/// // everything has been processed to an internal buffer,
357/// // but if we want our buffer to be displayed on the window,
358/// // we need to call `present`. We need to call this every time
359/// // we want to render a new frame on the window.
360/// canvas.present();
361/// // present does not "clear" the buffer, that means that
362/// // you have to clear it yourself before rendering again,
363/// // otherwise leftovers of what you've renderer before might
364/// // show up on the window !
365/// //
366/// // A good rule of thumb is to `clear()`, draw every texture
367/// // needed, and then `present()`; repeat this every new frame.
368///
369/// ```
370pub struct Canvas<T: RenderTarget> {
371    target: T,
372    context: Rc<RendererContext<T::Context>>,
373    default_pixel_format: PixelFormatEnum,
374}
375
376/// Alias for a `Canvas` that was created out of a `Surface`
377pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
378
379/// Methods for the `SurfaceCanvas`.
380impl<'s> Canvas<Surface<'s>> {
381    /// Creates a 2D software rendering context for a surface.
382    ///
383    /// This method should only fail if SDL2 is not built with rendering
384    /// support, or there's an out-of-memory error.
385    #[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    /// Gets a reference to the associated surface of the Canvas
403    #[inline]
404    pub fn surface(&self) -> &SurfaceRef {
405        &self.target
406    }
407
408    /// Gets a mutable reference to the associated surface of the Canvas
409    #[inline]
410    pub fn surface_mut(&mut self) -> &mut SurfaceRef {
411        &mut self.target
412    }
413
414    /// Gets the associated surface of the Canvas and destroys the Canvas
415    #[inline]
416    pub fn into_surface(self) -> Surface<'s> {
417        self.target
418    }
419
420    /// Returns a `TextureCreator` that can create Textures to be drawn on this `Canvas`
421    ///
422    /// This `TextureCreator` will share a reference to the renderer and target context.
423    ///
424    /// The target (i.e., `Window`) will not be destroyed and the SDL_Renderer will not be
425    /// destroyed if the `TextureCreator` is still in scope.
426    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    /// a non-zero area clipping rect
443    Some(Rect),
444    /// a clipping rect with zero area
445    Zero,
446    /// the absence of a clipping rect
447    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    /// shrink the clipping rect to the part which contains the position
482    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                        // clipping rect has infinite area, so it's just whatever position is
497                        ClippingRect::Some(position)
498                    }
499                }
500            }
501            None => {
502                // position is zero area so intersection result is zero
503                ClippingRect::Zero
504            }
505        }
506    }
507}
508
509/// Methods for the `WindowCanvas`.
510impl Canvas<Window> {
511    /// Gets a reference to the associated window of the Canvas
512    #[inline]
513    pub fn window(&self) -> &Window {
514        &self.target
515    }
516
517    /// Gets a mutable reference to the associated window of the Canvas
518    #[inline]
519    pub fn window_mut(&mut self) -> &mut Window {
520        &mut self.target
521    }
522
523    /// Gets the associated window of the Canvas and destroys the Canvas
524    #[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    /// Returns a `TextureCreator` that can create Textures to be drawn on this `Canvas`
535    ///
536    /// This `TextureCreator` will share a reference to the renderer and target context.
537    ///
538    /// The target (i.e., `Window`) will not be destroyed and the SDL_Renderer will not be
539    /// destroyed if the `TextureCreator` is still in scope.
540    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    /// Determine whether a window supports the use of render targets.
550    #[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    /// Temporarily sets the target of `Canvas` to a `Texture`. This effectively allows rendering
556    /// to a `Texture` in any way you want: you can make a `Texture` a combination of other
557    /// `Texture`s, be a complex geometry form with the `gfx` module, ... You can draw pixel by
558    /// pixel in it if you want, so you can do basically anything with that `Texture`.
559    ///
560    /// If you want to set the content of multiple `Texture` at once the most efficient way
561    /// possible, *don't* make a loop and call this function every time and use
562    /// `with_multiple_texture_canvas` instead. Using `with_texture_canvas` is actually
563    /// inefficient because the target is reset to the source (the `Window` or the `Surface`)
564    /// at the end of this function, but using it in a loop would make this reset useless.
565    /// Plus, the check that render_target is actually supported on that `Canvas` is also
566    /// done every time, leading to useless checks.
567    ///
568    /// # Notes
569    ///
570    /// Note that the `Canvas` in the closure is exactly the same as the one you call this
571    /// function with, meaning that you can call every function of your original `Canvas`.
572    ///
573    /// That means you can also call `with_texture_canvas` and `with_multiple_texture_canvas` from
574    /// the inside of the closure. Even though this is useless and inefficient, this is totally
575    /// safe to do and allowed.
576    ///
577    /// Since the render target is now a Texture, some calls of Canvas might return another result
578    /// than if the target was to be the original source. For instance `output_size` will return
579    /// this size of the current `Texture` in the closure, but the size of the `Window` or
580    /// `Surface` outside of the closure.
581    ///
582    /// You do not need to call `present` after drawing in the Canvas in the closure, the changes
583    /// are applied directly to the `Texture` instead of a hidden buffer.
584    ///
585    /// # Errors
586    ///
587    /// * returns `TargetRenderError::NotSupported`
588    /// if the renderer does not support the use of render targets
589    /// * returns `TargetRenderError::SdlError` if SDL2 returned with an error code.
590    ///
591    /// The texture *must* be created with the texture access:
592    /// `sdl2::render::TextureAccess::Target`.
593    /// Using a texture which was not created with the texture access `Target` is undefined
594    /// behavior.
595    ///
596    /// # Examples
597    ///
598    /// The example below changes a newly created `Texture` to be a 150-by-150 black texture with a
599    /// 50-by-50 red square in the middle.
600    ///
601    /// ```rust,no_run
602    /// # use sdl2::render::{Canvas, Texture};
603    /// # use sdl2::video::Window;
604    /// # use sdl2::pixels::Color;
605    /// # use sdl2::rect::Rect;
606    /// # let mut canvas : Canvas<Window> = unimplemented!();
607    /// let texture_creator = canvas.texture_creator();
608    /// let mut texture = texture_creator
609    ///     .create_texture_target(texture_creator.default_pixel_format(), 150, 150)
610    ///     .unwrap();
611    /// let result = canvas.with_texture_canvas(&mut texture, |texture_canvas| {
612    ///     texture_canvas.set_draw_color(Color::RGBA(0, 0, 0, 255));
613    ///     texture_canvas.clear();
614    ///     texture_canvas.set_draw_color(Color::RGBA(255, 0, 0, 255));
615    ///     texture_canvas.fill_rect(Rect::new(50, 50, 50, 50)).unwrap();
616    /// });
617    /// ```
618    ///
619
620    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    /// Same as `with_texture_canvas`, but allows to change multiple `Texture`s at once with the
640    /// least amount of overhead. It means that between every iteration the Target is not reset to
641    /// the source, and that the fact that the Canvas supports render target isn't checked every
642    /// iteration either; the check is actually only done once, at the beginning, avoiding useless
643    /// checks.
644    ///
645    /// The closure is run once for every `Texture` sent as parameter.
646    ///
647    /// The main changes from `with_texture_canvas` is that is takes an `Iterator` of `(&mut
648    /// Texture, U)`, where U is a type defined by the user. The closure takes a `&mut Canvas`, and
649    /// `&U` as arguments instead of a simple `&mut Canvas`. This user-defined type allows you to
650    /// keep track of what to do with the Canvas you have received in the closure.
651    ///
652    /// You will usually want to keep track of the number, a property, or anything that will allow
653    /// you to uniquely track this `Texture`, but it can also be an empty struct or `()` as well!
654    ///
655    /// # Examples
656    ///
657    /// Let's create two textures, one which will be yellow, and the other will be white
658    ///
659    /// ```rust,no_run
660    /// # use sdl2::pixels::Color;
661    /// # use sdl2::rect::Rect;
662    /// # use sdl2::video::Window;
663    /// # use sdl2::render::{Canvas, Texture};
664    /// # let mut canvas : Canvas<Window> = unimplemented!();
665    /// let texture_creator = canvas.texture_creator();
666    /// enum TextureColor {
667    ///     Yellow,
668    ///     White,
669    /// };
670    ///
671    /// let mut square_texture1 : Texture =
672    ///     texture_creator.create_texture_target(None, 100, 100).unwrap();
673    /// let mut square_texture2 : Texture =
674    ///     texture_creator.create_texture_target(None, 100, 100).unwrap();
675    /// let textures : Vec<(&mut Texture, TextureColor)> = vec![
676    ///     (&mut square_texture1, TextureColor::Yellow),
677    ///     (&mut square_texture2, TextureColor::White)
678    /// ];
679    /// let result : Result<(), _> =
680    ///     canvas.with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| {
681    ///     match *user_context {
682    ///         TextureColor::White => {
683    ///             texture_canvas.set_draw_color(Color::RGB(255, 255, 255));
684    ///         },
685    ///         TextureColor::Yellow => {
686    ///             texture_canvas.set_draw_color(Color::RGB(255, 255, 0));
687    ///         }
688    ///     };
689    ///     texture_canvas.clear();
690    /// });
691    /// // square_texture1 is now Yellow and square_texture2 is now White!
692    /// ```
693    ///
694    ///
695    #[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            // reset the target to its source
712            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            // reset the target to its source
736            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
745/// Creates Textures that cannot outlive the creator
746///
747/// The `TextureCreator` does not hold a lifetime to its Canvas by design choice.
748///
749/// If a `Canvas` is dropped before its `TextureCreator`, it is still safe to use.
750///
751/// It is, however, useless.
752///
753/// Any `Texture` created here can only be drawn onto the original `Canvas`. A `Texture` used in a
754/// `Canvas` must come from a `TextureCreator` coming from that same `Canvas`. Using a `Texture` to
755/// render to a `Canvas` not being the parent of the `Texture`'s `TextureCreator` is undefined
756/// behavior.
757pub struct TextureCreator<T> {
758    context: Rc<RendererContext<T>>,
759    default_pixel_format: PixelFormatEnum,
760}
761
762/// The type that allows you to build Window-based renderers.
763///
764/// By default, the renderer builder will prioritize for a hardware-accelerated
765/// renderer, which is probably what you want.
766pub struct CanvasBuilder {
767    window: Window,
768    index: Option<u32>,
769    renderer_flags: u32,
770}
771
772impl CanvasBuilder {
773    /// Initializes a new `CanvasBuilder`.
774    pub fn new(window: Window) -> CanvasBuilder {
775        CanvasBuilder {
776            window,
777            // -1 means to initialize the first rendering driver supporting the
778            // renderer flags
779            index: None,
780            // no flags gives priority to available SDL_RENDERER_ACCELERATED
781            // renderers
782            renderer_flags: 0,
783        }
784    }
785
786    /// Builds the renderer.
787    #[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    /// Sets the index of the rendering driver to initialize.
810    /// If you desire the first rendering driver to support the flags provided,
811    /// or if you're translating code from C which passes -1 for the index,
812    /// **do not** invoke the `index` method.
813    pub fn index(mut self, index: u32) -> CanvasBuilder {
814        self.index = Some(index);
815        self
816    }
817
818    /// Set the renderer to a software fallback.
819    /// This flag is accumulative, and may be specified with other flags.
820    pub fn software(mut self) -> CanvasBuilder {
821        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_SOFTWARE as u32;
822        self
823    }
824
825    /// Set the renderer to use hardware acceleration.
826    /// This flag is accumulative, and may be specified with other flags.
827    pub fn accelerated(mut self) -> CanvasBuilder {
828        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_ACCELERATED as u32;
829        self
830    }
831
832    /// Synchronize renderer `present` method calls with the refresh rate.
833    /// This flag is accumulative, and may be specified with other flags.
834    pub fn present_vsync(mut self) -> CanvasBuilder {
835        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_PRESENTVSYNC as u32;
836        self
837    }
838
839    /// Set the renderer to support rendering to a texture.
840    /// This flag is accumulative, and may be specified with other flags.
841    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    // If the pixel format is YUV 4:2:0 and planar, the width and height must
895    // be multiples-of-two. See issue #334 for details.
896    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
911/// Texture-creating methods for the renderer
912impl<T> TextureCreator<T> {
913    // this can prevent introducing UB until
914    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
915    #[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    /// Creates a texture for a rendering context.
925    ///
926    /// If format is `None`, the format will be the one the parent Window or Surface uses.
927    ///
928    /// If format is `Some(pixel_format)`, the default will be overridden, and the texture will be
929    /// created with the specified format if possible. If the PixelFormat is not supported, this
930    /// will return an error.
931    ///
932    /// You should prefer the default format if possible to have performance gains and to avoid
933    /// unsupported Pixel Formats that can cause errors. However, be careful with the default
934    /// `PixelFormat` if you want to create transparent textures.
935    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    /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)`
957    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    /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)`
971    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    /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)`
985    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    /// Creates a texture from an existing surface.
998    ///
999    /// # Remarks
1000    ///
1001    /// The access hint for the created texture is [`TextureAccess::Static`].
1002    ///
1003    /// ```no_run
1004    /// use sdl2::pixels::PixelFormatEnum;
1005    /// use sdl2::surface::Surface;
1006    /// use sdl2::render::{Canvas, Texture};
1007    /// use sdl2::video::Window;
1008    ///
1009    /// // We init systems.
1010    /// let sdl_context = sdl2::init().expect("failed to init SDL");
1011    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
1012    ///
1013    /// // We create a window.
1014    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
1015    ///     .build()
1016    ///     .expect("failed to build window");
1017    ///
1018    /// // We get the canvas from which we can get the `TextureCreator`.
1019    /// let mut canvas: Canvas<Window> = window.into_canvas()
1020    ///     .build()
1021    ///     .expect("failed to build window's canvas");
1022    /// let texture_creator = canvas.texture_creator();
1023    ///
1024    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
1025    /// let texture = texture_creator.create_texture_from_surface(surface).unwrap();
1026    /// ```
1027    #[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    /// Create a texture from its raw `SDL_Texture`.
1043    #[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    /// Create a texture from its raw `SDL_Texture`. Should be used with care.
1053    #[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
1059/// Drawing methods
1060impl<T: RenderTarget> Canvas<T> {
1061    // this can prevent introducing UB until
1062    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
1063    #[allow(clippy::trivially_copy_pass_by_ref)]
1064    pub fn raw(&self) -> *mut sys::SDL_Renderer {
1065        self.context.raw()
1066    }
1067
1068    /// Sets the color used for drawing operations (Rect, Line and Clear).
1069    #[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        // Should only fail on an invalid renderer
1074        if ret != 0 {
1075            panic!("{}", get_error())
1076        }
1077    }
1078
1079    /// Gets the color used for drawing operations (Rect, Line and Clear).
1080    #[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        // Should only fail on an invalid renderer
1087        if ret != 0 {
1088            panic!("{}", get_error())
1089        } else {
1090            pixels::Color::RGBA(r, g, b, a)
1091        }
1092    }
1093
1094    /// Sets the blend mode used for drawing operations (Fill and Line).
1095    #[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        // Should only fail on an invalid renderer
1100        if ret != 0 {
1101            panic!("{}", get_error())
1102        }
1103    }
1104
1105    /// Gets the blend mode used for drawing operations.
1106    #[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        // Should only fail on an invalid renderer
1111        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    /// Clears the current rendering target with the drawing color.
1120    #[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    /// Updates the screen with any rendering performed since the previous call.
1129    ///
1130    /// SDL's rendering functions operate on a backbuffer; that is, calling a
1131    /// rendering function such as `draw_line()` does not directly put a line on
1132    /// the screen, but rather updates the backbuffer.
1133    /// As such, you compose your entire scene and present the composed
1134    /// backbuffer to the screen as a complete picture.
1135    #[doc(alias = "SDL_RenderPresent")]
1136    pub fn present(&mut self) {
1137        unsafe { sys::SDL_RenderPresent(self.context.raw) }
1138    }
1139
1140    /// Gets the output size of a rendering context.
1141    #[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    /// Sets a device independent resolution for rendering.
1157    #[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    /// Gets device independent resolution for rendering.
1170    #[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    /// Sets the drawing area for rendering on the current target.
1181    #[doc(alias = "SDL_RenderSetViewport")]
1182    pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
1183        let rect = rect.into();
1184        // as_ref is important because we need rect to live until the end of the FFI call, but map_or consumes an Option<T>
1185        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    /// Gets the drawing area for the current target.
1193    #[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    /// Sets the clip rectangle for rendering on the specified target.
1202    #[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    /// Gets the clip rectangle for the current target.
1232    #[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    /// Sets whether to force integer scales for resolution-independent rendering.
1251    #[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    /// Gets whether integer scales are forced for resolution-independent rendering.
1271    #[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    /// Sets the drawing scale for rendering on the current target.
1277    #[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        // Should only fail on an invalid renderer
1281        if ret != 0 {
1282            Err(get_error())
1283        } else {
1284            Ok(())
1285        }
1286    }
1287
1288    /// Gets the drawing scale for the current target.
1289    #[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    /// Draws a point on the current rendering target.
1298    /// Errors if drawing fails for any reason (e.g. driver failure)
1299    #[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    /// Draws multiple points on the current rendering target.
1311    /// Errors if drawing fails for any reason (e.g. driver failure)
1312    #[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    /// Draws a line on the current rendering target.
1330    /// Errors if drawing fails for any reason (e.g. driver failure)
1331    #[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    /// Draws a series of connected lines on the current rendering target.
1350    /// Errors if drawing fails for any reason (e.g. driver failure)
1351    #[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    /// Draws a rectangle on the current rendering target.
1369    /// Errors if drawing fails for any reason (e.g. driver failure)
1370    #[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    /// Draws some number of rectangles on the current rendering target.
1381    /// Errors if drawing fails for any reason (e.g. driver failure)
1382    #[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    /// Fills a rectangle on the current rendering target with the drawing
1399    /// color.
1400    /// Passing None will fill the entire rendering target.
1401    /// Errors if drawing fails for any reason (e.g. driver failure)
1402    #[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    /// Fills some number of rectangles on the current rendering target with
1418    /// the drawing color.
1419    /// Errors if drawing fails for any reason (e.g. driver failure)
1420    #[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    /// Draws a point on the current rendering target.
1437    /// Errors if drawing fails for any reason (e.g. driver failure)
1438    #[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    /// Draws multiple points on the current rendering target.
1450    /// Errors if drawing fails for any reason (e.g. driver failure)
1451    #[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    /// Draws a line on the current rendering target.
1469    /// Errors if drawing fails for any reason (e.g. driver failure)
1470    #[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    /// Draws a series of connected lines on the current rendering target.
1489    /// Errors if drawing fails for any reason (e.g. driver failure)
1490    #[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    /// Draws a rectangle on the current rendering target.
1508    /// Errors if drawing fails for any reason (e.g. driver failure)
1509    #[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    /// Draws some number of rectangles on the current rendering target.
1520    /// Errors if drawing fails for any reason (e.g. driver failure)
1521    #[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    /// Fills a rectangle on the current rendering target with the drawing
1538    /// color.
1539    /// Passing None will fill the entire rendering target.
1540    /// Errors if drawing fails for any reason (e.g. driver failure)
1541    #[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    /// Fills some number of rectangles on the current rendering target with
1557    /// the drawing color.
1558    /// Errors if drawing fails for any reason (e.g. driver failure)
1559    #[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    /// Copies a portion of the texture to the current rendering target.
1576    ///
1577    /// * If `src` is `None`, the entire texture is copied.
1578    /// * If `dst` is `None`, the texture will be stretched to fill the given
1579    ///   rectangle.
1580    ///
1581    /// Errors if drawing fails for any reason (e.g. driver failure),
1582    /// or if the provided texture does not belong to the renderer.
1583    #[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    /// Copies a portion of the texture to the current rendering target,
1612    /// optionally rotating it by angle around the given center and also
1613    /// flipping it top-bottom and/or left-right.
1614    ///
1615    /// * If `src` is `None`, the entire texture is copied.
1616    /// * If `dst` is `None`, the texture will be stretched to fill the given
1617    ///   rectangle.
1618    /// * If `center` is `None`, rotation will be done around the center point
1619    ///   of `dst`, or `src` if `dst` is None.
1620    ///
1621    /// Errors if drawing fails for any reason (e.g. driver failure),
1622    /// if the provided texture does not belong to the renderer,
1623    /// or if the driver does not support RenderCopyEx.
1624    #[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    /// Copies a portion of the texture to the current rendering target.
1682    ///
1683    /// * If `src` is `None`, the entire texture is copied.
1684    /// * If `dst` is `None`, the texture will be stretched to fill the given
1685    ///   rectangle.
1686    ///
1687    /// Errors if drawing fails for any reason (e.g. driver failure),
1688    /// or if the provided texture does not belong to the renderer.
1689    #[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    /// Copies a portion of the texture to the current rendering target,
1718    /// optionally rotating it by angle around the given center and also
1719    /// flipping it top-bottom and/or left-right.
1720    ///
1721    /// * If `src` is `None`, the entire texture is copied.
1722    /// * If `dst` is `None`, the texture will be stretched to fill the given
1723    ///   rectangle.
1724    /// * If `center` is `None`, rotation will be done around the center point
1725    ///   of `dst`, or `src` if `dst` is None.
1726    ///
1727    /// Errors if drawing fails for any reason (e.g. driver failure),
1728    /// if the provided texture does not belong to the renderer,
1729    /// or if the driver does not support RenderCopyEx.
1730    #[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    /// Reads pixels from the current rendering target.
1788    /// # Remarks
1789    /// WARNING: This is a very slow operation, and should not be used frequently.
1790    #[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(); // calculated pitch
1806        let size = format.byte_size_of_pixels(w * h);
1807        let mut pixels = Vec::with_capacity(size);
1808
1809        // Pass the interior of `pixels: Vec<u8>` to SDL
1810        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    /// Creates a texture for a rendering context.
1829    ///
1830    /// If format is `None`, the format will be the one the parent Window or Surface uses.
1831    ///
1832    /// If format is `Some(pixel_format)`
1833    /// created with the specified format if possible. If the PixelFormat is not supported, this
1834    /// will return an error.
1835    ///
1836    /// You should prefer the default format if possible to have performance gains and to avoid
1837    /// unsupported Pixel Formats that can cause errors. However, be careful with the default
1838    /// `PixelFormat` if you want to create transparent textures.
1839    ///
1840    /// # Notes
1841    ///
1842    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature,
1843    /// because lifetimes otherwise prevent `Canvas` from creating and accessing `Texture`s at the
1844    /// same time.
1845    #[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    /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)`
1867    ///
1868    /// # Notes
1869    ///
1870    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1871    #[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    /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)`
1886    ///
1887    /// # Notes
1888    ///
1889    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1890    #[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    /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)`
1905    ///
1906    /// # Notes
1907    ///
1908    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1909    #[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    /// Creates a texture from an existing surface.
1924    ///
1925    /// # Remarks
1926    ///
1927    /// The access hint for the created texture is `TextureAccess::Static`.
1928    ///
1929    /// # Notes
1930    ///
1931    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1932    #[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    /// Create a texture from its raw `SDL_Texture`. Should be used with care.
1950    ///
1951    /// # Notes
1952    ///
1953    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1954    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)` is not needed for soundness in this crate, but users may expect it to be
1969// layout-compatible with `sys::SDL_Vertex`.
1970#[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    /// Vertices are rendered in sequential order.
1981    Sequential,
1982    /// [`u8`] vertex indices.
1983    U8(&'a [u8]),
1984    /// [`u16`] vertex indices.
1985    U16(&'a [u16]),
1986    /// [`u32`] vertex indices. If any index is larger than [`i32::MAX`], SDL will return an error.
1987    U32(&'a [u32]),
1988}
1989
1990impl VertexIndices<'_> {
1991    /// Returns (indices, num_indices, size_indices)
1992    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    /// Render triangles, optionally using a texture.
2082    ///
2083    /// If you have vertices in a different format, [`Canvas::render_geometry_raw`] (the advanced
2084    /// version of this function) might allow you to do the same as this function without having to
2085    /// convert the parameters to use [`Vertex`].
2086    ///
2087    /// `indices` can be of any of the following:
2088    /// - [`VertexIndices::Sequential`]: Vertices are rendered in sequential order. The number of
2089    ///   *vertices* must be divisible by 3, when using a list of indices, the number of *indices*
2090    ///   must be divisible by 3. SDL will check this and return an error if this is not the case.
2091    /// - `&[u8]`: Indices of the type [`u8`], note that this only works when using [`u8::MAX`]
2092    ///   (255) or less vertices.
2093    /// - `&[u16]`: Indices of the type [`u16`], note that this only works when using [`u16::MAX`]
2094    ///   (65535) or less vertices.
2095    /// - `&[u32]` or `&[i32]`: Indices of the type [`i32`], possibly represented using [`u32`].
2096    ///   Note that regardless of the type, indices must be positive and fit in [`i32`].
2097    /// - `&[[u8; 3]]`, `&[[u16; 3]]`, `&[[u32; 3]]` or `&[[i32; 3]]`, which work like `&[u8]`,
2098    ///   `&[u16]`, `&[u32]` or `&[i32]` but ensure at compile time that the number of indices is
2099    ///   divisible by 3.
2100    /// - Any other (possibly user defined) type that implements
2101    ///   [`Into<VertexIndices<'_>>`][VertexIndices#trait-implementations].
2102    #[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    /// Render triangles, optionally using a texture.
2126    ///
2127    /// In the documentation of this function field names of [`RenderGeometryTextureParams`] are
2128    /// used as if they are parameters. When they are used it only applies when a texture is used
2129    /// (`texture_params` is [`Some(_)`][Some]).
2130    ///
2131    /// Vertices may be passed as up to 3 separate lists. Elements of the lists may contain
2132    /// anything, but must contain the valid values at the given offset (in bytes).
2133    /// Using [`offset_of`][core::mem::offset_of] is advised to get the right offset of a field,
2134    /// especially when the element type does not have a stable layout.
2135    ///
2136    /// See the documentation of [`Canvas::render_geometry`] for usage of the `indices` parameter.
2137    ///
2138    /// When a texture is not used, the vertex type must still be specified (because of a Rust
2139    /// limitation, more info [here](https://github.com/rust-lang/rust/issues/36887)). This can be
2140    /// done with turbofish syntax after `None` like so: `None::<RenderGeometryTextureParams<()>>`.
2141    ///
2142    /// # Safety
2143    ///
2144    /// It must be sound to [create references to](core::ptr#pointer-to-reference-conversion):
2145    /// - `positions` offset by `position_offset` bytes, of type [`FPoint`] (or `[f32; 2]`),
2146    /// - `colors` offset by `color_offset` bytes, of type [`Color`][pixels::Color] (or `[u8; 4]`)
2147    /// - `tex_coords` offset by `tex_coord_offset` bytes, of type [`FPoint`] (or `[f32; 2]`).
2148    ///
2149    /// For the above to hold, make sure that the hypothetical references are properly aligned and
2150    /// point to valid values ([`f32`] and [`u8`] allow any bit pattern, but not
2151    /// uninitialized/padding bytes).
2152    ///
2153    /// # Panics
2154    ///
2155    /// The following conditions are checked. All must hold or the function panics.
2156    ///
2157    /// Vertices are passed as separate lists, all lists must have the same length.
2158    /// - `positions.len() == colors.len()`
2159    /// - `positions.len() == tex_coords.len()`
2160    ///
2161    /// Offsets must be correct.
2162    /// - `position_offset + size_of::<FPoint>() <= size_of::<PosVertex>()`: an [`FPoint`] must fit
2163    ///   in `PosVertex` at `position_offset` bytes from the start.
2164    /// - `color_offset + size_of::<Color>() <= size_of::<ColorVertex>()`: a
2165    ///   [`Color`][pixels::Color] must fit in `ColorVertex` at `color_offset` bytes from the
2166    ///   start.
2167    /// - `tex_coord_offset + size_of::<FPoint>() <= size_of::<TexCoordVertex>()`: an [`FPoint`]
2168    ///   must fit in `TexCoordVertex` at `tex_coord_offset` bytes from the start.
2169    ///
2170    /// Various sizes must fit in a [C `int`][c_int].
2171    /// - `positions.len() <= c_int::MAX`
2172    /// - `size_of::<PosVertex>() <= c_int::MAX`
2173    /// - `size_of::<ColorVertex>() <= c_int::MAX`
2174    /// - `size_of::<TexCoordVertex>() <= c_int::MAX`
2175    #[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/// A texture for a rendering context.
2259///
2260/// Every Texture is owned by a `TextureCreator` or `Canvas` (the latter is only possible with the
2261/// `unsafe_textures` feature).
2262///
2263/// # Differences between with and without `unsafe_textures` feature
2264///
2265/// Without the `unsafe_textures`, a texture is owned by a `TextureCreator` and a `Texture` cannot
2266/// outlive its parent `TextureCreator` thanks to lifetimes. A texture is destroyed via its `Drop`
2267/// implementation. While this is the most "Rust"-y way of doing things currently, it is pretty
2268/// cumbersome to use in some cases.
2269///
2270/// That is why the feature `unsafe_textures` was brought to life: the lifetimes are gone, meaning
2271/// that `Texture`s *can* outlive their parents. That means that the `Texture`s are not destroyed
2272/// on `Drop`, but destroyed when their parents are. That means if you create 10 000 textures with
2273/// this feature, they will only be destroyed after you drop the `Canvas` and every
2274/// `TextureCreator` linked to it. While this feature is enabled, this is the safest way to free
2275/// the memory taken by the `Texture`s, but there is still another, unsafe way to destroy the
2276/// `Texture` before its `Canvas`: the method `destroy`. This method is unsafe because *you* have
2277/// to make sure the parent `Canvas` or `TextureCreator` is still alive while calling this method.
2278///
2279/// **Calling the `destroy` method while no parent is alive is undefined behavior**
2280///
2281/// With the `unsafe_textures` feature, a `Texture` can be safely accessed (but not destroyed) after
2282/// the `Canvas` is dropped, but since any access (except `destroy`) requires the original `Canvas`,
2283/// it is not possible to access a `Texture` while the `Canvas` is dropped.
2284#[cfg(feature = "unsafe_textures")]
2285pub struct Texture {
2286    raw: *mut sys::SDL_Texture,
2287}
2288
2289/// A texture for a rendering context.
2290///
2291/// Every Texture is owned by a `TextureCreator`. Internally, a texture is destroyed via its `Drop`
2292/// implementation. A texture can only be used by the `Canvas` it was originally created from, it
2293/// is undefined behavior otherwise.
2294#[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    /// Destroy the Texture and its representation
2313    /// in the Renderer. This will most likely
2314    /// mean that the renderer engine will free video
2315    /// memory that was allocated for this texture.
2316    ///
2317    /// This method is unsafe because since Texture does not have
2318    /// a lifetime, it is legal in Rust to make this texture live
2319    /// longer than the Renderer. It is however illegal to destroy a SDL_Texture
2320    /// after its SDL_Renderer, therefore this function is unsafe because
2321    /// of this.
2322    ///
2323    /// Note however that you don't *have* to destroy a Texture before its Canvas,
2324    /// since whenever Canvas is destroyed, the SDL implementation will automatically
2325    /// destroy all the children Textures of that Canvas.
2326    ///
2327    /// **Calling this method while no parent is alive is undefined behavior**
2328    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        // Should only fail on an invalid texture
2468        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        // Should only fail on an invalid texture
2495        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        // Should only fail on an invalid texture
2537        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        // Should only fail on an invalid texture
2559        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        // Check if the rectangle's position or size is odd, and if the pitch is odd.
2585        // This needs to be done in case the texture's pixel format is planar YUV.
2586        // See issue #334 for details.
2587        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        // If the destination rectangle lies outside the texture boundaries,
2668        // SDL_UpdateYUVTexture will write outside allocated texture memory.
2669        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            // The destination rectangle cannot lie outside the texture boundaries
2677            if !inside {
2678                return Err(RectNotInsideTexture(*r));
2679            }
2680        }
2681
2682        // We need the height in order to check the array slice lengths.
2683        // Checking the lengths can prevent buffer overruns in SDL_UpdateYUVTexture.
2684        let height = match rect {
2685            Some(ref r) => r.height(),
2686            None => tex_info.height,
2687        } as usize;
2688
2689        //let wrong_length =
2690        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        // Call to SDL to populate pixel data
2769        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                    // This should never happen...
2836                    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    /// Queries the attributes of the texture.
2848    #[inline]
2849    pub fn query(&self) -> TextureQuery {
2850        InternalTexture { raw: self.raw }.query()
2851    }
2852
2853    /// Sets an additional color value multiplied into render copy operations.
2854    #[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    /// Gets the additional color value multiplied into render copy operations.
2860    #[inline]
2861    pub fn color_mod(&self) -> (u8, u8, u8) {
2862        InternalTexture { raw: self.raw }.color_mod()
2863    }
2864
2865    /// Sets the scale mode for use when rendered.
2866    #[inline]
2867    pub fn set_scale_mode(&mut self, scale: ScaleMode) {
2868        InternalTexture { raw: self.raw }.set_scale_mode(scale)
2869    }
2870
2871    /// Gets the scale mode for use when rendered.
2872    #[inline]
2873    pub fn scale_mode(&self) -> ScaleMode {
2874        InternalTexture { raw: self.raw }.scale_mode()
2875    }
2876
2877    /// Sets an additional alpha value multiplied into render copy operations.
2878    #[inline]
2879    pub fn set_alpha_mod(&mut self, alpha: u8) {
2880        InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2881    }
2882
2883    /// Gets the additional alpha value multiplied into render copy operations.
2884    #[inline]
2885    pub fn alpha_mod(&self) -> u8 {
2886        InternalTexture { raw: self.raw }.alpha_mod()
2887    }
2888
2889    /// Sets the blend mode used for drawing operations (Fill and Line).
2890    #[inline]
2891    pub fn set_blend_mode(&mut self, blend: BlendMode) {
2892        InternalTexture { raw: self.raw }.set_blend_mode(blend)
2893    }
2894
2895    /// Gets the blend mode used for texture copy operations.
2896    #[inline]
2897    pub fn blend_mode(&self) -> BlendMode {
2898        InternalTexture { raw: self.raw }.blend_mode()
2899    }
2900
2901    /// Updates the given texture rectangle with new pixel data.
2902    ///
2903    /// `pitch` is the number of bytes in a row of pixel data, including padding
2904    /// between lines
2905    ///
2906    /// * If `rect` is `None`, the entire texture is updated.
2907    #[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    /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data.
2921    #[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    /// Locks the texture for **write-only** pixel access.
2940    /// The texture must have been created with streaming access.
2941    ///
2942    /// `F` is a function that is passed the write-only texture buffer,
2943    /// and the pitch of the texture (size of a row in bytes).
2944    /// # Remarks
2945    /// As an optimization, the pixels made available for editing don't
2946    /// necessarily contain the old texture data.
2947    /// This is a write-only operation, and if you need to keep a copy of the
2948    /// texture data you should do that at the application level.
2949    #[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    /// Binds an OpenGL/ES/ES2 texture to the current
2959    /// context for use with when rendering OpenGL primitives directly.
2960    #[inline]
2961    pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2962        InternalTexture { raw: self.raw }.gl_bind_texture()
2963    }
2964
2965    /// Unbinds an OpenGL/ES/ES2 texture from the current context.
2966    #[inline]
2967    pub unsafe fn gl_unbind_texture(&mut self) {
2968        InternalTexture { raw: self.raw }.gl_unbind_texture()
2969    }
2970
2971    /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context.
2972    #[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    // this can prevent introducing UB until
2979    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
2980    #[allow(clippy::trivially_copy_pass_by_ref)]
2981    pub const fn raw(&self) -> *mut sys::SDL_Texture {
2982        self.raw
2983    }
2984
2985    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
2986    ///
2987    /// ```no_run
2988    /// use sdl2::pixels::PixelFormatEnum;
2989    /// use sdl2::surface::Surface;
2990    /// use sdl2::render::{Canvas, Texture};
2991    /// use sdl2::video::Window;
2992    ///
2993    /// // We init systems.
2994    /// let sdl_context = sdl2::init().expect("failed to init SDL");
2995    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
2996    ///
2997    /// // We create a window.
2998    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
2999    ///     .build()
3000    ///     .expect("failed to build window");
3001    ///
3002    /// // We get the canvas from which we can get the `TextureCreator`.
3003    /// let mut canvas: Canvas<Window> = window.into_canvas()
3004    ///     .build()
3005    ///     .expect("failed to build window's canvas");
3006    /// let texture_creator = canvas.texture_creator();
3007    ///
3008    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
3009    /// let texture = Texture::from_surface(&surface, &texture_creator).unwrap();
3010    /// ```
3011    #[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    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
3020    ///
3021    /// ```no_run
3022    /// use sdl2::pixels::PixelFormatEnum;
3023    /// use sdl2::surface::Surface;
3024    /// use sdl2::render::{Canvas, Texture};
3025    /// use sdl2::video::Window;
3026    ///
3027    /// // We init systems.
3028    /// let sdl_context = sdl2::init().expect("failed to init SDL");
3029    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
3030    ///
3031    /// // We create a window.
3032    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
3033    ///     .build()
3034    ///     .expect("failed to build window");
3035    ///
3036    /// // We get the canvas from which we can get the `TextureCreator`.
3037    /// let mut canvas: Canvas<Window> = window.into_canvas()
3038    ///     .build()
3039    ///     .expect("failed to build window's canvas");
3040    /// let texture_creator = canvas.texture_creator();
3041    ///
3042    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
3043    /// let texture = Texture::from_surface(&surface, &texture_creator).unwrap();
3044    /// ```
3045    #[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    /// Queries the attributes of the texture.
3057    #[inline]
3058    pub fn query(&self) -> TextureQuery {
3059        InternalTexture { raw: self.raw }.query()
3060    }
3061
3062    /// Sets an additional color value multiplied into render copy operations.
3063    #[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    /// Gets the additional color value multiplied into render copy operations.
3069    #[inline]
3070    pub fn color_mod(&self) -> (u8, u8, u8) {
3071        InternalTexture { raw: self.raw }.color_mod()
3072    }
3073
3074    /// Sets the scale mode for use when rendered.
3075    #[inline]
3076    pub fn set_scale_mode(&mut self, scale: ScaleMode) {
3077        InternalTexture { raw: self.raw }.set_scale_mode(scale)
3078    }
3079
3080    /// Gets the scale mode for use when rendered.
3081    #[inline]
3082    pub fn scale_mode(&self) -> ScaleMode {
3083        InternalTexture { raw: self.raw }.scale_mode()
3084    }
3085
3086    /// Sets an additional alpha value multiplied into render copy operations.
3087    #[inline]
3088    pub fn set_alpha_mod(&mut self, alpha: u8) {
3089        InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
3090    }
3091
3092    /// Gets the additional alpha value multiplied into render copy operations.
3093    #[inline]
3094    pub fn alpha_mod(&self) -> u8 {
3095        InternalTexture { raw: self.raw }.alpha_mod()
3096    }
3097
3098    /// Sets the blend mode used for drawing operations (Fill and Line).
3099    #[inline]
3100    pub fn set_blend_mode(&mut self, blend: BlendMode) {
3101        InternalTexture { raw: self.raw }.set_blend_mode(blend)
3102    }
3103
3104    /// Gets the blend mode used for texture copy operations.
3105    #[inline]
3106    pub fn blend_mode(&self) -> BlendMode {
3107        InternalTexture { raw: self.raw }.blend_mode()
3108    }
3109
3110    /// Updates the given texture rectangle with new pixel data.
3111    ///
3112    /// `pitch` is the number of bytes in a row of pixel data, including padding
3113    /// between lines
3114    ///
3115    /// * If `rect` is `None`, the entire texture is updated.
3116    #[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    /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data.
3130    #[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    /// Locks the texture for **write-only** pixel access.
3149    /// The texture must have been created with streaming access.
3150    ///
3151    /// `F` is a function that is passed the write-only texture buffer,
3152    /// and the pitch of the texture (size of a row in bytes).
3153    /// # Remarks
3154    /// As an optimization, the pixels made available for editing don't
3155    /// necessarily contain the old texture data.
3156    /// This is a write-only operation, and if you need to keep a copy of the
3157    /// texture data you should do that at the application level.
3158    #[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    /// Binds an OpenGL/ES/ES2 texture to the current
3168    /// context for use with when rendering OpenGL primitives directly.
3169    #[inline]
3170    pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
3171        InternalTexture { raw: self.raw }.gl_bind_texture()
3172    }
3173
3174    /// Unbinds an OpenGL/ES/ES2 texture from the current context.
3175    #[inline]
3176    pub unsafe fn gl_unbind_texture(&mut self) {
3177        InternalTexture { raw: self.raw }.gl_unbind_texture()
3178    }
3179
3180    /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context.
3181    #[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    // this can prevent introducing UB until
3188    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
3189    #[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
3201// panics if SDL_GetRenderDriverInfo returns a nonzero value,
3202// which should only happen if index is outside the range
3203// 0..SDL_GetNumRenderDrivers()
3204fn 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/// Gets an iterator of all render drivers compiled into the SDL2 library.
3277#[inline]
3278#[doc(alias = "SDL_GetNumRenderDrivers")]
3279pub fn drivers() -> DriverIterator {
3280    // This function is thread-safe and doesn't require the video subsystem to be initialized.
3281    // The list of drivers are read-only and statically compiled into SDL2, varying by platform.
3282
3283    // SDL_GetNumRenderDrivers can never return a negative value.
3284    DriverIterator {
3285        length: unsafe { sys::SDL_GetNumRenderDrivers() },
3286        index: 0,
3287    }
3288}