use gl;
use gl::types::*;
use sampler::Sampler;
use std::{convert::{TryFrom, TryInto}, mem};
use std::slice;
use std::os::raw::c_void;
use features::traits::{Image,ScanLines};
use state::StateRef;
use utils::{gl_format_from_internal, gl_type_from_internal};
use ::Result;
use ::Error;
use ::ErrorKind;
use ::buffer::BufferRange;
#[derive(Debug)]
pub struct Texture{
backend: Box<dyn TextureBackend>,
width: u32,
height: u32,
depth: u32,
levels: u32,
owned: bool,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: u32,
}
impl Drop for Texture{
fn drop(&mut self){
if self.owned {
self.backend.delete()
}
}
}
impl PartialEq for Texture {
fn eq(&self, other: &Self) -> bool {
self.backend.id() == other.backend.id()
}
}
impl Eq for Texture {}
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
pub enum Format {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Texture1D{
internal_format: GLenum,
width: u32,
levels: u32,
},
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Texture1DArray {
internal_format: GLenum,
width: u32,
layers: u32,
levels: u32,
},
Texture2D {
internal_format: GLenum,
width: u32,
height: u32,
levels: u32,
},
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Texture2DMultisample {
internal_format: GLenum,
width: u32,
height: u32,
samples: u32,
},
Texture2DArray {
internal_format: GLenum,
width: u32,
height: u32,
layers: u32,
levels: u32,
},
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Texture2DArrayMultisample {
internal_format: GLenum,
width: u32,
height: u32,
layers: u32,
samples: u32,
},
Texture3D {
internal_format: GLenum,
width: u32,
height: u32,
depth: u32,
levels: u32,
},
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
TextureRectangkle {
internal_format: GLenum,
width: u32,
height: u32,
levels: u32,
},
Custom {
target: GLenum,
internal_format: GLenum,
width: u32,
height: u32,
depth: u32,
levels: u32,
samples: u32,
},
}
impl Format {
pub fn new(internal: GLenum, width: u32, height: u32) -> Format {
Format::Texture2D {
internal_format: internal,
width,
height,
levels: 1,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_multisample(internal: GLenum, width: u32, height: u32, samples: u32) -> Format {
Format::Texture2DMultisample {
internal_format: internal,
width,
height,
samples,
}
}
pub fn new_3d(internal: GLenum, width: u32, height: u32, depth: u32) -> Format {
Format::Texture3D {
internal_format: internal,
width,
height,
depth,
levels: 1,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_1d(internal: GLenum, width: u32) -> Format {
Format::Texture1D {
internal_format: internal,
width,
levels: 1,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_1d_array(internal: GLenum, width: u32, layers: u32) -> Format {
Format::Texture1DArray {
internal_format: internal,
width,
layers,
levels: 1,
}
}
pub fn new_array(internal: GLenum, width: u32, height: u32, layers: u32) -> Format {
Format::Texture2DArray {
internal_format: internal,
width,
height,
layers,
levels: 1,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_multisample_array(internal: GLenum, width: u32, height: u32, layers: u32, samples: u32) -> Format {
Format::Texture2DArrayMultisample {
internal_format: internal,
width,
height,
layers,
samples,
}
}
pub fn target(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { .. } => gl::TEXTURE_1D,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1DArray { .. } => gl::TEXTURE_1D_ARRAY,
Format::Texture2D { .. } => gl::TEXTURE_2D,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DMultisample { .. } => gl::TEXTURE_2D_MULTISAMPLE,
Format::Texture2DArray { .. } => gl::TEXTURE_2D_ARRAY,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DArrayMultisample { .. } => gl::TEXTURE_2D_MULTISAMPLE_ARRAY,
Format::Texture3D { .. } => gl::TEXTURE_3D,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::TextureRectangkle { .. } => gl::TEXTURE_RECTANGLE,
Format::Custom { target, .. } => *target,
}
}
pub fn internal_format(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { internal_format, .. }
| Format::Texture1DArray { internal_format, .. }
| Format::Texture2DMultisample { internal_format, .. }
| Format::Texture2DArrayMultisample { internal_format, .. }
| Format::TextureRectangkle { internal_format, .. } => *internal_format,
Format::Texture2D { internal_format, .. }
| Format::Texture2DArray { internal_format, .. }
| Format::Texture3D { internal_format, .. }
| Format::Custom { internal_format, .. } => *internal_format,
}
}
pub fn width(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { width, .. }
| Format::Texture1DArray { width, .. }
| Format::Texture2DMultisample { width, .. }
| Format::Texture2DArrayMultisample { width, .. }
| Format::TextureRectangkle { width, .. } => *width,
Format::Texture2D { width, .. }
| Format::Texture2DArray { width, .. }
| Format::Texture3D { width, .. }
| Format::Custom { width, .. } => *width,
}
}
pub fn height(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { .. } => 0,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1DArray { layers, .. } => *layers,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DMultisample { height, .. }
| Format::Texture2DArrayMultisample { height, .. }
| Format::TextureRectangkle { height, .. } => *height,
Format::Texture2D { height, .. }
| Format::Texture2DArray { height, .. }
| Format::Texture3D { height, .. }
| Format::Custom { height, .. } => *height,
}
}
pub fn depth(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { .. }
| Format::Texture1DArray { .. }
| Format::Texture2DMultisample { .. }
| Format::TextureRectangkle { .. } => 0,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DArrayMultisample { layers, .. } => *layers,
Format::Texture2D { .. } => 0,
Format::Texture2DArray { layers, .. } => *layers,
Format::Texture3D { depth, .. } => *depth,
Format::Custom { depth, .. } => *depth,
}
}
pub fn samples(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { .. }
| Format::Texture1DArray { .. }
| Format::TextureRectangkle { .. } => 0,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DMultisample { samples, .. }
| Format::Texture2DArrayMultisample { samples, .. } => *samples,
Format::Texture2D { .. }
| Format::Texture3D { .. }
| Format::Texture2DArray { .. } => 0,
Format::Custom { samples, .. } => *samples,
}
}
pub fn levels(&self) -> GLenum {
match self {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture1D { levels, .. }
| Format::Texture1DArray { levels, .. }
| Format::TextureRectangkle { levels, .. } => *levels,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
Format::Texture2DMultisample { .. }
| Format::Texture2DArrayMultisample { .. } => 1,
Format::Texture2D { levels, .. }
| Format::Texture3D { levels, .. }
| Format::Texture2DArray { levels, .. }
| Format::Custom { levels, .. } => *levels,
}
}
}
#[derive(Clone, Debug)]
pub struct WrapperSettings{
pub id: GLuint,
pub owned: bool,
pub format: Format,
}
#[derive(Eq, PartialEq, Hash, Clone, Debug)]
pub struct LoadDataFormat{
pub texture_format: Format,
pub format: GLenum,
pub ty: GLenum,
}
impl LoadDataFormat{
pub fn new(internal: GLenum, width: u32, height: u32) -> Result<LoadDataFormat> {
Format::new(internal, width, height).try_into()
}
pub fn new_3d(internal: GLenum, width: u32, height: u32, depth: u32) -> Result<LoadDataFormat> {
Format::new_3d(internal, width, height, depth).try_into()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn new_1d(internal: GLenum, width: u32) -> Result<LoadDataFormat> {
Format::new_1d(internal, width).try_into()
}
pub fn new_array(internal: GLenum, width: u32, height: u32, layers: u32) -> Result<LoadDataFormat> {
Format::new_array(internal, width, height, layers).try_into()
}
pub fn texture_format(&self) -> &Format {
&self.texture_format
}
pub fn data_format(&self) -> DataFormat {
DataFormat{
width: self.texture_format.width(),
height: self.texture_format.height(),
depth: self.texture_format.depth(),
format: self.format,
ty: self.ty,
level: 0,
xoffset: 0,
yoffset: 0,
zoffset: 0,
}
}
}
impl TryFrom<Format> for LoadDataFormat {
type Error = Error;
fn try_from(texture_format: Format) -> Result<LoadDataFormat> {
let internal = texture_format.internal_format();
let format = gl_format_from_internal(internal)
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
format!("Can't guess gl format from internal format {}, please specify in DataFormat", internal).as_str()))?;
let ty = gl_type_from_internal(internal)
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
"Can't guess gl type from internal format, please specify in DataFormat"))?;
Ok(LoadDataFormat {
texture_format,
format,
ty
})
}
}
#[derive(Clone, Debug, Default, PartialEq, Eq, Hash)]
pub struct DataFormat{
pub width: u32,
pub height: u32,
pub depth: u32,
pub format: GLenum,
pub ty: GLenum,
pub level: u32,
pub xoffset: i32,
pub yoffset: i32,
pub zoffset: i32,
}
impl DataFormat{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn bytes(&self) -> Result<usize>{
let bpc = match self.ty{
gl::UNSIGNED_BYTE => 1,
gl::HALF_FLOAT | gl::UNSIGNED_SHORT | gl::SHORT => 2,
gl::FLOAT | gl::UNSIGNED_INT_24_8 | gl::UNSIGNED_INT | gl::INT => 4,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out bytes per components from gl type")),
};
let num_components = match self.format{
gl::RGBA | gl::BGRA | gl::RGBA_INTEGER => 4,
gl::RGB | gl::BGR | gl::RGB_INTEGER => 3,
gl::RG | gl::RG_INTEGER => 2,
gl::RED | gl::STENCIL_INDEX | gl::DEPTH_COMPONENT | gl::RED_INTEGER => 1,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out number of components from gl format")),
};
Ok((self.width * self.height * bpc * num_components) as usize)
}
#[cfg(feature = "gles")]
pub fn bytes(&self) -> Result<usize>{
let bpc = match self.ty{
gl::UNSIGNED_BYTE => 1,
gl::UNSIGNED_SHORT | gl::SHORT => 2,
gl::FLOAT | gl::UNSIGNED_INT | gl::INT => 4,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out bytes per components from gl type")),
};
let num_components = match self.format{
gl::RGBA | gl::RGBA_INTEGER => 4,
gl::RGB | gl::RGB_INTEGER => 3,
gl::RG | gl::STENCIL_INDEX | gl::LUMINANCE_ALPHA | gl::RG_INTEGER => 2,
gl::RED | gl::DEPTH_COMPONENT | gl::LUMINANCE | gl::RED_INTEGER => 1,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out number of components from gl format")),
};
Ok((self.width * self.height * bpc * num_components) as usize)
}
#[cfg(feature="webgl")]
pub fn bytes(&self) -> Result<usize>{
let bpc = match self.ty{
gl::UNSIGNED_BYTE => 1,
gl::UNSIGNED_SHORT | gl::SHORT => 2,
gl::FLOAT | gl::UNSIGNED_INT | gl::INT => 4,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out bytes per components from gl type")),
};
let num_components = match self.format{
gl::RGBA | gl::RGBA_INTEGER => 4,
gl::RGB | gl::RGB_INTEGER => 3,
gl::RG | gl::STENCIL_INDEX8 | gl::LUMINANCE_ALPHA | gl::RG_INTEGER => 2,
gl::RED | gl::DEPTH_COMPONENT | gl::LUMINANCE | gl::RED_INTEGER => 1,
_ => return Err(Error::new(ErrorKind::FormatNotSupported,
"Can't figure out number of components from gl format")),
};
Ok((self.width * self.height * bpc * num_components) as usize)
}
pub fn fill_defaults_from(&mut self, tex: &Texture) -> Result<()>{
if self.width == 0{
self.width = tex.width
}
if self.height == 0{
self.height = tex.height
}
if self.depth == 0{
self.depth = tex.depth
}
if self.format == 0{
self.format = gl_format_from_internal(tex.internal_format())
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
format!("Can't guess gl format from internal format {}, please specify in DataFormat", tex.internal_format()).as_str()))?;
}
if self.ty == 0{
self.ty = gl_type_from_internal(tex.internal_format())
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
"Can't guess gl type from internal format, please specify in DataFormat"))?;
}
Ok(())
}
pub fn default_from(texture: &Texture) -> Result<DataFormat> {
Ok(DataFormat {
width: texture.width,
height: texture.height,
depth: texture.depth,
format: gl_format_from_internal(texture.internal_format())
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
format!("Can't guess gl format from internal format {}, please specify in DataFormat", texture.internal_format()).as_str()))?,
ty: gl_type_from_internal(texture.internal_format())
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
"Can't guess gl type from internal format, please specify in DataFormat"))?,
level: 0,
xoffset: 0,
yoffset: 0,
zoffset: 0,
})
}
}
impl TryFrom<Format> for DataFormat {
type Error = Error;
fn try_from(texture_format: Format) -> Result<DataFormat> {
let internal = texture_format.internal_format();
let format = gl_format_from_internal(internal)
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
format!("Can't guess gl format from internal format {}, please specify in DataFormat", internal).as_str()))?;
let ty = gl_type_from_internal(internal)
.ok_or_else(|| Error::new(ErrorKind::FormatNotSupported,
"Can't guess gl type from internal format, please specify in DataFormat"))?;
Ok(DataFormat{
width: texture_format.width(),
height: texture_format.height(),
depth: texture_format.depth(),
format,
ty,
level: 0,
xoffset: 0,
yoffset: 0,
zoffset: 0,
})
}
}
#[derive(Copy,Clone,Debug,Default,PartialEq,Eq, Hash)]
pub struct CompressedDataFormat{
pub width: u32,
pub height: u32,
pub depth: u32,
pub format: GLenum,
pub level: u32,
pub xoffset: i32,
pub yoffset: i32,
pub zoffset: i32
}
impl From<Format> for CompressedDataFormat {
fn from(texture_format: Format) -> CompressedDataFormat {
let internal = texture_format.internal_format();
let format = internal;
CompressedDataFormat{
width: texture_format.width(),
height: texture_format.height(),
depth: texture_format.depth(),
format,
level: 0,
xoffset: 0,
yoffset: 0,
zoffset: 0,
}
}
}
#[cfg(not(feature="webgl"))]
#[derive(Copy,Clone,Debug,PartialEq,Eq, Hash)]
pub enum Component{
R=0,
G,
B,
A,
}
#[cfg(not(feature="webgl"))]
#[derive(Copy,Clone,Debug,PartialEq,Eq, Hash)]
pub struct Swizzles{
pub r: Component,
pub g: Component,
pub b: Component,
pub a: Component,
}
#[cfg(not(feature="webgl"))]
impl Default for Swizzles{
fn default() -> Swizzles{
Swizzles{
r: Component::R,
g: Component::G,
b: Component::B,
a: Component::A,
}
}
}
#[cfg(not(feature="webgl"))]
impl Component{
#[inline]
pub fn to_dst(self) -> GLenum{
gl::RED + self as GLenum
}
pub fn from_dst(dst: GLenum) -> Option<Component>{
let dst = match dst{
gl::RED => Component::R,
gl::GREEN => Component::G,
gl::BLUE => Component::B,
gl::ALPHA => Component::A,
_ => return None
};
Some(dst)
}
}
#[cfg(not(feature="webgl"))]
impl Swizzles{
#[inline]
pub fn rg_to_rgba() -> Swizzles{
Swizzles{
r: Component::R,
g: Component::R,
b: Component::R,
a: Component::G,
}
}
#[inline]
pub fn r_to_rgb() -> Swizzles{
Swizzles{
r: Component::R,
g: Component::R,
b: Component::R,
a: Component::A,
}
}
}
#[cfg(not(any(target_os = "macos", feature = "webgl", feature = "gles")))]
fn internal_format_supported(gl: &StateRef, internal: GLenum) -> bool{
if gl.capabilities().is_supported("GL_ARB_internalformat_query2"){
let mut supported = 0;
unsafe{
gl.GetInternalformati64v(
gl::TEXTURE_2D,
internal,
gl::INTERNALFORMAT_SUPPORTED,
1,
&mut supported);
supported == gl::TRUE as i64
}
}else{
true
}
}
#[cfg(target_os = "macos")]
fn internal_format_supported(gl: &StateRef, internal: GLenum) -> bool{
true
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn check_format(gl: &StateRef, format: &Format) -> Result<()>{
match format.target() {
gl::TEXTURE_1D => {
if format.width() == 0 {
return Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.width() > gl.capabilities().max_texture_size {
return Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() != 0 {
return Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.depth() != 0 {
return Err(Error::new(ErrorKind::DepthTooBig, None))
}else if format.target() != gl::TEXTURE_2D_MULTISAMPLE && format.samples() > 0 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with unsupported target"))
}else if format.samples() > 0 && format.levels() > 1 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with more than one level"))
}
},
gl::TEXTURE_2D | gl::TEXTURE_RECTANGLE | gl::TEXTURE_CUBE_MAP | gl::TEXTURE_2D_MULTISAMPLE | gl::TEXTURE_1D_ARRAY => {
if format.width() == 0 {
return Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
return Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.width() > gl.capabilities().max_texture_size {
return Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_texture_size {
return Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() != 0 {
return Err(Error::new(ErrorKind::DepthTooBig, None))
}else if format.target() != gl::TEXTURE_2D_MULTISAMPLE && format.samples() > 0 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with unsupported target"))
}else if format.samples() > 0 && format.levels() > 1 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with more than one level"))
}
},
gl::TEXTURE_2D_ARRAY | gl::TEXTURE_2D_MULTISAMPLE_ARRAY => {
if format.width() == 0 {
return Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
return Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.depth() == 0 {
return Err(Error::new(ErrorKind::ZeroDepth, None))
}else if format.width() > gl.capabilities().max_texture_size {
return Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_texture_size {
return Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() > gl.capabilities().max_texture_array_layers {
return Err(Error::new(ErrorKind::DepthTooBig, None))
}else if format.target() != gl::TEXTURE_2D_MULTISAMPLE_ARRAY && format.samples() > 0 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with unsupported target"))
}else if format.samples() > 0 && format.levels() > 1 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with more than one level"))
}
},
gl::TEXTURE_3D => {
if format.width() == 0 {
return Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
return Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.depth() == 0 {
return Err(Error::new(ErrorKind::ZeroDepth, None))
}else if format.width() > gl.capabilities().max_3d_texture_size {
return Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_3d_texture_size {
return Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() > gl.capabilities().max_3d_texture_size {
return Err(Error::new(ErrorKind::DepthTooBig, None))
}else if format.samples() > 0 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate multisample texture with unsupported target"))
}
},
_ => ()
}
if !internal_format_supported(gl, format.internal_format()){
Err(Error::new(ErrorKind::FormatNotSupported, "Internal format not supported"))
}else{
Ok(())
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
fn check_format(gl: &StateRef, format: &Format) -> Result<()>{
if format.samples() > 0 {
return Err(Error::new(ErrorKind::FormatNotSupported, "Trying to allocate unsupported multisample texture"))
}
match format.target() {
gl::TEXTURE_2D | gl::TEXTURE_CUBE_MAP =>{
if format.width() == 0 {
Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.width() > gl.capabilities().max_texture_size {
Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_texture_size {
Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() != 0 {
Err(Error::new(ErrorKind::DepthTooBig, None))
}else{
Ok(())
}
},
gl::TEXTURE_2D_ARRAY => {
if format.width() == 0 {
Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.depth() == 0 {
Err(Error::new(ErrorKind::ZeroDepth, None))
}else if format.width() > gl.capabilities().max_texture_size {
Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_texture_size {
Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() > gl.capabilities().max_texture_array_layers {
Err(Error::new(ErrorKind::DepthTooBig, None))
}else{
Ok(())
}
},
gl::TEXTURE_3D =>{
if format.width ()== 0 {
Err(Error::new(ErrorKind::ZeroWidth, None))
}else if format.height() == 0 {
Err(Error::new(ErrorKind::ZeroHeight, None))
}else if format.depth() == 0 {
Err(Error::new(ErrorKind::ZeroDepth, None))
}else if format.width() > gl.capabilities().max_3d_texture_size {
Err(Error::new(ErrorKind::WidthTooBig, None))
}else if format.height() > gl.capabilities().max_3d_texture_size {
Err(Error::new(ErrorKind::HeightTooBig, None))
}else if format.depth() > gl.capabilities().max_3d_texture_size {
Err(Error::new(ErrorKind::DepthTooBig, None))
}else{
Ok(())
}
},
_ => Ok(())
}
}
pub struct Builder<'a>(pub(crate) &'a StateRef);
impl<'a> Builder<'a>{
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn new_backend(&self, format: &Format) -> Box<dyn TextureBackend> {
if self.0.capabilities().supports_dsa() && format.samples() == 0{
Box::new(TextureDsa::new(self.0, format)) as Box<dyn TextureBackend>
}else{
Box::new(TextureBind::new(self.0, format)) as Box<dyn TextureBackend>
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
fn new_backend(&self, format: &Format) -> Box<dyn TextureBackend> {
Box::new(TextureBind::new(self.0, format)) as Box<dyn TextureBackend>
}
pub fn from_format(&self, format: Format) -> Result<Texture>{
check_format(self.0, &format).and_then(|_| {
Ok(Texture{
backend: self.new_backend(&format),
width: format.width(),
height: format.height(),
depth: format.depth(),
levels: format.levels(),
owned: true,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: format.samples(),
})
})
}
pub fn from_data_format<T: 'static>(&self, data_format: LoadDataFormat, data: &[T]) -> Result<Texture>{
let format = data_format.texture_format();
check_format(&self.0, &format).and_then(|_| {
let mut texture = Texture{
backend: self.new_backend(&format),
width: format.width(),
height: format.height(),
depth: format.depth(),
levels: format.levels(),
owned: true,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: format.samples(),
};
texture.load_data(data, data_format.data_format())?;
Ok(texture)
})
}
pub fn from_image<I: Image>(&self, img: &I, target: GLenum) -> Result<Texture>
where <I as Image>::DataType: Clone + 'static
{
let internal = img.gl_internal().ok_or(Error::new(
ErrorKind::FormatNotSupported,
"Image format doesn't have a supported internal"
))?;
let mut tex = Builder(self.0).from_format(Format::Custom{
target: target,
internal_format: internal,
width: img.width(0) as u32,
height: img.height(0) as u32,
depth: 0,
levels: img.levels() as u32,
samples: 0,
})?;
tex.load_image(img).map(|_| tex)
}
pub fn from_image_allocate_max_levels<I: Image>(&self, img: &I, target: GLenum) -> Result<Texture>
where <I as Image>::DataType: Clone + 'static
{
let internal = img.gl_internal().ok_or(ErrorKind::FormatNotSupported)?;
let levels = if img.levels() == 1 { img.max_levels() } else { img.levels() };
let mut tex = Builder(self.0).from_format(Format::Custom{
target: target,
internal_format: internal,
width: img.width(0) as u32,
height: img.height(0) as u32,
depth: 0,
levels: levels as u32,
samples: 0,
})?;
tex.load_image(img).map(|_| tex)
}
pub unsafe fn from_allocated(&self, settings: WrapperSettings) -> Result<Texture>{
let dim = if settings.format.height() > 0 && settings.format.depth() > 0 {
3
}else if settings.format.height() > 0 {
2
}else{
1
};
check_format(&self.0, &settings.format).and_then(|_| {
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
let backend = if self.0.capabilities().supports_dsa() && settings.format.samples() == 0{
Box::new(TextureDsa{
id: settings.id,
target: settings.format.target(),
internal_format: settings.format.internal_format(),
gl: self.0.clone(),
dim,
}) as Box<dyn TextureBackend>
}else{
Box::new(TextureBind{
id: settings.id,
target: settings.format.target(),
internal_format: settings.format.internal_format(),
gl: self.0.clone(),
dim,
}) as Box<dyn TextureBackend>
};
#[cfg(any(feature = "gles", feature="webgl"))]
let backend = Box::new(TextureBind{
id: settings.id,
target: settings.format.target(),
internal_format: settings.format.internal_format(),
gl: self.0.clone(),
dim,
}) as Box<dyn TextureBackend>;
Ok(Texture{
backend,
width: settings.format.width(),
height: settings.format.height(),
depth: settings.format.depth(),
levels: settings.format.levels(),
owned: false,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: settings.format.samples(),
})
})
}
}
impl Texture{
pub fn is_dsa(&self) -> bool{
self.backend.is_dsa()
}
pub fn load_data<T: 'static>(&mut self, data: &[T], mut format: DataFormat) -> Result<()>{
format.fill_defaults_from(self)?;
if format.width > self.width() || format.height > self.height(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanAllocated, None));
}
match format.bytes(){
Ok(format_bytes) => if format_bytes > data.len() * mem::size_of::<T>(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanData, None));
},
Err(err) => error!("{}, please open an issue reporting the undetected format or type", err)
}
unsafe{
self.backend.load_data_ptr(data.as_ptr() as *const c_void, format);
}
Ok(())
}
pub fn load_buffer<T: 'static, B>(&mut self, buffer: &B, mut format: DataFormat) -> Result<()>
where B: BufferRange<T>
{
format.fill_defaults_from(self)?;
if format.width > self.width() || format.height > self.height(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanAllocated, None));
}
match format.bytes(){
Ok(format_bytes) => if format_bytes > buffer.len() * mem::size_of::<T>(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanData, None));
},
Err(err) => error!("{}, please open an issue reporting the undetected format or type", err)
}
unsafe{
self.backend.load_buffer(
buffer.id(),
buffer.start() * mem::size_of::<T>(),
format);
}
Ok(())
}
pub fn load_compressed_data<T: 'static>(&mut self, data: &[T], mut format: CompressedDataFormat) -> Result<()>{
if format.width == 0{
format.width = self.width
}
if format.height == 0{
format.height = self.height
}
if format.format == 0{
return Err(Error::new(ErrorKind::FormatMandatoryOnCompressed, None));
}
if format.width > self.width() || format.height > self.height(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanAllocated, None));
}
if format.format != self.internal_format(){
return Err(Error::new(ErrorKind::FormatNotSupported,
"Compressed data format is different than texture internal format"));
}
let bytes = unsafe{
slice::from_raw_parts::<u8>(data.as_ptr() as *const u8, data.len() * mem::size_of::<T>())
};
unsafe{
self.backend.load_compressed_data(bytes, format);
}
Ok(())
}
pub fn load_compressed_buffer<B, T: 'static>(&mut self, buffer: &B, mut format: CompressedDataFormat) -> Result<()>
where B: BufferRange<T>
{
if format.width == 0{
format.width = self.width
}
if format.height == 0{
format.height = self.height
}
if format.format == 0{
return Err(Error::new(ErrorKind::FormatMandatoryOnCompressed, None));
}
if format.width > self.width() || format.height > self.height(){
return Err(Error::new(ErrorKind::FormatSizeBiggerThanAllocated, None));
}
if format.format != self.internal_format(){
return Err(Error::new(ErrorKind::FormatNotSupported,
"Compressed data format is different than texture internal format"));
}
unsafe{
self.backend.load_compressed_buffer(
buffer.id(),
buffer.start() * mem::size_of::<T>(),
buffer.len() * mem::size_of::<T>(),
format);
}
Ok(())
}
pub fn load_level_from_image<I: Image>(&mut self, img: &I, level: u32) -> Result<()>{
let format = img.gl_format().ok_or_else(|| Error::from(ErrorKind::FormatNotSupported))?;
if img.is_gpu_compressed(){
let format = CompressedDataFormat{
width: img.width(0) as u32,
height: img.height(0) as u32,
format: format,
level: level as u32,
.. Default::default()
};
self.load_compressed_data(img.data(), format)
}else{
let format = DataFormat{
width: img.width(0) as u32,
height: img.height(0) as u32,
format,
ty: img.gl_type().ok_or_else(|| Error::from(ErrorKind::FormatNotSupported))?,
level,
.. Default::default()
};
self.load_data(img.data(), format)
}
}
pub fn load_image<I: Image>(&mut self, img: &I) -> Result<()>{
let format = img.gl_format().ok_or_else(|| Error::from(ErrorKind::FormatNotSupported))?;
let ty = img.gl_type().ok_or_else(|| Error::from(ErrorKind::FormatNotSupported))?;
if img.is_gpu_compressed(){
for level in 0..img.levels(){
self.load_compressed_data(img.mipmap(level).ok_or(ErrorKind::CorruptedImage)?,
CompressedDataFormat{
width: img.width(level) as u32,
height: img.height(level) as u32,
format,
level: level as u32,
.. Default::default()
}).map_err(|err| Error::with_cause(ErrorKind::FormatNotSupported,
"Loading compressed texture data from image", err))?;
}
}else{
for level in 0..img.levels(){
if img.pitch_components(level) != img.width(level) {
let pitch = img.width(level) * img.num_components();
let size = pitch * img.height(level);
let mut pixels = vec![unsafe{mem::MaybeUninit::uninit().assume_init()}; size];
let scanlines = ScanLines::new(img, level);
for (line, src) in (0..img.height(level)).zip(scanlines){
let start = line * pitch;
let dst = &mut pixels[start .. start + pitch];
dst.clone_from_slice(src)
}
self.load_data(&pixels, DataFormat{
width: img.width(level) as u32,
height: img.height(level) as u32,
format,
level: level as u32,
ty,
.. Default::default()
}).map_err(|err| Error::with_cause(ErrorKind::FormatNotSupported,
"Loading pitched texture data from image", err))?;
}else{
self.load_data(img.mipmap(level).ok_or(ErrorKind::CorruptedImage)?,
DataFormat{
width: img.width(level) as u32,
height: img.height(level) as u32,
format,
level: level as u32,
ty,
.. Default::default()
}).map_err(|err| Error::with_cause(ErrorKind::FormatNotSupported,
"Loading texture data from image", err))?;
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
{
if format == gl::RED || format == gl::RG {
self.set_rg_to_rgba_swizzles()
}
}
}
}
Ok(())
}
pub fn width(&self) -> u32{
self.width
}
pub fn height(&self) -> u32{
self.height
}
pub fn depth(&self) -> u32{
self.depth
}
pub fn aspect_ratio(&self) -> f32{
self.width as f32 / self.height as f32
}
pub fn size(&self) -> (u32, u32) {
(self.width, self.height)
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn samples(&self) -> u32{
self.samples
}
pub fn levels(&self) -> u32{
self.levels
}
pub fn id(&self) -> GLuint{
self.backend.id()
}
pub fn target(&self) -> GLenum{
self.backend.target()
}
pub fn internal_format(&self) -> GLenum{
self.backend.internal_format()
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn view(&self) -> Texture{
Texture{
backend: self.backend.view(0, self.levels, 0, 1),
width: self.width,
height: self.height,
depth: self.depth,
levels: self.levels,
owned: true,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: self.samples,
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn set_rg_to_rgba_swizzles(&mut self){
match self.internal_format(){
gl::R8 | gl::R16 | gl::R32F | gl::DEPTH_COMPONENT16 | gl::DEPTH_COMPONENT24 | gl::DEPTH_COMPONENT32 =>{
self.set_swizzles(Swizzles::r_to_rgb())
}
gl::RG8 | gl::RG16 | gl::RG32F => {
self.set_swizzles(Swizzles::rg_to_rgba())
}
_ => {}
}
}
#[cfg(not(feature="webgl"))]
pub fn set_swizzle_r(&mut self, component: Component){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_SWIZZLE_R, component.to_dst() as GLint);
}
}
#[cfg(not(feature="webgl"))]
pub fn set_swizzle_g(&mut self, component: Component){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_SWIZZLE_G, component.to_dst() as GLint);
}
}
#[cfg(not(feature="webgl"))]
pub fn set_swizzle_b(&mut self, component: Component){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_SWIZZLE_B, component.to_dst() as GLint);
}
}
#[cfg(not(feature="webgl"))]
pub fn set_swizzle_a(&mut self, component: Component){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_SWIZZLE_A, component.to_dst() as GLint);
}
}
#[cfg(not(feature="webgl"))]
pub fn set_swizzles(&mut self, swizzles: Swizzles){
self.set_swizzle_r(swizzles.r);
self.set_swizzle_g(swizzles.g);
self.set_swizzle_b(swizzles.b);
self.set_swizzle_a(swizzles.a);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn read_to<T>(&self, pixels: &mut [T], format: GLenum, ty: GLenum){
self.backend.read_to(
pixels.as_ptr() as *mut c_void,
pixels.len() * mem::size_of::<T>(),
format,
ty);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn read_to_buffer<T, B>(&self, buffer: &mut B, format: GLenum, ty: GLenum)
where B: BufferRange<T>
{
self.backend.read_to_buffer(
buffer.id(),
buffer.start() * mem::size_of::<T>(),
buffer.len() * mem::size_of::<T>(),
format, ty)
}
#[cfg(not(feature="webgl"))]
pub fn set_anisotropy_level(&mut self, level: f32){
unsafe{
self.backend.set_parameterf(gl::TEXTURE_MAX_ANISOTROPY_EXT, level);
}
}
pub fn set_base_level(&mut self, level: GLint){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_BASE_LEVEL, level);
}
}
pub fn set_max_level(&mut self, level: GLint){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_MAX_LEVEL, level);
}
}
pub fn set_min_lod(&mut self, level: GLint){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_MIN_LOD, level);
}
}
pub fn set_max_lod(&mut self, level: GLint){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_MAX_LOD, level);
}
}
pub fn set_min_mag_filters(&mut self, min: GLuint, mag: GLuint){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_MIN_FILTER, min as GLint);
self.backend.set_parameteri(gl::TEXTURE_MAG_FILTER, mag as GLint);
}
}
pub fn set_wrap_s(&mut self, wrap: GLenum){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_WRAP_S, wrap as GLint);
}
}
pub fn set_wrap_t(&mut self, wrap: GLenum){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_WRAP_T, wrap as GLint);
}
}
pub fn set_wrap_r(&mut self, wrap: GLenum){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_WRAP_R, wrap as GLint);
}
}
pub fn set_compare_mode(&mut self, mode: GLenum){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_COMPARE_MODE, mode as GLint)
}
}
pub fn set_compare_func(&mut self, mode: GLenum){
unsafe{
self.backend.set_parameteri(gl::TEXTURE_COMPARE_FUNC, mode as GLint)
}
}
#[cfg(not(feature="webgl"))]
pub fn set_border_color(&mut self, color: &[f32;4]){
unsafe{
self.backend.set_parameterfv(gl::TEXTURE_BORDER_COLOR, color);
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_width(&self, level: u32) -> u32{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_WIDTH, level) as u32
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_height(&self, level: u32) -> u32{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_HEIGHT, level) as u32
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_internal_format(&self, level: u32) -> GLenum{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_INTERNAL_FORMAT, level) as GLenum
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_red_type(&self, level: u32) -> GLenum{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_RED_TYPE, level) as GLenum
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_green_type(&self, level: u32) -> GLenum{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_GREEN_TYPE, level) as GLenum
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_blue_type(&self, level: u32) -> GLenum{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_BLUE_TYPE, level) as GLenum
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_alpha_type(&self, level: u32) -> GLenum{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_ALPHA_TYPE, level) as GLenum
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn is_level_compressed(&self, level: u32) -> bool{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_COMPRESSED, level)!=0
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_compressed_image_len(&self, level: u32) -> usize{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_COMPRESSED_IMAGE_SIZE, level) as usize
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_red_size(&self, level: u32) -> usize{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_RED_SIZE, level) as usize
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_green_size(&self, level: u32) -> usize{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_GREEN_SIZE, level) as usize
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_blue_size(&self, level: u32) -> usize{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_BLUE_SIZE, level) as usize
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn level_alpha_size(&self, level: u32) -> usize{
unsafe{
self.backend.get_level_parameteriv(gl::TEXTURE_ALPHA_SIZE, level) as usize
}
}
#[cfg(not(feature="webgl"))]
pub fn depth_stencil_texture_mode(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::DEPTH_STENCIL_TEXTURE_MODE) as GLenum
}
}
pub fn mag_filter(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_MAG_FILTER) as GLenum
}
}
pub fn min_filter(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_MIN_FILTER) as GLenum
}
}
pub fn min_lod(&self) -> i32{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_MIN_LOD)
}
}
pub fn max_lod(&self) -> i32{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_MAX_LOD)
}
}
pub fn base_level(&self) -> i32{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_BASE_LEVEL)
}
}
pub fn max_level(&self) -> i32{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_MAX_LEVEL)
}
}
#[cfg(not(feature="webgl"))]
pub fn swizzle_r(&self) -> Component{
unsafe{
let dst = self.get_parameteri(gl::TEXTURE_SWIZZLE_R);
Component::from_dst(dst as GLenum).unwrap()
}
}
#[cfg(not(feature="webgl"))]
pub fn swizzle_g(&self) -> Component{
unsafe{
let dst = self.get_parameteri(gl::TEXTURE_SWIZZLE_G);
Component::from_dst(dst as GLenum).unwrap()
}
}
#[cfg(not(feature="webgl"))]
pub fn swizzle_b(&self) -> Component{
unsafe{
let dst = self.get_parameteri(gl::TEXTURE_SWIZZLE_B);
Component::from_dst(dst as GLenum).unwrap()
}
}
#[cfg(not(feature="webgl"))]
pub fn swizzle_a(&self) -> Component{
unsafe{
let dst = self.get_parameteri(gl::TEXTURE_SWIZZLE_A);
Component::from_dst(dst as GLenum).unwrap()
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn swizzles(&self) -> Swizzles{
let rgba = unsafe{
self.backend.get_parameterfv(gl::TEXTURE_SWIZZLE_RGBA, 4)
};
Swizzles{
r: Component::from_dst(rgba[0] as GLenum).unwrap(),
g: Component::from_dst(rgba[1] as GLenum).unwrap(),
b: Component::from_dst(rgba[2] as GLenum).unwrap(),
a: Component::from_dst(rgba[3] as GLenum).unwrap(),
}
}
pub fn wrap_s(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_WRAP_S) as GLenum
}
}
pub fn wrap_t(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_WRAP_T) as GLenum
}
}
pub fn wrap_r(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_WRAP_R) as GLenum
}
}
#[cfg(not(feature="webgl"))]
pub fn border_color(&self) -> [f32;4]{
unsafe{
let vector = self.backend.get_parameterfv(gl::TEXTURE_BORDER_COLOR, 4);
let mut arr = [0f32; 4];
arr.copy_from_slice(&vector);
arr
}
}
pub fn compare_mode(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_COMPARE_MODE) as GLenum
}
}
pub fn compare_func(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::TEXTURE_COMPARE_FUNC) as GLenum
}
}
#[cfg(not(feature="webgl"))]
pub fn image_format_compatibility_type(&self) -> GLenum{
unsafe{
self.backend.get_parameteri(gl::IMAGE_FORMAT_COMPATIBILITY_TYPE) as GLenum
}
}
pub unsafe fn set_parameteri(&mut self, parameter: GLenum, value: GLint){
self.backend.set_parameteri(parameter, value);
}
pub unsafe fn set_parameterf(&mut self, parameter: GLenum, value: GLfloat){
self.backend.set_parameterf(parameter, value);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub unsafe fn get_level_parameteriv(&self, parameter: GLenum, level: u32) -> GLint{
self.backend.get_level_parameteriv(parameter, level)
}
pub unsafe fn get_parameteri(&self, parameter: GLenum) -> GLint{
self.backend.get_parameteri(parameter)
}
pub unsafe fn get_parameterf(&self, parameter: GLenum) -> GLfloat{
self.backend.get_parameterf(parameter)
}
pub unsafe fn get_parameterfv(&self, parameter: GLenum, len: usize) -> Vec<GLfloat>{
self.backend.get_parameterfv(parameter, len)
}
pub fn generate_mipmaps(&self){
self.backend.generate_mipmaps();
}
pub fn format(&self) -> Format{
Format::Custom {
target: self.target(),
internal_format: self.internal_format(),
width: self.width,
height: self.height,
depth: self.depth,
levels: self.levels,
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
samples: self.samples,
#[cfg(any(feature = "gles", feature="webgl"))]
samples: 0,
}
}
pub fn texture_sampler<'a>(&'a self, sampler: &'a Sampler) -> TextureSampler<'a>{
TextureSampler{
texture: self,
sampler
}
}
}
#[derive(Clone, Copy)]
pub struct TextureSampler<'a>{
texture: &'a Texture,
sampler: &'a Sampler,
}
impl<'a> TextureSampler<'a>{
pub fn width(&self) -> u32{
self.texture.width
}
pub fn height(&self) -> u32{
self.texture.height
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
pub fn samples(&self) -> u32{
self.texture.samples
}
pub fn levels(&self) -> u32{
self.texture.levels
}
pub fn texture_id(&self) -> GLuint{
self.texture.backend.id()
}
pub fn sampler_id(&self) -> GLuint{
self.sampler.id()
}
pub fn target(&self) -> GLenum{
self.texture.backend.target()
}
pub fn internal_format(&self) -> GLenum{
self.texture.backend.internal_format()
}
}
trait TextureBackend: ::std::fmt::Debug{
fn is_dsa(&self) -> bool;
fn allocate(&mut self, settings: &Format);
unsafe fn load_data_ptr(&mut self, data: *const c_void, format: DataFormat);
unsafe fn load_buffer(&mut self, buffer: u32, offset_in_buffer: usize, format: DataFormat);
unsafe fn load_compressed_data(&mut self, data: &[u8], format: CompressedDataFormat);
unsafe fn load_compressed_buffer(&mut self, buffer: u32, offset_in_buffer: usize, size: usize, format: CompressedDataFormat);
fn generate_mipmaps(&self);
fn id(&self) -> GLuint;
fn internal_format(&self) -> GLenum;
fn target(&self) -> GLenum;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn view(&self, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32) -> Box<dyn TextureBackend>;
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn read_to(&self, pixels: *mut c_void, size: usize, format: GLenum, ty: GLenum);
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn read_to_buffer(&self, buffer: u32, offset_in_buffer: usize, size: usize, format: GLenum, ty: GLenum);
unsafe fn set_parameteri(&mut self, parameter: GLenum, value: GLint);
unsafe fn set_parameterf(&mut self, parameter: GLenum, value: GLfloat);
#[cfg(not(feature="webgl"))]
unsafe fn set_parameteriv(&mut self, parameter: GLenum, value: &[GLint]);
#[cfg(not(feature="webgl"))]
unsafe fn set_parameterfv(&mut self, parameter: GLenum, value: &[GLfloat]);
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn get_level_parameteriv(&self, parameter: GLenum, level: u32) -> GLint;
unsafe fn get_parameteri(&self, parameter: GLenum) -> GLint;
unsafe fn get_parameterf(&self, parameter: GLenum) -> GLfloat;
unsafe fn get_parameterfv(&self, parameter: GLenum, len: usize) -> Vec<GLfloat>;
fn delete(&mut self);
fn gl(&self) -> &StateRef;
}
#[derive(Debug)]
struct TextureBind{
id: GLuint,
target: GLenum,
internal_format: GLenum,
dim: u32,
gl: StateRef,
}
impl TextureBind{
fn new(gl: &StateRef, settings: &Format) -> TextureBind{
let mut id = 0;
unsafe{
gl.GenTextures(1, &mut id);
let target = settings.target();
let dim;
gl.BindTexture(target, id);
gl.TexParameteri(target, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
gl.TexParameteri(target, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
if settings.height() > 0 && settings.depth() > 0 {
gl.TexParameteri(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
gl.TexParameteri(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
gl.TexParameteri(target, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE as GLint);
dim = 3;
}else if settings.height() > 0 {
gl.TexParameteri(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
gl.TexParameteri(target, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
dim = 2;
}else {
gl.TexParameteri(target, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
dim = 1;
}
let mut backend = TextureBind{
id: id,
target,
internal_format: settings.internal_format(),
gl: gl.clone(),
dim,
};
backend.allocate(&settings);
backend
}
}
}
impl TextureBackend for TextureBind{
#[inline]
fn is_dsa(&self) -> bool{
false
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[inline]
fn allocate(&mut self, format: &Format){
unsafe{
match *format {
Format::Texture1D { internal_format, width, levels } => self.gl.TexStorage1D(
gl::TEXTURE_1D,
levels as GLint,
internal_format,
width as GLint,
),
Format::Texture1DArray { internal_format, width, layers, levels } => self.gl.TexStorage2D(
gl::TEXTURE_1D_ARRAY,
levels as GLint,
internal_format,
width as GLint,
layers as GLint
),
Format::Texture2D{internal_format, width, height, levels} => self.gl.TexStorage2D(
gl::TEXTURE_2D,
levels as GLint,
internal_format,
width as GLint,
height as GLint
),
Format::Texture2DMultisample { internal_format, width, height, samples } => self.gl.TexStorage2DMultisample(
gl::TEXTURE_2D_MULTISAMPLE,
samples as GLsizei,
internal_format,
width as GLsizei,
height as GLsizei,
gl::TRUE
),
Format::Texture2DArray { internal_format, width, height, layers, levels } => self.gl.TexStorage3D(
gl::TEXTURE_2D_ARRAY,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
layers as GLint
),
Format::Texture2DArrayMultisample { internal_format, width, height, layers, samples } => self.gl.TexStorage3DMultisample(
gl::TEXTURE_2D_MULTISAMPLE_ARRAY,
samples as GLint,
internal_format,
width as GLint,
height as GLint,
layers as GLint,
gl::TRUE
),
Format::Texture3D { internal_format, width, height, depth, levels } => self.gl.TexStorage3D(
gl::TEXTURE_3D,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint
),
Format::TextureRectangkle { internal_format, width, height, levels } => self.gl.TexStorage2D(
gl::TEXTURE_RECTANGLE,
levels as GLint,
internal_format,
width as GLint,
height as GLint
),
Format::Custom { target, internal_format, width, height, depth, levels, samples } => {
if height > 0 && depth > 0 && samples > 0 {
self.gl.TexStorage3DMultisample(
target,
samples as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint,
gl::TRUE
)
}else if height > 0 && depth > 0 {
self.gl.TexStorage3D(
target,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint
)
}else if height > 0 && samples > 0 {
self.gl.TexStorage2DMultisample(
target,
samples as GLsizei,
internal_format,
width as GLsizei,
height as GLsizei,
gl::TRUE
)
}else if height > 0 {
self.gl.TexStorage2D(
target,
levels as GLint,
internal_format,
width as GLint,
height as GLint
)
}else{
self.gl.TexStorage1D(
target,
levels as GLint,
internal_format,
width as GLint,
)
}
}
}
}
}
#[cfg(any(feature = "gles", feature="webgl"))]
#[inline]
fn allocate(&mut self, format: &Format){
unsafe{
let data_format = gl_format_from_internal(format.internal_format()).unwrap();
let ty = gl_type_from_internal(format.internal_format()).unwrap();
match *format {
Format::Texture2D{internal_format, mut width, mut height, levels} =>
for level in 0..levels {
self.gl.TexImage2D(
gl::TEXTURE_2D,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
0,
data_format,
ty,
::std::ptr::null());
width >>= 1;
height >>= 1;
},
Format::Texture2DArray { internal_format, mut width, mut height, layers, levels } =>
for level in 0..levels {
self.gl.TexImage3D(
gl::TEXTURE_2D_ARRAY,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
layers as GLint,
0,
data_format,
ty,
::std::ptr::null());
width >>= 1;
height >>= 1;
},
Format::Texture3D { internal_format, mut width, mut height, mut depth, levels } =>
for level in 0..levels {
self.gl.TexImage3D(
gl::TEXTURE_3D,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
depth as GLint,
0,
data_format,
ty,
::std::ptr::null());
width >>= 1;
height >>= 1;
depth >>= 1;
},
Format::Custom { target, internal_format, mut width, mut height, mut depth, levels, samples } => {
if target == gl::TEXTURE_CUBE_MAP {
for level in 0..levels {
for target in gl::TEXTURE_CUBE_MAP_POSITIVE_X ..= gl::TEXTURE_CUBE_MAP_NEGATIVE_Z {
self.gl.TexImage2D(
target,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
0,
data_format,
ty,
::std::ptr::null());
}
width >>= 1;
height >>= 1;
}
}else if height > 0 && depth > 0 {
for level in 0..levels {
self.gl.TexImage3D(
target,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
depth as GLint,
0,
data_format,
ty,
::std::ptr::null());
width >>= 1;
height >>= 1;
if target != gl::TEXTURE_2D_ARRAY {
depth >>= 1;
}
}
}else{
for level in 0..levels {
self.gl.TexImage2D(
target,
level as GLint,
internal_format as GLint,
width as GLint,
height as GLint,
0,
data_format,
ty,
::std::ptr::null());
width >>= 1;
height >>= 1;
}
}
}
}
}
}
#[inline]
unsafe fn load_data_ptr(&mut self, data: *const c_void, format: DataFormat){
self.gl.state().set_pixel_store(format.width as i32);
self.gl.BindTexture(self.target, self.id);
if self.dim == 3 {
self.gl.TexSubImage3D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
format.ty,
data);
}else if self.dim == 2 {
self.gl.TexSubImage2D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
format.ty,
data);
}else{
#[cfg(not(any(feature = "gles", feature="webgl")))]
self.gl.TexSubImage1D(self.target,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
format.ty,
data);
#[cfg(any(feature = "gles", feature="webgl"))]
unreachable!();
}
}
#[inline]
unsafe fn load_buffer(&mut self, buffer: u32, offset_in_buffer: usize, format: DataFormat){
self.gl.BindTexture(self.target, self.id);
self.gl.state_mut().bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer);
if self.dim == 3 {
self.gl.TexSubImage3D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
}else if self.dim == 2 {
self.gl.TexSubImage2D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
}else{
#[cfg(not(any(feature = "gles", feature="webgl")))]
self.gl.TexSubImage1D(self.target,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
#[cfg(any(feature = "gles", feature="webgl"))]
unreachable!()
}
}
#[inline]
unsafe fn load_compressed_data(&mut self, data: &[u8], format: CompressedDataFormat){
self.gl.BindTexture(self.target, self.id);
if self.dim == 3 {
self.gl.CompressedTexSubImage3D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
data.len() as i32,
mem::transmute(data.as_ptr()));
}else if self.dim == 2 {
self.gl.CompressedTexSubImage2D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
data.len() as i32,
mem::transmute(data.as_ptr()));
}else{
#[cfg(not(any(feature = "gles", feature="webgl")))]
self.gl.CompressedTexSubImage1D(self.target,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
data.len() as i32,
mem::transmute(data.as_ptr()));
#[cfg(any(feature = "gles", feature="webgl"))]
unreachable!()
}
}
#[cfg(feature="webgl")]
unsafe fn load_compressed_buffer(&mut self, buffer: u32, offset_in_buffer: usize, size: usize, format: CompressedDataFormat){
self.gl.BindTexture(self.target, self.id);
self.gl.state_mut().bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer);
if self.dim == 3 {
self.gl.CompressedTexSubImage3D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
size as i32,
offset_in_buffer as isize);
}else{
self.gl.CompressedTexSubImage2D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
size as i32,
offset_in_buffer as isize);
}
}
#[cfg(not(feature="webgl"))]
unsafe fn load_compressed_buffer(&mut self, buffer: u32, offset_in_buffer: usize, size: usize, format: CompressedDataFormat){
self.gl.BindTexture(self.target, self.id);
self.gl.state_mut().bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer);
if self.dim == 3 {
self.gl.CompressedTexSubImage3D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
}else if self.dim == 2 {
self.gl.CompressedTexSubImage2D(self.target,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
}else{
#[cfg(not(feature="gles"))]
self.gl.CompressedTexSubImage1D(self.target,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
#[cfg(feature="gles")]
unreachable!()
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
fn view(&self, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32) -> Box<dyn TextureBackend>{
unsafe{
let mut id = 0;
self.gl.GenTextures(1, &mut id);
self.gl.TextureView(
id, self.target, self.id, self.internal_format,
minlevel, numlevels, minlayer, numlayers
);
Box::new(TextureBind{
id: id,
target: self.target,
internal_format: self.internal_format,
gl: self.gl.clone(),
dim: self.dim,
})
}
}
#[inline]
fn id(&self) -> GLuint{
self.id
}
#[inline]
fn target(&self) -> GLenum{
self.target
}
#[inline]
fn internal_format(&self) -> GLenum{
self.internal_format
}
#[inline]
fn generate_mipmaps(&self){
unsafe{
self.gl.BindTexture(self.target, self.id);
self.gl.GenerateMipmap(self.target);
}
}
#[inline]
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn read_to(&self, pixels: *mut c_void, _size: usize, format: GLenum, ty: GLenum){
self.gl.BindTexture(self.target, self.id);
self.gl.GetTexImage(self.target, 0, format, ty, pixels);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn read_to_buffer(&self, buffer: u32, offset: usize, _size: usize, format: GLenum, ty: GLenum){
self.gl.BindTexture(self.target, self.id);
self.gl.state_mut().bind_buffer(gl::PIXEL_PACK_BUFFER, buffer);
self.gl.GetTexImage(self.target, 0, format, ty, offset as _);
}
#[inline]
unsafe fn set_parameteri(&mut self, parameter: GLenum, value: GLint){
self.gl.BindTexture(self.target, self.id);
self.gl.TexParameteri(self.target, parameter, value);
}
#[inline]
unsafe fn set_parameterf(&mut self, parameter: GLenum, value: GLfloat){
self.gl.BindTexture(self.target, self.id);
self.gl.TexParameterf(self.target, parameter, value);
}
#[inline]
#[cfg(not(feature="webgl"))]
unsafe fn set_parameteriv(&mut self, parameter: GLenum, value: &[GLint]){
self.gl.BindTexture(self.target, self.id);
self.gl.TexParameteriv(self.target, parameter, value.as_ptr());
}
#[inline]
#[cfg(not(feature="webgl"))]
unsafe fn set_parameterfv(&mut self, parameter: GLenum, value: &[GLfloat]){
self.gl.BindTexture(self.target, self.id);
self.gl.TexParameterfv(self.target, parameter, value.as_ptr());
}
#[inline]
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn get_level_parameteriv(&self, parameter: GLenum, level: u32) -> GLint{
let mut ret = 0;
self.gl.BindTexture( self.target, self.id );
let target = if self.target == gl::TEXTURE_CUBE_MAP {
gl::TEXTURE_CUBE_MAP_POSITIVE_X
}else{
gl::TEXTURE_CUBE_MAP
};
self.gl.GetTexLevelParameteriv(target, level as GLint, parameter, &mut ret);
ret
}
unsafe fn get_parameteri(&self, parameter: GLenum) -> GLint{
let mut ret = 0;
self.gl.BindTexture( self.target, self.id );
self.gl.GetTexParameteriv(self.target, parameter, &mut ret);
ret
}
unsafe fn get_parameterf(&self, parameter: GLenum) -> GLfloat{
let mut ret = 0f32;
self.gl.BindTexture( self.target, self.id );
self.gl.GetTexParameterfv(self.target, parameter, &mut ret);
ret
}
unsafe fn get_parameterfv(&self, parameter: GLenum, len: usize) -> Vec<GLfloat>{
let mut ret = Vec::with_capacity(len);
ret.set_len(len);
self.gl.BindTexture( self.target, self.id );
self.gl.GetTexParameterfv(self.target, parameter, ret.as_mut_ptr());
ret
}
#[inline]
fn delete(&mut self){
if self.id != 0{
unsafe{
self.gl.DeleteTextures(1, &self.id);
}
self.id = 0;
self.target = 0;
}
}
fn gl(&self) -> &StateRef{
&self.gl
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
#[derive(Debug)]
struct TextureDsa{
id: GLuint,
target: GLenum,
internal_format: GLenum,
gl: StateRef,
dim: u32,
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl TextureDsa{
#[inline]
fn new(gl: &StateRef, format: &Format) -> TextureDsa{
let mut id = 0;
unsafe{
gl.CreateTextures(format.target(), 1, &mut id);
let dim;
gl.TextureParameteri(id, gl::TEXTURE_MAG_FILTER, gl::LINEAR as GLint);
gl.TextureParameteri(id, gl::TEXTURE_MIN_FILTER, gl::LINEAR as GLint);
if format.height() > 0 && format.depth() > 0 {
dim = 3;
gl.TextureParameteri(id, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
gl.TextureParameteri(id, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
gl.TextureParameteri(id, gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE as GLint);
}else if format.height() > 0 {
dim = 2;
gl.TextureParameteri(id, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
gl.TextureParameteri(id, gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE as GLint);
}else {
dim = 1;
gl.TextureParameteri(id, gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE as GLint);
}
let mut backend = TextureDsa{
id: id,
target: format.target(),
internal_format: format.internal_format(),
gl: gl.clone(),
dim,
};
backend.allocate(&format);
backend
}
}
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
impl TextureBackend for TextureDsa{
#[inline]
fn is_dsa(&self) -> bool{
true
}
fn allocate(&mut self, format: &Format){
unsafe{
match *format {
Format::Texture1D { internal_format, width, levels } => self.gl.TextureStorage1D(
self.id,
levels as GLint,
internal_format,
width as GLint,
),
Format::Texture1DArray { internal_format, width, layers, levels } => self.gl.TextureStorage2D(
self.id,
levels as GLint,
internal_format,
width as GLint,
layers as GLint
),
Format::Texture2D{internal_format, width, height, levels} => self.gl.TextureStorage2D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint
),
Format::Texture2DMultisample { internal_format, width, height, samples } => self.gl.TextureStorage2DMultisample(
self.id,
samples as GLsizei,
internal_format,
width as GLsizei,
height as GLsizei,
gl::TRUE
),
Format::Texture2DArray { internal_format, width, height, layers, levels } => self.gl.TextureStorage3D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
layers as GLint
),
Format::Texture2DArrayMultisample { internal_format, width, height, layers, samples } => self.gl.TextureStorage3DMultisample(
self.id,
samples as GLint,
internal_format,
width as GLint,
height as GLint,
layers as GLint,
gl::TRUE
),
Format::Texture3D { internal_format, width, height, depth, levels } => self.gl.TextureStorage3D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint
),
Format::TextureRectangkle { internal_format, width, height, levels } => self.gl.TextureStorage2D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint
),
Format::Custom { internal_format, width, height, depth, levels, samples, .. } => {
if height > 0 && depth > 0 && samples > 0 {
self.gl.TextureStorage3DMultisample(
self.id,
samples as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint,
gl::TRUE
)
}else if height > 0 && depth > 0 {
self.gl.TextureStorage3D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint,
depth as GLint
)
}else if height > 0 && samples > 0 {
self.gl.TextureStorage2DMultisample(
self.id,
samples as GLsizei,
internal_format,
width as GLsizei,
height as GLsizei,
gl::TRUE
)
}else if height > 0 {
self.gl.TextureStorage2D(
self.id,
levels as GLint,
internal_format,
width as GLint,
height as GLint
)
}else{
self.gl.TextureStorage1D(
self.id,
levels as GLint,
internal_format,
width as GLint,
)
}
}
}
}
}
#[inline]
unsafe fn load_data_ptr(&mut self, data: *const c_void, format: DataFormat){
self.gl.state().set_pixel_store(format.width as i32);
if self.dim == 3 {
self.gl.TextureSubImage3D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
format.ty,
data as *const c_void);
}else if self.dim == 2 {
self.gl.TextureSubImage2D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
format.ty,
data as *const c_void);
}else{
self.gl.TextureSubImage1D(self.id,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
format.ty,
data as *const c_void);
}
}
#[inline]
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn load_buffer(&mut self, buffer: u32, offset_in_buffer: usize, format: DataFormat){
self.gl.state_mut().bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer);
if self.dim == 3 {
self.gl.TextureSubImage3D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
}else if self.dim == 2 {
self.gl.TextureSubImage2D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
}else{
self.gl.TextureSubImage1D(self.id,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
format.ty,
offset_in_buffer as *const c_void);
}
}
#[inline]
unsafe fn load_compressed_data(&mut self, data: &[u8], format: CompressedDataFormat){
if self.dim == 3 {
self.gl.CompressedTextureSubImage3D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
data.len() as i32,
data.as_ptr() as *const c_void);
}else if self.dim == 2 {
self.gl.CompressedTextureSubImage2D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
data.len() as i32,
data.as_ptr() as *const c_void);
}else{
self.gl.CompressedTextureSubImage1D(self.id,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
data.len() as i32,
data.as_ptr() as *const c_void);
}
}
unsafe fn load_compressed_buffer(&mut self, buffer: u32, offset_in_buffer: usize, size: usize, format: CompressedDataFormat){
self.gl.state_mut().bind_buffer(gl::PIXEL_UNPACK_BUFFER, buffer);
if self.dim == 3 {
self.gl.CompressedTextureSubImage3D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.zoffset as i32,
format.width as i32,
format.height as i32,
format.depth as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
}else if self.dim == 2 {
self.gl.CompressedTextureSubImage2D(self.id,
format.level as i32,
format.xoffset as i32,
format.yoffset as i32,
format.width as i32,
format.height as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
}else{
self.gl.CompressedTextureSubImage1D(self.id,
format.level as i32,
format.xoffset as i32,
format.width as i32,
format.format,
size as i32,
offset_in_buffer as *const c_void);
}
}
fn view(&self, minlevel: u32, numlevels: u32, minlayer: u32, numlayers: u32) -> Box<dyn TextureBackend>{
unsafe{
let mut id = 0;
self.gl.GetError();
self.gl.GenTextures(1, &mut id);
self.gl.TextureView(
id, self.target, self.id, self.internal_format,
minlevel, numlevels, minlayer, numlayers
);
let err = self.gl.GetError();
if err != 0 {
error!("Error after view {:?}", Error::with_gl_code(ErrorKind::FormatNotSupported, "Error creating view", err));
}
Box::new(TextureDsa{
id: id,
target: self.target,
internal_format: self.internal_format,
gl: self.gl.clone(),
dim: self.dim,
})
}
}
fn generate_mipmaps(&self){
unsafe{
self.gl.GenerateTextureMipmap(self.id);
}
}
#[inline]
fn id(&self) -> GLuint{
self.id
}
#[inline]
fn target(&self) -> GLenum{
self.target
}
#[inline]
fn internal_format(&self) -> GLenum{
self.internal_format
}
#[inline]
unsafe fn read_to(&self, pixels: *mut c_void, size: usize, format: GLenum, ty: GLenum){
self.gl.GetTextureImage(self.id, 0, format, ty, size as i32, pixels);
}
#[cfg(all(not(feature = "gles"), not(feature="webgl")))]
unsafe fn read_to_buffer(&self, buffer: u32, offset: usize, size: usize, format: GLenum, ty: GLenum){
self.gl.state_mut().bind_buffer(gl::PIXEL_PACK_BUFFER, buffer);
self.gl.GetTextureImage(self.id, 0, format, ty, size as i32, offset as _);
}
#[inline]
unsafe fn set_parameteri(&mut self, parameter: GLenum, value: GLint){
self.gl.TextureParameteri(self.id, parameter, value);
}
#[inline]
unsafe fn set_parameterf(&mut self, parameter: GLenum, value: GLfloat){
self.gl.TextureParameterf(self.id, parameter, value);
}
#[inline]
unsafe fn set_parameteriv(&mut self, parameter: GLenum, value: &[GLint]){
self.gl.TextureParameteriv(self.id, parameter, value.as_ptr());
}
#[inline]
unsafe fn set_parameterfv(&mut self, parameter: GLenum, value: &[GLfloat]){
self.gl.TextureParameterfv(self.id, parameter, value.as_ptr());
}
#[inline]
unsafe fn get_level_parameteriv(&self, parameter: GLenum, level: u32) -> GLint{
let mut ret = 0;
self.gl.GetTextureLevelParameteriv(self.id, level as GLint, parameter, &mut ret);
ret
}
unsafe fn get_parameteri(&self, parameter: GLenum) -> GLint{
let mut ret = 0;
self.gl.GetTextureParameteriv(self.id, parameter, &mut ret);
ret
}
unsafe fn get_parameterf(&self, parameter: GLenum) -> GLfloat{
let mut ret = 0f32;
self.gl.GetTextureParameterfv(self.id, parameter, &mut ret);
ret
}
unsafe fn get_parameterfv(&self, parameter: GLenum, len: usize) -> Vec<GLfloat>{
let mut ret = Vec::with_capacity(len);
ret.set_len(len);
self.gl.GetTextureParameterfv(self.id, parameter, ret.as_mut_ptr());
ret
}
#[inline]
fn delete(&mut self){
if self.id != 0{
unsafe{
self.gl.DeleteTextures(1, &self.id);
}
self.id = 0;
self.target = 0;
}
}
fn gl(&self) -> &StateRef{
&self.gl
}
}