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