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