use event::EventPump;
use video::{Window, WindowProperties, WindowPropertiesGetters};
use surface;
use surface::Surface;
use pixels;
use pixels::PixelFormatEnum;
use get_error;
use SdlResult;
use std::mem;
use std::ptr;
use libc::{c_int, uint32_t, c_double, c_void};
use rect::Point;
use rect::Rect;
use std::cell::UnsafeCell;
use std::ffi::CStr;
use num::FromPrimitive;
use std::vec::Vec;
use std::rc::Rc;
use sys::render as ll;
#[derive(Copy, Clone, PartialEq)]
pub enum TextureAccess {
Static = ll::SDL_TEXTUREACCESS_STATIC as isize,
Streaming = ll::SDL_TEXTUREACCESS_STREAMING as isize,
Target = ll::SDL_TEXTUREACCESS_TARGET as isize
}
impl FromPrimitive for TextureAccess {
fn from_i64(n: i64) -> Option<TextureAccess> {
use self::TextureAccess::*;
Some( match n as ll::SDL_TextureAccess {
ll::SDL_TEXTUREACCESS_STATIC => Static,
ll::SDL_TEXTUREACCESS_STREAMING => Streaming,
ll::SDL_TEXTUREACCESS_TARGET => Target,
_ => return None,
})
}
fn from_u64(n: u64) -> Option<TextureAccess> { FromPrimitive::from_i64(n as i64) }
}
#[derive(PartialEq)]
pub struct RendererInfo {
pub name: String,
pub flags: u32,
pub texture_formats: Vec<pixels::PixelFormatEnum>,
pub max_texture_width: i32,
pub max_texture_height: i32
}
#[derive(Copy, Clone, PartialEq)]
pub enum BlendMode {
None = ll::SDL_BLENDMODE_NONE as isize,
Blend = ll::SDL_BLENDMODE_BLEND as isize,
Add = ll::SDL_BLENDMODE_ADD as isize,
Mod = ll::SDL_BLENDMODE_MOD as isize
}
impl FromPrimitive for BlendMode {
fn from_i64(n: i64) -> Option<BlendMode> {
use self::BlendMode::*;
Some( match n as ll::SDL_BlendMode {
ll::SDL_BLENDMODE_NONE => None,
ll::SDL_BLENDMODE_BLEND => Blend,
ll::SDL_BLENDMODE_ADD => Add,
ll::SDL_BLENDMODE_MOD => Mod,
_ => return Option::None,
})
}
fn from_u64(n: u64) -> Option<BlendMode> { FromPrimitive::from_i64(n as i64) }
}
impl RendererInfo {
pub unsafe fn from_ll(info: &ll::SDL_RendererInfo) -> RendererInfo {
let texture_formats: Vec<pixels::PixelFormatEnum> = info.texture_formats[0..(info.num_texture_formats as usize)].iter().map(|&format| {
FromPrimitive::from_i64(format as i64).unwrap()
}).collect();
RendererInfo {
name: String::from_utf8_lossy(CStr::from_ptr(info.name).to_bytes()).to_string(),
flags: info.flags,
texture_formats: texture_formats,
max_texture_width: info.max_texture_width as i32,
max_texture_height: info.max_texture_height as i32
}
}
}
pub enum RendererParent<'a> {
Surface(Surface<'a>),
Window(Window)
}
pub struct Renderer<'a> {
raw: *mut ll::SDL_Renderer,
parent: Option<RendererParent<'a>>,
is_alive: Rc<UnsafeCell<bool>>
}
impl<'a> Drop for Renderer<'a> {
fn drop(&mut self) {
unsafe {
*self.is_alive.get() = false;
ll::SDL_DestroyRenderer(self.raw);
};
}
}
pub struct RendererBuilder {
window: Window,
index: i32,
renderer_flags: u32
}
impl RendererBuilder {
pub fn new(window: Window) -> RendererBuilder {
RendererBuilder {
window: window,
index: -1,
renderer_flags: 0
}
}
pub fn build(self) -> SdlResult<Renderer<'static>> {
let raw = unsafe {
ll::SDL_CreateRenderer(self.window.raw(), self.index, self.renderer_flags)
};
if raw.is_null() {
Err(get_error())
} else {
unsafe {
Ok(Renderer::from_ll(raw, RendererParent::Window(self.window)))
}
}
}
pub fn index(mut self, index: i32) -> RendererBuilder {
self.index = index;
self
}
pub fn software(mut self) -> RendererBuilder {
self.renderer_flags |= ll::SDL_RENDERER_SOFTWARE as u32;
self
}
pub fn accelerated(mut self) -> RendererBuilder {
self.renderer_flags |= ll::SDL_RENDERER_ACCELERATED as u32;
self
}
pub fn present_vsync(mut self) -> RendererBuilder {
self.renderer_flags |= ll::SDL_RENDERER_PRESENTVSYNC as u32;
self
}
pub fn target_texture(mut self) -> RendererBuilder {
self.renderer_flags |= ll::SDL_RENDERER_TARGETTEXTURE as u32;
self
}
}
impl<'a> Renderer<'a> {
pub fn from_surface(surface: surface::Surface<'a>) -> SdlResult<Renderer<'a>> {
let raw_renderer = unsafe { ll::SDL_CreateSoftwareRenderer(surface.raw()) };
if raw_renderer != ptr::null_mut() {
unsafe {
Ok(Renderer::from_ll(raw_renderer, RendererParent::Surface(surface)))
}
} else {
Err(get_error())
}
}
pub fn get_info(&self) -> RendererInfo {
unsafe {
let mut renderer_info_raw = mem::uninitialized();
if ll::SDL_GetRendererInfo(self.raw, &mut renderer_info_raw) != 0 {
panic!();
} else {
RendererInfo::from_ll(&renderer_info_raw)
}
}
}
#[inline]
pub fn get_parent(&self) -> &RendererParent { self.parent.as_ref().unwrap() }
#[inline]
pub fn get_parent_as_window(&self) -> Option<&Window> {
match self.get_parent() {
&RendererParent::Window(ref window) => Some(window),
_ => None
}
}
#[inline]
pub fn get_parent_as_surface(&self) -> Option<&Surface> {
match self.get_parent() {
&RendererParent::Surface(ref surface) => Some(surface),
_ => None
}
}
pub fn window_properties<'b>(&'b mut self, event: &'b EventPump) -> Option<WindowProperties<'b>>
{
match self.parent.as_mut() {
Some(&mut RendererParent::Window(ref mut window)) => Some(window.properties(event)),
_ => None
}
}
pub fn window_properties_getters<'b>(&'b self, event: &'b EventPump) -> Option<WindowPropertiesGetters<'b>>
{
match self.parent.as_ref() {
Some(&RendererParent::Window(ref window)) => Some(window.properties_getters(event)),
_ => None
}
}
#[inline]
pub fn unwrap_parent(mut self) -> RendererParent<'a> {
use std::mem;
mem::replace(&mut self.parent, None).unwrap()
}
#[inline]
pub fn unwrap_parent_as_window(self) -> Option<Window> {
match self.unwrap_parent() {
RendererParent::Window(window) => Some(window),
_ => None
}
}
#[inline]
pub fn unwrap_parent_as_surface(self) -> Option<Surface<'a>> {
match self.unwrap_parent() {
RendererParent::Surface(surface) => Some(surface),
_ => None
}
}
pub fn drawer(&mut self) -> RenderDrawer {
RenderDrawer::new(self.raw, &self.is_alive)
}
pub unsafe fn raw(&self) -> *mut ll::SDL_Renderer { self.raw }
pub unsafe fn from_ll(raw: *mut ll::SDL_Renderer, parent: RendererParent)
-> Renderer
{
Renderer {
raw: raw,
parent: Some(parent),
is_alive: Rc::new(UnsafeCell::new(true))
}
}
}
impl<'a> Renderer<'a> {
pub fn create_texture(&self, format: pixels::PixelFormatEnum, access: TextureAccess, size: (i32, i32)) -> SdlResult<Texture> {
let (width, height) = size;
match format {
PixelFormatEnum::YV12 | PixelFormatEnum::IYUV => {
if width % 2 != 0 || height % 2 != 0 {
return Err(format!("The width and height must be multiples-of-two for planar YUV 4:2:0 pixel formats"));
}
},
_ => ()
}
let result = unsafe { ll::SDL_CreateTexture(self.raw, format as uint32_t, access as c_int, width as c_int, height as c_int) };
if result == ptr::null_mut() {
Err(get_error())
} else {
unsafe { Ok(Texture::from_ll(self, result)) }
}
}
pub fn create_texture_static(&self, format: pixels::PixelFormatEnum, size: (i32, i32)) -> SdlResult<Texture> {
self.create_texture(format, TextureAccess::Static, size)
}
pub fn create_texture_streaming(&self, format: pixels::PixelFormatEnum, size: (i32, i32)) -> SdlResult<Texture> {
self.create_texture(format, TextureAccess::Streaming, size)
}
pub fn create_texture_target(&self, format: pixels::PixelFormatEnum, size: (i32, i32)) -> SdlResult<Texture> {
self.create_texture(format, TextureAccess::Target, size)
}
pub fn create_texture_from_surface(&self, surface: &surface::Surface) -> SdlResult<Texture> {
let result = unsafe { ll::SDL_CreateTextureFromSurface(self.raw, surface.raw()) };
if result == ptr::null_mut() {
Err(get_error())
} else {
unsafe { Ok(Texture::from_ll(self, result)) }
}
}
}
pub struct RenderDrawer<'renderer> {
raw: *mut ll::SDL_Renderer,
is_renderer_alive: &'renderer Rc<UnsafeCell<bool>>
}
impl<'renderer> RenderDrawer<'renderer> {
fn new<'l>(raw: *mut ll::SDL_Renderer, is_renderer_alive: &'l Rc<UnsafeCell<bool>>) -> RenderDrawer<'l> {
RenderDrawer {
raw: raw,
is_renderer_alive: is_renderer_alive
}
}
pub fn render_target_supported(&self) -> bool {
unsafe { ll::SDL_RenderTargetSupported(self.raw) == 1 }
}
pub fn render_target(&mut self) -> Option<RenderTarget> {
if self.render_target_supported() {
Some(RenderTarget {
raw: self.raw,
is_renderer_alive: self.is_renderer_alive
})
} else {
None
}
}
}
impl<'renderer> RenderDrawer<'renderer> {
pub fn set_draw_color(&mut self, color: pixels::Color) {
let ret = match color {
pixels::Color::RGB(r, g, b) => {
unsafe { ll::SDL_SetRenderDrawColor(self.raw, r, g, b, 255) }
},
pixels::Color::RGBA(r, g, b, a) => {
unsafe { ll::SDL_SetRenderDrawColor(self.raw, r, g, b, a) }
}
};
if ret != 0 { panic!(get_error()) }
}
pub fn get_draw_color(&self) -> pixels::Color {
let (mut r, mut g, mut b, mut a) = (0, 0, 0, 0);
let ret = unsafe { ll::SDL_GetRenderDrawColor(self.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 { ll::SDL_SetRenderDrawBlendMode(self.raw, FromPrimitive::from_i64(blend as i64).unwrap()) };
if ret != 0 { panic!(get_error()) }
}
pub fn get_blend_mode(&self) -> BlendMode {
let mut blend = 0;
let ret = unsafe { ll::SDL_GetRenderDrawBlendMode(self.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 { ll::SDL_RenderClear(self.raw) };
if ret != 0 { panic!("Could not clear: {}", get_error()) }
}
pub fn present(&mut self) {
unsafe { ll::SDL_RenderPresent(self.raw) }
}
pub fn get_output_size(&self) -> SdlResult<(i32, i32)> {
let mut width = 0;
let mut height = 0;
let result = unsafe { ll::SDL_GetRendererOutputSize(self.raw, &mut width, &mut height) == 0 };
if result {
Ok((width as i32, height as i32))
} else {
Err(get_error())
}
}
pub fn set_logical_size(&mut self, width: i32, height: i32) {
let ret = unsafe { ll::SDL_RenderSetLogicalSize(self.raw, width as c_int, height as c_int) };
if ret != 0 { panic!("Could not set logical size: {}", get_error()) }
}
pub fn get_logical_size(&self) -> (i32, i32) {
let mut width = 0;
let mut height = 0;
unsafe { ll::SDL_RenderGetLogicalSize(self.raw, &mut width, &mut height) };
(width as i32, height as i32)
}
pub fn set_viewport(&mut self, rect: Option<Rect>) {
let ptr = match rect {
Some(ref rect) => rect as *const _,
None => ptr::null()
};
let ret = unsafe { ll::SDL_RenderSetViewport(self.raw, ptr) };
if ret != 0 { panic!("Could not set viewport: {}", get_error()) }
}
pub fn get_viewport(&self) -> Rect {
let mut rect = unsafe { mem::uninitialized() };
unsafe { ll::SDL_RenderGetViewport(self.raw, &mut rect) };
rect
}
pub fn set_clip_rect(&mut self, rect: Option<Rect>) {
let ret = unsafe {
ll::SDL_RenderSetClipRect(
self.raw,
match rect {
Some(ref rect) => rect as *const _,
None => ptr::null()
}
)
};
if ret != 0 { panic!("Could not set clip rect: {}", get_error()) }
}
pub fn get_clip_rect(&self) -> Rect {
let mut rect = unsafe { mem::uninitialized() };
unsafe { ll::SDL_RenderGetClipRect(self.raw, &mut rect) };
rect
}
pub fn set_scale(&mut self, scale_x: f32, scale_y: f32) {
let ret = unsafe { ll::SDL_RenderSetScale(self.raw, scale_x, scale_y) };
if ret != 0 { panic!(get_error()) }
}
pub fn get_scale(&self) -> (f32, f32) {
let mut scale_x = 0.0;
let mut scale_y = 0.0;
unsafe { ll::SDL_RenderGetScale(self.raw, &mut scale_x, &mut scale_y) };
(scale_x, scale_y)
}
pub fn draw_point(&mut self, point: Point) {
unsafe {
if ll::SDL_RenderDrawPoint(self.raw, point.x, point.y) != 0 {
panic!("Error drawing point: {}", get_error())
}
}
}
pub fn draw_points(&mut self, points: &[Point]) {
unsafe {
if ll::SDL_RenderDrawPoints(self.raw, points.as_ptr(), points.len() as c_int) != 0 {
panic!("Error drawing points: {}", get_error())
}
}
}
pub fn draw_line(&mut self, start: Point, end: Point) {
unsafe {
if ll::SDL_RenderDrawLine(self.raw, start.x, start.y, end.x, end.y) != 0 {
panic!("Error drawing line: {}", get_error())
}
}
}
pub fn draw_lines(&mut self, points: &[Point]) {
unsafe {
if ll::SDL_RenderDrawLines(self.raw, points.as_ptr(), points.len() as c_int) != 0 {
panic!("Error drawing lines: {}", get_error())
}
}
}
pub fn draw_rect(&mut self, rect: Rect) {
unsafe {
if ll::SDL_RenderDrawRect(self.raw, &rect) != 0 {
panic!("Error drawing rect: {}", get_error())
}
}
}
pub fn draw_rects(&mut self, rects: &[Rect]) {
unsafe {
if ll::SDL_RenderDrawRects(self.raw, rects.as_ptr(), rects.len() as c_int) != 0 {
panic!("Error drawing rects: {}", get_error())
}
}
}
pub fn fill_rect(&mut self, rect: Rect) {
unsafe {
if ll::SDL_RenderFillRect(self.raw, &rect) != 0 {
panic!("Error filling rect: {}", get_error())
}
}
}
pub fn fill_rects(&mut self, rects: &[Rect]) {
unsafe {
if ll::SDL_RenderFillRects(self.raw, rects.as_ptr(), rects.len() as c_int) != 0 {
panic!("Error filling rects: {}", get_error())
}
}
}
pub fn copy(&mut self, texture: &Texture, src: Option<Rect>, dst: Option<Rect>) {
texture.check_renderer();
let ret = unsafe {
ll::SDL_RenderCopy(
self.raw,
texture.raw,
match src {
Some(ref rect) => rect as *const _,
None => ptr::null()
},
match dst {
Some(ref rect) => rect as *const _,
None => ptr::null()
}
)
};
if ret != 0 {
panic!("Error copying texture: {}", get_error())
}
}
pub fn copy_ex(&mut self, texture: &Texture, src: Option<Rect>, dst: Option<Rect>, angle: f64, center: Option<Point>, (flip_horizontal, flip_vertical): (bool, bool)) {
texture.check_renderer();
let flip = match (flip_horizontal, flip_vertical) {
(false, false) => ll::SDL_FLIP_NONE,
(true, false) => ll::SDL_FLIP_HORIZONTAL,
(false, true) => ll::SDL_FLIP_VERTICAL,
(true, true) => ll::SDL_FLIP_HORIZONTAL | ll::SDL_FLIP_VERTICAL,
};
let ret = unsafe {
ll::SDL_RenderCopyEx(
self.raw,
texture.raw,
match src {
Some(ref rect) => rect as *const _,
None => ptr::null()
},
match dst {
Some(ref rect) => rect as *const _,
None => ptr::null()
},
angle as c_double,
match center {
Some(ref point) => point as *const _,
None => ptr::null()
},
flip
)
};
if ret != 0 {
panic!("Error copying texture (ex): {}", get_error())
}
}
pub fn read_pixels(&self, rect: Option<Rect>, format: pixels::PixelFormatEnum) -> SdlResult<Vec<u8>> {
unsafe {
let (actual_rect, w, h) = match rect {
Some(ref rect) => (rect as *const _, rect.w as usize, rect.h as usize),
None => {
let (w, h) = try!(self.get_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 = {
ll::SDL_RenderReadPixels(self.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())
}
}
}
}
pub struct RenderTarget<'renderer> {
raw: *mut ll::SDL_Renderer,
is_renderer_alive: &'renderer Rc<UnsafeCell<bool>>
}
impl<'renderer> RenderTarget<'renderer> {
pub fn reset(&mut self) -> SdlResult<Option<Texture>> {
unsafe {
let old_texture_raw = ll::SDL_GetRenderTarget(self.raw);
if ll::SDL_SetRenderTarget(self.raw, ptr::null_mut()) == 0 {
Ok(match old_texture_raw.is_null() {
true => None,
false => Some(Texture {
raw: old_texture_raw,
is_renderer_alive: self.is_renderer_alive.clone()
})
})
} else {
Err(get_error())
}
}
}
pub fn set(&mut self, texture: Texture) -> SdlResult<Option<Texture>> {
texture.check_renderer();
unsafe {
let old_texture_raw = ll::SDL_GetRenderTarget(self.raw);
if ll::SDL_SetRenderTarget(self.raw, texture.raw) == 0 {
texture.forget();
Ok(match old_texture_raw.is_null() {
true => None,
false => Some(Texture {
raw: old_texture_raw,
is_renderer_alive: self.is_renderer_alive.clone()
})
})
} else {
Err(get_error())
}
}
}
pub fn create_and_set(&mut self, format: pixels::PixelFormatEnum, width: i32, height: i32) -> SdlResult<Option<Texture>> {
let new_texture_raw = unsafe {
let access = ll::SDL_TEXTUREACCESS_TARGET;
ll::SDL_CreateTexture(self.raw, format as uint32_t, access as c_int, width as c_int, height as c_int)
};
if new_texture_raw == ptr::null_mut() {
Err(get_error())
} else {
unsafe {
let old_texture_raw = ll::SDL_GetRenderTarget(self.raw);
if ll::SDL_SetRenderTarget(self.raw, new_texture_raw) == 0 {
Ok(match old_texture_raw.is_null() {
true => None,
false => Some(Texture {
raw: old_texture_raw,
is_renderer_alive: self.is_renderer_alive.clone()
})
})
} else {
Err(get_error())
}
}
}
}
}
#[derive(Copy, Clone)]
pub struct TextureQuery {
pub format: pixels::PixelFormatEnum,
pub access: TextureAccess,
pub width: i32,
pub height: i32
}
pub struct Texture {
raw: *mut ll::SDL_Texture,
is_renderer_alive: Rc<UnsafeCell<bool>>
}
impl Drop for Texture {
fn drop(&mut self) {
unsafe {
if *self.is_renderer_alive.get() {
ll::SDL_DestroyTexture(self.raw);
}
}
}
}
impl Texture {
#[inline]
fn check_renderer(&self) {
let alive = unsafe { *self.is_renderer_alive.get() };
if !alive {
panic!("renderer has been destroyed; cannot use Texture");
}
}
fn forget(self) {
unsafe {
let _is_renderer_alive: Rc<UnsafeCell<bool>> = mem::transmute_copy(&self.is_renderer_alive);
mem::forget(self);
}
}
pub fn query(&self) -> TextureQuery {
self.check_renderer();
let mut format = 0;
let mut access = 0;
let mut width = 0;
let mut height = 0;
let ret = unsafe { ll::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 i32,
height: height as i32
}
}
}
pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) {
self.check_renderer();
let ret = unsafe { ll::SDL_SetTextureColorMod(self.raw, red, green, blue) };
if ret != 0 {
panic!("Error setting color mod: {}", get_error())
}
}
pub fn get_color_mod(&self) -> (u8, u8, u8) {
self.check_renderer();
let (mut r, mut g, mut b) = (0, 0, 0);
let ret = unsafe { ll::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) {
self.check_renderer();
let ret = unsafe { ll::SDL_SetTextureAlphaMod(self.raw, alpha) };
if ret != 0 {
panic!("Error setting alpha mod: {}", get_error())
}
}
pub fn get_alpha_mod(&self) -> u8 {
self.check_renderer();
let mut alpha = 0;
let ret = unsafe { ll::SDL_GetTextureAlphaMod(self.raw, &mut alpha) };
if ret != 0 { panic!(get_error()) }
else { alpha }
}
pub fn set_blend_mode(&mut self, blend: BlendMode) {
self.check_renderer();
let ret = unsafe { ll::SDL_SetTextureBlendMode(self.raw, FromPrimitive::from_i64(blend as i64).unwrap()) };
if ret != 0 {
panic!("Error setting blend: {}", get_error())
}
}
pub fn get_blend_mode(&self) -> BlendMode {
self.check_renderer();
let mut blend = 0;
let ret = unsafe { ll::SDL_GetTextureBlendMode(self.raw, &mut blend) };
if ret != 0 { panic!(get_error()) }
else { FromPrimitive::from_i64(blend as i64).unwrap() }
}
pub fn update(&mut self, rect: Option<Rect>, pixel_data: &[u8], pitch: i32) -> SdlResult<()> {
self.check_renderer();
let ret = unsafe {
let rect_raw_ptr = match rect {
Some(ref rect) => rect as *const _,
None => ptr::null()
};
let rect_is_odd = match rect {
Some(r) => (r.x % 2 != 0) || (r.y % 2 != 0) || (r.w % 2 != 0) || (r.h % 2 != 0),
None => false
};
let pitch_is_odd = pitch % 2 != 0;
if rect_is_odd || pitch_is_odd {
match self.query() {
TextureQuery { format: PixelFormatEnum::YV12, .. } |
TextureQuery { format: PixelFormatEnum::IYUV, .. } => {
return Err(format!("The rectangle dimensions and pitch must be multiples-of-two for planar YUV 4:2:0 pixel formats"));
},
_ => ()
}
}
ll::SDL_UpdateTexture(self.raw, rect_raw_ptr, pixel_data.as_ptr() as *const _, pitch as c_int)
};
if ret == 0 { Ok(()) }
else { Err(get_error()) }
}
pub fn update_yuv(&mut self, rect: Option<Rect>, y_plane: &[u8], y_pitch: i32, u_plane: &[u8], u_pitch: i32, v_plane: &[u8], v_pitch: i32) -> SdlResult<()> {
self.check_renderer();
let rect_raw_ptr = match rect {
Some(ref rect) => rect as *const _,
None => ptr::null()
};
let rect_is_odd = match rect {
Some(r) => (r.x % 2 != 0) || (r.y % 2 != 0) || (r.w % 2 != 0) || (r.h % 2 != 0),
None => false
};
if rect_is_odd {
return Err(format!("The rectangle dimensions must be multiples-of-two for planar YUV 4:2:0 pixel formats"));
}
let height = match rect {
Some(r) => r.h,
None => self.query().height
};
let wrong_length =
(y_plane.len() != (y_pitch * height) as usize) ||
(u_plane.len() != (u_pitch * height/2) as usize) ||
(v_plane.len() != (v_pitch * height/2) as usize);
if wrong_length {
return Err(format!("One or more of the plane lengths is not correct (should be pitch * height)."));
}
unsafe {
let result = ll::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 { Ok(()) }
else { Err(get_error()) }
}
}
pub fn with_lock<F, R>(&mut self, rect: Option<Rect>, func: F) -> SdlResult<R>
where F: FnOnce(&mut [u8], usize) -> R
{
self.check_renderer();
let loaded = unsafe {
let q = self.query();
let mut pixels = ptr::null_mut();
let mut pitch = 0;
let (rect_raw_ptr, height) = match rect {
Some(ref rect) => (rect as *const _, rect.h as usize),
None => (ptr::null(), q.height as usize)
};
let ret = ll::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);
ll::SDL_UnlockTexture(self.raw);
}
Ok(result)
}
Err(e) => Err(e),
}
}
pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) {
self.check_renderer();
let mut texw = 0.0;
let mut texh = 0.0;
if ll::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) {
self.check_renderer();
if ll::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 {
self.check_renderer();
unsafe {
let mut texw = 0.0;
let mut texh = 0.0;
if ll::SDL_GL_BindTexture(self.raw, &mut texw, &mut texh) == 0 {
let return_value = f(texw, texh);
if ll::SDL_GL_UnbindTexture(self.raw) == 0 {
return_value
} else {
panic!();
}
} else {
panic!("OpenGL texture binding not supported");
}
}
}
pub unsafe fn from_ll(renderer: &Renderer, raw: *mut ll::SDL_Texture) -> Texture {
Texture {
raw: raw,
is_renderer_alive: renderer.is_alive.clone()
}
}
pub unsafe fn raw(&self) -> *mut ll::SDL_Texture { self.raw }
}
pub fn get_num_render_drivers() -> SdlResult<i32> {
let result = unsafe { ll::SDL_GetNumRenderDrivers() };
if result > 0 {
Ok(result as i32)
} else {
Err(get_error())
}
}
pub fn get_render_driver_info(index: i32) -> SdlResult<RendererInfo> {
let mut out = unsafe { mem::uninitialized() };
let result = unsafe { ll::SDL_GetRenderDriverInfo(index as c_int, &mut out) == 0 };
if result {
unsafe { Ok(RendererInfo::from_ll(&out)) }
} else {
Err(get_error())
}
}