use super::*;
use super::errors::*;
use std::os::raw::c_void;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TextureId(u32);
#[repr(C)]
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub struct TextureHandle(u64);
impl TextureHandle {
pub fn empty() -> TextureHandle {
TextureHandle(0)
}
}
impl From<TextureHandle> for u64 {
fn from(texture_handle: TextureHandle) -> Self {
texture_handle.0
}
}
impl TextureId {
pub fn empty() -> TextureId {
TextureId(0)
}
}
impl From<TextureId> for u32 {
fn from(texture_id: TextureId) -> Self {
texture_id.0
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureTarget {
Texture1D,
Texture2D,
Texture3D,
Texture1DArray,
Texture2DArray,
TextureRectangle,
TextureCubeMap,
TextureCubeMapArray,
TextureBuffer,
Texture2DMultisample,
Texture2DMultisampleArray,
}
impl From<TextureTarget> for u32 {
fn from(texture_target: TextureTarget) -> Self {
use self::TextureTarget::*;
match texture_target {
Texture1D => gl::TEXTURE_1D,
Texture2D => gl::TEXTURE_2D,
Texture3D => gl::TEXTURE_3D,
Texture1DArray => gl::TEXTURE_1D_ARRAY,
Texture2DArray => gl::TEXTURE_2D_ARRAY,
TextureRectangle => gl::TEXTURE_RECTANGLE,
TextureCubeMap => gl::TEXTURE_CUBE_MAP,
TextureCubeMapArray => gl::TEXTURE_CUBE_MAP_ARRAY,
TextureBuffer => gl::TEXTURE_BUFFER,
Texture2DMultisample => gl::TEXTURE_2D_MULTISAMPLE,
Texture2DMultisampleArray => gl::TEXTURE_2D_MULTISAMPLE_ARRAY,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureInternalFormat {
R8,
R8SN,
R8I,
R8UI,
R16,
R16F,
R16SN,
R16I,
R16UI,
R32F,
R32I,
R32UI,
RG8,
RG8SN,
RG8I,
RG8UI,
RG16,
RG16F,
RG16SN,
RG16I,
RG16UI,
RG32F,
RG32I,
RG32UI,
RGB8,
RGB8SN,
RGB8I,
RGB8UI,
RGB16,
RGB16F,
RGB16SN,
RGB16I,
RGB16UI,
RGB32F,
RGB32I,
RGB32UI,
RGBA8,
RGBA8SN,
RGBA8I,
RGBA8UI,
RGBA16,
RGBA16F,
RGBA16SN,
RGBA16I,
RGBA16UI,
RGBA32F,
RGBA32I,
RGBA32UI,
DepthComponent16F,
DepthComponent24F,
DepthComponent32F,
StencilIndex8U,
Depth24FStencil8U,
Depth32FStencil8U,
Alpha,
CompressedRGBABPTCUN,
CompressedRGBDTX1,
CompressedRGBADXT1,
CompressedRGBADXT3,
CompressedRGBADXT5,
}
impl From<TextureInternalFormat> for gl::types::GLenum {
fn from(internal_format: TextureInternalFormat) -> gl::types::GLenum {
use self::TextureInternalFormat::*;
match internal_format {
R8 => gl::R8,
R8SN => gl::R8_SNORM,
R8I => gl::R8I,
R8UI => gl::R8UI,
R16 => gl::R16,
R16F => gl::R16F,
R16SN => gl::R16_SNORM,
R16I => gl::R16I,
R16UI => gl::R16UI,
R32F => gl::R32F,
R32I => gl::R32I,
R32UI => gl::R32UI,
RG8 => gl::RG8,
RG8SN => gl::RG8_SNORM,
RG8I => gl::RG8I,
RG8UI => gl::RG8UI,
RG16 => gl::RG16,
RG16F => gl::RG16F,
RG16SN => gl::RG16_SNORM,
RG16I => gl::RG16I,
RG16UI => gl::RG16UI,
RG32F => gl::RG32F,
RG32I => gl::RG32I,
RG32UI => gl::RG32UI,
RGB8 => gl::RGB8,
RGB8SN => gl::RGB8_SNORM,
RGB8I => gl::RGB8I,
RGB8UI => gl::RGB8UI,
RGB16 => gl::RGB16,
RGB16F => gl::RGB16F,
RGB16SN => gl::RGB16_SNORM,
RGB16I => gl::RGB16I,
RGB16UI => gl::RGB16UI,
RGB32F => gl::RGB32F,
RGB32I => gl::RGB32I,
RGB32UI => gl::RGB32UI,
RGBA8 => gl::RGBA8,
RGBA8SN => gl::RGBA8_SNORM,
RGBA8I => gl::RGBA8I,
RGBA8UI => gl::RGBA8UI,
RGBA16 => gl::RGBA16,
RGBA16F => gl::RGBA16F,
RGBA16SN => gl::RGBA16_SNORM,
RGBA16I => gl::RGBA16I,
RGBA16UI => gl::RGBA16UI,
RGBA32F => gl::RGBA32F,
RGBA32I => gl::RGBA32I,
RGBA32UI => gl::RGBA32UI,
DepthComponent16F => gl::DEPTH_COMPONENT16,
DepthComponent24F => gl::DEPTH_COMPONENT24,
DepthComponent32F => gl::DEPTH_COMPONENT32F,
StencilIndex8U => gl::STENCIL_INDEX8,
Depth24FStencil8U => gl::DEPTH24_STENCIL8,
Depth32FStencil8U => gl::DEPTH32F_STENCIL8,
Alpha => gl::ALPHA,
CompressedRGBABPTCUN => gl::COMPRESSED_RGBA_BPTC_UNORM,
CompressedRGBDTX1 => gl::COMPRESSED_RGB_S3TC_DXT1_EXT,
CompressedRGBADXT1 => gl::COMPRESSED_RGBA_S3TC_DXT1_EXT,
CompressedRGBADXT3 => gl::COMPRESSED_RGBA_S3TC_DXT3_EXT,
CompressedRGBADXT5 => gl::COMPRESSED_RGBA_S3TC_DXT5_EXT,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureBufferInternalFormat {
R8,
R8I,
R8UI,
R16,
R16F,
R16I,
R16UI,
R32F,
R32I,
R32UI,
RG8,
RG8I,
RG8UI,
RG16,
RG16F,
RG16I,
RG16UI,
RG32F,
RG32I,
RG32UI,
RGB32F,
RGB32I,
RGB32UI,
RGBA8,
RGBA8I,
RGBA8UI,
RGBA16,
RGBA16F,
RGBA16I,
RGBA16UI,
RGBA32F,
RGBA32I,
RGBA32UI,
}
impl From<TextureBufferInternalFormat> for gl::types::GLenum {
fn from(internal_format: TextureBufferInternalFormat) -> gl::types::GLenum {
use self::TextureBufferInternalFormat::*;
match internal_format {
R8 => gl::R8,
R8I => gl::R8I,
R8UI => gl::R8UI,
R16 => gl::R16,
R16F => gl::R16F,
R16I => gl::R16I,
R16UI => gl::R16UI,
R32F => gl::R32F,
R32I => gl::R32I,
R32UI => gl::R32UI,
RG8 => gl::RG8,
RG8I => gl::RG8I,
RG8UI => gl::RG8UI,
RG16 => gl::RG16,
RG16F => gl::RG16F,
RG16I => gl::RG16I,
RG16UI => gl::RG16UI,
RG32F => gl::RG32F,
RG32I => gl::RG32I,
RG32UI => gl::RG32UI,
RGB32F => gl::RGB32F,
RGB32I => gl::RGB32I,
RGB32UI => gl::RGB32UI,
RGBA8 => gl::RGBA8,
RGBA8I => gl::RGBA8I,
RGBA8UI => gl::RGBA8UI,
RGBA16 => gl::RGBA16,
RGBA16F => gl::RGBA16F,
RGBA16I => gl::RGBA16I,
RGBA16UI => gl::RGBA16UI,
RGBA32F => gl::RGBA32F,
RGBA32I => gl::RGBA32I,
RGBA32UI => gl::RGBA32UI,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureDataType {
UnsignedByte,
Byte,
UnsignedShort,
Short,
UnsignedInt,
Int,
Float,
}
impl From<TextureDataType> for gl::types::GLenum {
fn from(texture_data_type: TextureDataType) -> Self {
match texture_data_type {
TextureDataType::UnsignedByte => gl::UNSIGNED_BYTE,
TextureDataType::Byte => gl::BYTE,
TextureDataType::UnsignedShort => gl::UNSIGNED_SHORT,
TextureDataType::Short => gl::SHORT,
TextureDataType::UnsignedInt => gl::UNSIGNED_INT,
TextureDataType::Int => gl::INT,
TextureDataType::Float => gl::FLOAT,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureFormat {
Alpha,
Red,
RG,
RGB,
BGR,
RGBA,
BGRA,
RedInteger,
GreenInteger,
BlueInteger,
RGBInteger,
RGBAInteger,
BGRInteger,
BGRAInteger,
DepthComponent,
StencilIndex,
}
impl From<TextureFormat> for gl::types::GLenum {
fn from(format: TextureFormat) -> Self {
match format {
TextureFormat::Alpha => gl::ALPHA,
TextureFormat::Red => gl::RED,
TextureFormat::RG => gl::RG,
TextureFormat::RGB => gl::RGB,
TextureFormat::BGR => gl::BGR,
TextureFormat::RGBA => gl::RGBA,
TextureFormat::BGRA => gl::BGRA,
TextureFormat::RedInteger => gl::RED_INTEGER,
TextureFormat::GreenInteger => gl::GREEN_INTEGER,
TextureFormat::BlueInteger => gl::BLUE_INTEGER,
TextureFormat::RGBInteger => gl::RGB_INTEGER,
TextureFormat::RGBAInteger => gl::RGBA_INTEGER,
TextureFormat::BGRInteger => gl::BGR_INTEGER,
TextureFormat::BGRAInteger => gl::BGRA_INTEGER,
TextureFormat::DepthComponent => gl::DEPTH_COMPONENT,
TextureFormat::StencilIndex => gl::STENCIL_INDEX,
}
}
}
impl TextureFormat {
pub fn n_components(&self) -> usize {
use self::TextureFormat::*;
match *self {
Alpha => 1,
Red => 1,
RG => 2,
RGB => 3,
BGR => 3,
RGBA => 4,
BGRA => 4,
RedInteger => 1,
GreenInteger => 1,
BlueInteger => 1,
RGBInteger => 3,
RGBAInteger => 4,
BGRInteger => 3,
BGRAInteger => 4,
DepthComponent => 1,
StencilIndex => 1,
}
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureTexelFilter {
Nearest,
Linear,
}
impl Default for TextureTexelFilter {
fn default() -> TextureTexelFilter {
TextureTexelFilter::Nearest
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureWrapMode {
ClampToEdge,
ClampToBorder,
Repeat,
MirroredRepeat,
MirrorClampToEdge,
}
impl Default for TextureWrapMode {
fn default() -> TextureWrapMode {
TextureWrapMode::Repeat
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureMipmapFilter {
None,
Nearest,
Linear,
}
impl Default for TextureMipmapFilter {
fn default() -> TextureMipmapFilter {
TextureMipmapFilter::None
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureSeamless {
True,
False,
}
impl From<TextureSeamless> for bool {
fn from(seamless: TextureSeamless) -> Self {
match seamless {
TextureSeamless::True => true,
TextureSeamless::False => false,
}
}
}
impl Default for TextureSeamless {
fn default() -> TextureSeamless {
TextureSeamless::False
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum TextureParameterOption {
MinFilter(TextureTexelFilter, TextureMipmapFilter),
MagFilter(TextureTexelFilter),
WrapS(TextureWrapMode),
WrapT(TextureWrapMode),
WrapR(TextureWrapMode),
CubemapSeamless(TextureSeamless),
}
impl From<TextureParameterOption> for (gl::types::GLenum, gl::types::GLenum) {
fn from(filter: TextureParameterOption) -> Self {
match filter {
TextureParameterOption::MinFilter(texel, mipmap) => match (texel, mipmap) {
(TextureTexelFilter::Nearest, TextureMipmapFilter::None) => (gl::TEXTURE_MIN_FILTER, gl::NEAREST),
(TextureTexelFilter::Nearest, TextureMipmapFilter::Nearest) => {
(gl::TEXTURE_MIN_FILTER, gl::NEAREST_MIPMAP_NEAREST)
}
(TextureTexelFilter::Nearest, TextureMipmapFilter::Linear) => {
(gl::TEXTURE_MIN_FILTER, gl::NEAREST_MIPMAP_LINEAR)
}
(TextureTexelFilter::Linear, TextureMipmapFilter::None) => (gl::TEXTURE_MIN_FILTER, gl::LINEAR),
(TextureTexelFilter::Linear, TextureMipmapFilter::Nearest) => {
(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_NEAREST)
}
(TextureTexelFilter::Linear, TextureMipmapFilter::Linear) => {
(gl::TEXTURE_MIN_FILTER, gl::LINEAR_MIPMAP_LINEAR)
}
},
TextureParameterOption::MagFilter(texel) => match texel {
TextureTexelFilter::Nearest => (gl::TEXTURE_MAG_FILTER, gl::NEAREST),
TextureTexelFilter::Linear => (gl::TEXTURE_MAG_FILTER, gl::LINEAR),
},
TextureParameterOption::WrapS(mode) => match mode {
TextureWrapMode::ClampToEdge => (gl::TEXTURE_WRAP_S, gl::CLAMP_TO_EDGE),
TextureWrapMode::ClampToBorder => (gl::TEXTURE_WRAP_S, gl::CLAMP_TO_BORDER),
TextureWrapMode::Repeat => (gl::TEXTURE_WRAP_S, gl::REPEAT),
TextureWrapMode::MirroredRepeat => (gl::TEXTURE_WRAP_S, gl::MIRRORED_REPEAT),
TextureWrapMode::MirrorClampToEdge => (gl::TEXTURE_WRAP_S, gl::MIRROR_CLAMP_TO_EDGE),
},
TextureParameterOption::WrapT(mode) => match mode {
TextureWrapMode::ClampToEdge => (gl::TEXTURE_WRAP_T, gl::CLAMP_TO_EDGE),
TextureWrapMode::ClampToBorder => (gl::TEXTURE_WRAP_T, gl::CLAMP_TO_BORDER),
TextureWrapMode::Repeat => (gl::TEXTURE_WRAP_T, gl::REPEAT),
TextureWrapMode::MirroredRepeat => (gl::TEXTURE_WRAP_T, gl::MIRRORED_REPEAT),
TextureWrapMode::MirrorClampToEdge => (gl::TEXTURE_WRAP_T, gl::MIRROR_CLAMP_TO_EDGE),
},
TextureParameterOption::WrapR(mode) => match mode {
TextureWrapMode::ClampToEdge => (gl::TEXTURE_WRAP_R, gl::CLAMP_TO_EDGE),
TextureWrapMode::ClampToBorder => (gl::TEXTURE_WRAP_R, gl::CLAMP_TO_BORDER),
TextureWrapMode::Repeat => (gl::TEXTURE_WRAP_R, gl::REPEAT),
TextureWrapMode::MirroredRepeat => (gl::TEXTURE_WRAP_R, gl::MIRRORED_REPEAT),
TextureWrapMode::MirrorClampToEdge => (gl::TEXTURE_WRAP_R, gl::MIRROR_CLAMP_TO_EDGE),
},
TextureParameterOption::CubemapSeamless(seamless) => match seamless {
TextureSeamless::True => (gl::TEXTURE_CUBE_MAP_SEAMLESS, gl::TRUE as u32),
TextureSeamless::False => (gl::TEXTURE_CUBE_MAP_SEAMLESS, gl::FALSE as u32),
},
}
}
}
pub unsafe fn create_texture(target: TextureTarget) -> TextureId {
let mut texture_id: u32 = 0;
let texture_id_ptr: *mut u32 = &mut texture_id;
gl::CreateTextures(target.into(), 1, texture_id_ptr);
TextureId(texture_id)
}
pub unsafe fn texture_storage_1d(
texture: TextureId,
levels: usize,
internal_format: TextureInternalFormat,
width: usize,
) -> Result<()> {
gl::TextureStorage1D(
texture.into(),
levels as i32,
internal_format.into(),
width as i32,
);
get_error(())
}
pub unsafe fn texture_storage_2d(
texture: TextureId,
levels: usize,
internal_format: TextureInternalFormat,
dimensions: (usize, usize),
) -> Result<()> {
gl::TextureStorage2D(
texture.into(),
levels as i32,
internal_format.into(),
dimensions.0 as i32,
dimensions.1 as i32,
);
get_error(())
}
pub unsafe fn texture_storage_3d(
texture: TextureId,
levels: usize,
internal_format: TextureInternalFormat,
dimensions: (usize, usize, usize),
) -> Result<()> {
gl::TextureStorage3D(
texture.into(),
levels as i32,
internal_format.into(),
dimensions.0 as i32,
dimensions.1 as i32,
dimensions.2 as i32,
);
get_error(())
}
pub unsafe fn texture_subimage_1d<T>(
texture: TextureId,
level: usize,
offset: usize,
width: usize,
format: TextureFormat,
data_type: u32,
pixels: &[T],
) -> Result<()> {
let pixels_ptr = pixels.as_ptr() as *const c_void;
gl::TextureSubImage1D(
texture.into(),
level as i32,
offset as i32,
width as i32,
format.into(),
data_type,
pixels_ptr,
);
get_error(())
}
pub unsafe fn texture_subimage_2d<T>(
texture: TextureId,
level: usize,
offset: (usize, usize),
dimensions: (usize, usize),
format: TextureFormat,
data_type: u32,
pixels: &[T],
) -> Result<()> {
let pixels_ptr = pixels.as_ptr() as *const c_void;
gl::TextureSubImage2D(
texture.into(),
level as i32,
offset.0 as i32,
offset.1 as i32,
dimensions.0 as i32,
dimensions.1 as i32,
format.into(),
data_type,
pixels_ptr,
);
get_error(())
}
pub unsafe fn texture_subimage_3d<T>(
texture: TextureId,
level: usize,
offset: (usize, usize, usize),
dimensions: (usize, usize, usize),
format: TextureFormat,
data_type: u32,
pixels: &[T],
) -> Result<()> {
let pixels_ptr = pixels.as_ptr() as *const c_void;
gl::TextureSubImage3D(
texture.into(),
level as i32,
offset.0 as i32,
offset.1 as i32,
offset.2 as i32,
dimensions.0 as i32,
dimensions.1 as i32,
dimensions.2 as i32,
format.into(),
data_type,
pixels_ptr,
);
get_error(())
}
pub unsafe fn texture_buffer(
texture_id: TextureId,
format: TextureBufferInternalFormat,
buffer_id: BufferId,
) -> Result<()> {
gl::TextureBuffer(texture_id.into(), format.into(), buffer_id.into());
get_error(())
}
pub unsafe fn texture_buffer_range(
texture_id: TextureId,
format: TextureBufferInternalFormat,
buffer_id: BufferId,
offset: usize,
size: usize,
) -> Result<()> {
gl::TextureBufferRange(
texture_id.into(),
format.into(),
buffer_id.into(),
offset as isize,
size as isize,
);
get_error(())
}
pub unsafe fn delete_texture(id: TextureId) {
gl::DeleteTextures(1, &id.into());
}
pub unsafe fn texture_parameter_i(texture: TextureId, parameter: TextureParameterOption) -> Result<()> {
let (pname, param) = parameter.into();
gl::TextureParameteri(texture.into(), pname, param as i32);
get_error(())
}
pub unsafe fn bind_texture_unit(unit: usize, id: TextureId) {
gl::BindTextureUnit(unit as u32, id.into());
}
pub unsafe fn bind_textures(first: usize, textures: &[TextureId]) -> Result<()> {
gl::BindTextures(
first as u32,
textures.len() as i32,
textures.as_ptr() as *const u32,
);
get_error(())
}
pub unsafe fn generate_texture_mipmap(id: TextureId) -> Result<()> {
gl::GenerateTextureMipmap(id.into());
get_error(())
}
pub unsafe fn clear_tex_image_null(
id: TextureId,
level: usize,
format: TextureFormat,
data_type: TextureDataType,
) -> Result<()> {
gl::ClearTexImage(
id.into(),
level as i32,
format.into(),
data_type.into(),
::std::ptr::null(),
);
get_error(())
}
pub unsafe fn get_texture_handle(id: TextureId) -> Result<TextureHandle> {
get_error(TextureHandle(gl::GetTextureHandleARB(id.into())))
}
pub unsafe fn make_texture_handle_resident(handle: TextureHandle) -> Result<()> {
get_error(gl::MakeTextureHandleResidentARB(handle.into()))
}