tea/
texture.rs

1extern crate gl;
2
3#[cfg_attr(feature = "gles2", path = "texture/gles2.rs")]
4#[cfg_attr(feature = "gl2", path = "texture/gl2.rs")]
5#[cfg_attr(all(not(feature = "gl2"), not(feature = "gles2")), path = "texture/gl3.rs")]
6pub mod defs;
7
8pub use crate::texture::defs::*;
9
10use crate::{GlEnum, GlBind, GlObject, GlTarget, GlslType, impl_glsl};
11use std::ffi::c_void;
12
13#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)]
14pub enum PixelDataType {
15    Byte,
16    #[default]
17    UByte,
18    Short,
19    UShort,
20    Int,
21    UInt,
22    Float,
23    UByte3_3_2,
24    UByte2_3_3Rev,
25    UShort5_6_5,
26    UShort5_6_5Rev,
27    UShort4_4_4_4,
28    UShort5_5_5_1,
29    UShort1_5_5_5Rev,
30    UInt8_8_8_8,
31    UInt8_8_8_8Rev,
32    UInt10_10_10_2,
33    UInt2_10_10_10Rev,
34}
35
36impl GlEnum for PixelDataType {
37    fn to_enum(&self) -> u32 {
38        match self {
39            Self::Byte => { gl::BYTE },
40            Self::UByte => { gl::UNSIGNED_BYTE },
41            Self::Short => { gl::SHORT },
42            Self::UShort => { gl::UNSIGNED_SHORT },
43            Self::Int => { gl::INT },
44            Self::UInt => { gl::UNSIGNED_INT },
45            Self::Float => { gl::FLOAT },
46            _ => { gl::NONE }
47        }
48    }
49}
50
51fn gen_texture() -> u32 {
52    let mut handle = 0;
53    unsafe { gl::GenTextures(1, &mut handle) };
54    handle
55}
56
57pub trait GlTexture: GlBind + GlObject + GlTarget {
58    type Size;
59    fn set_min_filter(&self, filter: TexFilter) {
60        unsafe {
61            gl::TexParameteri(Self::target(), gl::TEXTURE_MIN_FILTER, filter.to_enum() as i32);
62        }
63    }
64    fn set_mag_filter(&self, filter: TexFilter) {
65        unsafe {
66            gl::TexParameteri(Self::target(), gl::TEXTURE_MAG_FILTER, filter.to_enum() as i32);
67        }
68    }
69
70    fn set_wrap_s(&self, wrap: TexWrap) {
71        unsafe {
72            gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_S, wrap.to_enum() as i32);
73        }
74    }
75
76    fn set_wrap_t(&self, wrap: TexWrap) {
77        unsafe {
78            gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_T, wrap.to_enum() as i32);
79        }
80    }
81
82    fn set_wrap_r(&self, wrap: TexWrap) {
83        unsafe {
84            gl::TexParameteri(Self::target(), gl::TEXTURE_WRAP_R, wrap.to_enum() as i32);
85        }
86    }
87
88    fn data(&self, level: i32, format: PixelFormat, size: Self::Size, data_type: PixelDataType, data: Vec<u8>);
89}
90
91macro_rules! impl_gl_traits {
92    ($Name: ident, $target: expr, $binding: expr ) => {
93        #[derive(Default, Debug, PartialEq, Eq, PartialOrd, Ord)]
94        pub struct $Name(u32);
95
96        impl GlObject for $Name {
97            fn get_id(&self) -> u32 { self.0 }
98        }
99
100        impl GlBind for $Name {
101            fn bind(&self) {
102                unsafe { gl::BindTexture(Self::target(), self.0) }
103            }
104
105            fn unbind(&self) {
106                unsafe { gl::BindTexture(Self::target(), 0) }
107            }
108        }
109
110        impl GlTarget for $Name {
111            fn target() -> u32 { $target }
112            fn binding() -> u32 { $binding }
113        }
114
115        impl Drop for $Name {
116            fn drop(&mut self) {
117                unsafe { gl::DeleteTextures(1, &mut self.0) };
118            }
119        }
120    }
121}
122
123impl_gl_traits!(Texture1D, gl::TEXTURE_1D, gl::TEXTURE_BINDING_1D);
124impl_gl_traits!(Texture2D, gl::TEXTURE_2D, gl::TEXTURE_BINDING_2D);
125impl_gl_traits!(TextureCubeMap, gl::TEXTURE_CUBE_MAP, gl::TEXTURE_BINDING_CUBE_MAP);
126impl_gl_traits!(Texture3D, gl::TEXTURE_3D, gl::TEXTURE_BINDING_3D);
127
128fn tex_image_2d(target: u32, level: i32, internal: PixelFormat, size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
129    let pixels: *const c_void;
130    if data.is_empty() {
131        pixels = std::ptr::null();
132    } else {
133        pixels = data.as_ptr() as *const c_void;
134    }
135
136    unsafe {
137        gl::TexImage2D(
138            target, level,
139            internal.to_enum() as i32, size.0, size.1, 0,
140            format.to_enum(), data_type.to_enum(), pixels
141        );
142    }
143}
144
145fn tex_subimage_2d(target: u32, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
146    let pixels: *const c_void;
147    if data.is_empty() {
148        pixels = std::ptr::null();
149    } else {
150        pixels = data.as_ptr() as *const c_void;
151    }
152
153    unsafe {
154        gl::TexSubImage2D(
155            target, level,
156            offset.0, offset.1,
157            size.0, size.1,
158            format.to_enum(), data_type.to_enum(), pixels
159        );
160    }
161}
162
163impl GlTexture for Texture2D {
164    type Size = (i32, i32);
165    fn data(&self, level: i32, format: PixelFormat, size: Self::Size, data_type: PixelDataType, data: Vec<u8>) {
166        tex_image_2d(Self::target(), level, format, size, format, data_type, data);
167    }
168}
169
170impl Texture1D {
171    pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) }
172}
173
174impl Texture2D {
175    pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) }
176
177    pub fn data(&self, level: i32, format: PixelFormat, size: (i32, i32), data_type: PixelDataType, data: Vec<u8>) {
178        tex_image_2d(Self::target(), level, format, size, format, data_type, data);
179    }
180
181    pub fn subdata(&self, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
182        tex_subimage_2d(Self::target(), level, offset, size, format, data_type, data); 
183    }
184}
185impl Texture3D { pub fn new() -> Result<Self, String> { Ok(Self(gen_texture())) } }
186
187#[derive(Default, Debug, Copy, Clone, PartialEq, PartialOrd, Eq, Ord)]
188pub enum CubeMapSide {
189    #[default]
190    PositiveX,
191    NegativeX,
192    PositiveY,
193    NegativeY,
194    PositiveZ,
195    NegativeZ
196}
197
198impl GlEnum for CubeMapSide {
199    fn to_enum(&self) -> u32 {
200        match self {
201            Self::PositiveX => { gl::TEXTURE_CUBE_MAP_POSITIVE_X },
202            Self::NegativeX => { gl::TEXTURE_CUBE_MAP_NEGATIVE_X },
203            Self::PositiveY => { gl::TEXTURE_CUBE_MAP_POSITIVE_Y },
204            Self::NegativeY => { gl::TEXTURE_CUBE_MAP_POSITIVE_Y },
205            Self::PositiveZ => { gl::TEXTURE_CUBE_MAP_NEGATIVE_Z },
206            Self::NegativeZ => { gl::TEXTURE_CUBE_MAP_NEGATIVE_Z },
207        }
208    }
209}
210
211impl TextureCubeMap {
212    pub fn new() -> Result<Self, String> {
213        let mut handle = 0;
214        unsafe { gl::GenTextures(1, &mut handle) };
215        Ok(Self(handle))
216    }
217
218    pub fn data(&self, side: CubeMapSide, level: i32, format: PixelFormat, size: (i32, i32), data_type: PixelDataType, data: Vec<u8>) { 
219        tex_image_2d(side.to_enum(), level, format, size, format, data_type, data);
220    }
221
222    pub fn subdata(&self, side: CubeMapSide, level: i32, offset: (i32, i32), size: (i32, i32), format: PixelFormat, data_type: PixelDataType, data: Vec<u8>) {
223        tex_subimage_2d(side.to_enum(), level, offset, size, format, data_type, data);
224    }
225}
226
227pub struct Sampler2D;
228impl_glsl!(Sampler2D, "sampler2D");