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