use video::{Window, WindowContext};
use surface;
use surface::{Surface, SurfaceRef, SurfaceContext};
use pixels;
use pixels::PixelFormatEnum;
use get_error;
use std::fmt;
use std::error::Error;
#[cfg(not(feature = "unsafe_textures"))]
use std::marker::PhantomData;
use std::mem;
use std::ops::Deref;
use std::ptr;
use std::rc::Rc;
use libc::{c_int, uint32_t, c_double};
use rect::Point;
use rect::Rect;
use std::ffi::CStr;
use num::FromPrimitive;
use std::vec::Vec;
use common::{validate_int, IntegerOrSdlError};
use std::mem::{transmute, uninitialized};
use std::os::raw::c_void;
use sys;
#[derive(Debug)]
pub struct SdlError(String);
#[derive(Debug)]
pub enum TargetRenderError {
SdlError(SdlError),
NotSupported,
}
impl fmt::Display for SdlError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let &SdlError(ref e) = self;
write!(f, "SDL error: {}", e)
}
}
impl Error for SdlError {
fn description(&self) -> &str {
let &SdlError(ref e) = self;
e
}
}
impl fmt::Display for TargetRenderError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::TargetRenderError::*;
match *self {
SdlError(ref e) => e.fmt(f),
NotSupported => write!(f, "The renderer does not support the use of render targets"),
}
}
}
impl Error for TargetRenderError {
fn description(&self) -> &str {
use self::TargetRenderError::*;
match *self {
SdlError(ref e) => e.description(),
NotSupported => "The renderer does not support the use of render targets",
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
#[repr(i32)]
pub enum TextureAccess {
Static = sys::SDL_TextureAccess::SDL_TEXTUREACCESS_STATIC as i32,
Streaming = sys::SDL_TextureAccess::SDL_TEXTUREACCESS_STREAMING as i32,
Target = sys::SDL_TextureAccess::SDL_TEXTUREACCESS_TARGET as i32,
}
impl FromPrimitive for TextureAccess {
fn from_i64(n: i64) -> Option<TextureAccess> {
use self::TextureAccess::*;
let n = n as u32;
Some(match unsafe { transmute::<u32, sys::SDL_TextureAccess>(n) } {
sys::SDL_TextureAccess::SDL_TEXTUREACCESS_STATIC => Static,
sys::SDL_TextureAccess::SDL_TEXTUREACCESS_STREAMING => Streaming,
sys::SDL_TextureAccess::SDL_TEXTUREACCESS_TARGET => Target,
})
}
fn from_u64(n: u64) -> Option<TextureAccess> {
FromPrimitive::from_i64(n as i64)
}
}
#[derive(Clone, Eq, PartialEq, Hash, Debug)]
pub struct RendererInfo {
pub name: &'static str,
pub flags: u32,
pub texture_formats: Vec<PixelFormatEnum>,
pub max_texture_width: u32,
pub max_texture_height: u32,
}
#[repr(i32)]
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub enum BlendMode {
None = sys::SDL_BlendMode::SDL_BLENDMODE_NONE as i32,
Blend = sys::SDL_BlendMode::SDL_BLENDMODE_BLEND as i32,
Add = sys::SDL_BlendMode::SDL_BLENDMODE_ADD as i32,
Mod = sys::SDL_BlendMode::SDL_BLENDMODE_MOD as i32,
Invalid = sys::SDL_BlendMode::SDL_BLENDMODE_INVALID as i32,
}
impl FromPrimitive for BlendMode {
fn from_i64(n: i64) -> Option<BlendMode> {
use self::BlendMode::*;
let n = n as u32;
Some(match unsafe { transmute::<u32, sys::SDL_BlendMode>(n) } {
sys::SDL_BlendMode::SDL_BLENDMODE_NONE => None,
sys::SDL_BlendMode::SDL_BLENDMODE_BLEND => Blend,
sys::SDL_BlendMode::SDL_BLENDMODE_ADD => Add,
sys::SDL_BlendMode::SDL_BLENDMODE_MOD => Mod,
sys::SDL_BlendMode::SDL_BLENDMODE_INVALID => Invalid,
})
}
fn from_u64(n: u64) -> Option<BlendMode> {
FromPrimitive::from_i64(n as i64)
}
}
impl RendererInfo {
pub unsafe fn from_ll(info: &sys::SDL_RendererInfo) -> RendererInfo {
let texture_formats: Vec<PixelFormatEnum> =
info.texture_formats[0..(info.num_texture_formats as usize)]
.iter()
.map(|&format| {
PixelFormatEnum::from_i64(format as i64)
.unwrap_or(PixelFormatEnum::Unknown)
})
.collect();
let name = CStr::from_ptr(info.name as *const _).to_str().unwrap();
RendererInfo {
name: name,
flags: info.flags,
texture_formats: texture_formats,
max_texture_width: info.max_texture_width as u32,
max_texture_height: info.max_texture_height as u32,
}
}
}
pub struct RendererContext<T> {
raw: *mut sys::SDL_Renderer,
_target: Rc<T>,
}
impl<T> Drop for RendererContext<T> {
fn drop(&mut self) {
unsafe {
sys::SDL_DestroyRenderer(self.raw);
};
}
}
impl<T> RendererContext<T> {
pub fn info(&self) -> RendererInfo {
unsafe {
let mut renderer_info_raw = mem::uninitialized();
if sys::SDL_GetRendererInfo(self.raw, &mut renderer_info_raw) != 0 {
panic!();
} else {
RendererInfo::from_ll(&renderer_info_raw)
}
}
}
pub fn raw(&self) -> *mut sys::SDL_Renderer {
self.raw
}
pub unsafe fn from_ll(raw: *mut sys::SDL_Renderer, target: Rc<T>) -> Self {
RendererContext {
raw: raw,
_target: target,
}
}
unsafe fn set_raw_target(&self, raw_texture: *mut sys::SDL_Texture) -> Result<(), SdlError> {
if sys::SDL_SetRenderTarget(self.raw, raw_texture) == 0 {
Ok(())
} else {
Err(SdlError(get_error()))
}
}
unsafe fn get_raw_target(&self) -> *mut sys::SDL_Texture {
sys::SDL_GetRenderTarget(self.raw)
}
}
impl<T: RenderTarget> Deref for Canvas<T> {
type Target = RendererContext<T::Context>;
fn deref(&self) -> &RendererContext<T::Context> {
self.context.as_ref()
}
}
pub trait RenderTarget {
type Context;
}
impl<'s> RenderTarget for Surface<'s> {
type Context = SurfaceContext<'s>;
}
pub struct Canvas<T: RenderTarget> {
target: T,
context: Rc<RendererContext<T::Context>>,
default_pixel_format: PixelFormatEnum,
}
pub type SurfaceCanvas<'s> = Canvas<Surface<'s>>;
impl<'s> Canvas<Surface<'s>> {
pub fn from_surface(surface: surface::Surface<'s>) -> Result<Self, String> {
let raw_renderer = unsafe { sys::SDL_CreateSoftwareRenderer(surface.raw()) };
if !raw_renderer.is_null() {
let context =
Rc::new(unsafe { RendererContext::from_ll(raw_renderer, surface.context()) });
let default_pixel_format = surface.pixel_format_enum();
Ok(Canvas {
target: surface,
context: context,
default_pixel_format: default_pixel_format,
})
} else {
Err(get_error())
}
}
#[inline]
pub fn surface(&self) -> &SurfaceRef {
&self.target
}
#[inline]
pub fn surface_mut(&mut self) -> &mut SurfaceRef {
&mut self.target
}
#[inline]
pub fn into_surface(self) -> Surface<'s> {
self.target
}
pub fn texture_creator(&self) -> TextureCreator<SurfaceContext<'s>> {
TextureCreator {
context: self.context.clone(),
default_pixel_format: self.default_pixel_format,
}
}
}
pub type WindowCanvas = Canvas<Window>;
impl RenderTarget for Window {
type Context = WindowContext;
}
impl Canvas<Window> {
#[inline]
pub fn window(&self) -> &Window {
&self.target
}
#[inline]
pub fn window_mut(&mut self) -> &mut Window {
&mut self.target
}
#[inline]
pub fn into_window(self) -> Window {
self.target
}
#[inline]
pub fn default_pixel_format(&self) -> PixelFormatEnum {
self.window().window_pixel_format()
}
pub fn texture_creator(&self) -> TextureCreator<WindowContext> {
TextureCreator {
context: self.context.clone(),
default_pixel_format: self.default_pixel_format(),
}
}
}
impl<T: RenderTarget> Canvas<T> {
pub fn render_target_supported(&self) -> bool {
unsafe { sys::SDL_RenderTargetSupported(self.context.raw) == sys::SDL_bool::SDL_TRUE }
}
pub fn with_texture_canvas<F>(&mut self, texture: &mut Texture, f: F)
-> Result<(), TargetRenderError> where for<'r> F: FnOnce(&'r mut Canvas<T>,) {
if self.render_target_supported() {
let target = unsafe { self.get_raw_target() };
unsafe { self.set_raw_target(texture.raw) }
.map_err(|e| TargetRenderError::SdlError(e))?;
f(self);
unsafe { self.set_raw_target(target) }
.map_err(|e| TargetRenderError::SdlError(e))?;
Ok(())
} else {
Err(TargetRenderError::NotSupported)
}
}
#[cfg(not(feature = "unsafe_textures"))]
pub fn 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)> {
if self.render_target_supported() {
let target = unsafe { self.get_raw_target() };
for &(ref texture, ref user_context) in textures {
unsafe { self.set_raw_target(texture.raw) }
.map_err(|e| TargetRenderError::SdlError(e))?;
f(self, user_context);
}
unsafe { self.set_raw_target(target) }
.map_err(|e| TargetRenderError::SdlError(e))?;
Ok(())
} else {
Err(TargetRenderError::NotSupported)
}
}
#[cfg(feature = "unsafe_textures")]
pub fn 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)> {
if self.render_target_supported() {
for &(ref texture, ref user_context) in textures {
unsafe { self.set_raw_target(texture.raw) }
.map_err(|e| TargetRenderError::SdlError(e))?;
f(self, &user_context);
}
unsafe { self.set_raw_target(ptr::null_mut()) }
.map_err(|e| TargetRenderError::SdlError(e))?;
Ok(())
} else {
Err(TargetRenderError::NotSupported)
}
}
}
pub struct TextureCreator<T> {
context: Rc<RendererContext<T>>,
default_pixel_format: PixelFormatEnum,
}
pub struct CanvasBuilder {
window: Window,
index: Option<u32>,
renderer_flags: u32,
}
impl CanvasBuilder {
pub fn new(window: Window) -> CanvasBuilder {
CanvasBuilder {
window: window,
index: None,
renderer_flags: 0,
}
}
pub fn build(self) -> Result<WindowCanvas, IntegerOrSdlError> {
use common::IntegerOrSdlError::*;
let index = match self.index {
None => -1,
Some(index) => try!(validate_int(index, "index")),
};
let raw = unsafe { sys::SDL_CreateRenderer(self.window.raw(), index, self.renderer_flags) };
if raw.is_null() {
Err(SdlError(get_error()))
} else {
let context = Rc::new(unsafe { RendererContext::from_ll(raw, self.window.context()) });
let default_pixel_format = self.window.window_pixel_format();
Ok(Canvas {
context: context,
target: self.window,
default_pixel_format: default_pixel_format,
})
}
}
pub fn index(mut self, index: u32) -> CanvasBuilder {
self.index = Some(index);
self
}
pub fn software(mut self) -> CanvasBuilder {
self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_SOFTWARE as u32;
self
}
pub fn accelerated(mut self) -> CanvasBuilder {
self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_ACCELERATED as u32;
self
}
pub fn present_vsync(mut self) -> CanvasBuilder {
self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_PRESENTVSYNC as u32;
self
}
pub fn target_texture(mut self) -> CanvasBuilder {
self.renderer_flags |= sys::SDL_RendererFlags::SDL_RENDERER_TARGETTEXTURE as u32;
self
}
}
#[derive(Debug)]
pub enum TextureValueError {
WidthOverflows(u32),
HeightOverflows(u32),
WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
SdlError(String),
}
impl fmt::Display for TextureValueError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::TextureValueError::*;
match *self {
WidthOverflows(value) => write!(f, "Integer width overflows ({})", value),
HeightOverflows(value) => write!(f, "Integer height overflows ({})", value),
WidthMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"Texture width must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
SdlError(ref e) => write!(f, "SDL error: {}", e),
}
}
}
impl Error for TextureValueError {
fn description(&self) -> &str {
use self::TextureValueError::*;
match *self {
WidthOverflows(_) => "texture width overflow",
HeightOverflows(_) => "texture height overflow",
WidthMustBeMultipleOfTwoForFormat(..) => "texture width must be multiple of two",
SdlError(ref e) => e,
}
}
}
fn ll_create_texture(context: *mut sys::SDL_Renderer,
pixel_format: PixelFormatEnum,
access: TextureAccess,
width: u32,
height: u32)
-> Result<*mut sys::SDL_Texture, TextureValueError> {
use self::TextureValueError::*;
let w = match validate_int(width, "width") {
Ok(w) => w,
Err(_) => return Err(WidthOverflows(width)),
};
let h = match validate_int(height, "height") {
Ok(h) => h,
Err(_) => return Err(HeightOverflows(height)),
};
match pixel_format {
PixelFormatEnum::YV12 |
PixelFormatEnum::IYUV => {
if w % 2 != 0 || h % 2 != 0 {
return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format));
}
}
_ => (),
};
Ok(unsafe {
sys::SDL_CreateTexture(context, pixel_format as uint32_t, access as c_int, w, h)
})
}
impl<T> TextureCreator<T> {
pub fn raw(&self) -> *mut sys::SDL_Renderer {
self.context.raw()
}
pub fn default_pixel_format(&self) -> PixelFormatEnum {
self.default_pixel_format
}
pub fn create_texture<F>(&self,
format: F,
access: TextureAccess,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
use self::TextureValueError::*;
let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
if result.is_null() {
Err(SdlError(get_error()))
} else {
unsafe { Ok(self.raw_create_texture(result)) }
}
}
#[inline]
pub fn create_texture_static<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Static, width, height)
}
#[inline]
pub fn create_texture_streaming<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Streaming, width, height)
}
#[inline]
pub fn create_texture_target<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Target, width, height)
}
pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>
(&self,
surface: S)
-> Result<Texture, TextureValueError> {
use self::TextureValueError::*;
let result =
unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
if result.is_null() {
Err(SdlError(get_error()))
} else {
unsafe { Ok(self.raw_create_texture(result)) }
}
}
#[cfg(not(feature = "unsafe_textures"))]
#[inline]
pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
Texture {
raw: raw,
_marker: PhantomData,
}
}
#[cfg(feature = "unsafe_textures")]
pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
Texture {
raw: raw,
}
}
}
impl<T: RenderTarget> Canvas<T> {
pub fn raw(&self) -> *mut sys::SDL_Renderer {
self.context.raw()
}
pub fn set_draw_color(&mut self, color: pixels::Color) {
let (r, g, b, a) = color.rgba();
let ret = unsafe { sys::SDL_SetRenderDrawColor(self.raw, r, g, b, a) };
if ret != 0 {
panic!(get_error())
}
}
pub fn draw_color(&self) -> pixels::Color {
let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
let ret =
unsafe { sys::SDL_GetRenderDrawColor(self.context.raw, &mut r, &mut g, &mut b, &mut a) };
if ret != 0 {
panic!(get_error())
} else {
pixels::Color::RGBA(r, g, b, a)
}
}
pub fn set_blend_mode(&mut self, blend: BlendMode) {
let ret = unsafe {
sys::SDL_SetRenderDrawBlendMode(self.context.raw, transmute(blend as u32))
};
if ret != 0 {
panic!(get_error())
}
}
pub fn blend_mode(&self) -> BlendMode {
let mut blend: sys::SDL_BlendMode;
unsafe { blend = uninitialized(); }
let ret = unsafe { sys::SDL_GetRenderDrawBlendMode(self.context.raw, &mut blend) };
if ret != 0 {
panic!(get_error())
} else {
FromPrimitive::from_i64(blend as i64).unwrap()
}
}
pub fn clear(&mut self) {
let ret = unsafe { sys::SDL_RenderClear(self.context.raw) };
if ret != 0 {
panic!("Could not clear: {}", get_error())
}
}
pub fn present(&mut self) {
unsafe { sys::SDL_RenderPresent(self.context.raw) }
}
pub fn output_size(&self) -> Result<(u32, u32), String> {
let mut width = 0;
let mut height = 0;
let result =
unsafe { sys::SDL_GetRendererOutputSize(self.context.raw, &mut width, &mut height) };
if result == 0 {
Ok((width as u32, height as u32))
} else {
Err(get_error())
}
}
pub fn set_logical_size(&mut self, width: u32, height: u32) -> Result<(), IntegerOrSdlError> {
use common::IntegerOrSdlError::*;
let width = try!(validate_int(width, "width"));
let height = try!(validate_int(height, "height"));
let result = unsafe { sys::SDL_RenderSetLogicalSize(self.context.raw, width, height) };
match result {
0 => Ok(()),
_ => Err(SdlError(get_error())),
}
}
pub fn logical_size(&self) -> (u32, u32) {
let mut width = 0;
let mut height = 0;
unsafe { sys::SDL_RenderGetLogicalSize(self.context.raw, &mut width, &mut height) };
(width as u32, height as u32)
}
pub fn set_viewport<R: Into<Option<Rect>>>(&mut self, rect: R) {
let ptr = match rect.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
};
let ret = unsafe { sys::SDL_RenderSetViewport(self.context.raw, ptr) };
if ret != 0 {
panic!("Could not set viewport: {}", get_error())
}
}
pub fn viewport(&self) -> Rect {
let mut rect = unsafe { mem::uninitialized() };
unsafe { sys::SDL_RenderGetViewport(self.context.raw, &mut rect) };
Rect::from_ll(rect)
}
pub fn set_clip_rect<R: Into<Option<Rect>>>(&mut self, rect: R) {
let ret = unsafe {
sys::SDL_RenderSetClipRect(self.context.raw,
match rect.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
})
};
if ret != 0 {
panic!("Could not set clip rect: {}", get_error())
}
}
pub fn clip_rect(&self) -> Option<Rect> {
let mut raw = unsafe { mem::uninitialized() };
unsafe { sys::SDL_RenderGetClipRect(self.context.raw, &mut raw) };
if raw.w == 0 || raw.h == 0 {
None
} else {
Some(Rect::from_ll(raw))
}
}
pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) -> Result<(), String> {
let ret = unsafe { sys::SDL_RenderSetScale(self.context.raw, scale_x, scale_y) };
if ret != 0 { Err(get_error()) } else { Ok(()) }
}
pub fn scale(&self) -> (f32, f32) {
let mut scale_x = 0.0;
let mut scale_y = 0.0;
unsafe { sys::SDL_RenderGetScale(self.context.raw, &mut scale_x, &mut scale_y) };
(scale_x, scale_y)
}
pub fn draw_point<P: Into<Point>>(&mut self, point: P) -> Result<(), String> {
let point = point.into();
let result = unsafe { sys::SDL_RenderDrawPoint(self.context.raw, point.x(), point.y()) };
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn draw_points<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
let points = points.into();
let result = unsafe {
sys::SDL_RenderDrawPoints(self.context.raw,
Point::raw_slice(points),
points.len() as c_int)
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn draw_line<P1: Into<Point>, P2: Into<Point>>(&mut self,
start: P1,
end: P2)
-> Result<(), String> {
let start = start.into();
let end = end.into();
let result = unsafe {
sys::SDL_RenderDrawLine(self.context.raw, start.x(), start.y(), end.x(), end.y())
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn draw_lines<'a, P: Into<&'a [Point]>>(&mut self, points: P) -> Result<(), String> {
let points = points.into();
let result = unsafe {
sys::SDL_RenderDrawLines(self.context.raw,
Point::raw_slice(points),
points.len() as c_int)
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn draw_rect(&mut self, rect: Rect) -> Result<(), String> {
let result = unsafe { sys::SDL_RenderDrawRect(self.context.raw, rect.raw()) };
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn draw_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
let result = unsafe {
sys::SDL_RenderDrawRects(self.context.raw,
Rect::raw_slice(rects),
rects.len() as c_int)
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn fill_rect<R: Into<Option<Rect>>>(&mut self, rect: R) -> Result<(), String> {
let result = unsafe {
sys::SDL_RenderFillRect(self.context.raw,
rect.into()
.as_ref()
.map(|r| r.raw())
.unwrap_or(ptr::null()))
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn fill_rects(&mut self, rects: &[Rect]) -> Result<(), String> {
let result = unsafe {
sys::SDL_RenderFillRects(self.context.raw,
Rect::raw_slice(rects),
rects.len() as c_int)
};
if result != 0 {
Err(get_error())
} else {
Ok(())
}
}
pub fn copy<R1, R2>(&mut self, texture: &Texture, src: R1, dst: R2) -> Result<(), String>
where R1: Into<Option<Rect>>,
R2: Into<Option<Rect>>
{
let ret = unsafe {
sys::SDL_RenderCopy(self.context.raw,
texture.raw,
match src.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
},
match dst.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
})
};
if ret != 0 { Err(get_error()) } else { Ok(()) }
}
pub fn 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>>
{
use sys::SDL_RendererFlip::*;
let flip = unsafe { match (flip_horizontal, flip_vertical) {
(false, false) => SDL_FLIP_NONE,
(true, false) => SDL_FLIP_HORIZONTAL,
(false, true) => SDL_FLIP_VERTICAL,
(true, true) => transmute::<u32, sys::SDL_RendererFlip>(
transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_HORIZONTAL) |
transmute::<sys::SDL_RendererFlip, u32>(SDL_FLIP_VERTICAL)
),
}};
let ret = unsafe {
sys::SDL_RenderCopyEx(self.context.raw,
texture.raw,
match src.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
},
match dst.into() {
Some(ref rect) => rect.raw(),
None => ptr::null(),
},
angle as c_double,
match center.into() {
Some(ref point) => point.raw(),
None => ptr::null(),
},
flip)
};
if ret != 0 { Err(get_error()) } else { Ok(()) }
}
pub fn read_pixels<R: Into<Option<Rect>>>(&self,
rect: R,
format: pixels::PixelFormatEnum)
-> Result<Vec<u8>, String> {
unsafe {
let rect = rect.into();
let (actual_rect, w, h) = match rect {
Some(ref rect) => (rect.raw(), rect.width() as usize, rect.height() as usize),
None => {
let (w, h) = try!(self.output_size());
(ptr::null(), w as usize, h as usize)
}
};
let pitch = w * format.byte_size_per_pixel();
let size = format.byte_size_of_pixels(w * h);
let mut pixels = Vec::with_capacity(size);
pixels.set_len(size);
let ret = {
sys::SDL_RenderReadPixels(self.context.raw,
actual_rect,
format as uint32_t,
pixels.as_mut_ptr() as *mut c_void,
pitch as c_int)
};
if ret == 0 {
Ok(pixels)
} else {
Err(get_error())
}
}
}
#[cfg(feature = "unsafe_textures")]
pub fn create_texture<F>(&self,
format: F,
access: TextureAccess,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
use self::TextureValueError::*;
let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format);
let result = ll_create_texture(self.context.raw(), format, access, width, height)?;
if result.is_null() {
Err(SdlError(get_error()))
} else {
unsafe { Ok(self.raw_create_texture(result)) }
}
}
#[cfg(feature = "unsafe_textures")]
#[inline]
pub fn create_texture_static<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Static, width, height)
}
#[cfg(feature = "unsafe_textures")]
#[inline]
pub fn create_texture_streaming<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Streaming, width, height)
}
#[cfg(feature = "unsafe_textures")]
#[inline]
pub fn create_texture_target<F>(&self,
format: F,
width: u32,
height: u32)
-> Result<Texture, TextureValueError>
where F: Into<Option<PixelFormatEnum>>
{
self.create_texture(format, TextureAccess::Target, width, height)
}
#[cfg(feature = "unsafe_textures")]
pub fn create_texture_from_surface<S: AsRef<SurfaceRef>>
(&self,
surface: S)
-> Result<Texture, TextureValueError> {
use self::TextureValueError::*;
let result =
unsafe { sys::SDL_CreateTextureFromSurface(self.context.raw, surface.as_ref().raw()) };
if result.is_null() {
Err(SdlError(get_error()))
} else {
unsafe { Ok(self.raw_create_texture(result)) }
}
}
#[cfg(feature = "unsafe_textures")]
pub unsafe fn raw_create_texture(&self, raw: *mut sys::SDL_Texture) -> Texture {
Texture {
raw: raw,
}
}
}
#[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)]
pub struct TextureQuery {
pub format: pixels::PixelFormatEnum,
pub access: TextureAccess,
pub width: u32,
pub height: u32,
}
#[cfg(feature = "unsafe_textures")]
pub struct Texture {
raw: *mut sys::SDL_Texture,
}
#[cfg(not(feature = "unsafe_textures"))]
pub struct Texture<'r> {
raw: *mut sys::SDL_Texture,
_marker: PhantomData<&'r ()>,
}
#[cfg(not(feature = "unsafe_textures"))]
impl<'r> Drop for Texture<'r> {
fn drop(&mut self) {
unsafe {
sys::SDL_DestroyTexture(self.raw);
}
}
}
#[cfg(feature = "unsafe_textures")]
impl Texture {
pub unsafe fn destroy(self) {
sys::SDL_DestroyTexture(self.raw)
}
}
#[derive(Debug)]
pub enum UpdateTextureError {
PitchOverflows(usize),
PitchMustBeMultipleOfTwoForFormat(usize, PixelFormatEnum),
XMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
YMustBeMultipleOfTwoForFormat(i32, PixelFormatEnum),
WidthMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
HeightMustBeMultipleOfTwoForFormat(u32, PixelFormatEnum),
SdlError(String),
}
impl fmt::Display for UpdateTextureError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::UpdateTextureError::*;
match *self {
PitchOverflows(value) => write!(f, "Pitch overflows ({})", value),
PitchMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"Pitch must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
XMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"X must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
YMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"Y must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
WidthMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"Width must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
HeightMustBeMultipleOfTwoForFormat(value, format) => {
write!(f,
"Height must be multiple of two for pixel format '{:?}' ({})",
format,
value)
}
SdlError(ref e) => write!(f, "SDL error: {}", e),
}
}
}
impl Error for UpdateTextureError {
fn description(&self) -> &str {
use self::UpdateTextureError::*;
match *self {
PitchOverflows(_) => "pitch overflow",
PitchMustBeMultipleOfTwoForFormat(..) => "pitch must be multiple of two",
XMustBeMultipleOfTwoForFormat(..) => "x must be multiple of two",
YMustBeMultipleOfTwoForFormat(..) => "y must be multiple of two",
WidthMustBeMultipleOfTwoForFormat(..) => "width must be multiple of two",
HeightMustBeMultipleOfTwoForFormat(..) => "height must be multiple of two",
SdlError(ref e) => e,
}
}
}
#[derive(Debug)]
pub enum UpdateTextureYUVError {
PitchOverflows { plane: &'static str, value: usize },
InvalidPlaneLength {
plane: &'static str,
length: usize,
pitch: usize,
height: usize,
},
XMustBeMultipleOfTwoForFormat(i32),
YMustBeMultipleOfTwoForFormat(i32),
WidthMustBeMultipleOfTwoForFormat(u32),
HeightMustBeMultipleOfTwoForFormat(u32),
RectNotInsideTexture(Rect),
SdlError(String),
}
impl fmt::Display for UpdateTextureYUVError {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
use self::UpdateTextureYUVError::*;
match *self {
PitchOverflows { plane, value } => {
write!(f, "Pitch overflows on {} plane ({})", plane, value)
}
InvalidPlaneLength {
plane,
length,
pitch,
height,
} => {
write!(f,
"The {} plane is wrong length ({}, should be {} * {})",
plane,
length,
pitch,
height)
}
XMustBeMultipleOfTwoForFormat(value) => {
write!(f, "X must be multiple of two ({})", value)
}
YMustBeMultipleOfTwoForFormat(value) => {
write!(f, "Y must be multiple of two ({})", value)
}
WidthMustBeMultipleOfTwoForFormat(value) => {
write!(f, "Width must be multiple of two ({})", value)
}
HeightMustBeMultipleOfTwoForFormat(value) => {
write!(f, "Height must be multiple of two ({})", value)
}
RectNotInsideTexture(_) => write!(f, "Rect must be inside texture"),
SdlError(ref e) => write!(f, "SDL error: {}", e),
}
}
}
impl Error for UpdateTextureYUVError {
fn description(&self) -> &str {
use self::UpdateTextureYUVError::*;
match *self {
PitchOverflows { .. } => "pitch overflow",
InvalidPlaneLength { .. } => "invalid plane length",
XMustBeMultipleOfTwoForFormat(_) => "x must be multiple of two",
YMustBeMultipleOfTwoForFormat(_) => "y must be multiple of two",
WidthMustBeMultipleOfTwoForFormat(_) => "width must be multiple of two",
HeightMustBeMultipleOfTwoForFormat(_) => "height must be multiple of two",
RectNotInsideTexture(_) => "rect must be inside texture",
SdlError(ref e) => e,
}
}
}
struct InternalTexture {
raw: *mut sys::SDL_Texture,
}
impl InternalTexture {
pub fn query(&self) -> TextureQuery {
let mut format = 0;
let mut access = 0;
let mut width = 0;
let mut height = 0;
let ret = unsafe {
sys::SDL_QueryTexture(self.raw, &mut format, &mut access, &mut width, &mut height)
};
if ret != 0 {
panic!(get_error())
} else {
TextureQuery {
format: FromPrimitive::from_i64(format as i64).unwrap(),
access: FromPrimitive::from_i64(access as i64).unwrap(),
width: width as u32,
height: height as u32,
}
}
}
pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
let ret = unsafe { sys::SDL_SetTextureColorMod(self.raw, red, green, blue) };
if ret != 0 {
panic!("Error setting color mod: {}", get_error())
}
}
pub fn color_mod(&self) -> (u8, u8, u8) {
let (mut r, mut g, mut b) = (0, 0, 0);
let ret = unsafe { sys::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) };
if ret != 0 {
panic!(get_error())
} else {
(r, g, b)
}
}
pub fn set_alpha_mod(&mut self, alpha: u8) {
let ret = unsafe { sys::SDL_SetTextureAlphaMod(self.raw, alpha) };
if ret != 0 {
panic!("Error setting alpha mod: {}", get_error())
}
}
pub fn alpha_mod(&self) -> u8 {
let mut alpha = 0;
let ret = unsafe { sys::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
if ret != 0 { panic!(get_error()) } else { alpha }
}
pub fn set_blend_mode(&mut self, blend: BlendMode) {
let ret = unsafe {
sys::SDL_SetTextureBlendMode(self.raw, transmute(blend as u32))
};
if ret != 0 {
panic!("Error setting blend: {}", get_error())
}
}
pub fn blend_mode(&self) -> BlendMode {
let mut blend: sys::SDL_BlendMode;
unsafe { blend = uninitialized(); }
let ret = unsafe { sys::SDL_GetTextureBlendMode(self.raw, &mut blend) };
if ret != 0 {
panic!(get_error())
} else {
FromPrimitive::from_i64(blend as i64).unwrap()
}
}
pub fn update<R>(&mut self,
rect: R,
pixel_data: &[u8],
pitch: usize)
-> Result<(), UpdateTextureError>
where R: Into<Option<Rect>>
{
use self::UpdateTextureError::*;
let rect = rect.into();
let rect_raw_ptr = match rect {
Some(ref rect) => rect.raw(),
None => ptr::null(),
};
let TextureQuery { format, .. } = self.query();
match format {
PixelFormatEnum::YV12 |
PixelFormatEnum::IYUV => {
match rect {
Some(r) => {
if r.x() % 2 != 0 {
return Err(XMustBeMultipleOfTwoForFormat(r.x(), format));
} else if r.y() % 2 != 0 {
return Err(YMustBeMultipleOfTwoForFormat(r.y(), format));
} else if r.width() % 2 != 0 {
return Err(WidthMustBeMultipleOfTwoForFormat(r.width(), format));
} else if r.height() % 2 != 0 {
return Err(HeightMustBeMultipleOfTwoForFormat(r.height(), format));
}
}
_ => {}
};
if pitch % 2 != 0 {
return Err(PitchMustBeMultipleOfTwoForFormat(pitch, format));
}
}
_ => {}
}
let pitch = match validate_int(pitch as u32, "pitch") {
Ok(p) => p,
Err(_) => return Err(PitchOverflows(pitch)),
};
let result = unsafe {
sys::SDL_UpdateTexture(self.raw,
rect_raw_ptr,
pixel_data.as_ptr() as *const _,
pitch)
};
if result != 0 {
Err(SdlError(get_error()))
} else {
Ok(())
}
}
pub fn 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>>
{
use self::UpdateTextureYUVError::*;
let rect = rect.into();
let rect_raw_ptr = match rect {
Some(ref rect) => rect.raw(),
None => ptr::null(),
};
match rect {
Some(ref r) => {
if r.x() % 2 != 0 {
return Err(XMustBeMultipleOfTwoForFormat(r.x()));
} else if r.y() % 2 != 0 {
return Err(YMustBeMultipleOfTwoForFormat(r.y()));
} else if r.width() % 2 != 0 {
return Err(WidthMustBeMultipleOfTwoForFormat(r.width()));
} else if r.height() % 2 != 0 {
return Err(HeightMustBeMultipleOfTwoForFormat(r.height()));
}
}
_ => {}
};
let tex_info = self.query();
if let Some(ref r) = rect {
let tex_rect = Rect::new(0, 0, tex_info.width, tex_info.height);
let inside = match r.intersection(tex_rect) {
Some(intersection) => intersection == *r,
None => false,
};
if !inside {
return Err(RectNotInsideTexture(*r));
}
}
let height = match rect {
Some(ref r) => r.height(),
None => tex_info.height,
} as usize;
if y_plane.len() != (y_pitch * height) {
return Err(InvalidPlaneLength {
plane: "y",
length: y_plane.len(),
pitch: y_pitch,
height: height,
});
}
if u_plane.len() != (u_pitch * height / 2) {
return Err(InvalidPlaneLength {
plane: "u",
length: u_plane.len(),
pitch: u_pitch,
height: height / 2,
});
}
if v_plane.len() != (v_pitch * height / 2) {
return Err(InvalidPlaneLength {
plane: "v",
length: v_plane.len(),
pitch: v_pitch,
height: height / 2,
});
}
let y_pitch = match validate_int(y_pitch as u32, "y_pitch") {
Ok(p) => p,
Err(_) => {
return Err(PitchOverflows {
plane: "y",
value: y_pitch,
})
}
};
let u_pitch = match validate_int(u_pitch as u32, "u_pitch") {
Ok(p) => p,
Err(_) => {
return Err(PitchOverflows {
plane: "u",
value: u_pitch,
})
}
};
let v_pitch = match validate_int(v_pitch as u32, "v_pitch") {
Ok(p) => p,
Err(_) => {
return Err(PitchOverflows {
plane: "v",
value: v_pitch,
})
}
};
let result = unsafe {
sys::SDL_UpdateYUVTexture(self.raw,
rect_raw_ptr,
y_plane.as_ptr(),
y_pitch,
u_plane.as_ptr(),
u_pitch,
v_plane.as_ptr(),
v_pitch)
};
if result != 0 {
Err(SdlError(get_error()))
} else {
Ok(())
}
}
pub fn 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>>
{
let loaded = unsafe {
let q = self.query();
let mut pixels = ptr::null_mut();
let mut pitch = 0;
let (rect_raw_ptr, height) = match rect.into() {
Some(ref rect) => (rect.raw(), rect.height() as usize),
None => (ptr::null(), q.height as usize),
};
let ret = sys::SDL_LockTexture(self.raw, rect_raw_ptr, &mut pixels, &mut pitch);
if ret == 0 {
let size = q.format
.byte_size_from_pitch_and_height(pitch as usize, height);
Ok((::std::slice::from_raw_parts_mut(pixels as *mut u8, size), pitch))
} else {
Err(get_error())
}
};
match loaded {
Ok((interior, pitch)) => {
let result;
unsafe {
result = func(interior, pitch as usize);
sys::SDL_UnlockTexture(self.raw);
}
Ok(result)
}
Err(e) => Err(e),
}
}
pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
let mut texw = 0.0;
let mut texh = 0.0;
if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
(texw, texh)
} else {
panic!("OpenGL texture binding not supported");
}
}
pub unsafe fn gl_unbind_texture(&mut self) {
if sys::SDL_GL_UnbindTexture(self.raw) != 0 {
panic!("OpenGL texture unbinding not supported");
}
}
pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
unsafe {
let mut texw = 0.0;
let mut texh = 0.0;
if sys::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
let return_value = f(texw, texh);
if sys::SDL_GL_UnbindTexture(self.raw) == 0 {
return_value
} else {
panic!();
}
} else {
panic!("OpenGL texture binding not supported");
}
}
}
}
#[cfg(not(feature = "unsafe_textures"))]
impl<'r> Texture<'r> {
#[inline]
pub fn query(&self) -> TextureQuery {
InternalTexture{ raw: self.raw }.query()
}
#[inline]
pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
InternalTexture{ raw: self.raw }.set_color_mod(red, green, blue)
}
#[inline]
pub fn color_mod(&self) -> (u8, u8, u8) {
InternalTexture{ raw: self.raw }.color_mod()
}
#[inline]
pub fn set_alpha_mod(&mut self, alpha: u8) {
InternalTexture{ raw: self.raw }.set_alpha_mod(alpha)
}
#[inline]
pub fn alpha_mod(&self) -> u8 {
InternalTexture{ raw: self.raw }.alpha_mod()
}
#[inline]
pub fn set_blend_mode(&mut self, blend: BlendMode) {
InternalTexture{ raw: self.raw }.set_blend_mode(blend)
}
#[inline]
pub fn blend_mode(&self) -> BlendMode {
InternalTexture{ raw: self.raw }.blend_mode()
}
#[inline]
pub fn update<R>(&mut self,
rect: R,
pixel_data: &[u8],
pitch: usize)
-> Result<(), UpdateTextureError>
where R: Into<Option<Rect>> {
InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
}
#[inline]
pub fn 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>> {
InternalTexture { raw: self.raw }.update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
}
#[inline]
pub fn 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>>
{
InternalTexture { raw: self.raw }.with_lock(rect, func)
}
#[inline]
pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
InternalTexture { raw: self.raw }.gl_bind_texture()
}
#[inline]
pub unsafe fn gl_unbind_texture(&mut self) {
InternalTexture { raw: self.raw }.gl_unbind_texture()
}
#[inline]
pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
InternalTexture { raw: self.raw }.gl_with_bind(f)
}
#[inline]
pub fn raw(&self) -> *mut sys::SDL_Texture {
self.raw
}
}
#[cfg(feature = "unsafe_textures")]
impl<> Texture<> {
#[inline]
pub fn query(&self) -> TextureQuery {
InternalTexture{ raw: self.raw }.query()
}
#[inline]
pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
InternalTexture{ raw: self.raw }.set_color_mod(red, green, blue)
}
#[inline]
pub fn color_mod(&self) -> (u8, u8, u8) {
InternalTexture{ raw: self.raw }.color_mod()
}
#[inline]
pub fn set_alpha_mod(&mut self, alpha: u8) {
InternalTexture{ raw: self.raw }.set_alpha_mod(alpha)
}
#[inline]
pub fn alpha_mod(&self) -> u8 {
InternalTexture{ raw: self.raw }.alpha_mod()
}
#[inline]
pub fn set_blend_mode(&mut self, blend: BlendMode) {
InternalTexture{ raw: self.raw }.set_blend_mode(blend)
}
#[inline]
pub fn blend_mode(&self) -> BlendMode {
InternalTexture{ raw: self.raw }.blend_mode()
}
#[inline]
pub fn update<R>(&mut self,
rect: R,
pixel_data: &[u8],
pitch: usize)
-> Result<(), UpdateTextureError>
where R: Into<Option<Rect>> {
InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch)
}
#[inline]
pub fn 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>> {
InternalTexture { raw: self.raw }.update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch)
}
#[inline]
pub fn 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>>
{
InternalTexture { raw: self.raw }.with_lock(rect, func)
}
#[inline]
pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
InternalTexture { raw: self.raw }.gl_bind_texture()
}
#[inline]
pub unsafe fn gl_unbind_texture(&mut self) {
InternalTexture { raw: self.raw }.gl_unbind_texture()
}
#[inline]
pub fn gl_with_bind<R, F: FnOnce(f32, f32) -> R>(&mut self, f: F) -> R {
InternalTexture { raw: self.raw }.gl_with_bind(f)
}
#[inline]
pub fn raw(&self) -> *mut sys::SDL_Texture {
self.raw
}
}
#[derive(Copy, Clone)]
pub struct DriverIterator {
length: i32,
index: i32,
}
impl Iterator for DriverIterator {
type Item = RendererInfo;
#[inline]
fn next(&mut self) -> Option<RendererInfo> {
if self.index >= self.length {
None
} else {
let mut out = unsafe { mem::uninitialized() };
let result = unsafe { sys::SDL_GetRenderDriverInfo(self.index, &mut out) == 0 };
assert!(result, 0);
self.index += 1;
unsafe { Some(RendererInfo::from_ll(&out)) }
}
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
let l = self.length as usize;
(l, Some(l))
}
}
impl ExactSizeIterator for DriverIterator {}
#[inline]
pub fn drivers() -> DriverIterator {
DriverIterator {
length: unsafe { sys::SDL_GetNumRenderDrivers() },
index: 0,
}
}