#![allow(unreachable_code)]
use std::borrow::Cow;
use std::fmt;
use std::error::Error;
use image_format::FormatNotSupportedError;
pub use image_format::{ClientFormat, TextureFormat};
pub use image_format::{UncompressedFloatFormat, UncompressedIntFormat, UncompressedUintFormat};
pub use image_format::{CompressedFormat, DepthFormat, DepthStencilFormat, StencilFormat};
pub use image_format::{CompressedSrgbFormat, SrgbFormat};
pub use self::any::{TextureAny, TextureAnyMipmap, TextureAnyLayer, TextureAnyLayerMipmap};
pub use self::any::{TextureAnyImage, Dimensions};
pub use self::bindless::{ResidentTexture, TextureHandle, BindlessTexturesNotSupportedError};
pub use self::get_format::{InternalFormat, InternalFormatType, GetFormatError};
pub use self::pixel::PixelValue;
pub use self::ty_support::{is_texture_1d_supported, is_texture_2d_supported};
pub use self::ty_support::{is_texture_3d_supported, is_texture_1d_array_supported};
pub use self::ty_support::{is_texture_2d_array_supported, is_texture_2d_multisample_supported};
pub use self::ty_support::{is_texture_2d_multisample_array_supported, is_cubemaps_supported};
pub use self::ty_support::is_cubemap_arrays_supported;
pub mod bindless;
pub mod buffer_texture;
pub mod pixel_buffer;
mod any;
mod get_format;
mod pixel;
mod ty_support;
include!(concat!(env!("OUT_DIR"), "/textures.rs"));
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum CubeLayer {
PositiveX,
NegativeX,
PositiveY,
NegativeY,
PositiveZ,
NegativeZ,
}
impl CubeLayer {
pub fn get_layer_index(&self) -> usize {
match self {
&CubeLayer::PositiveX => 0,
&CubeLayer::NegativeX => 1,
&CubeLayer::PositiveY => 2,
&CubeLayer::NegativeY => 3,
&CubeLayer::PositiveZ => 4,
&CubeLayer::NegativeZ => 5,
}
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
#[allow(missing_docs)]
pub enum TextureKind {
Float,
Integral,
Unsigned,
Depth,
Stencil,
DepthStencil,
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum MipmapsOption {
NoMipmap,
EmptyMipmaps,
EmptyMipmapsMax(u32),
AutoGeneratedMipmaps,
AutoGeneratedMipmapsMax(u32),
}
impl MipmapsOption {
#[inline]
fn should_generate(self) -> bool {
use self::MipmapsOption::*;
match self {
AutoGeneratedMipmaps | AutoGeneratedMipmapsMax(_) => true,
_ => false,
}
}
fn num_levels(self, width: u32, height: Option<u32>, depth: Option<u32>) -> u32 {
use self::MipmapsOption::*;
use std::cmp;
use std::num::FpCategory;
match self {
NoMipmap => 1,
EmptyMipmaps | AutoGeneratedMipmaps => {
let max_dimension = cmp::max(width, cmp::max(height.unwrap_or(1),
depth.unwrap_or(1))) as f32;
if max_dimension.classify() == FpCategory::Zero {
1
} else {
1 + max_dimension.log2() as u32
}
},
EmptyMipmapsMax(i) | AutoGeneratedMipmapsMax(i) => {
let max = EmptyMipmaps.num_levels(width, height, depth) - 1;
if i > max {
panic!("Too many mipmap levels, received {}, maximum for this texture dimension is {}.", i, max);
}
1 + i
},
}
}
}
impl From<CompressedMipmapsOption> for MipmapsOption {
fn from(opt: CompressedMipmapsOption) -> MipmapsOption {
match opt {
CompressedMipmapsOption::NoMipmap => MipmapsOption::NoMipmap,
CompressedMipmapsOption::EmptyMipmaps => MipmapsOption::EmptyMipmaps,
CompressedMipmapsOption::EmptyMipmapsMax(i) => MipmapsOption::EmptyMipmapsMax(i),
}
}
}
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
pub enum CompressedMipmapsOption {
NoMipmap,
EmptyMipmaps,
EmptyMipmapsMax(u32),
}
pub trait Texture1dDataSource<'a> {
type Data: Send + Copy + Clone + 'a;
fn into_raw(self) -> RawImage1d<'a, Self::Data>;
}
pub trait Texture1dDataSink<T> {
fn from_raw(data: Cow<[T]>, width: u32) -> Self where [T]: ToOwned;
}
pub struct RawImage1d<'a, T: Clone + 'a> {
pub data: Cow<'a, [T]>,
pub width: u32,
pub format: ClientFormat,
}
impl<'a, P: PixelValue> Texture1dDataSource<'a> for Vec<P> where P: Copy + Clone + Send + 'static {
type Data = P;
#[inline]
fn into_raw(self) -> RawImage1d<'a, P> {
let width = self.len() as u32;
RawImage1d {
data: Cow::Owned(self),
width: width,
format: <P as PixelValue>::get_format(),
}
}
}
impl<'a, P: PixelValue + Clone> Texture1dDataSource<'a> for RawImage1d<'a, P> {
type Data = P;
#[inline]
fn into_raw(self) -> RawImage1d<'a, P> {
self
}
}
impl<P> Texture1dDataSink<P> for Vec<P> where P: Copy + Clone + Send {
#[inline]
fn from_raw(data: Cow<[P]>, _width: u32) -> Self {
data.into_owned()
}
}
impl<'a, P: PixelValue> Texture1dDataSource<'a> for &'a[P] where P: Copy + Clone + Send + 'static {
type Data = P;
#[inline]
fn into_raw(self) -> RawImage1d<'a, P> {
let width = self.len();
RawImage1d {
data: Cow::Borrowed(self),
width: width as u32,
format: <P as PixelValue>::get_format(),
}
}
}
impl<'a, T: Clone + 'a> RawImage1d<'a, T> {
pub fn from_raw_rgb(data: Vec<T>) -> RawImage1d<'a, T>
where T: ToClientFormat {
RawImage1d {
width: (data.len() / 3) as u32,
data: Cow::Owned(data),
format: T::rgb_format(),
}
}
pub fn from_raw_rgba(data: Vec<T>) -> RawImage1d<'a, T>
where T: ToClientFormat {
RawImage1d {
width: (data.len() / 4) as u32,
data: Cow::Owned(data),
format: T::rgba_format(),
}
}
}
pub trait Texture2dDataSource<'a> {
type Data: Send + Copy + Clone + 'a;
fn into_raw(self) -> RawImage2d<'a, Self::Data>;
}
pub trait Texture2dDataSink<T> {
fn from_raw(data: Cow<[T]>, width: u32, height: u32) -> Self where [T]: ToOwned;
}
pub struct RawImage2d<'a, T: Clone + 'a> {
pub data: Cow<'a, [T]>,
pub width: u32,
pub height: u32,
pub format: ClientFormat,
}
#[allow(missing_docs)]
pub trait ToClientFormat {
fn rgb_format() -> ClientFormat;
fn rgba_format() -> ClientFormat;
}
impl ToClientFormat for u8 {
fn rgb_format() -> ClientFormat { ClientFormat::U8U8U8 }
fn rgba_format() -> ClientFormat { ClientFormat::U8U8U8U8 }
}
impl ToClientFormat for i8 {
fn rgb_format() -> ClientFormat { ClientFormat::I8I8I8 }
fn rgba_format() -> ClientFormat { ClientFormat::I8I8I8I8 }
}
impl ToClientFormat for u16 {
fn rgb_format() -> ClientFormat { ClientFormat::U16U16U16 }
fn rgba_format() -> ClientFormat { ClientFormat::U16U16U16U16 }
}
impl ToClientFormat for i16 {
fn rgb_format() -> ClientFormat { ClientFormat::I16I16I16 }
fn rgba_format() -> ClientFormat { ClientFormat::I16I16I16I16 }
}
impl ToClientFormat for u32 {
fn rgb_format() -> ClientFormat { ClientFormat::U32U32U32 }
fn rgba_format() -> ClientFormat { ClientFormat::U32U32U32U32 }
}
impl ToClientFormat for i32 {
fn rgb_format() -> ClientFormat { ClientFormat::I32I32I32 }
fn rgba_format() -> ClientFormat { ClientFormat::I32I32I32I32 }
}
impl ToClientFormat for f32 {
fn rgb_format() -> ClientFormat { ClientFormat::F32F32F32 }
fn rgba_format() -> ClientFormat { ClientFormat::F32F32F32F32 }
}
impl<'a, T: Clone + 'a> RawImage2d<'a, T> {
pub fn from_raw_rgb(data: Vec<T>, dimensions: (u32, u32)) -> RawImage2d<'a, T>
where T: ToClientFormat {
RawImage2d {
data: Cow::Owned(data),
width: dimensions.0,
height: dimensions.1,
format: T::rgb_format(),
}
}
pub fn from_raw_rgba(data: Vec<T>, dimensions: (u32, u32)) -> RawImage2d<'a, T>
where T: ToClientFormat {
RawImage2d {
data: Cow::Owned(data),
width: dimensions.0,
height: dimensions.1,
format: T::rgba_format(),
}
}
pub fn from_raw_rgb_reversed(data: &[T], dimensions: (u32, u32)) -> RawImage2d<'a, T>
where T: ToClientFormat {
let data = data
.chunks(dimensions.0 as usize * 3)
.rev()
.flat_map(|row| row.iter())
.map(|p| p.clone())
.collect();
RawImage2d::from_raw_rgb(data, dimensions)
}
pub fn from_raw_rgba_reversed(data: &[T], dimensions: (u32, u32)) -> RawImage2d<'a, T>
where T: ToClientFormat {
let data = data
.chunks(dimensions.0 as usize * 4)
.rev()
.flat_map(|row| row.iter())
.map(|p| p.clone())
.collect();
RawImage2d::from_raw_rgba(data, dimensions)
}
pub fn from_vec_raw1d(arr: &Vec<RawImage1d<'a, T>>) -> RawImage2d<'a, T> {
let width = arr[0].width;
let height = arr.len() as u32;
let format = arr[0].format;
let raw_data = {
let mut vec = Vec::<T>::with_capacity((width * height) as usize);
for i in arr {
if width != i.width {
panic!("Varying dimensions were found.");
} else if format != i.format {
panic!("Varying formats were found.");
}
for j in i.data.iter() {
vec.push(j.clone());
}
}
vec
};
RawImage2d {
data: Cow::Owned(raw_data),
width: width,
height: height,
format: format,
}
}
}
impl<'a, P: PixelValue + Clone> Texture2dDataSource<'a> for Vec<Vec<P>> {
type Data = P;
fn into_raw(self) -> RawImage2d<'a, P> {
let width = self.iter().next().map(|e| e.len()).unwrap_or(0) as u32;
let height = self.len() as u32;
RawImage2d {
data: Cow::Owned(self.into_iter().flat_map(|e| e.into_iter()).collect()),
width: width,
height: height,
format: <P as PixelValue>::get_format(),
}
}
}
impl<'a, P: PixelValue + Clone> Texture2dDataSource<'a> for RawImage2d<'a, P> {
type Data = P;
#[inline]
fn into_raw(self) -> RawImage2d<'a, P> {
self
}
}
impl<P> Texture2dDataSink<P> for Vec<Vec<P>> where P: Copy + Clone {
fn from_raw(data: Cow<[P]>, width: u32, height: u32) -> Self {
data.chunks(width as usize).map(|e| e.to_vec()).collect()
}
}
macro_rules! impl_2d_sink_for_raw_image {
(($t1:ty, $t2:ty, $t3:ty, $t4:ty)) => (
impl<'a> Texture2dDataSink<($t1, $t2, $t3, $t4)> for RawImage2d<'a, $t1> {
fn from_raw(data: Cow<[($t1, $t2, $t3, $t4)]>, width: u32, height: u32) -> Self {
RawImage2d {
data: Cow::Owned( {
let mut v = Vec::with_capacity(data.len() * 4);
for (a, b, c, d) in data.into_owned() {
v.push(a);
v.push(b);
v.push(c);
v.push(d);
}
v
} ),
width: width,
height: height,
format: <($t1, $t2, $t3, $t4) as PixelValue>::get_format(),
}
}
}
);
(($t1:ty, $t2:ty, $t3:ty)) => (
impl<'a> Texture2dDataSink<($t1, $t2, $t3)> for RawImage2d<'a, $t1> {
fn from_raw(data: Cow<[($t1, $t2, $t3)]>, width: u32, height: u32) -> Self {
RawImage2d {
data: Cow::Owned( {
let mut v = Vec::with_capacity(data.len() * 3);
for (a, b, c) in data.into_owned() {
v.push(a);
v.push(b);
v.push(c);
}
v
} ),
width: width,
height: height,
format: <($t1, $t2, $t3) as PixelValue>::get_format(),
}
}
}
);
(($t1:ty, $t2:ty)) => (
impl<'a> Texture2dDataSink<($t1, $t2)> for RawImage2d<'a, $t1> {
fn from_raw(data: Cow<[($t1, $t2)]>, width: u32, height: u32) -> Self {
RawImage2d {
data: Cow::Owned( {
let mut v = Vec::with_capacity(data.len() * 2);
for (a, b) in data.into_owned() {
v.push(a);
v.push(b);
}
v
} ),
width: width,
height: height,
format: <($t1, $t2) as PixelValue>::get_format(),
}
}
}
);
($t1:ty) => (
impl<'a> Texture2dDataSink<$t1> for RawImage2d<'a, $t1> {
fn from_raw(data: Cow<[$t1]>, width: u32, height: u32) -> Self {
RawImage2d {
data: Cow::Owned(data.into_owned()),
width: width,
height: height,
format: <$t1 as PixelValue>::get_format(),
}
}
}
);
}
impl_2d_sink_for_raw_image!(i8);
impl_2d_sink_for_raw_image!((i8, i8));
impl_2d_sink_for_raw_image!((i8, i8, i8));
impl_2d_sink_for_raw_image!((i8, i8, i8, i8));
impl_2d_sink_for_raw_image!(u8);
impl_2d_sink_for_raw_image!((u8, u8));
impl_2d_sink_for_raw_image!((u8, u8, u8));
impl_2d_sink_for_raw_image!((u8, u8, u8, u8));
impl_2d_sink_for_raw_image!(i16);
impl_2d_sink_for_raw_image!((i16, i16));
impl_2d_sink_for_raw_image!((i16, i16, i16));
impl_2d_sink_for_raw_image!((i16, i16, i16, i16));
impl_2d_sink_for_raw_image!(u16);
impl_2d_sink_for_raw_image!((u16, u16));
impl_2d_sink_for_raw_image!((u16, u16, u16));
impl_2d_sink_for_raw_image!((u16, u16, u16, u16));
impl_2d_sink_for_raw_image!(i32);
impl_2d_sink_for_raw_image!((i32, i32));
impl_2d_sink_for_raw_image!((i32, i32, i32));
impl_2d_sink_for_raw_image!((i32, i32, i32, i32));
impl_2d_sink_for_raw_image!(u32);
impl_2d_sink_for_raw_image!((u32, u32));
impl_2d_sink_for_raw_image!((u32, u32, u32));
impl_2d_sink_for_raw_image!((u32, u32, u32, u32));
impl_2d_sink_for_raw_image!(f32);
impl_2d_sink_for_raw_image!((f32, f32));
impl_2d_sink_for_raw_image!((f32, f32, f32));
impl_2d_sink_for_raw_image!((f32, f32, f32, f32));
pub trait Texture3dDataSource<'a> {
type Data: Send + Copy + Clone + 'a;
fn into_raw(self) -> RawImage3d<'a, Self::Data>;
}
pub trait Texture3dDataSink<T> {
fn from_raw(data: Cow<[T]>, width: u32, height: u32, depth: u32) -> Self where [T]: ToOwned;
}
pub struct RawImage3d<'a, T: Clone + 'a> {
pub data: Cow<'a, [T]>,
pub width: u32,
pub height: u32,
pub depth: u32,
pub format: ClientFormat,
}
impl<'a, T: Clone + 'a> RawImage3d<'a, T> {
pub fn from_vec_raw2d(arr: &Vec<RawImage2d<'a, T>>) -> RawImage3d<'a, T> {
let depth = arr.len() as u32;
let width = arr[0].width;
let height = arr[0].height;
let format = arr[0].format;
let raw_data = {
let mut vec = Vec::<T>::with_capacity((width * height * depth) as usize);
for i in arr {
if width != i.width || height != i.height {
panic!("Varying dimensions were found.");
} else if format != i.format {
panic!("Varying formats were found.");
}
for j in i.data.iter() {
vec.push(j.clone());
}
}
vec
};
RawImage3d {
data: Cow::Owned(raw_data),
width: width,
height: height,
depth: depth,
format: format,
}
}
}
impl<'a, P: PixelValue + Clone> Texture3dDataSource<'a> for Vec<Vec<Vec<P>>> {
type Data = P;
fn into_raw(self) -> RawImage3d<'a, P> {
let width = self.iter().next().and_then(|e| e.iter().next()).map(|e| e.len()).unwrap_or(0)
as u32;
let height = self.iter().next().map(|e| e.len()).unwrap_or(0) as u32;
let depth = self.len() as u32;
RawImage3d {
data: self.into_iter().flat_map(|e| e.into_iter()).flat_map(|e| e.into_iter())
.collect(),
width: width,
height: height,
depth: depth,
format: <P as PixelValue>::get_format(),
}
}
}
impl<'a, P: PixelValue + Clone> Texture3dDataSource<'a> for RawImage3d<'a, P> {
type Data = P;
#[inline]
fn into_raw(self) -> RawImage3d<'a, P> {
self
}
}
impl<P> Texture3dDataSink<P> for Vec<Vec<Vec<P>>> where P: Copy + Clone {
#[inline]
fn from_raw(_data: Cow<[P]>, _width: u32, _height: u32, _depth: u32) -> Self {
unimplemented!()
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum TextureCreationError {
FormatNotSupported,
DimensionsNotSupported,
TypeNotSupported,
}
impl fmt::Display for TextureCreationError {
fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
use self::TextureCreationError::*;
let desc = match *self {
FormatNotSupported =>
"The requested format is not supported by the backend",
DimensionsNotSupported =>
"The requested texture dimensions are not supported",
TypeNotSupported =>
"The texture format is not supported by the backend",
};
fmt.write_str(desc)
}
}
impl Error for TextureCreationError {}
impl From<FormatNotSupportedError> for TextureCreationError {
#[inline]
fn from(_: FormatNotSupportedError) -> TextureCreationError {
TextureCreationError::FormatNotSupported
}
}