extern crate gl;
#[cfg_attr(feature = "gles2", path = "texture/gles2.rs")]
#[cfg_attr(feature = "gl2", path = "texture/gl2.rs")]
#[cfg_attr(all(not(feature = "gl2"), not(feature = "gles2")), path = "texture/gl3.rs")]
pub mod defs;
pub use crate::texture::defs::*;
use crate::{GlEnum, GlBind, GlObject, GlTarget, GlslType, impl_glsl};
use std::ffi::c_void;
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub enum PixelDataType {
Byte,
#[default]
UByte,
Short,
UShort,
Int,
UInt,
Float,
UByte3_3_2,
UByte2_3_3Rev,
UShort5_6_5,
UShort5_6_5Rev,
UShort4_4_4_4,
UShort5_5_5_1,
UShort1_5_5_5Rev,
UInt8_8_8_8,
UInt8_8_8_8Rev,
UInt10_10_10_2,
UInt2_10_10_10Rev,
}
impl GlEnum for PixelDataType {
fn to_enum(&self) -> u32 {
match self {
Self::Byte => { gl::BYTE },
Self::UByte => { gl::UNSIGNED_BYTE },
Self::Short => { gl::SHORT },
Self::UShort => { gl::UNSIGNED_SHORT },
Self::Int => { gl::INT },
Self::UInt => { gl::UNSIGNED_INT },
Self::Float => { gl::FLOAT },
_ => { gl::NONE }
}
}
}
fn gen_texture() -> u32 {
let mut handle = 0;
unsafe { gl::GenTextures(1, &mut handle) };
handle
}
pub trait GlTexture: GlBind + GlObject + GlTarget {
type Size;
fn set_min_filter(&self, filter: TexFilter) {
unsafe {
gl::TexParameteri(Self::target(), gl::TEXTURE_MIN_FILTER, filter.to_enum() as i32);
}
}
fn set_mag_filter(&self, filter: TexFilter) {
unsafe {
gl::TexParameteri(Self::target(), gl::TEXTURE_MAG_FILTER, filter.to_enum() as i32);
}
}
fn set_wrap_s(&self, wrap: TexWrap) {
unsafe {
gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_S, wrap.to_enum() as i32);
}
}
fn set_wrap_t(&self, wrap: TexWrap) {
unsafe {
gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_T, wrap.to_enum() as i32);
}
}
fn set_wrap_r(&self, wrap: TexWrap) {
unsafe {
gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_R, wrap.to_enum() as i32);
}
}
fn data(&self, level: i32, format: PixelFormat, size: Self::Size, data_type: PixelDataType, data: Vec<u8>);
}
macro_rules! impl_gl_traits {
($Name: ident, $target: expr, $binding: expr ) => {
#[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct $Name(u32);
impl GlObject for $Name {
fn get_id(&self) -> u32 { self.0 }
}
impl GlBind for $Name {
fn bind(&self) {
unsafe { gl::BindTexture(Self::target(), self.0) }
}
fn unbind(&self) {
unsafe { gl::BindTexture(Self::target(), 0) }
}
}
impl GlTarget for $Name {
fn target() -> u32 { $target }
fn binding() -> u32 { $binding }
}
impl Drop for $Name {
fn drop(&mut self) {
unsafe { gl::DeleteTextures(1, &mut self.0) };
}
}
}
}
impl_gl_traits!(Texture1D, gl::TEXTURE_1D, gl::TEXTURE_BINDING_1D);
impl_gl_traits!(Texture2D, gl::TEXTURE_2D, gl::TEXTURE_BINDING_2D);
impl_gl_traits!(TextureCubeMap, gl::TEXTURE_CUBE_MAP, gl::TEXTURE_BINDING_CUBE_MAP);
impl_gl_traits!(Texture3D, gl::TEXTURE_3D, gl::TEXTURE_BINDING_3D);
fn tex_image_2d(target: u32, level: i32, internal: PixelFormat, size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
let pixels: *const c_void;
if data.is_empty() {
pixels = std::ptr::null();
} else {
pixels = data.as_ptr() as *const c_void;
}
unsafe {
gl::TexImage2D(
target, level,
internal.to_enum() as i32, size.0, size.1, 0,
format.to_enum(), data_type.to_enum(), pixels
);
}
}
fn tex_subimage_2d(target: u32, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
let pixels: *const c_void;
if data.is_empty() {
pixels = std::ptr::null();
} else {
pixels = data.as_ptr() as *const c_void;
}
unsafe {
gl::TexSubImage2D(
target, level,
offset.0, offset.1,
size.0, size.1,
format.to_enum(), data_type.to_enum(), pixels
);
}
}
impl GlTexture for Texture2D {
type Size = (i32, i32);
fn data(&self, level: i32, format: PixelFormat, size: Self::Size, data_type: PixelDataType, data: Vec<u8>) {
tex_image_2d(Self::target(), level, format, size, format, data_type, data);
}
}
impl Texture1D {
pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) }
}
impl Texture2D {
pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) }
pub fn data(&self, level: i32, format: PixelFormat, size: (i32, i32), data_type: PixelDataType, data: Vec<u8>) {
tex_image_2d(Self::target(), level, format, size, format, data_type, data);
}
pub fn subdata(&self, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
tex_subimage_2d(Self::target(), level, offset, size, format, data_type, data);
}
}
impl Texture3D { pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) } }
#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
pub enum CubeMapSide {
#[default]
PositiveX,
NegativeX,
PositiveY,
NegativeY,
PositiveZ,
NegativeZ
}
impl GlEnum for CubeMapSide {
fn to_enum(&self) -> u32 {
match self {
Self::PositiveX => { gl::TEXTURE_CUBE_MAP_POSITIVE_X },
Self::NegativeX => { gl::TEXTURE_CUBE_MAP_NEGATIVE_X },
Self::PositiveY => { gl::TEXTURE_CUBE_MAP_POSITIVE_Y },
Self::NegativeY => { gl::TEXTURE_CUBE_MAP_POSITIVE_Y },
Self::PositiveZ => { gl::TEXTURE_CUBE_MAP_NEGATIVE_Z },
Self::NegativeZ => { gl::TEXTURE_CUBE_MAP_NEGATIVE_Z },
}
}
}
impl TextureCubeMap {
pub fn new() -> Result<Self, String> {
let mut handle = 0;
unsafe { gl::GenTextures(1, &mut handle) };
Ok(Self(handle))
}
pub fn data(&self, side: CubeMapSide, level: i32, format: PixelFormat, size: (i32, i32), data_type: PixelDataType, data: Vec<u8>) {
tex_image_2d(side.to_enum(), level, format, size, format, data_type, data);
}
pub fn subdata(&self, side: CubeMapSide, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
tex_subimage_2d(side.to_enum(), level, offset, size, format, data_type, data);
}
}
pub struct Sampler2D;
impl_glsl!(Sampler2D, "sampler2D");