From fb82743b4bdc0cc2f4ee3f25f87ddcdc99660688 Mon Sep 17 00:00:00 2001 From: Cobrand Date: Sun, 9 Jul 2017 01:26:54 +0000 Subject: [PATCH] Add 'unsafe_textures' feature to get rid of the Texture lifetime --- Cargo.toml | 1 + src/sdl2/render.rs | 508 +++++++++++++++++++++++++++++++++++++++------ 2 files changed, 445 insertions(+), 64 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8643914d..fbf12ac6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -35,6 +35,7 @@ optional = true [features] +unsafe_textures = [] default = [] ttf = [] image = [] diff --git a/src/sdl2/render.rs b/src/sdl2/render.rs index 266708b7..c4d37054 100644 --- a/src/sdl2/render.rs +++ b/src/sdl2/render.rs @@ -36,6 +36,7 @@ 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; @@ -317,6 +318,7 @@ impl<'s> RenderTarget for Surface<'s> { pub struct Canvas { target: T, context: Rc>, + default_pixel_format: PixelFormatEnum, } /// Alias for a `Canvas` that was created out of a `Surface` @@ -333,9 +335,11 @@ impl<'s> Canvas> { 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()) @@ -369,7 +373,7 @@ impl<'s> Canvas> { pub fn texture_creator(&self) -> TextureCreator> { TextureCreator { context: self.context.clone(), - default_pixel_format: self.surface().pixel_format_enum(), + default_pixel_format: self.default_pixel_format, } } } @@ -399,6 +403,11 @@ impl Canvas { pub fn into_window(self) -> Window { self.target } + + #[inline] + pub fn default_pixel_format(&self) -> PixelFormatEnum { + self.window().window_pixel_format() + } /// Returns a `TextureCreator` that can create Textures to be drawn on this `Canvas` /// @@ -409,7 +418,7 @@ impl Canvas { pub fn texture_creator(&self) -> TextureCreator { TextureCreator { context: self.context.clone(), - default_pixel_format: self.window().window_pixel_format(), + default_pixel_format: self.default_pixel_format(), } } } @@ -556,6 +565,7 @@ impl Canvas { /// ``` /// /// + #[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, &U), I: Iterator, U)> { @@ -574,6 +584,25 @@ impl Canvas { 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, &U), I: Iterator { + 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); + } + // reset the target to its source + unsafe { self.set_raw_target(ptr::null_mut()) } + .map_err(|e| TargetRenderError::SdlError(e))?; + Ok(()) + } else { + Err(TargetRenderError::NotSupported) + } + } } /// Creates Textures that cannot outlive the creator @@ -630,9 +659,11 @@ impl CanvasBuilder { 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, }) } } @@ -714,6 +745,39 @@ impl Error for TextureValueError { } } +fn ll_create_texture(context: *mut ll::SDL_Renderer, + pixel_format: PixelFormatEnum, + access: TextureAccess, + width: u32, + height: u32) + -> Result<*mut ll::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)), + }; + + // If the pixel format is YUV 4:2:0 and planar, the width and height must + // be multiples-of-two. See issue #334 for details. + match pixel_format { + PixelFormatEnum::YV12 | + PixelFormatEnum::IYUV => { + if w % 2 != 0 || h % 2 != 0 { + return Err(WidthMustBeMultipleOfTwoForFormat(width, pixel_format)); + } + } + _ => (), + }; + + Ok(unsafe { + ll::SDL_CreateTexture(context, pixel_format as uint32_t, access as c_int, w, h) + }) +} + /// Texture-creating methods for the renderer impl TextureCreator { pub fn raw(&self) -> *mut ll::SDL_Renderer { @@ -728,7 +792,7 @@ impl TextureCreator { /// /// If format is `None`, the format will be the one the parent Window or Surface uses. /// - /// If format is `Some(pixel_format)` the default will be overridden and the texture will be + /// If format is `Some(pixel_format)` /// created with the specified format if possible. If the PixelFormat is not supported, this /// will return an error. /// @@ -744,31 +808,8 @@ impl TextureCreator { where F: Into> { 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)), - }; let format: PixelFormatEnum = format.into().unwrap_or(self.default_pixel_format); - - // If the pixel format is YUV 4:2:0 and planar, the width and height must - // be multiples-of-two. See issue #334 for details. - match format { - PixelFormatEnum::YV12 | - PixelFormatEnum::IYUV => { - if w % 2 != 0 || h % 2 != 0 { - return Err(WidthMustBeMultipleOfTwoForFormat(width, format)); - } - } - _ => (), - } - - let result = unsafe { - ll::SDL_CreateTexture(self.context.raw, format as uint32_t, access as c_int, w, h) - }; + let result = ll_create_texture(self.context.raw(), format, access, width, height)?; if result.is_null() { Err(SdlError(get_error())) } else { @@ -776,6 +817,7 @@ impl TextureCreator { } } + #[inline] /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)` pub fn create_texture_static(&self, format: F, @@ -787,6 +829,7 @@ impl TextureCreator { self.create_texture(format, TextureAccess::Static, width, height) } + #[inline] /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)` pub fn create_texture_streaming(&self, format: F, @@ -798,6 +841,7 @@ impl TextureCreator { self.create_texture(format, TextureAccess::Streaming, width, height) } + #[inline] /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)` pub fn create_texture_target(&self, format: F, @@ -810,7 +854,9 @@ impl TextureCreator { } /// Creates a texture from an existing surface. + /// /// # Remarks + /// /// The access hint for the created texture is `TextureAccess::Static`. pub fn create_texture_from_surface> (&self, @@ -826,22 +872,24 @@ impl TextureCreator { } } + + #[cfg(not(feature = "unsafe_textures"))] + #[inline] pub unsafe fn raw_create_texture(&self, raw: *mut ll::SDL_Texture) -> Texture { Texture { raw: raw, _marker: PhantomData, } } + + #[cfg(feature = "unsafe_textures")] + pub unsafe fn raw_create_texture(&self, raw: *mut ll::SDL_Texture) -> Texture { + Texture { + raw: raw, + } + } } -// pub struct TextureTarget<'r, 't, TC> { -// raw_renderer: &'r *mut ll::SDL_Renderer, -// _texture_marker: PhantomData<&'t ()>, -// // unfortunately there is no way to know which kind of Renderer we have here at compile time, -// // so this PhantomData is here to keep track of that. -// _texture_target: PhantomData, -// } - /// Drawing methods impl Canvas { pub fn raw(&self) -> *mut ll::SDL_Renderer { @@ -1258,6 +1306,102 @@ impl Canvas { } } } + + /// Creates a texture for a rendering context. + /// + /// If format is `None`, the format will be the one the parent Window or Surface uses. + /// + /// If format is `Some(pixel_format)` + /// created with the specified format if possible. If the PixelFormat is not supported, this + /// will return an error. + /// + /// You should prefer the default format if possible to have performance gains and to avoid + /// unsupported Pixel Formats that can cause errors. However, be careful with the default + /// `PixelFormat` if you want to create transparent textures. + #[cfg(feature = "unsafe_textures")] + pub fn create_texture(&self, + format: F, + access: TextureAccess, + width: u32, + height: u32) + -> Result + where F: Into> + { + 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)) } + } + } + + /// Shorthand for `create_texture(format, TextureAccess::Static, width, height)` + #[cfg(feature = "unsafe_textures")] + #[inline] + pub fn create_texture_static(&self, + format: F, + width: u32, + height: u32) + -> Result + where F: Into> + { + self.create_texture(format, TextureAccess::Static, width, height) + } + + /// Shorthand for `create_texture(format, TextureAccess::Streaming, width, height)` + #[cfg(feature = "unsafe_textures")] + #[inline] + pub fn create_texture_streaming(&self, + format: F, + width: u32, + height: u32) + -> Result + where F: Into> + { + self.create_texture(format, TextureAccess::Streaming, width, height) + } + + /// Shorthand for `create_texture(format, TextureAccess::Target, width, height)` + #[cfg(feature = "unsafe_textures")] + #[inline] + pub fn create_texture_target(&self, + format: F, + width: u32, + height: u32) + -> Result + where F: Into> + { + self.create_texture(format, TextureAccess::Target, width, height) + } + + /// Creates a texture from an existing surface. + /// + /// # Remarks + /// + /// The access hint for the created texture is `TextureAccess::Static`. + #[cfg(feature = "unsafe_textures")] + pub fn create_texture_from_surface> + (&self, + surface: S) + -> Result { + use self::TextureValueError::*; + let result = + unsafe { ll::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 ll::SDL_Texture) -> Texture { + Texture { + raw: raw, + } + } } #[derive(Copy, Clone, Eq, PartialEq, Hash, Debug)] @@ -1274,11 +1418,18 @@ pub struct TextureQuery { /// A `Texture` cannot outlive the `TextureCreator` /// /// A `Texture` can be safely accessed after the `Canvas` is dropped. +#[cfg(feature = "unsafe_textures")] +pub struct Texture { + raw: *mut ll::SDL_Texture, +} + +#[cfg(not(feature = "unsafe_textures"))] pub struct Texture<'r> { raw: *mut ll::SDL_Texture, _marker: PhantomData<&'r ()>, } +#[cfg(not(feature = "unsafe_textures"))] impl<'r> Drop for Texture<'r> { fn drop(&mut self) { unsafe { @@ -1287,6 +1438,27 @@ impl<'r> Drop for Texture<'r> { } } +#[cfg(feature = "unsafe_textures")] +impl Texture { + /// Destroy the Texture and its representation + /// in the Renderer. This will most likely + /// mean that the renderer engine will free video + /// memory that was allocated for this texture. + /// + /// This method is unsafe because since Texture does not have + /// a lifetime, it is legal in Rust to make this texture live + /// longer than the Renderer. It is however illegal to destroy a SDL_Texture + /// after its SDL_Renderer, therefore this function is unsafe because + /// of this. + /// + /// Note however that you don't *have* to destroy a Texture before its Canvas, + /// since whenever Canvas is destroyed, the SDL implementation will automatically + /// destroy all the children Textures of that Canvas. + pub unsafe fn destroy(self) { + ll::SDL_DestroyTexture(self.raw) + } +} + #[derive(Debug)] pub enum UpdateTextureError { PitchOverflows(usize), @@ -1428,8 +1600,11 @@ impl Error for UpdateTextureYUVError { } } -impl<'r> Texture<'r> { - /// Queries the attributes of the texture. +struct InternalTexture { + raw: *mut ll::SDL_Texture, +} + +impl InternalTexture { pub fn query(&self) -> TextureQuery { let mut format = 0; let mut access = 0; @@ -1452,7 +1627,6 @@ impl<'r> Texture<'r> { } } - /// Sets an additional color value multiplied into render copy operations. pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) { let ret = unsafe { ll::SDL_SetTextureColorMod(self.raw, red, green, blue) }; @@ -1461,7 +1635,6 @@ impl<'r> Texture<'r> { } } - /// Gets the additional color value multiplied into render copy operations. pub fn color_mod(&self) -> (u8, u8, u8) { let (mut r, mut g, mut b) = (0, 0, 0); let ret = unsafe { ll::SDL_GetTextureColorMod(self.raw, &mut r, &mut g, &mut b) }; @@ -1474,7 +1647,6 @@ impl<'r> Texture<'r> { } } - /// Sets an additional alpha value multiplied into render copy operations. pub fn set_alpha_mod(&mut self, alpha: u8) { let ret = unsafe { ll::SDL_SetTextureAlphaMod(self.raw, alpha) }; @@ -1483,7 +1655,6 @@ impl<'r> Texture<'r> { } } - /// Gets the additional alpha value multiplied into render copy operations. pub fn alpha_mod(&self) -> u8 { let mut alpha = 0; let ret = unsafe { ll::SDL_GetTextureAlphaMod(self.raw, &mut alpha) }; @@ -1492,7 +1663,6 @@ impl<'r> Texture<'r> { if ret != 0 { panic!(get_error()) } else { alpha } } - /// Sets the blend mode for a texture, used by `Renderer::copy()`. pub fn set_blend_mode(&mut self, blend: BlendMode) { let ret = unsafe { ll::SDL_SetTextureBlendMode(self.raw, FromPrimitive::from_i64(blend as i64).unwrap()) @@ -1503,7 +1673,6 @@ impl<'r> Texture<'r> { } } - /// Gets the blend mode used for texture copy operations. pub fn blend_mode(&self) -> BlendMode { let mut blend = 0; let ret = unsafe { ll::SDL_GetTextureBlendMode(self.raw, &mut blend) }; @@ -1516,12 +1685,6 @@ impl<'r> Texture<'r> { } } - /// Updates the given texture rectangle with new pixel data. - /// - /// `pitch` is the number of bytes in a row of pixel data, including padding - /// between lines - /// - /// * If `rect` is `None`, the entire texture is updated. pub fn update(&mut self, rect: R, pixel_data: &[u8], @@ -1583,7 +1746,6 @@ impl<'r> Texture<'r> { } } - /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data. pub fn update_yuv(&mut self, rect: R, y_plane: &[u8], @@ -1712,16 +1874,6 @@ impl<'r> Texture<'r> { } } - /// Locks the texture for **write-only** pixel access. - /// The texture must have been created with streaming access. - /// - /// `F` is a function that is passed the write-only texture buffer, - /// and the pitch of the texture (size of a row in bytes). - /// # Remarks - /// As an optimization, the pixels made available for editing don't - /// necessarily contain the old texture data. - /// This is a write-only operation, and if you need to keep a copy of the - /// texture data you should do that at the application level. pub fn with_lock(&mut self, rect: R2, func: F) -> Result where F: FnOnce(&mut [u8], usize) -> R, R2: Into> @@ -1760,8 +1912,6 @@ impl<'r> Texture<'r> { } } - /// Binds an OpenGL/ES/ES2 texture to the current - /// context for use with when rendering OpenGL primitives directly. pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) { let mut texw = 0.0; let mut texh = 0.0; @@ -1773,14 +1923,12 @@ impl<'r> Texture<'r> { } } - /// Unbinds an OpenGL/ES/ES2 texture from the current context. pub unsafe fn gl_unbind_texture(&mut self) { if ll::SDL_GL_UnbindTexture(self.raw) != 0 { panic!("OpenGL texture unbinding not supported"); } } - /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context. pub fn gl_with_bind R>(&mut self, f: F) -> R { unsafe { let mut texw = 0.0; @@ -1800,7 +1948,239 @@ impl<'r> Texture<'r> { } } } +} +#[cfg(not(feature = "unsafe_textures"))] +impl<'r> Texture<'r> { + /// Queries the attributes of the texture. + #[inline] + pub fn query(&self) -> TextureQuery { + InternalTexture{ raw: self.raw }.query() + } + + /// Sets an additional color value multiplied into render copy operations. + #[inline] + pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) { + InternalTexture{ raw: self.raw }.set_color_mod(red, green, blue) + } + + /// Gets the additional color value multiplied into render copy operations. + #[inline] + pub fn color_mod(&self) -> (u8, u8, u8) { + InternalTexture{ raw: self.raw }.color_mod() + } + + /// Sets an additional alpha value multiplied into render copy operations. + #[inline] + pub fn set_alpha_mod(&mut self, alpha: u8) { + InternalTexture{ raw: self.raw }.set_alpha_mod(alpha) + } + + /// Gets the additional alpha value multiplied into render copy operations. + #[inline] + pub fn alpha_mod(&self) -> u8 { + InternalTexture{ raw: self.raw }.alpha_mod() + } + + /// Sets the blend mode used for drawing operations (Fill and Line). + #[inline] + pub fn set_blend_mode(&mut self, blend: BlendMode) { + InternalTexture{ raw: self.raw }.set_blend_mode(blend) + } + + /// Gets the blend mode used for texture copy operations. + #[inline] + pub fn blend_mode(&self) -> BlendMode { + InternalTexture{ raw: self.raw }.blend_mode() + } + + /// Updates the given texture rectangle with new pixel data. + /// + /// `pitch` is the number of bytes in a row of pixel data, including padding + /// between lines + /// + /// * If `rect` is `None`, the entire texture is updated. + #[inline] + pub fn update(&mut self, + rect: R, + pixel_data: &[u8], + pitch: usize) + -> Result<(), UpdateTextureError> + where R: Into> { + InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch) + } + + /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data. + #[inline] + pub fn update_yuv(&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> { + InternalTexture { raw: self.raw }.update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch) + } + + /// Locks the texture for **write-only** pixel access. + /// The texture must have been created with streaming access. + /// + /// `F` is a function that is passed the write-only texture buffer, + /// and the pitch of the texture (size of a row in bytes). + /// # Remarks + /// As an optimization, the pixels made available for editing don't + /// necessarily contain the old texture data. + /// This is a write-only operation, and if you need to keep a copy of the + /// texture data you should do that at the application level. + #[inline] + pub fn with_lock(&mut self, rect: R2, func: F) -> Result + where F: FnOnce(&mut [u8], usize) -> R, + R2: Into> + { + InternalTexture { raw: self.raw }.with_lock(rect, func) + } + + /// Binds an OpenGL/ES/ES2 texture to the current + /// context for use with when rendering OpenGL primitives directly. + #[inline] + pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) { + InternalTexture { raw: self.raw }.gl_bind_texture() + } + + /// Unbinds an OpenGL/ES/ES2 texture from the current context. + #[inline] + pub unsafe fn gl_unbind_texture(&mut self) { + InternalTexture { raw: self.raw }.gl_unbind_texture() + } + + /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context. + #[inline] + pub fn gl_with_bind R>(&mut self, f: F) -> R { + InternalTexture { raw: self.raw }.gl_with_bind(f) + } + + #[inline] + pub fn raw(&self) -> *mut ll::SDL_Texture { + self.raw + } +} + +#[cfg(feature = "unsafe_textures")] +impl<> Texture<> { + /// Queries the attributes of the texture. + #[inline] + pub fn query(&self) -> TextureQuery { + InternalTexture{ raw: self.raw }.query() + } + + /// Sets an additional color value multiplied into render copy operations. + #[inline] + pub fn set_color_mod(&mut self, red: u8, green: u8, blue: u8) { + InternalTexture{ raw: self.raw }.set_color_mod(red, green, blue) + } + + /// Gets the additional color value multiplied into render copy operations. + #[inline] + pub fn color_mod(&self) -> (u8, u8, u8) { + InternalTexture{ raw: self.raw }.color_mod() + } + + /// Sets an additional alpha value multiplied into render copy operations. + #[inline] + pub fn set_alpha_mod(&mut self, alpha: u8) { + InternalTexture{ raw: self.raw }.set_alpha_mod(alpha) + } + + /// Gets the additional alpha value multiplied into render copy operations. + #[inline] + pub fn alpha_mod(&self) -> u8 { + InternalTexture{ raw: self.raw }.alpha_mod() + } + + /// Sets the blend mode used for drawing operations (Fill and Line). + #[inline] + pub fn set_blend_mode(&mut self, blend: BlendMode) { + InternalTexture{ raw: self.raw }.set_blend_mode(blend) + } + + /// Gets the blend mode used for texture copy operations. + #[inline] + pub fn blend_mode(&self) -> BlendMode { + InternalTexture{ raw: self.raw }.blend_mode() + } + + /// Updates the given texture rectangle with new pixel data. + /// + /// `pitch` is the number of bytes in a row of pixel data, including padding + /// between lines + /// + /// * If `rect` is `None`, the entire texture is updated. + #[inline] + pub fn update(&mut self, + rect: R, + pixel_data: &[u8], + pitch: usize) + -> Result<(), UpdateTextureError> + where R: Into> { + InternalTexture { raw: self.raw }.update(rect, pixel_data, pitch) + } + + /// Updates a rectangle within a planar YV12 or IYUV texture with new pixel data. + #[inline] + pub fn update_yuv(&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> { + InternalTexture { raw: self.raw }.update_yuv(rect, y_plane, y_pitch, u_plane, u_pitch, v_plane, v_pitch) + } + + /// Locks the texture for **write-only** pixel access. + /// The texture must have been created with streaming access. + /// + /// `F` is a function that is passed the write-only texture buffer, + /// and the pitch of the texture (size of a row in bytes). + /// # Remarks + /// As an optimization, the pixels made available for editing don't + /// necessarily contain the old texture data. + /// This is a write-only operation, and if you need to keep a copy of the + /// texture data you should do that at the application level. + #[inline] + pub fn with_lock(&mut self, rect: R2, func: F) -> Result + where F: FnOnce(&mut [u8], usize) -> R, + R2: Into> + { + InternalTexture { raw: self.raw }.with_lock(rect, func) + } + + /// Binds an OpenGL/ES/ES2 texture to the current + /// context for use with when rendering OpenGL primitives directly. + #[inline] + pub unsafe fn gl_bind_texture(&mut self) -> (f32, f32) { + InternalTexture { raw: self.raw }.gl_bind_texture() + } + + /// Unbinds an OpenGL/ES/ES2 texture from the current context. + #[inline] + pub unsafe fn gl_unbind_texture(&mut self) { + InternalTexture { raw: self.raw }.gl_unbind_texture() + } + + /// Binds and unbinds an OpenGL/ES/ES2 texture from the current context. + #[inline] + pub fn gl_with_bind R>(&mut self, f: F) -> R { + InternalTexture { raw: self.raw }.gl_with_bind(f) + } + + #[inline] pub fn raw(&self) -> *mut ll::SDL_Texture { self.raw }