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");