[go: up one dir, main page]

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;
45use std::error::Error;
46use std::ffi::CStr;
47use std::fmt;
48#[cfg(not(feature = "unsafe_textures"))]
49use std::marker::PhantomData;
50use std::mem;
51use std::mem::{transmute, MaybeUninit};
52use std::ops::Deref;
53use std::ptr;
54use std::rc::Rc;
55
56use crate::sys;
57use crate::sys::SDL_BlendMode;
58use crate::sys::SDL_TextureAccess;
59
60/// Contains the description of an error returned by SDL
61#[derive(Debug, Clone)]
62pub struct SdlError(String);
63
64/// Possible errors returned by targeting a `Canvas` to render to a `Texture`
65#[derive(Debug, Clone)]
66pub enum TargetRenderError {
67    SdlError(SdlError),
68    NotSupported,
69}
70
71impl fmt::Display for SdlError {
72    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
73        write!(f, "SDL error: {}", self.0)
74    }
75}
76
77impl Error for SdlError {}
78
79impl fmt::Display for TargetRenderError {
80    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
81        use self::TargetRenderError::*;
82        match *self {
83            SdlError(ref e) => e.fmt(f),
84            NotSupported => write!(f, "The renderer does not support the use of render targets"),
85        }
86    }
87}
88
89impl Error for TargetRenderError {
90    fn source(&self) -> Option<&(dyn Error + 'static)> {
91        match self {
92            Self::SdlError(err) => Some(err),
93            Self::NotSupported => None,
94        }
95    }
96}
97
98#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
99#[repr(i32)]
100pub enum TextureAccess {
101    Static = SDL_TextureAccess::SDL_TEXTUREACCESS_STATIC as i32,
102    Streaming = SDL_TextureAccess::SDL_TEXTUREACCESS_STREAMING as i32,
103    Target = SDL_TextureAccess::SDL_TEXTUREACCESS_TARGET as i32,
104}
105
106impl TryFrom<u32> for TextureAccess {
107    type Error = ();
108
109    fn try_from(n: u32) -> Result<Self, Self::Error> {
110        use self::TextureAccess::*;
111        use crate::sys::SDL_TextureAccess::*;
112
113        Ok(match unsafe { transmute(n) } {
114            SDL_TEXTUREACCESS_STATIC => Static,
115            SDL_TEXTUREACCESS_STREAMING => Streaming,
116            SDL_TEXTUREACCESS_TARGET => Target,
117        })
118    }
119}
120
121/// A structure that contains information on the capabilities of a render driver
122/// or the current render context.
123#[derive(Clone, Eq, PartialEq, Hash, Debug)]
124pub struct RendererInfo {
125    pub name: &'static str,
126    pub flags: u32,
127    pub texture_formats: Vec<PixelFormatEnum>,
128    pub max_texture_width: u32,
129    pub max_texture_height: u32,
130}
131
132/// Blend mode for `Canvas`, `Texture` or `Surface`.
133#[repr(i32)]
134#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
135pub enum BlendMode {
136    /// no blending (replace destination with source).
137    None = SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
138    /// Alpha blending
139    ///
140    /// dstRGB = (srcRGB * srcA) + (dstRGB * (1-srcA))
141    ///
142    /// dstA = srcA + (dstA * (1-srcA))
143    Blend = SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
144    /// Additive blending
145    ///
146    /// dstRGB = (srcRGB * srcA) + dstRGB
147    ///
148    /// dstA = dstA (keep original alpha)
149    Add = SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
150    /// Color modulate
151    ///
152    /// dstRGB = srcRGB * dstRGB
153    Mod = SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
154    /// Color multiply
155    Mul = SDL_BlendMode::SDL_BLENDMODE_MUL as i32,
156    /// Invalid blending mode (indicates error)
157    Invalid = SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
158}
159
160impl TryFrom<u32> for BlendMode {
161    type Error = ();
162
163    fn try_from(n: u32) -> Result<Self, Self::Error> {
164        use self::BlendMode::*;
165        use crate::sys::SDL_BlendMode::*;
166
167        Ok(match unsafe { transmute(n) } {
168            SDL_BLENDMODE_NONE => None,
169            SDL_BLENDMODE_BLEND => Blend,
170            SDL_BLENDMODE_ADD => Add,
171            SDL_BLENDMODE_MOD => Mod,
172            SDL_BLENDMODE_MUL => Mul,
173            SDL_BLENDMODE_INVALID => Invalid,
174        })
175    }
176}
177
178impl RendererInfo {
179    pub unsafe fn from_ll(info: &sys::SDL_RendererInfo) -> RendererInfo {
180        let texture_formats: Vec<PixelFormatEnum> = info.texture_formats
181            [0..(info.num_texture_formats as usize)]
182            .iter()
183            .map(|&format| PixelFormatEnum::try_from(format).unwrap_or(PixelFormatEnum::Unknown))
184            .collect();
185
186        // The driver name is always a static string, compiled into SDL2.
187        let name = CStr::from_ptr(info.name as *const _).to_str().unwrap();
188
189        RendererInfo {
190            name,
191            flags: info.flags,
192            texture_formats,
193            max_texture_width: info.max_texture_width as u32,
194            max_texture_height: info.max_texture_height as u32,
195        }
196    }
197}
198
199/// Manages what keeps a `SDL_Renderer` alive
200///
201/// When the `RendererContext` is dropped, it destroys the `SDL_Renderer`
202pub struct RendererContext<T> {
203    raw: *mut sys::SDL_Renderer,
204    _target: Rc<T>,
205}
206
207impl<T> Drop for RendererContext<T> {
208    #[doc(alias = "SDL_DestroyRenderer")]
209    fn drop(&mut self) {
210        unsafe {
211            sys::SDL_DestroyRenderer(self.raw);
212        };
213    }
214}
215
216impl<T> RendererContext<T> {
217    /// Gets information about the rendering context.
218    #[doc(alias = "SDL_GetRendererInfo")]
219    pub fn info(&self) -> RendererInfo {
220        let mut renderer_info_raw = mem::MaybeUninit::uninit();
221        let result =
222            unsafe { sys::SDL_GetRendererInfo(self.raw, renderer_info_raw.as_mut_ptr()) != 0 };
223
224        if result {
225            // Should only fail on an invalid renderer
226            panic!();
227        } else {
228            unsafe {
229                let renderer_info_raw = renderer_info_raw.assume_init();
230                RendererInfo::from_ll(&renderer_info_raw)
231            }
232        }
233    }
234
235    /// Gets the raw pointer to the SDL_Renderer
236    // this can prevent introducing UB until
237    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
238    #[allow(clippy::trivially_copy_pass_by_ref)]
239    pub fn raw(&self) -> *mut sys::SDL_Renderer {
240        self.raw
241    }
242
243    pub unsafe fn from_ll(raw: *mut sys::SDL_Renderer, target: Rc<T>) -> Self {
244        RendererContext {
245            raw,
246            _target: target,
247        }
248    }
249
250    unsafe fn set_raw_target(&self, raw_texture: *mut sys::SDL_Texture) -> Result<(), SdlError> {
251        if sys::SDL_SetRenderTarget(self.raw, raw_texture) == 0 {
252            Ok(())
253        } else {
254            Err(SdlError(get_error()))
255        }
256    }
257
258    unsafe fn get_raw_target(&self) -> *mut sys::SDL_Texture {
259        sys::SDL_GetRenderTarget(self.raw)
260    }
261}
262
263impl<T: RenderTarget> Deref for Canvas<T> {
264    type Target = RendererContext<T::Context>;
265
266    fn deref(&self) -> &RendererContext<T::Context> {
267        self.context.as_ref()
268    }
269}
270
271/// Represents structs which can be the target of a `SDL_Renderer` (or Canvas).
272///
273/// This is intended for internal use only. It should not be used outside of this crate,
274/// but is still visible for documentation reasons.
275pub trait RenderTarget {
276    type Context;
277}
278
279impl<'s> RenderTarget for Surface<'s> {
280    type Context = SurfaceContext<'s>;
281}
282
283/// Manages and owns a target (`Surface` or `Window`) and allows drawing in it.
284///
285/// If the `Window` manipulates the shell of the Window, `Canvas<Window>` allows you to
286/// manipulate both the shell and the inside of the window;
287/// you can manipulate pixel by pixel (*not recommended*), lines, colored rectangles, or paste
288/// `Texture`s to this `Canvas`.
289///
290/// Drawing to the `Canvas` does not take effect immediately, it draws to a buffer until you
291/// call `present()`, where all the operations you did until the last `present()`
292/// are updated to your target
293///
294/// Its context may be shared with the `TextureCreator`.
295///
296/// The context will not be dropped until all references of it are out of scope.
297///
298/// # Examples
299///
300/// ```rust,no_run
301/// # use sdl2::render::Canvas;
302/// # use sdl2::video::Window;
303/// # use sdl2::pixels::Color;
304/// # use sdl2::rect::Rect;
305/// # let sdl_context = sdl2::init().unwrap();
306/// # let video_subsystem = sdl_context.video().unwrap();
307/// let window = video_subsystem.window("Example", 800, 600).build().unwrap();
308///
309/// // Let's create a Canvas which we will use to draw in our Window
310/// let mut canvas : Canvas<Window> = window.into_canvas()
311///     .present_vsync() //< this means the screen cannot
312///     // render faster than your display rate (usually 60Hz or 144Hz)
313///     .build().unwrap();
314///
315/// canvas.set_draw_color(Color::RGB(0, 0, 0));
316/// // fills the canvas with the color we set in `set_draw_color`.
317/// canvas.clear();
318///
319/// // change the color of our drawing with a gold-color ...
320/// canvas.set_draw_color(Color::RGB(255, 210, 0));
321/// // A draw a rectangle which almost fills our window with it !
322/// canvas.fill_rect(Rect::new(10, 10, 780, 580));
323///
324/// // However the canvas has not been updated to the window yet,
325/// // everything has been processed to an internal buffer,
326/// // but if we want our buffer to be displayed on the window,
327/// // we need to call `present`. We need to call this every time
328/// // we want to render a new frame on the window.
329/// canvas.present();
330/// // present does not "clear" the buffer, that means that
331/// // you have to clear it yourself before rendering again,
332/// // otherwise leftovers of what you've renderer before might
333/// // show up on the window !
334/// //
335/// // A good rule of thumb is to `clear()`, draw every texture
336/// // needed, and then `present()`; repeat this every new frame.
337///
338/// ```
339pub struct Canvas<T: RenderTarget> {
340    target: T,
341    context: Rc<RendererContext<T::Context>>,
342    default_pixel_format: PixelFormatEnum,
343}
344
345/// Alias for a `Canvas` that was created out of a `Surface`
346pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
347
348/// Methods for the `SurfaceCanvas`.
349impl<'s> Canvas<Surface<'s>> {
350    /// Creates a 2D software rendering context for a surface.
351    ///
352    /// This method should only fail if SDL2 is not built with rendering
353    /// support, or there's an out-of-memory error.
354    #[doc(alias = "SDL_CreateSoftwareRenderer")]
355    pub fn from_surface(surface: surface::Surface<'s>) -> Result<Self, String> {
356        let raw_renderer = unsafe { sys::SDL_CreateSoftwareRenderer(surface.raw()) };
357        if !raw_renderer.is_null() {
358            let context =
359                Rc::new(unsafe { RendererContext::from_ll(raw_renderer, surface.context()) });
360            let default_pixel_format = surface.pixel_format_enum();
361            Ok(Canvas {
362                target: surface,
363                context,
364                default_pixel_format,
365            })
366        } else {
367            Err(get_error())
368        }
369    }
370
371    /// Gets a reference to the associated surface of the Canvas
372    #[inline]
373    pub fn surface(&self) -> &SurfaceRef {
374        &self.target
375    }
376
377    /// Gets a mutable reference to the associated surface of the Canvas
378    #[inline]
379    pub fn surface_mut(&mut self) -> &mut SurfaceRef {
380        &mut self.target
381    }
382
383    /// Gets the associated surface of the Canvas and destroys the Canvas
384    #[inline]
385    pub fn into_surface(self) -> Surface<'s> {
386        self.target
387    }
388
389    /// Returns a `TextureCreator` that can create Textures to be drawn on this `Canvas`
390    ///
391    /// This `TextureCreator` will share a reference to the renderer and target context.
392    ///
393    /// The target (i.e., `Window`) will not be destroyed and the SDL_Renderer will not be
394    /// destroyed if the `TextureCreator` is still in scope.
395    pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>> {
396        TextureCreator {
397            context: self.context.clone(),
398            default_pixel_format: self.default_pixel_format,
399        }
400    }
401}
402
403pub type WindowCanvas = Canvas<Window>;
404
405impl RenderTarget for Window {
406    type Context = WindowContext;
407}
408
409/// Methods for the `WindowCanvas`.
410impl Canvas<Window> {
411    /// Gets a reference to the associated window of the Canvas
412    #[inline]
413    pub fn window(&self) -> &Window {
414        &self.target
415    }
416
417    /// Gets a mutable reference to the associated window of the Canvas
418    #[inline]
419    pub fn window_mut(&mut self) -> &mut Window {
420        &mut self.target
421    }
422
423    /// Gets the associated window of the Canvas and destroys the Canvas
424    #[inline]
425    pub fn into_window(self) -> Window {
426        self.target
427    }
428
429    #[inline]
430    pub fn default_pixel_format(&self) -> PixelFormatEnum {
431        self.window().window_pixel_format()
432    }
433
434    /// Returns a `TextureCreator` that can create Textures to be drawn on this `Canvas`
435    ///
436    /// This `TextureCreator` will share a reference to the renderer and target context.
437    ///
438    /// The target (i.e., `Window`) will not be destroyed and the SDL_Renderer will not be
439    /// destroyed if the `TextureCreator` is still in scope.
440    pub fn texture_creator(&self) -> TextureCreator<WindowContext> {
441        TextureCreator {
442            context: self.context.clone(),
443            default_pixel_format: self.default_pixel_format(),
444        }
445    }
446}
447
448impl<T: RenderTarget> Canvas<T> {
449    /// Determine whether a window supports the use of render targets.
450    #[doc(alias = "SDL_RenderTargetSupported")]
451    pub fn render_target_supported(&self) -> bool {
452        unsafe { sys::SDL_RenderTargetSupported(self.context.raw) == sys::SDL_bool::SDL_TRUE }
453    }
454
455    /// Temporarily sets the target of `Canvas` to a `Texture`. This effectively allows rendering
456    /// to a `Texture` in any way you want: you can make a `Texture` a combination of other
457    /// `Texture`s, be a complex geometry form with the `gfx` module, ... You can draw pixel by
458    /// pixel in it if you want, so you can do basically anything with that `Texture`.
459    ///
460    /// If you want to set the content of multiple `Texture` at once the most efficient way
461    /// possible, *don't* make a loop and call this function every time and use
462    /// `with_multiple_texture_canvas` instead. Using `with_texture_canvas` is actually
463    /// inefficient because the target is reset to the source (the `Window` or the `Surface`)
464    /// at the end of this function, but using it in a loop would make this reset useless.
465    /// Plus, the check that render_target is actually supported on that `Canvas` is also
466    /// done every time, leading to useless checks.
467    ///
468    /// # Notes
469    ///
470    /// Note that the `Canvas` in the closure is exactly the same as the one you call this
471    /// function with, meaning that you can call every function of your original `Canvas`.
472    ///
473    /// That means you can also call `with_texture_canvas` and `with_multiple_texture_canvas` from
474    /// the inside of the closure. Even though this is useless and inefficient, this is totally
475    /// safe to do and allowed.
476    ///
477    /// Since the render target is now a Texture, some calls of Canvas might return another result
478    /// than if the target was to be the original source. For instance `output_size` will return
479    /// this size of the current `Texture` in the closure, but the size of the `Window` or
480    /// `Surface` outside of the closure.
481    ///
482    /// You do not need to call `present` after drawing in the Canvas in the closure, the changes
483    /// are applied directly to the `Texture` instead of a hidden buffer.
484    ///
485    /// # Errors
486    ///
487    /// * returns `TargetRenderError::NotSupported`
488    /// if the renderer does not support the use of render targets
489    /// * returns `TargetRenderError::SdlError` if SDL2 returned with an error code.
490    ///
491    /// The texture *must* be created with the texture access:
492    /// `sdl2::render::TextureAccess::Target`.
493    /// Using a texture which was not created with the texture access `Target` is undefined
494    /// behavior.
495    ///
496    /// # Examples
497    ///
498    /// The example below changes a newly created `Texture` to be a 150-by-150 black texture with a
499    /// 50-by-50 red square in the middle.
500    ///
501    /// ```rust,no_run
502    /// # use sdl2::render::{Canvas, Texture};
503    /// # use sdl2::video::Window;
504    /// # use sdl2::pixels::Color;
505    /// # use sdl2::rect::Rect;
506    /// # let mut canvas : Canvas<Window> = unimplemented!();
507    /// let texture_creator = canvas.texture_creator();
508    /// let mut texture = texture_creator
509    ///     .create_texture_target(texture_creator.default_pixel_format(), 150, 150)
510    ///     .unwrap();
511    /// let result = canvas.with_texture_canvas(&mut texture, |texture_canvas| {
512    ///     texture_canvas.set_draw_color(Color::RGBA(0, 0, 0, 255));
513    ///     texture_canvas.clear();
514    ///     texture_canvas.set_draw_color(Color::RGBA(255, 0, 0, 255));
515    ///     texture_canvas.fill_rect(Rect::new(50, 50, 50, 50)).unwrap();
516    /// });
517    /// ```
518    ///
519
520    pub fn with_texture_canvas<F>(
521        &mut self,
522        texture: &mut Texture,
523        f: F,
524    ) -> Result<(), TargetRenderError>
525    where
526        for<'r> F: FnOnce(&'r mut Canvas<T>),
527    {
528        if self.render_target_supported() {
529            let target = unsafe { self.get_raw_target() };
530            unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
531            f(self);
532            unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
533            Ok(())
534        } else {
535            Err(TargetRenderError::NotSupported)
536        }
537    }
538
539    /// Same as `with_texture_canvas`, but allows to change multiple `Texture`s at once with the
540    /// least amount of overhead. It means that between every iteration the Target is not reset to
541    /// the source, and that the fact that the Canvas supports render target isn't checked every
542    /// iteration either; the check is actually only done once, at the beginning, avoiding useless
543    /// checks.
544    ///
545    /// The closure is run once for every `Texture` sent as parameter.
546    ///
547    /// The main changes from `with_texture_canvas` is that is takes an `Iterator` of `(&mut
548    /// Texture, U)`, where U is a type defined by the user. The closure takes a `&mut Canvas`, and
549    /// `&U` as arguments instead of a simple `&mut Canvas`. This user-defined type allows you to
550    /// keep track of what to do with the Canvas you have received in the closure.
551    ///
552    /// You will usually want to keep track of the number, a property, or anything that will allow
553    /// you to uniquely track this `Texture`, but it can also be an empty struct or `()` as well!
554    ///
555    /// # Examples
556    ///
557    /// Let's create two textures, one which will be yellow, and the other will be white
558    ///
559    /// ```rust,no_run
560    /// # use sdl2::pixels::Color;
561    /// # use sdl2::rect::Rect;
562    /// # use sdl2::video::Window;
563    /// # use sdl2::render::{Canvas, Texture};
564    /// # let mut canvas : Canvas<Window> = unimplemented!();
565    /// let texture_creator = canvas.texture_creator();
566    /// enum TextureColor {
567    ///     Yellow,
568    ///     White,
569    /// };
570    ///
571    /// let mut square_texture1 : Texture =
572    ///     texture_creator.create_texture_target(None, 100, 100).unwrap();
573    /// let mut square_texture2 : Texture =
574    ///     texture_creator.create_texture_target(None, 100, 100).unwrap();
575    /// let textures : Vec<(&mut Texture, TextureColor)> = vec![
576    ///     (&mut square_texture1, TextureColor::Yellow),
577    ///     (&mut square_texture2, TextureColor::White)
578    /// ];
579    /// let result : Result<(), _> =
580    ///     canvas.with_multiple_texture_canvas(textures.iter(), |texture_canvas, user_context| {
581    ///     match *user_context {
582    ///         TextureColor::White => {
583    ///             texture_canvas.set_draw_color(Color::RGB(255, 255, 255));
584    ///         },
585    ///         TextureColor::Yellow => {
586    ///             texture_canvas.set_draw_color(Color::RGB(255, 255, 0));
587    ///         }
588    ///     };
589    ///     texture_canvas.clear();
590    /// });
591    /// // square_texture1 is now Yellow and square_texture2 is now White!
592    /// ```
593    ///
594    ///
595    #[cfg(not(feature = "unsafe_textures"))]
596    pub fn with_multiple_texture_canvas<'t: 'a, 'a: 's, 's, I, F, U: 's>(
597        &mut self,
598        textures: I,
599        mut f: F,
600    ) -> Result<(), TargetRenderError>
601    where
602        for<'r> F: FnMut(&'r mut Canvas<T>, &U),
603        I: Iterator<Item = &'s (&'a mut Texture<'t>, U)>,
604    {
605        if self.render_target_supported() {
606            let target = unsafe { self.get_raw_target() };
607            for (texture, user_context) in textures {
608                unsafe { self.set_raw_target(texture.raw) }.map_err(TargetRenderError::SdlError)?;
609                f(self, user_context);
610            }
611            // reset the target to its source
612            unsafe { self.set_raw_target(target) }.map_err(TargetRenderError::SdlError)?;
613            Ok(())
614        } else {
615            Err(TargetRenderError::NotSupported)
616        }
617    }
618
619    #[cfg(feature = "unsafe_textures")]
620    pub fn with_multiple_texture_canvas<'a: 's, 's, I, F, U: 's>(
621        &mut self,
622        textures: I,
623        mut f: F,
624    ) -> Result<(), TargetRenderError>
625    where
626        for<'r> F: FnMut(&'r mut Canvas<T>, &U),
627        I: Iterator<Item = &'s (&'a mut Texture, U)>,
628    {
629        if self.render_target_supported() {
630            for &(ref texture, ref user_context) in textures {
631                unsafe { self.set_raw_target(texture.raw) }
632                    .map_err(|e| TargetRenderError::SdlError(e))?;
633                f(self, &user_context);
634            }
635            // reset the target to its source
636            unsafe { self.set_raw_target(ptr::null_mut()) }
637                .map_err(|e| TargetRenderError::SdlError(e))?;
638            Ok(())
639        } else {
640            Err(TargetRenderError::NotSupported)
641        }
642    }
643}
644
645/// Creates Textures that cannot outlive the creator
646///
647/// The `TextureCreator` does not hold a lifetime to its Canvas by design choice.
648///
649/// If a `Canvas` is dropped before its `TextureCreator`, it is still safe to use.
650///
651/// It is, however, useless.
652///
653/// Any `Texture` created here can only be drawn onto the original `Canvas`. A `Texture` used in a
654/// `Canvas` must come from a `TextureCreator` coming from that same `Canvas`. Using a `Texture` to
655/// render to a `Canvas` not being the parent of the `Texture`'s `TextureCreator` is undefined
656/// behavior.
657pub struct TextureCreator<T> {
658    context: Rc<RendererContext<T>>,
659    default_pixel_format: PixelFormatEnum,
660}
661
662/// The type that allows you to build Window-based renderers.
663///
664/// By default, the renderer builder will prioritize for a hardware-accelerated
665/// renderer, which is probably what you want.
666pub struct CanvasBuilder {
667    window: Window,
668    index: Option<u32>,
669    renderer_flags: u32,
670}
671
672impl CanvasBuilder {
673    /// Initializes a new `CanvasBuilder`.
674    pub fn new(window: Window) -> CanvasBuilder {
675        CanvasBuilder {
676            window,
677            // -1 means to initialize the first rendering driver supporting the
678            // renderer flags
679            index: None,
680            // no flags gives priority to available SDL_RENDERER_ACCELERATED
681            // renderers
682            renderer_flags: 0,
683        }
684    }
685
686    /// Builds the renderer.
687    #[doc(alias = "SDL_CreateRenderer")]
688    pub fn build(self) -> Result<WindowCanvas, IntegerOrSdlError> {
689        use crate::common::IntegerOrSdlError::*;
690        let index = match self.index {
691            None => -1,
692            Some(index) => validate_int(index, "index")?,
693        };
694        let raw = unsafe { sys::SDL_CreateRenderer(self.window.raw(), index, self.renderer_flags) };
695
696        if raw.is_null() {
697            Err(SdlError(get_error()))
698        } else {
699            let context = Rc::new(unsafe { RendererContext::from_ll(raw, self.window.context()) });
700            let default_pixel_format = self.window.window_pixel_format();
701            Ok(Canvas {
702                context,
703                target: self.window,
704                default_pixel_format,
705            })
706        }
707    }
708
709    /// Sets the index of the rendering driver to initialize.
710    /// If you desire the first rendering driver to support the flags provided,
711    /// or if you're translating code from C which passes -1 for the index,
712    /// **do not** invoke the `index` method.
713    pub fn index(mut self, index: u32) -> CanvasBuilder {
714        self.index = Some(index);
715        self
716    }
717
718    /// Set the renderer to a software fallback.
719    /// This flag is accumulative, and may be specified with other flags.
720    pub fn software(mut self) -> CanvasBuilder {
721        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_SOFTWARE as u32;
722        self
723    }
724
725    /// Set the renderer to use hardware acceleration.
726    /// This flag is accumulative, and may be specified with other flags.
727    pub fn accelerated(mut self) -> CanvasBuilder {
728        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_ACCELERATED as u32;
729        self
730    }
731
732    /// Synchronize renderer `present` method calls with the refresh rate.
733    /// This flag is accumulative, and may be specified with other flags.
734    pub fn present_vsync(mut self) -> CanvasBuilder {
735        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_PRESENTVSYNC as u32;
736        self
737    }
738
739    /// Set the renderer to support rendering to a texture.
740    /// This flag is accumulative, and may be specified with other flags.
741    pub fn target_texture(mut self) -> CanvasBuilder {
742        self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_TARGETTEXTURE as u32;
743        self
744    }
745}
746
747#[derive(Debug, Clone)]
748pub enum TextureValueError {
749    WidthOverflows(u32),
750    HeightOverflows(u32),
751    WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
752    SdlError(String),
753}
754
755impl fmt::Display for TextureValueError {
756    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
757        use self::TextureValueError::*;
758
759        match *self {
760            WidthOverflows(value) => write!(f, "Integer width overflows ({})", value),
761            HeightOverflows(value) => write!(f, "Integer height overflows ({})", value),
762            WidthMustBeMultipleOfTwoForFormat(value, format) => {
763                write!(
764                    f,
765                    "Texture width must be multiple of two for pixel format '{:?}' ({})",
766                    format, value
767                )
768            }
769            SdlError(ref e) => write!(f, "SDL error: {}", e),
770        }
771    }
772}
773
774impl Error for TextureValueError {}
775
776#[doc(alias = "SDL_CreateTexture")]
777fn ll_create_texture(
778    context: *mut sys::SDL_Renderer,
779    pixel_format: PixelFormatEnum,
780    access: TextureAccess,
781    width: u32,
782    height: u32,
783) -> Result<*mut sys::SDL_Texture, TextureValueError> {
784    use self::TextureValueError::*;
785    let w = match validate_int(width, "width") {
786        Ok(w) => w,
787        Err(_) => return Err(WidthOverflows(width)),
788    };
789    let h = match validate_int(height, "height") {
790        Ok(h) => h,
791        Err(_) => return Err(HeightOverflows(height)),
792    };
793
794    // If the pixel format is YUV 4:2:0 and planar, the width and height must
795    // be multiples-of-two. See issue #334 for details.
796    match pixel_format {
797        PixelFormatEnum::YV12
798        | PixelFormatEnum::IYUV
799        | PixelFormatEnum::NV12
800        | PixelFormatEnum::NV21 => {
801            if w % 2 != 0 || h % 2 != 0 {
802                return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format));
803            }
804        }
805        _ => (),
806    };
807
808    Ok(unsafe { sys::SDL_CreateTexture(context, pixel_format as u32, access as c_int, w, h) })
809}
810
811/// Texture-creating methods for the renderer
812impl<T> TextureCreator<T> {
813    // this can prevent introducing UB until
814    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
815    #[allow(clippy::trivially_copy_pass_by_ref)]
816    pub fn raw(&self) -> *mut sys::SDL_Renderer {
817        self.context.raw()
818    }
819
820    pub fn default_pixel_format(&self) -> PixelFormatEnum {
821        self.default_pixel_format
822    }
823
824    /// Creates a texture for a rendering context.
825    ///
826    /// If format is `None`, the format will be the one the parent Window or Surface uses.
827    ///
828    /// If format is `Some(pixel_format)`, the default will be overridden, and the texture will be
829    /// created with the specified format if possible. If the PixelFormat is not supported, this
830    /// will return an error.
831    ///
832    /// You should prefer the default format if possible to have performance gains and to avoid
833    /// unsupported Pixel Formats that can cause errors. However, be careful with the default
834    /// `PixelFormat` if you want to create transparent textures.
835    pub fn create_texture<F>(
836        &self,
837        format: F,
838        access: TextureAccess,
839        width: u32,
840        height: u32,
841    ) -> Result<Texture, TextureValueError>
842    where
843        F: Into<Option<PixelFormatEnum>>,
844    {
845        use self::TextureValueError::*;
846        let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
847        let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
848        if result.is_null() {
849            Err(SdlError(get_error()))
850        } else {
851            unsafe { Ok(self.raw_create_texture(result)) }
852        }
853    }
854
855    #[inline]
856    /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)`
857    pub fn create_texture_static<F>(
858        &self,
859        format: F,
860        width: u32,
861        height: u32,
862    ) -> Result<Texture, TextureValueError>
863    where
864        F: Into<Option<PixelFormatEnum>>,
865    {
866        self.create_texture(format, TextureAccess::Static, width, height)
867    }
868
869    #[inline]
870    /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)`
871    pub fn create_texture_streaming<F>(
872        &self,
873        format: F,
874        width: u32,
875        height: u32,
876    ) -> Result<Texture, TextureValueError>
877    where
878        F: Into<Option<PixelFormatEnum>>,
879    {
880        self.create_texture(format, TextureAccess::Streaming, width, height)
881    }
882
883    #[inline]
884    /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)`
885    pub fn create_texture_target<F>(
886        &self,
887        format: F,
888        width: u32,
889        height: u32,
890    ) -> Result<Texture, TextureValueError>
891    where
892        F: Into<Option<PixelFormatEnum>>,
893    {
894        self.create_texture(format, TextureAccess::Target, width, height)
895    }
896
897    /// Creates a texture from an existing surface.
898    ///
899    /// # Remarks
900    ///
901    /// The access hint for the created texture is [`TextureAccess::Static`].
902    ///
903    /// ```no_run
904    /// use sdl2::pixels::PixelFormatEnum;
905    /// use sdl2::surface::Surface;
906    /// use sdl2::render::{Canvas, Texture};
907    /// use sdl2::video::Window;
908    ///
909    /// // We init systems.
910    /// let sdl_context = sdl2::init().expect("failed to init SDL");
911    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
912    ///
913    /// // We create a window.
914    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
915    ///     .build()
916    ///     .expect("failed to build window");
917    ///
918    /// // We get the canvas from which we can get the `TextureCreator`.
919    /// let mut canvas: Canvas<Window> = window.into_canvas()
920    ///     .build()
921    ///     .expect("failed to build window's canvas");
922    /// let texture_creator = canvas.texture_creator();
923    ///
924    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
925    /// let texture = texture_creator.create_texture_from_surface(surface).unwrap();
926    /// ```
927    #[doc(alias = "SDL_CreateTextureFromSurface")]
928    pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
929        &self,
930        surface: S,
931    ) -> Result<Texture, TextureValueError> {
932        use self::TextureValueError::*;
933        let result =
934            unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
935        if result.is_null() {
936            Err(SdlError(get_error()))
937        } else {
938            unsafe { Ok(self.raw_create_texture(result)) }
939        }
940    }
941
942    /// Create a texture from its raw `SDL_Texture`.
943    #[cfg(not(feature = "unsafe_textures"))]
944    #[inline]
945    pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
946        Texture {
947            raw,
948            _marker: PhantomData,
949        }
950    }
951
952    /// Create a texture from its raw `SDL_Texture`. Should be used with care.
953    #[cfg(feature = "unsafe_textures")]
954    pub const unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
955        Texture { raw }
956    }
957}
958
959/// Drawing methods
960impl<T: RenderTarget> Canvas<T> {
961    // this can prevent introducing UB until
962    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
963    #[allow(clippy::trivially_copy_pass_by_ref)]
964    pub fn raw(&self) -> *mut sys::SDL_Renderer {
965        self.context.raw()
966    }
967
968    /// Sets the color used for drawing operations (Rect, Line and Clear).
969    #[doc(alias = "SDL_SetRenderDrawColor")]
970    pub fn set_draw_color<C: Into<pixels::Color>>(&mut self, color: C) {
971        let (r, g, b, a) = color.into().rgba();
972        let ret = unsafe { sys::SDL_SetRenderDrawColor(self.raw, r, g, b, a) };
973        // Should only fail on an invalid renderer
974        if ret != 0 {
975            panic!("{}", get_error())
976        }
977    }
978
979    /// Gets the color used for drawing operations (Rect, Line and Clear).
980    #[doc(alias = "SDL_GetRenderDrawColor")]
981    pub fn draw_color(&self) -> pixels::Color {
982        let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
983        let ret = unsafe {
984            sys::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a)
985        };
986        // Should only fail on an invalid renderer
987        if ret != 0 {
988            panic!("{}", get_error())
989        } else {
990            pixels::Color::RGBA(r, g, b, a)
991        }
992    }
993
994    /// Sets the blend mode used for drawing operations (Fill and Line).
995    #[doc(alias = "SDL_SetRenderDrawBlendMode")]
996    pub fn set_blend_mode(&mut self, blend: BlendMode) {
997        let ret =
998            unsafe { sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32)) };
999        // Should only fail on an invalid renderer
1000        if ret != 0 {
1001            panic!("{}", get_error())
1002        }
1003    }
1004
1005    /// Gets the blend mode used for drawing operations.
1006    #[doc(alias = "SDL_GetRenderDrawBlendMode")]
1007    pub fn blend_mode(&self) -> BlendMode {
1008        let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
1009        let ret = unsafe { sys::SDL_GetRenderDrawBlendMode(self.context.raw, blend.as_mut_ptr()) };
1010        // Should only fail on an invalid renderer
1011        if ret != 0 {
1012            panic!("{}", get_error())
1013        } else {
1014            let blend = unsafe { blend.assume_init() };
1015            BlendMode::try_from(blend as u32).unwrap()
1016        }
1017    }
1018
1019    /// Clears the current rendering target with the drawing color.
1020    #[doc(alias = "SDL_RenderClear")]
1021    pub fn clear(&mut self) {
1022        let ret = unsafe { sys::SDL_RenderClear(self.context.raw) };
1023        if ret != 0 {
1024            panic!("Could not clear: {}", get_error())
1025        }
1026    }
1027
1028    /// Updates the screen with any rendering performed since the previous call.
1029    ///
1030    /// SDL's rendering functions operate on a backbuffer; that is, calling a
1031    /// rendering function such as `draw_line()` does not directly put a line on
1032    /// the screen, but rather updates the backbuffer.
1033    /// As such, you compose your entire scene and present the composed
1034    /// backbuffer to the screen as a complete picture.
1035    #[doc(alias = "SDL_RenderPresent")]
1036    pub fn present(&mut self) {
1037        unsafe { sys::SDL_RenderPresent(self.context.raw) }
1038    }
1039
1040    /// Gets the output size of a rendering context.
1041    #[doc(alias = "SDL_GetRendererOutputSize")]
1042    pub fn output_size(&self) -> Result<(u32, u32), String> {
1043        let mut width = 0;
1044        let mut height = 0;
1045
1046        let result =
1047            unsafe { sys::SDL_GetRendererOutputSize(self.context.raw, &mut width, &mut height) };
1048
1049        if result == 0 {
1050            Ok((width as u32, height as u32))
1051        } else {
1052            Err(get_error())
1053        }
1054    }
1055
1056    /// Sets a device independent resolution for rendering.
1057    #[doc(alias = "SDL_RenderSetLogicalSize")]
1058    pub fn set_logical_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
1059        use crate::common::IntegerOrSdlError::*;
1060        let width = validate_int(width, "width")?;
1061        let height = validate_int(height, "height")?;
1062        let result = unsafe { sys::SDL_RenderSetLogicalSize(self.context.raw, width, height) };
1063        match result {
1064            0 => Ok(()),
1065            _ => Err(SdlError(get_error())),
1066        }
1067    }
1068
1069    /// Gets device independent resolution for rendering.
1070    #[doc(alias = "SDL_RenderGetLogicalSize")]
1071    pub fn logical_size(&self) -> (u32, u32) {
1072        let mut width = 0;
1073        let mut height = 0;
1074
1075        unsafe { sys::SDL_RenderGetLogicalSize(self.context.raw, &mut width, &mut height) };
1076
1077        (width as u32, height as u32)
1078    }
1079
1080    /// Sets the drawing area for rendering on the current target.
1081    #[doc(alias = "SDL_RenderSetViewport")]
1082    pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
1083        let rect = rect.into();
1084        // as_ref is important because we need rect to live until the end of the FFI call, but map_or consumes an Option<T>
1085        let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1086        let ret = unsafe { sys::SDL_RenderSetViewport(self.context.raw, ptr) };
1087        if ret != 0 {
1088            panic!("Could not set viewport: {}", get_error())
1089        }
1090    }
1091
1092    /// Gets the drawing area for the current target.
1093    #[doc(alias = "SDL_RenderGetViewport")]
1094    pub fn viewport(&self) -> Rect {
1095        let mut rect = mem::MaybeUninit::uninit();
1096        unsafe { sys::SDL_RenderGetViewport(self.context.raw, rect.as_mut_ptr()) };
1097        let rect = unsafe { rect.assume_init() };
1098        Rect::from_ll(rect)
1099    }
1100
1101    /// Sets the clip rectangle for rendering on the specified target.
1102    ///
1103    /// If the rectangle is `None`, clipping will be disabled.
1104    #[doc(alias = "SDL_RenderSetClipRect")]
1105    pub fn set_clip_rect<R: Into<Option<Rect>>>(&mut self, rect: R) {
1106        let rect = rect.into();
1107        // as_ref is important because we need rect to live until the end of the FFI call, but map_or consumes an Option<T>
1108        let ptr = rect.as_ref().map_or(ptr::null(), |rect| rect.raw());
1109        let ret = unsafe { sys::SDL_RenderSetClipRect(self.context.raw, ptr) };
1110        if ret != 0 {
1111            panic!("Could not set clip rect: {}", get_error())
1112        }
1113    }
1114
1115    /// Gets the clip rectangle for the current target.
1116    ///
1117    /// Returns `None` if clipping is disabled.
1118    #[doc(alias = "SDL_RenderGetClipRect")]
1119    pub fn clip_rect(&self) -> Option<Rect> {
1120        let mut raw = mem::MaybeUninit::uninit();
1121        unsafe { sys::SDL_RenderGetClipRect(self.context.raw, raw.as_mut_ptr()) };
1122        let raw = unsafe { raw.assume_init() };
1123        if raw.w == 0 || raw.h == 0 {
1124            None
1125        } else {
1126            Some(Rect::from_ll(raw))
1127        }
1128    }
1129
1130    /// Sets whether to force integer scales for resolution-independent rendering.
1131    #[doc(alias = "SDL_RenderSetIntegerScale")]
1132    pub fn set_integer_scale(&mut self, scale: bool) -> Result<(), String> {
1133        let ret = unsafe {
1134            sys::SDL_RenderSetIntegerScale(
1135                self.raw(),
1136                if scale {
1137                    sys::SDL_bool::SDL_TRUE
1138                } else {
1139                    sys::SDL_bool::SDL_FALSE
1140                },
1141            )
1142        };
1143        if ret != 0 {
1144            Err(get_error())
1145        } else {
1146            Ok(())
1147        }
1148    }
1149
1150    /// Gets whether integer scales are forced for resolution-independent rendering.
1151    #[doc(alias = "SDL_RenderGetIntegerScale")]
1152    pub fn integer_scale(&self) -> bool {
1153        unsafe { sys::SDL_RenderGetIntegerScale(self.raw()) == sys::SDL_bool::SDL_TRUE }
1154    }
1155
1156    /// Sets the drawing scale for rendering on the current target.
1157    #[doc(alias = "SDL_RenderSetScale")]
1158    pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String> {
1159        let ret = unsafe { sys::SDL_RenderSetScale(self.context.raw, scale_x, scale_y) };
1160        // Should only fail on an invalid renderer
1161        if ret != 0 {
1162            Err(get_error())
1163        } else {
1164            Ok(())
1165        }
1166    }
1167
1168    /// Gets the drawing scale for the current target.
1169    #[doc(alias = "SDL_RenderGetScale")]
1170    pub fn scale(&self) -> (f32, f32) {
1171        let mut scale_x = 0.0;
1172        let mut scale_y = 0.0;
1173        unsafe { sys::SDL_RenderGetScale(self.context.raw, &mut scale_x, &mut scale_y) };
1174        (scale_x, scale_y)
1175    }
1176
1177    /// Draws a point on the current rendering target.
1178    /// Errors if drawing fails for any reason (e.g. driver failure)
1179    #[doc(alias = "SDL_RenderDrawPoint")]
1180    pub fn draw_point<P: Into<Point>>(&mut self, point: P) -> Result<(), String> {
1181        let point = point.into();
1182        let result = unsafe { sys::SDL_RenderDrawPoint(self.context.raw, point.x(), point.y()) };
1183        if result != 0 {
1184            Err(get_error())
1185        } else {
1186            Ok(())
1187        }
1188    }
1189
1190    /// Draws multiple points on the current rendering target.
1191    /// Errors if drawing fails for any reason (e.g. driver failure)
1192    #[doc(alias = "SDL_RenderDrawPoints")]
1193    pub fn draw_points<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1194        let points = points.into();
1195        let result = unsafe {
1196            sys::SDL_RenderDrawPoints(
1197                self.context.raw,
1198                Point::raw_slice(points),
1199                points.len() as c_int,
1200            )
1201        };
1202        if result != 0 {
1203            Err(get_error())
1204        } else {
1205            Ok(())
1206        }
1207    }
1208
1209    /// Draws a line on the current rendering target.
1210    /// Errors if drawing fails for any reason (e.g. driver failure)
1211    #[doc(alias = "SDL_RenderDrawLine")]
1212    pub fn draw_line<P1: Into<Point>, P2: Into<Point>>(
1213        &mut self,
1214        start: P1,
1215        end: P2,
1216    ) -> Result<(), String> {
1217        let start = start.into();
1218        let end = end.into();
1219        let result = unsafe {
1220            sys::SDL_RenderDrawLine(self.context.raw, start.x(), start.y(), end.x(), end.y())
1221        };
1222        if result != 0 {
1223            Err(get_error())
1224        } else {
1225            Ok(())
1226        }
1227    }
1228
1229    /// Draws a series of connected lines on the current rendering target.
1230    /// Errors if drawing fails for any reason (e.g. driver failure)
1231    #[doc(alias = "SDL_RenderDrawLines")]
1232    pub fn draw_lines<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
1233        let points = points.into();
1234        let result = unsafe {
1235            sys::SDL_RenderDrawLines(
1236                self.context.raw,
1237                Point::raw_slice(points),
1238                points.len() as c_int,
1239            )
1240        };
1241        if result != 0 {
1242            Err(get_error())
1243        } else {
1244            Ok(())
1245        }
1246    }
1247
1248    /// Draws a rectangle on the current rendering target.
1249    /// Errors if drawing fails for any reason (e.g. driver failure)
1250    #[doc(alias = "SDL_RenderDrawRect")]
1251    pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String> {
1252        let result = unsafe { sys::SDL_RenderDrawRect(self.context.raw, rect.raw()) };
1253        if result != 0 {
1254            Err(get_error())
1255        } else {
1256            Ok(())
1257        }
1258    }
1259
1260    /// Draws some number of rectangles on the current rendering target.
1261    /// Errors if drawing fails for any reason (e.g. driver failure)
1262    #[doc(alias = "SDL_RenderDrawRects")]
1263    pub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1264        let result = unsafe {
1265            sys::SDL_RenderDrawRects(
1266                self.context.raw,
1267                Rect::raw_slice(rects),
1268                rects.len() as c_int,
1269            )
1270        };
1271        if result != 0 {
1272            Err(get_error())
1273        } else {
1274            Ok(())
1275        }
1276    }
1277
1278    /// Fills a rectangle on the current rendering target with the drawing
1279    /// color.
1280    /// Passing None will fill the entire rendering target.
1281    /// Errors if drawing fails for any reason (e.g. driver failure)
1282    #[doc(alias = "SDL_RenderFillRect")]
1283    pub fn fill_rect<R: Into<Option<Rect>>>(&mut self, rect: R) -> Result<(), String> {
1284        let result = unsafe {
1285            sys::SDL_RenderFillRect(
1286                self.context.raw,
1287                rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1288            )
1289        };
1290        if result != 0 {
1291            Err(get_error())
1292        } else {
1293            Ok(())
1294        }
1295    }
1296
1297    /// Fills some number of rectangles on the current rendering target with
1298    /// the drawing color.
1299    /// Errors if drawing fails for any reason (e.g. driver failure)
1300    #[doc(alias = "SDL_RenderFillRects")]
1301    pub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
1302        let result = unsafe {
1303            sys::SDL_RenderFillRects(
1304                self.context.raw,
1305                Rect::raw_slice(rects),
1306                rects.len() as c_int,
1307            )
1308        };
1309        if result != 0 {
1310            Err(get_error())
1311        } else {
1312            Ok(())
1313        }
1314    }
1315
1316    /// Draws a point on the current rendering target.
1317    /// Errors if drawing fails for any reason (e.g. driver failure)
1318    #[doc(alias = "SDL_RenderDrawPointF")]
1319    pub fn draw_fpoint<P: Into<FPoint>>(&mut self, point: P) -> Result<(), String> {
1320        let point = point.into();
1321        let result = unsafe { sys::SDL_RenderDrawPointF(self.context.raw, point.x(), point.y()) };
1322        if result != 0 {
1323            Err(get_error())
1324        } else {
1325            Ok(())
1326        }
1327    }
1328
1329    /// Draws multiple points on the current rendering target.
1330    /// Errors if drawing fails for any reason (e.g. driver failure)
1331    #[doc(alias = "SDL_RenderDrawPointsF")]
1332    pub fn draw_fpoints<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1333        let points = points.into();
1334        let result = unsafe {
1335            sys::SDL_RenderDrawPointsF(
1336                self.context.raw,
1337                FPoint::raw_slice(points),
1338                points.len() as c_int,
1339            )
1340        };
1341        if result != 0 {
1342            Err(get_error())
1343        } else {
1344            Ok(())
1345        }
1346    }
1347
1348    /// Draws a line on the current rendering target.
1349    /// Errors if drawing fails for any reason (e.g. driver failure)
1350    #[doc(alias = "SDL_RenderDrawLineF")]
1351    pub fn draw_fline<P1: Into<FPoint>, P2: Into<FPoint>>(
1352        &mut self,
1353        start: P1,
1354        end: P2,
1355    ) -> Result<(), String> {
1356        let start = start.into();
1357        let end = end.into();
1358        let result = unsafe {
1359            sys::SDL_RenderDrawLineF(self.context.raw, start.x(), start.y(), end.x(), end.y())
1360        };
1361        if result != 0 {
1362            Err(get_error())
1363        } else {
1364            Ok(())
1365        }
1366    }
1367
1368    /// Draws a series of connected lines on the current rendering target.
1369    /// Errors if drawing fails for any reason (e.g. driver failure)
1370    #[doc(alias = "SDL_RenderDrawLinesF")]
1371    pub fn draw_flines<'a, P: Into<&'a [FPoint]>>(&mut self, points: P) -> Result<(), String> {
1372        let points = points.into();
1373        let result = unsafe {
1374            sys::SDL_RenderDrawLinesF(
1375                self.context.raw,
1376                FPoint::raw_slice(points),
1377                points.len() as c_int,
1378            )
1379        };
1380        if result != 0 {
1381            Err(get_error())
1382        } else {
1383            Ok(())
1384        }
1385    }
1386
1387    /// Draws a rectangle on the current rendering target.
1388    /// Errors if drawing fails for any reason (e.g. driver failure)
1389    #[doc(alias = "SDL_RenderDrawRectF")]
1390    pub fn draw_frect(&mut self, rect: FRect) -> Result<(), String> {
1391        let result = unsafe { sys::SDL_RenderDrawRectF(self.context.raw, rect.raw()) };
1392        if result != 0 {
1393            Err(get_error())
1394        } else {
1395            Ok(())
1396        }
1397    }
1398
1399    /// Draws some number of rectangles on the current rendering target.
1400    /// Errors if drawing fails for any reason (e.g. driver failure)
1401    #[doc(alias = "SDL_RenderDrawRectsF")]
1402    pub fn draw_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1403        let result = unsafe {
1404            sys::SDL_RenderDrawRectsF(
1405                self.context.raw,
1406                FRect::raw_slice(rects),
1407                rects.len() as c_int,
1408            )
1409        };
1410        if result != 0 {
1411            Err(get_error())
1412        } else {
1413            Ok(())
1414        }
1415    }
1416
1417    /// Fills a rectangle on the current rendering target with the drawing
1418    /// color.
1419    /// Passing None will fill the entire rendering target.
1420    /// Errors if drawing fails for any reason (e.g. driver failure)
1421    #[doc(alias = "SDL_RenderFillRectF")]
1422    pub fn fill_frect<R: Into<Option<FRect>>>(&mut self, rect: R) -> Result<(), String> {
1423        let result = unsafe {
1424            sys::SDL_RenderFillRectF(
1425                self.context.raw,
1426                rect.into().as_ref().map(|r| r.raw()).unwrap_or(ptr::null()),
1427            )
1428        };
1429        if result != 0 {
1430            Err(get_error())
1431        } else {
1432            Ok(())
1433        }
1434    }
1435
1436    /// Fills some number of rectangles on the current rendering target with
1437    /// the drawing color.
1438    /// Errors if drawing fails for any reason (e.g. driver failure)
1439    #[doc(alias = "SDL_RenderFillRectsF")]
1440    pub fn fill_frects(&mut self, rects: &[FRect]) -> Result<(), String> {
1441        let result = unsafe {
1442            sys::SDL_RenderFillRectsF(
1443                self.context.raw,
1444                FRect::raw_slice(rects),
1445                rects.len() as c_int,
1446            )
1447        };
1448        if result != 0 {
1449            Err(get_error())
1450        } else {
1451            Ok(())
1452        }
1453    }
1454
1455    /// Copies a portion of the texture to the current rendering target.
1456    ///
1457    /// * If `src` is `None`, the entire texture is copied.
1458    /// * If `dst` is `None`, the texture will be stretched to fill the given
1459    ///   rectangle.
1460    ///
1461    /// Errors if drawing fails for any reason (e.g. driver failure),
1462    /// or if the provided texture does not belong to the renderer.
1463    #[doc(alias = "SDL_RenderCopyF")]
1464    pub fn copy_f<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1465    where
1466        R1: Into<Option<Rect>>,
1467        R2: Into<Option<FRect>>,
1468    {
1469        let ret = unsafe {
1470            sys::SDL_RenderCopyF(
1471                self.context.raw,
1472                texture.raw,
1473                match src.into() {
1474                    Some(ref rect) => rect.raw(),
1475                    None => ptr::null(),
1476                },
1477                match dst.into() {
1478                    Some(ref rect) => rect.raw(),
1479                    None => ptr::null(),
1480                },
1481            )
1482        };
1483
1484        if ret != 0 {
1485            Err(get_error())
1486        } else {
1487            Ok(())
1488        }
1489    }
1490
1491    /// Copies a portion of the texture to the current rendering target,
1492    /// optionally rotating it by angle around the given center and also
1493    /// flipping it top-bottom and/or left-right.
1494    ///
1495    /// * If `src` is `None`, the entire texture is copied.
1496    /// * If `dst` is `None`, the texture will be stretched to fill the given
1497    ///   rectangle.
1498    /// * If `center` is `None`, rotation will be done around the center point
1499    ///   of `dst`, or `src` if `dst` is None.
1500    ///
1501    /// Errors if drawing fails for any reason (e.g. driver failure),
1502    /// if the provided texture does not belong to the renderer,
1503    /// or if the driver does not support RenderCopyEx.
1504    #[doc(alias = "SDL_RenderCopyExF")]
1505    pub fn copy_ex_f<R1, R2, P>(
1506        &mut self,
1507        texture: &Texture,
1508        src: R1,
1509        dst: R2,
1510        angle: f64,
1511        center: P,
1512        flip_horizontal: bool,
1513        flip_vertical: bool,
1514    ) -> Result<(), String>
1515    where
1516        R1: Into<Option<Rect>>,
1517        R2: Into<Option<FRect>>,
1518        P: Into<Option<FPoint>>,
1519    {
1520        use crate::sys::SDL_RendererFlip::*;
1521        let flip = unsafe {
1522            match (flip_horizontal, flip_vertical) {
1523                (false, false) => SDL_FLIP_NONE,
1524                (true, false) => SDL_FLIP_HORIZONTAL,
1525                (false, true) => SDL_FLIP_VERTICAL,
1526                (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1527                    transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1528                        | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1529                ),
1530            }
1531        };
1532
1533        let ret = unsafe {
1534            sys::SDL_RenderCopyExF(
1535                self.context.raw,
1536                texture.raw,
1537                match src.into() {
1538                    Some(ref rect) => rect.raw(),
1539                    None => ptr::null(),
1540                },
1541                match dst.into() {
1542                    Some(ref rect) => rect.raw(),
1543                    None => ptr::null(),
1544                },
1545                angle as c_double,
1546                match center.into() {
1547                    Some(ref point) => point.raw(),
1548                    None => ptr::null(),
1549                },
1550                flip,
1551            )
1552        };
1553
1554        if ret != 0 {
1555            Err(get_error())
1556        } else {
1557            Ok(())
1558        }
1559    }
1560
1561    /// Copies a portion of the texture to the current rendering target.
1562    ///
1563    /// * If `src` is `None`, the entire texture is copied.
1564    /// * If `dst` is `None`, the texture will be stretched to fill the given
1565    ///   rectangle.
1566    ///
1567    /// Errors if drawing fails for any reason (e.g. driver failure),
1568    /// or if the provided texture does not belong to the renderer.
1569    #[doc(alias = "SDL_RenderCopy")]
1570    pub fn copy<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
1571    where
1572        R1: Into<Option<Rect>>,
1573        R2: Into<Option<Rect>>,
1574    {
1575        let ret = unsafe {
1576            sys::SDL_RenderCopy(
1577                self.context.raw,
1578                texture.raw,
1579                match src.into() {
1580                    Some(ref rect) => rect.raw(),
1581                    None => ptr::null(),
1582                },
1583                match dst.into() {
1584                    Some(ref rect) => rect.raw(),
1585                    None => ptr::null(),
1586                },
1587            )
1588        };
1589
1590        if ret != 0 {
1591            Err(get_error())
1592        } else {
1593            Ok(())
1594        }
1595    }
1596
1597    /// Copies a portion of the texture to the current rendering target,
1598    /// optionally rotating it by angle around the given center and also
1599    /// flipping it top-bottom and/or left-right.
1600    ///
1601    /// * If `src` is `None`, the entire texture is copied.
1602    /// * If `dst` is `None`, the texture will be stretched to fill the given
1603    ///   rectangle.
1604    /// * If `center` is `None`, rotation will be done around the center point
1605    ///   of `dst`, or `src` if `dst` is None.
1606    ///
1607    /// Errors if drawing fails for any reason (e.g. driver failure),
1608    /// if the provided texture does not belong to the renderer,
1609    /// or if the driver does not support RenderCopyEx.
1610    #[doc(alias = "SDL_RenderCopyEx")]
1611    pub fn copy_ex<R1, R2, P>(
1612        &mut self,
1613        texture: &Texture,
1614        src: R1,
1615        dst: R2,
1616        angle: f64,
1617        center: P,
1618        flip_horizontal: bool,
1619        flip_vertical: bool,
1620    ) -> Result<(), String>
1621    where
1622        R1: Into<Option<Rect>>,
1623        R2: Into<Option<Rect>>,
1624        P: Into<Option<Point>>,
1625    {
1626        use crate::sys::SDL_RendererFlip::*;
1627        let flip = unsafe {
1628            match (flip_horizontal, flip_vertical) {
1629                (false, false) => SDL_FLIP_NONE,
1630                (true, false) => SDL_FLIP_HORIZONTAL,
1631                (false, true) => SDL_FLIP_VERTICAL,
1632                (true, true) => transmute::<u32, sys::SDL_RendererFlip>(
1633                    transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL)
1634                        | transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL),
1635                ),
1636            }
1637        };
1638
1639        let ret = unsafe {
1640            sys::SDL_RenderCopyEx(
1641                self.context.raw,
1642                texture.raw,
1643                match src.into() {
1644                    Some(ref rect) => rect.raw(),
1645                    None => ptr::null(),
1646                },
1647                match dst.into() {
1648                    Some(ref rect) => rect.raw(),
1649                    None => ptr::null(),
1650                },
1651                angle as c_double,
1652                match center.into() {
1653                    Some(ref point) => point.raw(),
1654                    None => ptr::null(),
1655                },
1656                flip,
1657            )
1658        };
1659
1660        if ret != 0 {
1661            Err(get_error())
1662        } else {
1663            Ok(())
1664        }
1665    }
1666
1667    /// Reads pixels from the current rendering target.
1668    /// # Remarks
1669    /// WARNING: This is a very slow operation, and should not be used frequently.
1670    #[doc(alias = "SDL_RenderReadPixels")]
1671    pub fn read_pixels<R: Into<Option<Rect>>>(
1672        &self,
1673        rect: R,
1674        format: pixels::PixelFormatEnum,
1675    ) -> Result<Vec<u8>, String> {
1676        let rect = rect.into();
1677        let (actual_rect, w, h) = match rect {
1678            Some(ref rect) => (rect.raw(), rect.width() as usize, rect.height() as usize),
1679            None => {
1680                let (w, h) = self.output_size()?;
1681                (ptr::null(), w as usize, h as usize)
1682            }
1683        };
1684
1685        let pitch = w * format.byte_size_per_pixel(); // calculated pitch
1686        let size = format.byte_size_of_pixels(w * h);
1687        let mut pixels = Vec::with_capacity(size);
1688
1689        // Pass the interior of `pixels: Vec<u8>` to SDL
1690        let ret = unsafe {
1691            sys::SDL_RenderReadPixels(
1692                self.context.raw,
1693                actual_rect,
1694                format as u32,
1695                pixels.as_mut_ptr() as *mut c_void,
1696                pitch as c_int,
1697            )
1698        };
1699
1700        if ret == 0 {
1701            unsafe { pixels.set_len(size) };
1702            Ok(pixels)
1703        } else {
1704            Err(get_error())
1705        }
1706    }
1707
1708    /// Creates a texture for a rendering context.
1709    ///
1710    /// If format is `None`, the format will be the one the parent Window or Surface uses.
1711    ///
1712    /// If format is `Some(pixel_format)`
1713    /// created with the specified format if possible. If the PixelFormat is not supported, this
1714    /// will return an error.
1715    ///
1716    /// You should prefer the default format if possible to have performance gains and to avoid
1717    /// unsupported Pixel Formats that can cause errors. However, be careful with the default
1718    /// `PixelFormat` if you want to create transparent textures.
1719    ///
1720    /// # Notes
1721    ///
1722    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature,
1723    /// because lifetimes otherwise prevent `Canvas` from creating and accessing `Texture`s at the
1724    /// same time.
1725    #[cfg(feature = "unsafe_textures")]
1726    pub fn create_texture<F>(
1727        &self,
1728        format: F,
1729        access: TextureAccess,
1730        width: u32,
1731        height: u32,
1732    ) -> Result<Texture, TextureValueError>
1733    where
1734        F: Into<Option<PixelFormatEnum>>,
1735    {
1736        use self::TextureValueError::*;
1737        let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
1738        let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
1739        if result.is_null() {
1740            Err(SdlError(get_error()))
1741        } else {
1742            unsafe { Ok(self.raw_create_texture(result)) }
1743        }
1744    }
1745
1746    /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)`
1747    ///
1748    /// # Notes
1749    ///
1750    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1751    #[cfg(feature = "unsafe_textures")]
1752    #[inline]
1753    pub fn create_texture_static<F>(
1754        &self,
1755        format: F,
1756        width: u32,
1757        height: u32,
1758    ) -> Result<Texture, TextureValueError>
1759    where
1760        F: Into<Option<PixelFormatEnum>>,
1761    {
1762        self.create_texture(format, TextureAccess::Static, width, height)
1763    }
1764
1765    /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)`
1766    ///
1767    /// # Notes
1768    ///
1769    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1770    #[cfg(feature = "unsafe_textures")]
1771    #[inline]
1772    pub fn create_texture_streaming<F>(
1773        &self,
1774        format: F,
1775        width: u32,
1776        height: u32,
1777    ) -> Result<Texture, TextureValueError>
1778    where
1779        F: Into<Option<PixelFormatEnum>>,
1780    {
1781        self.create_texture(format, TextureAccess::Streaming, width, height)
1782    }
1783
1784    /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)`
1785    ///
1786    /// # Notes
1787    ///
1788    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1789    #[cfg(feature = "unsafe_textures")]
1790    #[inline]
1791    pub fn create_texture_target<F>(
1792        &self,
1793        format: F,
1794        width: u32,
1795        height: u32,
1796    ) -> Result<Texture, TextureValueError>
1797    where
1798        F: Into<Option<PixelFormatEnum>>,
1799    {
1800        self.create_texture(format, TextureAccess::Target, width, height)
1801    }
1802
1803    /// Creates a texture from an existing surface.
1804    ///
1805    /// # Remarks
1806    ///
1807    /// The access hint for the created texture is `TextureAccess::Static`.
1808    ///
1809    /// # Notes
1810    ///
1811    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1812    #[cfg(feature = "unsafe_textures")]
1813    #[doc(alias = "SDL_CreateTextureFromSurface")]
1814    pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>(
1815        &self,
1816        surface: S,
1817    ) -> Result<Texture, TextureValueError> {
1818        use self::TextureValueError::*;
1819        let result =
1820            unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
1821        if result.is_null() {
1822            Err(SdlError(get_error()))
1823        } else {
1824            unsafe { Ok(self.raw_create_texture(result)) }
1825        }
1826    }
1827
1828    #[cfg(feature = "unsafe_textures")]
1829    /// Create a texture from its raw `SDL_Texture`. Should be used with care.
1830    ///
1831    /// # Notes
1832    ///
1833    /// Note that this method is only accessible in Canvas with the `unsafe_textures` feature.
1834    pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
1835        Texture { raw }
1836    }
1837
1838    #[doc(alias = "SDL_RenderFlush")]
1839    pub unsafe fn render_flush(&self) {
1840        let ret = sys::SDL_RenderFlush(self.context.raw);
1841
1842        if ret != 0 {
1843            panic!("Error setting blend: {}", get_error())
1844        }
1845    }
1846}
1847
1848#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
1849pub struct TextureQuery {
1850    pub format: pixels::PixelFormatEnum,
1851    pub access: TextureAccess,
1852    pub width: u32,
1853    pub height: u32,
1854}
1855
1856/// A texture for a rendering context.
1857///
1858/// Every Texture is owned by a `TextureCreator` or `Canvas` (the latter is only possible with the
1859/// `unsafe_textures` feature).
1860///
1861/// # Differences between with and without `unsafe_textures` feature
1862///
1863/// Without the `unsafe_textures`, a texture is owned by a `TextureCreator` and a `Texture` cannot
1864/// outlive its parent `TextureCreator` thanks to lifetimes. A texture is destroyed via its `Drop`
1865/// implementation. While this is the most "Rust"-y way of doing things currently, it is pretty
1866/// cumbersome to use in some cases.
1867///
1868/// That is why the feature `unsafe_textures` was brought to life: the lifetimes are gone, meaning
1869/// that `Texture`s *can* outlive their parents. That means that the `Texture`s are not destroyed
1870/// on `Drop`, but destroyed when their parents are. That means if you create 10 000 textures with
1871/// this feature, they will only be destroyed after you drop the `Canvas` and every
1872/// `TextureCreator` linked to it. While this feature is enabled, this is the safest way to free
1873/// the memory taken by the `Texture`s, but there is still another, unsafe way to destroy the
1874/// `Texture` before its `Canvas`: the method `destroy`. This method is unsafe because *you* have
1875/// to make sure the parent `Canvas` or `TextureCreator` is still alive while calling this method.
1876///
1877/// **Calling the `destroy` method while no parent is alive is undefined behavior**
1878///
1879/// With the `unsafe_textures` feature, a `Texture` can be safely accessed (but not destroyed) after
1880/// the `Canvas` is dropped, but since any access (except `destroy`) requires the original `Canvas`,
1881/// it is not possible to access a `Texture` while the `Canvas` is dropped.
1882#[cfg(feature = "unsafe_textures")]
1883pub struct Texture {
1884    raw: *mut sys::SDL_Texture,
1885}
1886
1887/// A texture for a rendering context.
1888///
1889/// Every Texture is owned by a `TextureCreator`. Internally, a texture is destroyed via its `Drop`
1890/// implementation. A texture can only be used by the `Canvas` it was originally created from, it
1891/// is undefined behavior otherwise.
1892#[cfg(not(feature = "unsafe_textures"))]
1893pub struct Texture<'r> {
1894    raw: *mut sys::SDL_Texture,
1895    _marker: PhantomData<&'r ()>,
1896}
1897
1898#[cfg(not(feature = "unsafe_textures"))]
1899impl<'r> Drop for Texture<'r> {
1900    #[doc(alias = "SDL_DestroyTexture")]
1901    fn drop(&mut self) {
1902        unsafe {
1903            sys::SDL_DestroyTexture(self.raw);
1904        }
1905    }
1906}
1907
1908#[cfg(feature = "unsafe_textures")]
1909impl Texture {
1910    /// Destroy the Texture and its representation
1911    /// in the Renderer. This will most likely
1912    /// mean that the renderer engine will free video
1913    /// memory that was allocated for this texture.
1914    ///
1915    /// This method is unsafe because since Texture does not have
1916    /// a lifetime, it is legal in Rust to make this texture live
1917    /// longer than the Renderer. It is however illegal to destroy a SDL_Texture
1918    /// after its SDL_Renderer, therefore this function is unsafe because
1919    /// of this.
1920    ///
1921    /// Note however that you don't *have* to destroy a Texture before its Canvas,
1922    /// since whenever Canvas is destroyed, the SDL implementation will automatically
1923    /// destroy all the children Textures of that Canvas.
1924    ///
1925    /// **Calling this method while no parent is alive is undefined behavior**
1926    pub unsafe fn destroy(self) {
1927        sys::SDL_DestroyTexture(self.raw)
1928    }
1929}
1930
1931#[derive(Debug, Clone)]
1932pub enum UpdateTextureError {
1933    PitchOverflows(usize),
1934    PitchMustBeMultipleOfTwoForFormat(usize, PixelFormatEnum),
1935    XMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
1936    YMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
1937    WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
1938    HeightMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
1939    SdlError(String),
1940}
1941
1942impl fmt::Display for UpdateTextureError {
1943    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
1944        use self::UpdateTextureError::*;
1945
1946        match *self {
1947            PitchOverflows(value) => write!(f, "Pitch overflows ({})", value),
1948            PitchMustBeMultipleOfTwoForFormat(value, format) => {
1949                write!(
1950                    f,
1951                    "Pitch must be multiple of two for pixel format '{:?}' ({})",
1952                    format, value
1953                )
1954            }
1955            XMustBeMultipleOfTwoForFormat(value, format) => {
1956                write!(
1957                    f,
1958                    "X must be multiple of two for pixel format '{:?}' ({})",
1959                    format, value
1960                )
1961            }
1962            YMustBeMultipleOfTwoForFormat(value, format) => {
1963                write!(
1964                    f,
1965                    "Y must be multiple of two for pixel format '{:?}' ({})",
1966                    format, value
1967                )
1968            }
1969            WidthMustBeMultipleOfTwoForFormat(value, format) => {
1970                write!(
1971                    f,
1972                    "Width must be multiple of two for pixel format '{:?}' ({})",
1973                    format, value
1974                )
1975            }
1976            HeightMustBeMultipleOfTwoForFormat(value, format) => {
1977                write!(
1978                    f,
1979                    "Height must be multiple of two for pixel format '{:?}' ({})",
1980                    format, value
1981                )
1982            }
1983            SdlError(ref e) => write!(f, "SDL error: {}", e),
1984        }
1985    }
1986}
1987
1988impl Error for UpdateTextureError {}
1989
1990#[derive(Debug, Clone)]
1991pub enum UpdateTextureYUVError {
1992    PitchOverflows {
1993        plane: &'static str,
1994        value: usize,
1995    },
1996    InvalidPlaneLength {
1997        plane: &'static str,
1998        length: usize,
1999        pitch: usize,
2000        height: usize,
2001    },
2002    XMustBeMultipleOfTwoForFormat(i32),
2003    YMustBeMultipleOfTwoForFormat(i32),
2004    WidthMustBeMultipleOfTwoForFormat(u32),
2005    HeightMustBeMultipleOfTwoForFormat(u32),
2006    RectNotInsideTexture(Rect),
2007    SdlError(String),
2008}
2009
2010impl fmt::Display for UpdateTextureYUVError {
2011    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
2012        use self::UpdateTextureYUVError::*;
2013
2014        match *self {
2015            PitchOverflows { plane, value } => {
2016                write!(f, "Pitch overflows on {} plane ({})", plane, value)
2017            }
2018            InvalidPlaneLength {
2019                plane,
2020                length,
2021                pitch,
2022                height,
2023            } => {
2024                write!(
2025                    f,
2026                    "The {} plane is wrong length ({}, should be {} * {})",
2027                    plane, length, pitch, height
2028                )
2029            }
2030            XMustBeMultipleOfTwoForFormat(value) => {
2031                write!(f, "X must be multiple of two ({})", value)
2032            }
2033            YMustBeMultipleOfTwoForFormat(value) => {
2034                write!(f, "Y must be multiple of two ({})", value)
2035            }
2036            WidthMustBeMultipleOfTwoForFormat(value) => {
2037                write!(f, "Width must be multiple of two ({})", value)
2038            }
2039            HeightMustBeMultipleOfTwoForFormat(value) => {
2040                write!(f, "Height must be multiple of two ({})", value)
2041            }
2042            RectNotInsideTexture(_) => write!(f, "Rect must be inside texture"),
2043            SdlError(ref e) => write!(f, "SDL error: {}", e),
2044        }
2045    }
2046}
2047
2048impl Error for UpdateTextureYUVError {}
2049
2050struct InternalTexture {
2051    raw: *mut sys::SDL_Texture,
2052}
2053
2054impl InternalTexture {
2055    #[doc(alias = "SDL_QueryTexture")]
2056    pub fn query(&self) -> TextureQuery {
2057        let mut format = 0;
2058        let mut access = 0;
2059        let mut width = 0;
2060        let mut height = 0;
2061
2062        let ret = unsafe {
2063            sys::SDL_QueryTexture(self.raw, &mut format, &mut access, &mut width, &mut height)
2064        };
2065        // Should only fail on an invalid texture
2066        if ret != 0 {
2067            panic!("{}", get_error())
2068        } else {
2069            TextureQuery {
2070                format: PixelFormatEnum::try_from(format).unwrap(),
2071                access: TextureAccess::try_from(access as u32).unwrap(),
2072                width: width as u32,
2073                height: height as u32,
2074            }
2075        }
2076    }
2077
2078    #[doc(alias = "SDL_SetTextureColorMod")]
2079    pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2080        let ret = unsafe { sys::SDL_SetTextureColorMod(self.raw, red, green, blue) };
2081
2082        if ret != 0 {
2083            panic!("Error setting color mod: {}", get_error())
2084        }
2085    }
2086
2087    #[doc(alias = "SDL_GetTextureColorMod")]
2088    pub fn color_mod(&self) -> (u8, u8, u8) {
2089        let (mut r, mut g, mut b) = (0, 0, 0);
2090        let ret = unsafe { sys::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) };
2091
2092        // Should only fail on an invalid texture
2093        if ret != 0 {
2094            panic!("{}", get_error())
2095        } else {
2096            (r, g, b)
2097        }
2098    }
2099
2100    #[doc(alias = "SDL_SetTextureAlphaMod")]
2101    pub fn set_alpha_mod(&mut self, alpha: u8) {
2102        let ret = unsafe { sys::SDL_SetTextureAlphaMod(self.raw, alpha) };
2103
2104        if ret != 0 {
2105            panic!("Error setting alpha mod: {}", get_error())
2106        }
2107    }
2108
2109    #[doc(alias = "SDL_GetTextureAlphaMod")]
2110    pub fn alpha_mod(&self) -> u8 {
2111        let mut alpha = 0;
2112        let ret = unsafe { sys::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
2113
2114        // Should only fail on an invalid texture
2115        if ret != 0 {
2116            panic!("{}", get_error())
2117        } else {
2118            alpha
2119        }
2120    }
2121
2122    #[doc(alias = "SDL_SetTextureBlendMode")]
2123    pub fn set_blend_mode(&mut self, blend: BlendMode) {
2124        let ret = unsafe { sys::SDL_SetTextureBlendMode(self.raw, transmute(blend as u32)) };
2125
2126        if ret != 0 {
2127            panic!("Error setting blend: {}", get_error())
2128        }
2129    }
2130
2131    #[doc(alias = "SDL_GetTextureBlendMode")]
2132    pub fn blend_mode(&self) -> BlendMode {
2133        let mut blend: MaybeUninit<SDL_BlendMode> = mem::MaybeUninit::uninit();
2134        let ret = unsafe { sys::SDL_GetTextureBlendMode(self.raw, blend.as_mut_ptr()) };
2135
2136        // Should only fail on an invalid texture
2137        if ret != 0 {
2138            panic!("{}", get_error())
2139        } else {
2140            let blend = unsafe { blend.assume_init() };
2141            BlendMode::try_from(blend as u32).unwrap()
2142        }
2143    }
2144
2145    #[doc(alias = "SDL_UpdateTexture")]
2146    pub fn update<R>(
2147        &mut self,
2148        rect: R,
2149        pixel_data: &[u8],
2150        pitch: usize,
2151    ) -> Result<(), UpdateTextureError>
2152    where
2153        R: Into<Option<Rect>>,
2154    {
2155        use self::UpdateTextureError::*;
2156        let rect = rect.into();
2157        let rect_raw_ptr = match rect {
2158            Some(ref rect) => rect.raw(),
2159            None => ptr::null(),
2160        };
2161
2162        // Check if the rectangle's position or size is odd, and if the pitch is odd.
2163        // This needs to be done in case the texture's pixel format is planar YUV.
2164        // See issue #334 for details.
2165        let TextureQuery { format, .. } = self.query();
2166        match format {
2167            PixelFormatEnum::YV12
2168            | PixelFormatEnum::IYUV
2169            | PixelFormatEnum::NV12
2170            | PixelFormatEnum::NV21 => {
2171                if let Some(r) = rect {
2172                    if r.x() % 2 != 0 {
2173                        return Err(XMustBeMultipleOfTwoForFormat(r.x(), format));
2174                    } else if r.y() % 2 != 0 {
2175                        return Err(YMustBeMultipleOfTwoForFormat(r.y(), format));
2176                    } else if r.width() % 2 != 0 {
2177                        return Err(WidthMustBeMultipleOfTwoForFormat(r.width(), format));
2178                    } else if r.height() % 2 != 0 {
2179                        return Err(HeightMustBeMultipleOfTwoForFormat(r.height(), format));
2180                    }
2181                };
2182                if pitch % 2 != 0 {
2183                    return Err(PitchMustBeMultipleOfTwoForFormat(pitch, format));
2184                }
2185            }
2186            _ => {}
2187        }
2188
2189        let pitch = match validate_int(pitch as u32, "pitch") {
2190            Ok(p) => p,
2191            Err(_) => return Err(PitchOverflows(pitch)),
2192        };
2193
2194        let result = unsafe {
2195            sys::SDL_UpdateTexture(
2196                self.raw,
2197                rect_raw_ptr,
2198                pixel_data.as_ptr() as *const _,
2199                pitch,
2200            )
2201        };
2202
2203        if result != 0 {
2204            Err(SdlError(get_error()))
2205        } else {
2206            Ok(())
2207        }
2208    }
2209
2210    #[doc(alias = "SDL_UpdateYUVTexture")]
2211    pub fn update_yuv<R>(
2212        &mut self,
2213        rect: R,
2214        y_plane: &[u8],
2215        y_pitch: usize,
2216        u_plane: &[u8],
2217        u_pitch: usize,
2218        v_plane: &[u8],
2219        v_pitch: usize,
2220    ) -> Result<(), UpdateTextureYUVError>
2221    where
2222        R: Into<Option<Rect>>,
2223    {
2224        use self::UpdateTextureYUVError::*;
2225
2226        let rect = rect.into();
2227
2228        let rect_raw_ptr = match rect {
2229            Some(ref rect) => rect.raw(),
2230            None => ptr::null(),
2231        };
2232
2233        if let Some(ref r) = rect {
2234            if r.x() % 2 != 0 {
2235                return Err(XMustBeMultipleOfTwoForFormat(r.x()));
2236            } else if r.y() % 2 != 0 {
2237                return Err(YMustBeMultipleOfTwoForFormat(r.y()));
2238            } else if r.width() % 2 != 0 {
2239                return Err(WidthMustBeMultipleOfTwoForFormat(r.width()));
2240            } else if r.height() % 2 != 0 {
2241                return Err(HeightMustBeMultipleOfTwoForFormat(r.height()));
2242            }
2243        };
2244
2245        // If the destination rectangle lies outside the texture boundaries,
2246        // SDL_UpdateYUVTexture will write outside allocated texture memory.
2247        let tex_info = self.query();
2248        if let Some(ref r) = rect {
2249            let tex_rect = Rect::new(0, 0, tex_info.width, tex_info.height);
2250            let inside = match r.intersection(tex_rect) {
2251                Some(intersection) => intersection == *r,
2252                None => false,
2253            };
2254            // The destination rectangle cannot lie outside the texture boundaries
2255            if !inside {
2256                return Err(RectNotInsideTexture(*r));
2257            }
2258        }
2259
2260        // We need the height in order to check the array slice lengths.
2261        // Checking the lengths can prevent buffer overruns in SDL_UpdateYUVTexture.
2262        let height = match rect {
2263            Some(ref r) => r.height(),
2264            None => tex_info.height,
2265        } as usize;
2266
2267        //let wrong_length =
2268        if y_plane.len() != (y_pitch * height) {
2269            return Err(InvalidPlaneLength {
2270                plane: "y",
2271                length: y_plane.len(),
2272                pitch: y_pitch,
2273                height,
2274            });
2275        }
2276        if u_plane.len() != (u_pitch * height / 2) {
2277            return Err(InvalidPlaneLength {
2278                plane: "u",
2279                length: u_plane.len(),
2280                pitch: u_pitch,
2281                height: height / 2,
2282            });
2283        }
2284        if v_plane.len() != (v_pitch * height / 2) {
2285            return Err(InvalidPlaneLength {
2286                plane: "v",
2287                length: v_plane.len(),
2288                pitch: v_pitch,
2289                height: height / 2,
2290            });
2291        }
2292
2293        let y_pitch = match validate_int(y_pitch as u32, "y_pitch") {
2294            Ok(p) => p,
2295            Err(_) => {
2296                return Err(PitchOverflows {
2297                    plane: "y",
2298                    value: y_pitch,
2299                })
2300            }
2301        };
2302        let u_pitch = match validate_int(u_pitch as u32, "u_pitch") {
2303            Ok(p) => p,
2304            Err(_) => {
2305                return Err(PitchOverflows {
2306                    plane: "u",
2307                    value: u_pitch,
2308                })
2309            }
2310        };
2311        let v_pitch = match validate_int(v_pitch as u32, "v_pitch") {
2312            Ok(p) => p,
2313            Err(_) => {
2314                return Err(PitchOverflows {
2315                    plane: "v",
2316                    value: v_pitch,
2317                })
2318            }
2319        };
2320
2321        let result = unsafe {
2322            sys::SDL_UpdateYUVTexture(
2323                self.raw,
2324                rect_raw_ptr,
2325                y_plane.as_ptr(),
2326                y_pitch,
2327                u_plane.as_ptr(),
2328                u_pitch,
2329                v_plane.as_ptr(),
2330                v_pitch,
2331            )
2332        };
2333        if result != 0 {
2334            Err(SdlError(get_error()))
2335        } else {
2336            Ok(())
2337        }
2338    }
2339
2340    #[doc(alias = "SDL_LockTexture")]
2341    pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2342    where
2343        F: FnOnce(&mut [u8], usize) -> R,
2344        R2: Into<Option<Rect>>,
2345    {
2346        // Call to SDL to populate pixel data
2347        let loaded = unsafe {
2348            let q = self.query();
2349            let mut pixels = ptr::null_mut();
2350            let mut pitch = 0;
2351
2352            let (rect_raw_ptr, height) = match rect.into() {
2353                Some(ref rect) => (rect.raw(), rect.height() as usize),
2354                None => (ptr::null(), q.height as usize),
2355            };
2356
2357            let ret = sys::SDL_LockTexture(self.raw, rect_raw_ptr, &mut pixels, &mut pitch);
2358            if ret == 0 {
2359                let size = q
2360                    .format
2361                    .byte_size_from_pitch_and_height(pitch as usize, height);
2362                Ok((
2363                    ::std::slice::from_raw_parts_mut(pixels as *mut u8, size),
2364                    pitch,
2365                ))
2366            } else {
2367                Err(get_error())
2368            }
2369        };
2370
2371        match loaded {
2372            Ok((interior, pitch)) => {
2373                let result;
2374                unsafe {
2375                    result = func(interior, pitch as usize);
2376                    sys::SDL_UnlockTexture(self.raw);
2377                }
2378                Ok(result)
2379            }
2380            Err(e) => Err(e),
2381        }
2382    }
2383
2384    pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2385        let mut texw = 0.0;
2386        let mut texh = 0.0;
2387
2388        if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2389            (texw, texh)
2390        } else {
2391            panic!("OpenGL texture binding not supported");
2392        }
2393    }
2394
2395    pub unsafe fn gl_unbind_texture(&mut self) {
2396        if sys::SDL_GL_UnbindTexture(self.raw) != 0 {
2397            panic!("OpenGL texture unbinding not supported");
2398        }
2399    }
2400
2401    #[doc(alias = "SDL_GL_BindTexture")]
2402    pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2403        unsafe {
2404            let mut texw = 0.0;
2405            let mut texh = 0.0;
2406
2407            if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
2408                let return_value = f(texw, texh);
2409
2410                if sys::SDL_GL_UnbindTexture(self.raw) == 0 {
2411                    return_value
2412                } else {
2413                    // This should never happen...
2414                    panic!();
2415                }
2416            } else {
2417                panic!("OpenGL texture binding not supported");
2418            }
2419        }
2420    }
2421}
2422
2423#[cfg(not(feature = "unsafe_textures"))]
2424impl<'r> Texture<'r> {
2425    /// Queries the attributes of the texture.
2426    #[inline]
2427    pub fn query(&self) -> TextureQuery {
2428        InternalTexture { raw: self.raw }.query()
2429    }
2430
2431    /// Sets an additional color value multiplied into render copy operations.
2432    #[inline]
2433    pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2434        InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2435    }
2436
2437    /// Gets the additional color value multiplied into render copy operations.
2438    #[inline]
2439    pub fn color_mod(&self) -> (u8, u8, u8) {
2440        InternalTexture { raw: self.raw }.color_mod()
2441    }
2442
2443    /// Sets an additional alpha value multiplied into render copy operations.
2444    #[inline]
2445    pub fn set_alpha_mod(&mut self, alpha: u8) {
2446        InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2447    }
2448
2449    /// Gets the additional alpha value multiplied into render copy operations.
2450    #[inline]
2451    pub fn alpha_mod(&self) -> u8 {
2452        InternalTexture { raw: self.raw }.alpha_mod()
2453    }
2454
2455    /// Sets the blend mode used for drawing operations (Fill and Line).
2456    #[inline]
2457    pub fn set_blend_mode(&mut self, blend: BlendMode) {
2458        InternalTexture { raw: self.raw }.set_blend_mode(blend)
2459    }
2460
2461    /// Gets the blend mode used for texture copy operations.
2462    #[inline]
2463    pub fn blend_mode(&self) -> BlendMode {
2464        InternalTexture { raw: self.raw }.blend_mode()
2465    }
2466
2467    /// Updates the given texture rectangle with new pixel data.
2468    ///
2469    /// `pitch` is the number of bytes in a row of pixel data, including padding
2470    /// between lines
2471    ///
2472    /// * If `rect` is `None`, the entire texture is updated.
2473    #[inline]
2474    pub fn update<R>(
2475        &mut self,
2476        rect: R,
2477        pixel_data: &[u8],
2478        pitch: usize,
2479    ) -> Result<(), UpdateTextureError>
2480    where
2481        R: Into<Option<Rect>>,
2482    {
2483        InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2484    }
2485
2486    /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data.
2487    #[inline]
2488    pub fn update_yuv<R>(
2489        &mut self,
2490        rect: R,
2491        y_plane: &[u8],
2492        y_pitch: usize,
2493        u_plane: &[u8],
2494        u_pitch: usize,
2495        v_plane: &[u8],
2496        v_pitch: usize,
2497    ) -> Result<(), UpdateTextureYUVError>
2498    where
2499        R: Into<Option<Rect>>,
2500    {
2501        InternalTexture { raw: self.raw }
2502            .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2503    }
2504
2505    /// Locks the texture for **write-only** pixel access.
2506    /// The texture must have been created with streaming access.
2507    ///
2508    /// `F` is a function that is passed the write-only texture buffer,
2509    /// and the pitch of the texture (size of a row in bytes).
2510    /// # Remarks
2511    /// As an optimization, the pixels made available for editing don't
2512    /// necessarily contain the old texture data.
2513    /// This is a write-only operation, and if you need to keep a copy of the
2514    /// texture data you should do that at the application level.
2515    #[inline]
2516    pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2517    where
2518        F: FnOnce(&mut [u8], usize) -> R,
2519        R2: Into<Option<Rect>>,
2520    {
2521        InternalTexture { raw: self.raw }.with_lock(rect, func)
2522    }
2523
2524    /// Binds an OpenGL/ES/ES2 texture to the current
2525    /// context for use with when rendering OpenGL primitives directly.
2526    #[inline]
2527    pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2528        InternalTexture { raw: self.raw }.gl_bind_texture()
2529    }
2530
2531    /// Unbinds an OpenGL/ES/ES2 texture from the current context.
2532    #[inline]
2533    pub unsafe fn gl_unbind_texture(&mut self) {
2534        InternalTexture { raw: self.raw }.gl_unbind_texture()
2535    }
2536
2537    /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context.
2538    #[inline]
2539    pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2540        InternalTexture { raw: self.raw }.gl_with_bind(f)
2541    }
2542
2543    #[inline]
2544    // this can prevent introducing UB until
2545    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
2546    #[allow(clippy::trivially_copy_pass_by_ref)]
2547    pub const fn raw(&self) -> *mut sys::SDL_Texture {
2548        self.raw
2549    }
2550
2551    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
2552    ///
2553    /// ```no_run
2554    /// use sdl2::pixels::PixelFormatEnum;
2555    /// use sdl2::surface::Surface;
2556    /// use sdl2::render::{Canvas, Texture};
2557    /// use sdl2::video::Window;
2558    ///
2559    /// // We init systems.
2560    /// let sdl_context = sdl2::init().expect("failed to init SDL");
2561    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
2562    ///
2563    /// // We create a window.
2564    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
2565    ///     .build()
2566    ///     .expect("failed to build window");
2567    ///
2568    /// // We get the canvas from which we can get the `TextureCreator`.
2569    /// let mut canvas: Canvas<Window> = window.into_canvas()
2570    ///     .build()
2571    ///     .expect("failed to build window's canvas");
2572    /// let texture_creator = canvas.texture_creator();
2573    ///
2574    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
2575    /// let texture = Texture::from_surface(&surface, &texture_creator).unwrap();
2576    /// ```
2577    #[cfg(not(feature = "unsafe_textures"))]
2578    pub fn from_surface<'a, T>(
2579        surface: &Surface,
2580        texture_creator: &'a TextureCreator<T>,
2581    ) -> Result<Texture<'a>, TextureValueError> {
2582        texture_creator.create_texture_from_surface(surface)
2583    }
2584
2585    /// A convenience function for [`TextureCreator::create_texture_from_surface`].
2586    ///
2587    /// ```no_run
2588    /// use sdl2::pixels::PixelFormatEnum;
2589    /// use sdl2::surface::Surface;
2590    /// use sdl2::render::{Canvas, Texture};
2591    /// use sdl2::video::Window;
2592    ///
2593    /// // We init systems.
2594    /// let sdl_context = sdl2::init().expect("failed to init SDL");
2595    /// let video_subsystem = sdl_context.video().expect("failed to get video context");
2596    ///
2597    /// // We create a window.
2598    /// let window = video_subsystem.window("sdl2 demo", 800, 600)
2599    ///     .build()
2600    ///     .expect("failed to build window");
2601    ///
2602    /// // We get the canvas from which we can get the `TextureCreator`.
2603    /// let mut canvas: Canvas<Window> = window.into_canvas()
2604    ///     .build()
2605    ///     .expect("failed to build window's canvas");
2606    /// let texture_creator = canvas.texture_creator();
2607    ///
2608    /// let surface = Surface::new(512, 512, PixelFormatEnum::RGB24).unwrap();
2609    /// let texture = Texture::from_surface(&surface, &texture_creator).unwrap();
2610    /// ```
2611    #[cfg(feature = "unsafe_textures")]
2612    pub fn from_surface<T>(
2613        surface: &Surface,
2614        texture_creator: &TextureCreator<T>,
2615    ) -> Result<Texture, TextureValueError> {
2616        texture_creator.create_texture_from_surface(surface)
2617    }
2618}
2619
2620#[cfg(feature = "unsafe_textures")]
2621impl Texture {
2622    /// Queries the attributes of the texture.
2623    #[inline]
2624    pub fn query(&self) -> TextureQuery {
2625        InternalTexture { raw: self.raw }.query()
2626    }
2627
2628    /// Sets an additional color value multiplied into render copy operations.
2629    #[inline]
2630    pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
2631        InternalTexture { raw: self.raw }.set_color_mod(red, green, blue)
2632    }
2633
2634    /// Gets the additional color value multiplied into render copy operations.
2635    #[inline]
2636    pub fn color_mod(&self) -> (u8, u8, u8) {
2637        InternalTexture { raw: self.raw }.color_mod()
2638    }
2639
2640    /// Sets an additional alpha value multiplied into render copy operations.
2641    #[inline]
2642    pub fn set_alpha_mod(&mut self, alpha: u8) {
2643        InternalTexture { raw: self.raw }.set_alpha_mod(alpha)
2644    }
2645
2646    /// Gets the additional alpha value multiplied into render copy operations.
2647    #[inline]
2648    pub fn alpha_mod(&self) -> u8 {
2649        InternalTexture { raw: self.raw }.alpha_mod()
2650    }
2651
2652    /// Sets the blend mode used for drawing operations (Fill and Line).
2653    #[inline]
2654    pub fn set_blend_mode(&mut self, blend: BlendMode) {
2655        InternalTexture { raw: self.raw }.set_blend_mode(blend)
2656    }
2657
2658    /// Gets the blend mode used for texture copy operations.
2659    #[inline]
2660    pub fn blend_mode(&self) -> BlendMode {
2661        InternalTexture { raw: self.raw }.blend_mode()
2662    }
2663
2664    /// Updates the given texture rectangle with new pixel data.
2665    ///
2666    /// `pitch` is the number of bytes in a row of pixel data, including padding
2667    /// between lines
2668    ///
2669    /// * If `rect` is `None`, the entire texture is updated.
2670    #[inline]
2671    pub fn update<R>(
2672        &mut self,
2673        rect: R,
2674        pixel_data: &[u8],
2675        pitch: usize,
2676    ) -> Result<(), UpdateTextureError>
2677    where
2678        R: Into<Option<Rect>>,
2679    {
2680        InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
2681    }
2682
2683    /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data.
2684    #[inline]
2685    pub fn update_yuv<R>(
2686        &mut self,
2687        rect: R,
2688        y_plane: &[u8],
2689        y_pitch: usize,
2690        u_plane: &[u8],
2691        u_pitch: usize,
2692        v_plane: &[u8],
2693        v_pitch: usize,
2694    ) -> Result<(), UpdateTextureYUVError>
2695    where
2696        R: Into<Option<Rect>>,
2697    {
2698        InternalTexture { raw: self.raw }
2699            .update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
2700    }
2701
2702    /// Locks the texture for **write-only** pixel access.
2703    /// The texture must have been created with streaming access.
2704    ///
2705    /// `F` is a function that is passed the write-only texture buffer,
2706    /// and the pitch of the texture (size of a row in bytes).
2707    /// # Remarks
2708    /// As an optimization, the pixels made available for editing don't
2709    /// necessarily contain the old texture data.
2710    /// This is a write-only operation, and if you need to keep a copy of the
2711    /// texture data you should do that at the application level.
2712    #[inline]
2713    pub fn with_lock<F, R, R2>(&mut self, rect: R2, func: F) -> Result<R, String>
2714    where
2715        F: FnOnce(&mut [u8], usize) -> R,
2716        R2: Into<Option<Rect>>,
2717    {
2718        InternalTexture { raw: self.raw }.with_lock(rect, func)
2719    }
2720
2721    /// Binds an OpenGL/ES/ES2 texture to the current
2722    /// context for use with when rendering OpenGL primitives directly.
2723    #[inline]
2724    pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
2725        InternalTexture { raw: self.raw }.gl_bind_texture()
2726    }
2727
2728    /// Unbinds an OpenGL/ES/ES2 texture from the current context.
2729    #[inline]
2730    pub unsafe fn gl_unbind_texture(&mut self) {
2731        InternalTexture { raw: self.raw }.gl_unbind_texture()
2732    }
2733
2734    /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context.
2735    #[inline]
2736    pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
2737        InternalTexture { raw: self.raw }.gl_with_bind(f)
2738    }
2739
2740    #[inline]
2741    // this can prevent introducing UB until
2742    // https://github.com/rust-lang/rust-clippy/issues/5953 is fixed
2743    #[allow(clippy::trivially_copy_pass_by_ref)]
2744    pub const fn raw(&self) -> *mut sys::SDL_Texture {
2745        self.raw
2746    }
2747}
2748
2749#[derive(Copy, Clone)]
2750pub struct DriverIterator {
2751    length: i32,
2752    index: i32,
2753}
2754
2755// panics if SDL_GetRenderDriverInfo returns a nonzero value,
2756// which should only happen if index is outside the range
2757// 0..SDL_GetNumRenderDrivers()
2758fn get_render_driver_info(index: i32) -> RendererInfo {
2759    let mut out = mem::MaybeUninit::uninit();
2760    let result = unsafe { sys::SDL_GetRenderDriverInfo(index, out.as_mut_ptr()) };
2761    assert_eq!(result, 0);
2762
2763    unsafe { RendererInfo::from_ll(&out.assume_init()) }
2764}
2765
2766impl Iterator for DriverIterator {
2767    type Item = RendererInfo;
2768
2769    #[inline]
2770    #[doc(alias = "SDL_GetRenderDriverInfo")]
2771    fn next(&mut self) -> Option<RendererInfo> {
2772        if self.index >= self.length {
2773            None
2774        } else {
2775            let driver = get_render_driver_info(self.index);
2776            self.index += 1;
2777
2778            Some(driver)
2779        }
2780    }
2781
2782    #[inline]
2783    fn size_hint(&self) -> (usize, Option<usize>) {
2784        let remaining = (self.length - self.index) as usize;
2785        (remaining, Some(remaining))
2786    }
2787
2788    #[inline]
2789    fn nth(&mut self, n: usize) -> Option<RendererInfo> {
2790        use std::convert::TryInto;
2791
2792        self.index = match n.try_into().ok().and_then(|n| self.index.checked_add(n)) {
2793            Some(index) if index < self.length => index,
2794            _ => self.length,
2795        };
2796
2797        self.next()
2798    }
2799}
2800
2801impl DoubleEndedIterator for DriverIterator {
2802    #[inline]
2803    fn next_back(&mut self) -> Option<RendererInfo> {
2804        if self.index >= self.length {
2805            None
2806        } else {
2807            self.length -= 1;
2808
2809            Some(get_render_driver_info(self.length))
2810        }
2811    }
2812
2813    #[inline]
2814    fn nth_back(&mut self, n: usize) -> Option<RendererInfo> {
2815        use std::convert::TryInto;
2816
2817        self.length = match n.try_into().ok().and_then(|n| self.length.checked_sub(n)) {
2818            Some(length) if length > self.index => length,
2819            _ => self.index,
2820        };
2821
2822        self.next_back()
2823    }
2824}
2825
2826impl ExactSizeIterator for DriverIterator {}
2827
2828impl std::iter::FusedIterator for DriverIterator {}
2829
2830/// Gets an iterator of all render drivers compiled into the SDL2 library.
2831#[inline]
2832#[doc(alias = "SDL_GetNumRenderDrivers")]
2833pub fn drivers() -> DriverIterator {
2834    // This function is thread-safe and doesn't require the video subsystem to be initialized.
2835    // The list of drivers are read-only and statically compiled into SDL2, varying by platform.
2836
2837    // SDL_GetNumRenderDrivers can never return a negative value.
2838    DriverIterator {
2839        length: unsafe { sys::SDL_GetNumRenderDrivers() },
2840        index: 0,
2841    }
2842}