globject_rs/
gltexture.rs

1
2#![allow(clippy::too_many_arguments)]
3#![allow(clippy::suspicious_else_formatting)]
4
5use crate::prelude::*;
6use std::{
7	any::type_name,
8	ffi::{OsStr, c_void},
9	fmt::{self, Debug, Formatter},
10	marker::PhantomData,
11	mem::size_of_val,
12	path::Path,
13	ptr::null,
14	rc::Rc,
15};
16use image::{ImageReader, Pixel, ImageBuffer, RgbImage, DynamicImage};
17
18/// The dimension of the texture represents the type of texture
19#[derive(Clone, Copy, PartialEq)]
20pub enum TextureDimension {
21	Tex1d = GL_TEXTURE_1D as isize,
22	Tex2d = GL_TEXTURE_2D as isize,
23	Tex3d = GL_TEXTURE_3D as isize,
24	TexCube = GL_TEXTURE_CUBE_MAP as isize,
25}
26
27/// The binding target of the texture includes the 6 faces of a cubemap
28#[derive(Clone, Copy, PartialEq)]
29pub enum TextureTarget {
30	Tex1d = GL_TEXTURE_1D as isize,
31	Tex2d = GL_TEXTURE_2D as isize,
32	Tex3d = GL_TEXTURE_3D as isize,
33	TexCube = GL_TEXTURE_CUBE_MAP as isize,
34	TexCubePosX = GL_TEXTURE_CUBE_MAP_POSITIVE_X as isize,
35	TexCubeNegX = GL_TEXTURE_CUBE_MAP_NEGATIVE_X as isize,
36	TexCubePosY = GL_TEXTURE_CUBE_MAP_POSITIVE_Y as isize,
37	TexCubeNegY = GL_TEXTURE_CUBE_MAP_NEGATIVE_Y as isize,
38	TexCubePosZ = GL_TEXTURE_CUBE_MAP_POSITIVE_Z as isize,
39	TexCubeNegZ = GL_TEXTURE_CUBE_MAP_NEGATIVE_Z as isize,
40}
41
42/// The cubemap faces enum
43#[derive(Clone, Copy, PartialEq)]
44pub enum CubeMapFaces {
45	TexCubePosX = TextureTarget::TexCubePosX as isize,
46	TexCubeNegX = TextureTarget::TexCubeNegX as isize,
47	TexCubePosY = TextureTarget::TexCubePosY as isize,
48	TexCubeNegY = TextureTarget::TexCubeNegY as isize,
49	TexCubePosZ = TextureTarget::TexCubePosZ as isize,
50	TexCubeNegZ = TextureTarget::TexCubeNegZ as isize,
51}
52
53/// The constant helps to conveniently iterate through the 6 faces of a cubemap
54pub const CUBE_FACE_TARGETS: [CubeMapFaces; 6] = [
55	CubeMapFaces::TexCubePosX,
56	CubeMapFaces::TexCubeNegX,
57	CubeMapFaces::TexCubePosY,
58	CubeMapFaces::TexCubeNegY,
59	CubeMapFaces::TexCubePosZ,
60	CubeMapFaces::TexCubeNegZ,
61];
62
63/// The **internal format** of the texture indicates how the pixels are stored in the GPU texture
64#[derive(Clone, Copy, PartialEq)]
65pub enum TextureFormat {
66	Depth = GL_DEPTH_COMPONENT as isize,
67	DepthStencil = GL_DEPTH_STENCIL as isize,
68	Red = GL_RED as isize,
69	Rg = GL_RG as isize,
70	Rgb = GL_RGB as isize,
71	Rgba = GL_RGBA as isize,
72	Red8 = GL_R8 as isize,
73	Red8Snorm = GL_R8_SNORM as isize,
74	Red16 = GL_R16 as isize,
75	Red16Snorm = GL_R16_SNORM as isize,
76	Rg8 = GL_RG8 as isize,
77	Rg8Snorm = GL_RG8_SNORM as isize,
78	Rg16 = GL_RG16 as isize,
79	Rg16Snorm = GL_RG16_SNORM as isize,
80	R3g3b2 = GL_R3_G3_B2 as isize,
81	Rgb4 = GL_RGB4 as isize,
82	Rgb5 = GL_RGB5 as isize,
83	Rgb8 = GL_RGB8 as isize,
84	Rgb8Snorm = GL_RGB8_SNORM as isize,
85	Rgb10 = GL_RGB10 as isize,
86	Rgb12 = GL_RGB12 as isize,
87	Rgb16Snorm = GL_RGB16_SNORM as isize,
88	Rgba2 = GL_RGBA2 as isize,
89	Rgba4 = GL_RGBA4 as isize,
90	Rgb5a1 = GL_RGB5_A1 as isize,
91	Rgba8 = GL_RGBA8 as isize,
92	Rgba8Snorm = GL_RGBA8_SNORM as isize,
93	Rgb10a2 = GL_RGB10_A2 as isize,
94	Rgb10a2ui = GL_RGB10_A2UI as isize,
95	Rgba12 = GL_RGBA12 as isize,
96	Rgba16 = GL_RGBA16 as isize,
97	R32f = GL_R32F as isize,
98	Rg32f = GL_RG32F as isize,
99	Rgb32f = GL_RGB32F as isize,
100	Rgba32f = GL_RGBA32F as isize,
101	R11fg11fb10f = GL_R11F_G11F_B10F as isize,
102	Rgb9e5 = GL_RGB9_E5 as isize,
103	R8i = GL_R8I as isize,
104	R8ui = GL_R8UI as isize,
105	R16i = GL_R16I as isize,
106	R16ui = GL_R16UI as isize,
107	R32i = GL_R32I as isize,
108	R32ui = GL_R32UI as isize,
109	Rg8i = GL_RG8I as isize,
110	Rg8ui = GL_RG8UI as isize,
111	Rg16i = GL_RG16I as isize,
112	Rg16ui = GL_RG16UI as isize,
113	Rg32i = GL_RG32I as isize,
114	Rg32ui = GL_RG32UI as isize,
115	Rgb8i = GL_RGB8I as isize,
116	Rgb8ui = GL_RGB8UI as isize,
117	Rgb16i = GL_RGB16I as isize,
118	Rgb16ui = GL_RGB16UI as isize,
119	Rgb32i = GL_RGB32I as isize,
120	Rgb32ui = GL_RGB32UI as isize,
121	Rgba8i = GL_RGBA8I as isize,
122	Rgba8ui = GL_RGBA8UI as isize,
123	Rgba16i = GL_RGBA16I as isize,
124	Rgba16ui = GL_RGBA16UI as isize,
125	Rgba32i = GL_RGBA32I as isize,
126	Rgba32ui = GL_RGBA32UI as isize,
127}
128
129/// The wrapping rules of the textures
130#[derive(Clone, Copy, PartialEq)]
131pub enum TextureWrapping {
132	ClampToEdge = GL_CLAMP_TO_EDGE as isize,
133	ClampToBorder = GL_CLAMP_TO_BORDER as isize,
134	MirrorClampToEdge = GL_MIRROR_CLAMP_TO_EDGE as isize,
135
136	/// **NOTE**: `Repeat` is only supported to the 2^N size of the textures by most of the GPU
137	Repeat = GL_REPEAT as isize,
138
139	/// **NOTE**: `MirroredRepeat` is only supported to the 2^N size of the textures by most of the GPU
140	MirroredRepeat = GL_MIRRORED_REPEAT as isize,
141}
142
143/// The sampler filters of the textures, including how mipmap sampling should be done
144#[derive(Clone, Copy, PartialEq)]
145pub enum SamplerFilter {
146	Nearest = GL_NEAREST as isize,
147	Linear = GL_LINEAR as isize,
148	NearestMipmapNearest = GL_NEAREST_MIPMAP_NEAREST as isize,
149	LinearMipmapNearest = GL_LINEAR_MIPMAP_NEAREST as isize,
150	NearestMipmapLinear = GL_NEAREST_MIPMAP_LINEAR as isize,
151	LinearMipmapLinear = GL_LINEAR_MIPMAP_LINEAR as isize,
152}
153
154/// The sampler filters of the textures, only for magnifying sampling
155#[derive(Clone, Copy, PartialEq)]
156pub enum SamplerMagFilter {
157	Nearest = GL_NEAREST as isize,
158	Linear = GL_LINEAR as isize,
159}
160
161/// The channel type of a pixel
162#[derive(Clone, Copy, PartialEq)]
163pub enum ChannelType {
164	Red = GL_RED as isize,
165	Rg = GL_RG as isize,
166	Rgb = GL_RGB as isize,
167	Bgr = GL_BGR as isize,
168	Rgba = GL_RGBA as isize,
169	Bgra = GL_BGRA as isize,
170	RedInteger = GL_RED_INTEGER as isize,
171	RgInteger = GL_RG_INTEGER as isize,
172	RgbInteger = GL_RGB_INTEGER as isize,
173	BgrInteger = GL_BGR_INTEGER as isize,
174	RgbaInteger = GL_RGBA_INTEGER as isize,
175	BgraInteger = GL_BGRA_INTEGER as isize,
176	StencilIndex = GL_STENCIL_INDEX as isize,
177	Depth = GL_DEPTH_COMPONENT as isize,
178	DepthStencil = GL_DEPTH_STENCIL as isize,
179}
180
181/// The component type for each channel of a pixel
182#[derive(Clone, Copy, PartialEq)]
183pub enum ComponentType {
184	U8 = GL_UNSIGNED_BYTE as isize,
185	I8 = GL_BYTE as isize,
186	U16 = GL_UNSIGNED_SHORT as isize,
187	I16 = GL_SHORT as isize,
188	U32 = GL_UNSIGNED_INT as isize,
189	I32 = GL_INT as isize,
190	F16 = GL_HALF_FLOAT as isize,
191	F32 = GL_FLOAT as isize,
192	U8_332 = GL_UNSIGNED_BYTE_3_3_2 as isize,
193	U8_233Rev = GL_UNSIGNED_BYTE_2_3_3_REV as isize,
194	U16_565 = GL_UNSIGNED_SHORT_5_6_5 as isize,
195	U16_565Rev = GL_UNSIGNED_SHORT_5_6_5_REV as isize,
196	U16_4444 = GL_UNSIGNED_SHORT_4_4_4_4 as isize,
197	U16_4444Rev = GL_UNSIGNED_SHORT_4_4_4_4_REV as isize,
198	U16_5551 = GL_UNSIGNED_SHORT_5_5_5_1 as isize,
199	U16_1555Rev = GL_UNSIGNED_SHORT_1_5_5_5_REV as isize,
200	U32_8888 = GL_UNSIGNED_INT_8_8_8_8 as isize,
201	U32_8888Rev = GL_UNSIGNED_INT_8_8_8_8_REV as isize,
202	U32_10_10_10_2 = GL_UNSIGNED_INT_10_10_10_2 as isize,
203	U32_2_10_10_10Rev = GL_UNSIGNED_INT_2_10_10_10_REV as isize,
204}
205
206/// Get the size for each pixel
207pub fn size_of_pixel(channel_type: ChannelType, component_type: ComponentType) -> usize {
208	let component_len = match component_type {
209		ComponentType::U8_332 |
210		ComponentType::U8_233Rev => return 1,
211		ComponentType::U16_565 |
212		ComponentType::U16_565Rev |
213		ComponentType::U16_4444 |
214		ComponentType::U16_4444Rev |
215		ComponentType::U16_5551 |
216		ComponentType::U16_1555Rev => return 2,
217		ComponentType::U32_8888 |
218		ComponentType::U32_8888Rev |
219		ComponentType::U32_10_10_10_2 |
220		ComponentType::U32_2_10_10_10Rev => return 4,
221		ComponentType::U8 |
222		ComponentType::I8 => 1,
223		ComponentType::U16 |
224		ComponentType::I16 |
225		ComponentType::F16 => 2,
226		ComponentType::U32 |
227		ComponentType::I32 |
228		ComponentType::F32 => 4,
229	};
230	match channel_type {
231		ChannelType::Red |
232		ChannelType::RedInteger |
233		ChannelType::StencilIndex |
234		ChannelType::Depth => component_len,
235		ChannelType::Rg |
236		ChannelType::RgInteger |
237		ChannelType::DepthStencil => component_len * 2,
238		ChannelType::Rgb |
239		ChannelType::RgbInteger |
240		ChannelType::Bgr |
241		ChannelType::BgrInteger => component_len * 3,
242		ChannelType::Rgba |
243		ChannelType::RgbaInteger |
244		ChannelType::Bgra |
245		ChannelType::BgraInteger => component_len * 4,
246	}
247}
248
249/// The pixel type trait must be able to be a `BufferVec` item
250pub trait PixelType: BufferVecItem {}
251impl<T> PixelType for T where T: BufferVecItem {}
252
253/// The pixel buffer object (PBO) for the texture helps with asynchronous texture updating or retrieving back to the system memory
254#[derive(Debug)]
255pub struct PixelBuffer<B, BP>
256where
257	B: BufferVec<BP>,
258	BP: BufferVecItem {
259	buffer: B,
260	pixel_size: usize,
261	width: u32,
262	height: u32,
263	depth: u32,
264	pitch: usize,
265	pitch_wh: usize,
266	channel_type: ChannelType,
267	component_type: ComponentType,
268	_pixel_type: PhantomData<BP>,
269}
270
271/// The OpenGL texture object
272pub struct Texture<B, BP>
273where
274	B: BufferVec<BP>,
275	BP: BufferVecItem {
276	pub glcore: Rc<GLCore>,
277	name: u32,
278	dim: TextureDimension,
279	format: TextureFormat,
280	width: u32,
281	height: u32,
282	depth: u32,
283	has_mipmap: bool,
284	mag_filter: SamplerMagFilter,
285	min_filter: SamplerFilter,
286	bytes_of_texture: usize,
287	bytes_of_face: usize,
288	pixel_buffer: Option<PixelBuffer<B, BP>>,
289	_pixel_type: PhantomData<BP>,
290}
291
292/// The binding state of the texture, utilizing the RAII rules to manage the binding state
293pub struct TextureBind<'a> {
294	pub texture: &'a dyn GenericTexture,
295	target: TextureTarget,
296}
297
298/// The error for loading an image from a file, decoding the byte stream of the image
299#[derive(Debug)]
300pub enum LoadImageError {
301	IOError(std::io::Error),
302	TurboJpegError(turbojpeg::Error),
303	ImageError(image::ImageError),
304	UnsupportedImageType(String),
305}
306
307impl From<std::io::Error> for LoadImageError {
308	fn from(err: std::io::Error) -> Self {
309		Self::IOError(err)
310	}
311}
312
313impl From<turbojpeg::Error> for LoadImageError {
314	fn from(err: turbojpeg::Error) -> Self {
315		Self::TurboJpegError(err)
316	}
317}
318
319impl From<image::ImageError> for LoadImageError {
320	fn from(err: image::ImageError) -> Self {
321		Self::ImageError(err)
322	}
323}
324
325#[derive(Debug)]
326pub enum TextureError {
327	LoadImageError(LoadImageError),
328	GLCoreError(GLCoreError),
329}
330
331impl From<LoadImageError> for TextureError {
332	fn from(val: LoadImageError) -> Self {
333		Self::LoadImageError(val)
334	}
335}
336
337impl From<GLCoreError> for TextureError {
338	fn from(val: GLCoreError) -> Self {
339		Self::GLCoreError(val)
340	}
341}
342
343
344impl From<std::io::Error> for TextureError {
345	fn from(err: std::io::Error) -> Self {
346		Self::LoadImageError(LoadImageError::IOError(err))
347	}
348}
349
350impl From<turbojpeg::Error> for TextureError {
351	fn from(err: turbojpeg::Error) -> Self {
352		Self::LoadImageError(LoadImageError::TurboJpegError(err))
353	}
354}
355
356impl From<image::ImageError> for TextureError {
357	fn from(err: image::ImageError) -> Self {
358		Self::LoadImageError(LoadImageError::ImageError(err))
359	}
360}
361
362impl TextureFormat {
363	/// Get how many bits that composed of a pixel. The implementation is just to ask anything from OpenGL
364	pub fn bits_of_pixel(&self, glcore: &GLCore, target: TextureTarget) -> Result<usize, TextureError> {
365		let target = target as u32;
366		let mut data: i32 = 0;
367		let mut size: usize = 0;
368		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_DEPTH_SIZE, &mut data as *mut _)?;	size += data as usize;
369		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_STENCIL_SIZE, &mut data as *mut _)?;	size += data as usize;
370		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_RED_SIZE, &mut data as *mut _)?;		size += data as usize;
371		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_GREEN_SIZE, &mut data as *mut _)?;	size += data as usize;
372		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_BLUE_SIZE, &mut data as *mut _)?;		size += data as usize;
373		glcore.glGetTexLevelParameteriv(target, 0, GL_TEXTURE_ALPHA_SIZE, &mut data as *mut _)?;	size += data as usize;
374		Ok(size)
375	}
376
377	/// Create a `TextureFormat` from the channel type and the component type, returns `None` if the combination couldn't have its corresponding format
378	pub fn from_channel_type_and_component_type(channel_type: ChannelType, component_type: ComponentType) -> Option<Self> {
379		match component_type {
380			ComponentType::U8_332 => Some(Self::R3g3b2),
381			ComponentType::U16_4444 => Some(Self::Rgba4),
382			ComponentType::U16_5551 => Some(Self::Rgb5a1),
383			ComponentType::U32_8888 => Some(Self::Rgba8),
384			ComponentType::U32_10_10_10_2 => Some(Self::Rgb10a2),
385			ComponentType::I8 => match channel_type {
386				ChannelType::Red =>  Some(Self::R8i),
387				ChannelType::Rg =>   Some(Self::Rg8i),
388				ChannelType::Rgb =>  Some(Self::Rgb8i),
389				ChannelType::Rgba => Some(Self::Rgba8i),
390				_ => None,
391			}
392			ComponentType::U8 => match channel_type {
393				ChannelType::Red =>  Some(Self::R8ui),
394				ChannelType::Rg =>   Some(Self::Rg8ui),
395				ChannelType::Rgb =>  Some(Self::Rgb8ui),
396				ChannelType::Rgba => Some(Self::Rgba8ui),
397				_ => None,
398			}
399			ComponentType::I16 => match channel_type {
400				ChannelType::Red =>  Some(Self::R16i),
401				ChannelType::Rg =>   Some(Self::Rg16i),
402				ChannelType::Rgb =>  Some(Self::Rgb16i),
403				ChannelType::Rgba => Some(Self::Rgba16i),
404				_ => None,
405			}
406			ComponentType::U16 => match channel_type {
407				ChannelType::Red =>  Some(Self::R16ui),
408				ChannelType::Rg =>   Some(Self::Rg16ui),
409				ChannelType::Rgb =>  Some(Self::Rgb16ui),
410				ChannelType::Rgba => Some(Self::Rgba16ui),
411				_ => None,
412			}
413			ComponentType::I32 => match channel_type {
414				ChannelType::Red =>  Some(Self::R32i),
415				ChannelType::Rg =>   Some(Self::Rg32i),
416				ChannelType::Rgb =>  Some(Self::Rgb32i),
417				ChannelType::Rgba => Some(Self::Rgba32i),
418				_ => None,
419			}
420			ComponentType::U32 => match channel_type {
421				ChannelType::Red =>  Some(Self::R32ui),
422				ChannelType::Rg =>   Some(Self::Rg32ui),
423				ChannelType::Rgb =>  Some(Self::Rgb32ui),
424				ChannelType::Rgba => Some(Self::Rgba32ui),
425				_ => None,
426			}
427			ComponentType::F32 => match channel_type {
428				ChannelType::Red =>  Some(Self::R32f),
429				ChannelType::Rg =>   Some(Self::Rg32f),
430				ChannelType::Rgb =>  Some(Self::Rgb32f),
431				ChannelType::Rgba => Some(Self::Rgba32f),
432				_ => None,
433			}
434			_ => None
435		}
436	}
437}
438
439impl ComponentType {
440	/// Get the component type from a string
441	pub fn from_typename(typename: &str) -> Self {
442		if typename.ends_with("u8" ) {Self::U8} else
443		if typename.ends_with("u16") {Self::U16} else
444		if typename.ends_with("u32") {Self::U32} else
445		if typename.ends_with("i8" ) {Self::I8} else
446		if typename.ends_with("i16") {Self::I16} else
447		if typename.ends_with("i32") {Self::I32} else
448		if typename.ends_with("f16") {Self::F16} else
449		if typename.ends_with("f32") {Self::F32} else
450		{panic!("Currently only supports: u8, u16, u32, i8, i16, i32, f16, f32.")}
451	}
452}
453
454/// Input a generic type of `P` as the pixel data type, retrieve the channel type, and the component type
455pub fn get_channel_type_and_component_type_from_image_pixel<P: Pixel>(channel_type: &mut ChannelType, component_type: &mut ComponentType) -> Result<(), LoadImageError> {
456	*component_type = ComponentType::from_typename(type_name::<P::Subpixel>());
457	*channel_type = match component_type {
458		ComponentType::I32 | ComponentType::U32 => {
459			match P::CHANNEL_COUNT {
460				1 => ChannelType::RedInteger,
461				2 => ChannelType::RgInteger,
462				3 => ChannelType::RgbInteger,
463				4 => ChannelType::RgbaInteger,
464				o => return Err(LoadImageError::UnsupportedImageType(format!("Unknown channel count ({o}) of the `ImageBuffer`"))),
465			}
466		}
467		_ => {
468			match P::CHANNEL_COUNT {
469				1 => ChannelType::Red,
470				2 => ChannelType::Rg,
471				3 => ChannelType::Rgb,
472				4 => ChannelType::Rgba,
473				o => return Err(LoadImageError::UnsupportedImageType(format!("Unknown channel count ({o}) of the `ImageBuffer`"))),
474			}
475		}
476	};
477	Ok(())
478}
479
480/// The `GenericPixelBuffer` trait helps the `PixelBuffer` struct to be able to turn into an object
481pub trait GenericPixelBuffer: Debug {
482	/// Get the underlying buffer
483	fn get_buffer(&self) -> &Buffer;
484
485	/// Get the channel type
486	fn get_channel_type(&self) -> ChannelType;
487
488	/// Get the component type
489	fn get_component_type(&self) -> ComponentType;
490
491	/// Get the size of the buffer
492	fn size_in_bytes(&self) -> usize {
493		self.get_buffer().size()
494	}
495
496	/// Create a `BufferBind` to use the RAII system to manage the binding state
497	fn bind<'a>(&'a self) -> Result<BufferBind<'a>, TextureError> {
498		Ok(self.get_buffer().bind()?)
499	}
500}
501
502impl<B, BP> PixelBuffer<B, BP>
503where
504	B: BufferVec<BP>,
505	BP: BufferVecItem {
506	/// Create a new pixel buffer
507	pub fn new(glcore: Rc<GLCore>,
508			width: u32,
509			height: u32,
510			depth: u32,
511			size_in_bytes: usize,
512			channel_type: ChannelType,
513			component_type: ComponentType,
514			initial_data: Option<*const c_void>,
515		) -> Result<Self, TextureError> {
516		let pixel_size = size_of_pixel(channel_type, component_type);
517		let pitch = ((width as usize * pixel_size - 1) / 4 + 1) * 4;
518		let pitch_wh = pitch * height as usize;
519		let buffer = match initial_data {
520			Some(initial_data) => Buffer::new(glcore.clone(), BufferTarget::PixelUnpackBuffer, size_in_bytes, BufferUsage::StreamDraw, initial_data)?,
521			None => {
522				let empty_data = vec![0u8; size_in_bytes];
523				Buffer::new(glcore.clone(), BufferTarget::PixelUnpackBuffer, size_in_bytes, BufferUsage::StreamDraw, empty_data.as_ptr() as *const c_void)?
524			}
525		};
526		let buffer = B::from(buffer);
527		Ok(Self {
528			buffer,
529			pixel_size,
530			width,
531			height,
532			depth,
533			pitch,
534			pitch_wh,
535			channel_type,
536			component_type,
537			_pixel_type: PhantomData,
538		})
539	}
540
541	/// Create from an `ImageBuffer`
542	pub fn from_image<P: Pixel>(glcore: Rc<GLCore>, img: &ImageBuffer<P, Vec<P::Subpixel>>) -> Result<Self, TextureError> {
543		let container = img.as_raw();
544		let mut channel_type = ChannelType::Rgb;
545		let mut component_type = ComponentType::U8;
546		get_channel_type_and_component_type_from_image_pixel::<P>(&mut channel_type, &mut component_type).unwrap();
547		Self::new(glcore, img.width(), img.height(), 1, size_of_val(&container[..]), channel_type, component_type, Some(container.as_ptr() as *const c_void))
548	}
549
550	/// Create from a file
551	pub fn from_file(glcore: Rc<GLCore>, path: &Path) -> Result<Self, TextureError> {
552		let ext = path.extension().map_or_else(String::new, |ext| OsStr::to_str(ext).unwrap().to_lowercase());
553		match &ext[..] {
554			"jpg" | "jpeg" => {
555				let image_data = std::fs::read(path)?;
556				let img: RgbImage = turbojpeg::decompress_image(&image_data)?;
557				Ok(Self::from_image(glcore, &img)?)
558			}
559			_ => {
560				match ImageReader::open(path)?.decode()? {
561					DynamicImage::ImageLuma8(img) => Ok(Self::from_image(glcore, &img)?),
562					DynamicImage::ImageLumaA8(img) => Ok(Self::from_image(glcore, &img)?),
563					DynamicImage::ImageRgb8(img) => Ok(Self::from_image(glcore, &img)?),
564					DynamicImage::ImageRgba8(img) => Ok(Self::from_image(glcore, &img)?),
565					DynamicImage::ImageLuma16(img) => Ok(Self::from_image(glcore, &img)?),
566					DynamicImage::ImageLumaA16(img) => Ok(Self::from_image(glcore, &img)?),
567					DynamicImage::ImageRgb16(img) => Ok(Self::from_image(glcore, &img)?),
568					DynamicImage::ImageRgba16(img) => Ok(Self::from_image(glcore, &img)?),
569					DynamicImage::ImageRgb32F(img) => Ok(Self::from_image(glcore, &img)?),
570					DynamicImage::ImageRgba32F(img) => Ok(Self::from_image(glcore, &img)?),
571					_ => Err(LoadImageError::UnsupportedImageType(format!("Unsupported image type when loading pixel buffer from {path:?}")))?,
572				}
573			}
574		}
575	}
576}
577
578impl<B, BP> GenericPixelBuffer for PixelBuffer<B, BP>
579where
580	B: BufferVec<BP>,
581	BP: BufferVecItem {
582	fn get_buffer(&self) -> &Buffer {
583		self.buffer.get_buffer()
584	}
585
586	fn get_channel_type(&self) -> ChannelType {
587		self.channel_type
588	}
589
590	fn get_component_type(&self) -> ComponentType {
591		self.component_type
592	}
593}
594
595/// The `GenericTexture` trait helps the `Texture` struct to be able to turn into an object
596pub trait GenericTexture: Debug {
597	/// Get the OpenGL core
598	fn get_glcore(&self) -> &GLCore;
599
600	/// Get the internal name of the texture
601	fn get_name(&self) -> u32;
602
603	/// Get the dimension of the texture
604	fn get_dim(&self) -> TextureDimension;
605
606	/// Get width
607	fn get_width(&self) -> u32;
608
609	/// Get height
610	fn get_height(&self) -> u32;
611
612	/// Get depth
613	fn get_depth(&self) -> u32;
614
615	/// Get the texture internal format
616	fn get_format(&self) -> TextureFormat;
617
618	/// Get byte of face
619	fn get_bytes_of_face(&self) -> usize;
620
621	/// Get byte of texture level 0
622	fn get_bytes_of_texture(&self) -> usize;
623
624	/// Get if have mipmap
625	fn has_mipmap(&self) -> bool;
626
627	/// Get the pixel buffer
628	fn get_pixel_buffer(&self) -> Option<&dyn GenericPixelBuffer>;
629
630	/// Create the PBO if not been created earlier
631	fn create_pixel_buffer(&mut self, buffer_channel_type: ChannelType, buffer_component_type: ComponentType, initial_data: Option<*const c_void>) -> Result<(), TextureError>;
632
633	/// Discard the PBO if not necessarily need it
634	fn drop_pixel_buffer(&mut self);
635
636	/// Map the pixel buffer for the specified access
637	fn map_buffer<'a>(&'a mut self, access: MapAccess) -> Result<Option<(BufferBind<'a>, BufferMapping<'a>, *mut c_void)>, TextureError> {
638		if let Some(b) = self.get_pixel_buffer().as_ref() {
639			let bind = b.bind()?;
640			let (mapping, address) = bind.map(access)?;
641			Ok(Some((bind, mapping, address)))
642		} else {
643			Ok(None)
644		}
645	}
646
647	/// Bind the texture, using the RAII system to manage the binding state
648	fn bind<'a>(&'a self) -> Result<TextureBind<'a>, TextureError>;
649
650	/// Bind a cubemap face, using the RAII system to manage the binding state
651	fn bind_face<'a>(&'a self, face: CubeMapFaces) -> Result<TextureBind<'a>, TextureError>;
652
653	/// Retrieve the pixels from the texture to the specified data pointer regardless of is currently using a PBO or not
654	///
655	/// # Safety
656	///
657	/// When binding a pixel pack buffer, the pointer `data` refers to the offset of the buffer in bytes.
658	/// When not bound to any pixel pack buffers, the pointer `data` is the pointer to your image buffer in the system memory.
659	unsafe fn download_texture(&self, data: *mut c_void, buffer_channel_type: ChannelType, buffer_component_type: ComponentType) -> Result<(), TextureError> {
660		let glcore = self.get_glcore();
661		let pointer = data as *mut u8;
662		match self.get_dim() {
663			TextureDimension::Tex1d => {
664				let bind_tex = self.bind()?;
665				glcore.glGetTexImage(TextureTarget::Tex1d as u32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *mut c_void)?;
666				bind_tex.unbind();
667			}
668			TextureDimension::Tex2d => {
669				let bind_tex = self.bind()?;
670				glcore.glGetTexImage(TextureTarget::Tex2d as u32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *mut c_void)?;
671				bind_tex.unbind();
672			}
673			TextureDimension::Tex3d => {
674				let bind_tex = self.bind()?;
675				glcore.glGetTexImage(TextureTarget::Tex3d as u32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *mut c_void)?;
676				bind_tex.unbind();
677			}
678			TextureDimension::TexCube => {
679				for (i, target) in CUBE_FACE_TARGETS.iter().enumerate() {
680					let target = *target;
681					let bind_tex = self.bind_face(target)?;
682					let pointer = pointer.wrapping_add(i * self.get_bytes_of_face());
683					glcore.glGetTexImage(target as u32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *mut c_void)?;
684					bind_tex.unbind();
685				}
686			}
687		}
688		Ok(())
689	}
690
691	/// Load the texture with the specified data pointer regardless of is currently using a PBO or not
692	///
693	/// # Safety
694	///
695	/// When binding a pixel unpack buffer, the pointer `data` refers to the offset of the buffer in bytes.
696	/// When not bound to any pixel unpack buffers, the pointer `data` is the pointer to your image buffer in the system memory.
697	unsafe fn upload_texture(&self, data: *const c_void, buffer_channel_type: ChannelType, buffer_component_type: ComponentType, regen_mipmap: bool) -> Result<(), TextureError> {
698		let glcore = self.get_glcore();
699		let pointer = data as *const u8;
700		match self.get_dim() {
701			TextureDimension::Tex1d => {
702				let bind_tex = self.bind()?;
703				glcore.glTexImage1D(TextureTarget::Tex1d as u32, 0, self.get_format() as i32, self.get_width() as i32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *const c_void)?;
704				if regen_mipmap && self.has_mipmap() {
705					glcore.glGenerateMipmap(TextureTarget::Tex1d as u32)?;
706				}
707				bind_tex.unbind();
708				Ok(())
709			}
710			TextureDimension::Tex2d => {
711				let bind_tex = self.bind()?;
712				glcore.glTexImage2D(TextureTarget::Tex2d as u32, 0, self.get_format() as i32, self.get_width() as i32, self.get_height() as i32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *const c_void)?;
713				if regen_mipmap && self.has_mipmap() {
714					glcore.glGenerateMipmap(TextureTarget::Tex2d as u32)?;
715				}
716				bind_tex.unbind();
717				Ok(())
718			}
719			TextureDimension::Tex3d => {
720				let bind_tex = self.bind()?;
721				glcore.glTexImage3D(TextureTarget::Tex3d as u32, 0, self.get_format() as i32, self.get_width() as i32, self.get_height() as i32, self.get_depth() as i32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *const c_void)?;
722				if regen_mipmap && self.has_mipmap() {
723					glcore.glGenerateMipmap(TextureTarget::Tex3d as u32)?;
724				}
725				bind_tex.unbind();
726				Ok(())
727			}
728			TextureDimension::TexCube => {
729				for (i, target) in CUBE_FACE_TARGETS.iter().enumerate() {
730					let target = *target;
731					let bind_tex = self.bind_face(target)?;
732					let pointer = pointer.wrapping_add(i * self.get_bytes_of_face());
733					glcore.glTexImage2D(target as u32, 0, self.get_format() as i32, self.get_width() as i32, self.get_height() as i32, 0, buffer_channel_type as u32, buffer_component_type as u32, pointer as *const c_void)?;
734					if regen_mipmap && self.has_mipmap() {
735						glcore.glGenerateMipmap(target as u32)?;
736					}
737					bind_tex.unbind();
738				}
739				Ok(())
740			}
741		}
742	}
743
744	/// Read the pixels from the texture to the pixel buffer
745	fn pack_pixel_buffer(&self) -> Result<(), TextureError> {
746		let pixel_buffer = self.get_pixel_buffer().unwrap();
747		let buffer_channel_type = pixel_buffer.get_channel_type();
748		let buffer_component_type = pixel_buffer.get_component_type();
749		let bind_pbo = pixel_buffer.bind()?;
750		unsafe {self.download_texture(std::ptr::null_mut::<c_void>(), buffer_channel_type, buffer_component_type)?};
751		bind_pbo.unbind();
752		Ok(())
753	}
754
755	/// Apply the change to the pixel buffer of the texture
756	fn unpack_pixel_buffer(&self, regen_mipmap: bool) -> Result<(), TextureError> {
757		let pixel_buffer = self.get_pixel_buffer().unwrap();
758		let buffer_channel_type = pixel_buffer.get_channel_type();
759		let buffer_component_type = pixel_buffer.get_component_type();
760		let bind_pbo = pixel_buffer.bind()?;
761		unsafe {self.upload_texture(std::ptr::null(), buffer_channel_type, buffer_component_type, regen_mipmap)?};
762		bind_pbo.unbind();
763		Ok(())
764	}
765
766	/// Set the active texture unit
767	fn set_active_unit(&self, unit: u32) -> Result<(), TextureError> {
768		Ok(self.get_glcore().glActiveTexture(GL_TEXTURE0 + unit)?)
769	}
770}
771
772impl<B, BP> Texture<B, BP>
773where
774	B: BufferVec<BP>,
775	BP: BufferVecItem {
776	/// When to create a new texture, must set up all of the parameters that are needed to be set up due to the specifications of OpenGL
777	fn set_texture_params(
778			glcore: Rc<GLCore>,
779			name: u32,
780			dim: TextureDimension,
781			width: u32,
782			height: &mut u32,
783			depth: &mut u32,
784			size_mod: &mut usize,
785			wrapping_s: TextureWrapping,
786			wrapping_t: TextureWrapping,
787			wrapping_r: TextureWrapping,
788			mag_filter: SamplerMagFilter,
789			min_filter: SamplerFilter,
790		) -> Result<TextureTarget, TextureError>
791	{
792		let target;
793		match dim {
794			TextureDimension::Tex1d => {
795				target = TextureTarget::Tex1d;
796				*height = 1;
797				*depth = 1;
798				*size_mod = 1;
799			}
800			TextureDimension::Tex2d => {
801				target = TextureTarget::Tex2d;
802				*depth = 1;
803				*size_mod = 1;
804			}
805			TextureDimension::Tex3d => {
806				target = TextureTarget::Tex3d;
807				*size_mod = 1;
808			}
809			TextureDimension::TexCube => {
810				target = TextureTarget::TexCube;
811				*height = width;
812				*depth = 1;
813				*size_mod = 6;
814			}
815		}
816		glcore.glBindTexture(target as u32, name)?;
817		match dim {
818			TextureDimension::Tex1d => {
819				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_S, wrapping_s as i32)?;
820			}
821			TextureDimension::Tex2d => {
822				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_S, wrapping_s as i32)?;
823				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_T, wrapping_t as i32)?;
824			}
825			TextureDimension::Tex3d => {
826				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_S, wrapping_s as i32)?;
827				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_T, wrapping_t as i32)?;
828				glcore.glTexParameteri(target as u32, GL_TEXTURE_WRAP_R, wrapping_r as i32)?;
829			}
830			_ => {}
831		}
832		glcore.glTexParameteri(target as u32, GL_TEXTURE_MAG_FILTER, mag_filter as i32)?;
833		glcore.glTexParameteri(target as u32, GL_TEXTURE_MIN_FILTER, min_filter as i32)?;
834		Ok(target)
835	}
836
837	/// Create an unallocated texture for further initialization
838	fn new_unallocates(
839			glcore: Rc<GLCore>,
840			dim: TextureDimension,
841			format: TextureFormat,
842			width: u32,
843			mut height: u32,
844			mut depth: u32,
845			wrapping_s: TextureWrapping,
846			wrapping_t: TextureWrapping,
847			wrapping_r: TextureWrapping,
848			has_mipmap: bool,
849			mag_filter: SamplerMagFilter,
850			min_filter: SamplerFilter,
851		) -> Result<Self, TextureError> {
852		let mut name: u32 = 0;
853		glcore.glGenTextures(1, &mut name as *mut _)?;
854		let mut size_mod = 1;
855		let target = Self::set_texture_params(glcore.clone(), name, dim, width, &mut height, &mut depth, &mut size_mod, wrapping_s, wrapping_t, wrapping_r, mag_filter, min_filter)?;
856		let pixel_bits = format.bits_of_pixel(glcore.as_ref(), target)?;
857		let pitch = ((pixel_bits - 1) / 32 + 1) * 4;
858		let bytes_of_face = pitch * height as usize * depth as usize;
859		let bytes_of_texture = bytes_of_face * size_mod;
860		Ok(Self {
861			glcore,
862			name,
863			dim,
864			format,
865			width,
866			height,
867			depth,
868			has_mipmap,
869			mag_filter,
870			min_filter,
871			bytes_of_texture,
872			bytes_of_face,
873			pixel_buffer: None,
874			_pixel_type: PhantomData,
875		})
876	}
877
878	/// Create from a pixel buffer
879	fn new_from_pixel_buffer(
880			glcore: Rc<GLCore>,
881			dim: TextureDimension,
882			format: TextureFormat,
883			width: u32,
884			height: u32,
885			depth: u32,
886			wrapping_s: TextureWrapping,
887			wrapping_t: TextureWrapping,
888			wrapping_r: TextureWrapping,
889			has_mipmap: bool,
890			mag_filter: SamplerMagFilter,
891			min_filter: SamplerFilter,
892			pixel_buffer: PixelBuffer<B, BP>,
893		) -> Result<Self, TextureError> {
894		let ret = Self::new_unallocates(glcore, dim, format, width, height, depth, wrapping_s, wrapping_t, wrapping_r, has_mipmap, mag_filter, min_filter)?;
895		unsafe {ret.upload_texture(null(), pixel_buffer.get_channel_type(), pixel_buffer.get_component_type(), has_mipmap)?};
896		Ok(ret)
897	}
898
899	/// Create without pixel buffer
900	fn new(glcore: Rc<GLCore>,
901			dim: TextureDimension,
902			format: TextureFormat,
903			width: u32,
904			height: u32,
905			depth: u32,
906			wrapping_s: TextureWrapping,
907			wrapping_t: TextureWrapping,
908			wrapping_r: TextureWrapping,
909			has_mipmap: bool,
910			mag_filter: SamplerMagFilter,
911			min_filter: SamplerFilter,
912			buffering: bool,
913			buffer_channel_type: ChannelType,
914			buffer_component_type: ComponentType,
915			initial_data: Option<*const c_void>,
916		) -> Result<Self, TextureError> {
917		let mut ret = Self::new_unallocates(glcore, dim, format, width, height, depth, wrapping_s, wrapping_t, wrapping_r, has_mipmap, mag_filter, min_filter)?;
918		if buffering {
919			ret.create_pixel_buffer(buffer_channel_type, buffer_component_type, initial_data)?;
920		} else if let Some(data_pointer) = initial_data {
921			unsafe {ret.upload_texture(data_pointer, buffer_channel_type, buffer_component_type, has_mipmap)?};
922		} else {
923			let empty_data = vec![0u8; ret.bytes_of_texture];
924			unsafe {ret.upload_texture(empty_data.as_ptr() as *const c_void, buffer_channel_type, buffer_component_type, has_mipmap)?};
925		}
926		Ok(ret)
927	}
928
929	/// Create an 1D texture
930	pub fn new_1d(
931	        glcore: Rc<GLCore>,
932	        format: TextureFormat,
933	        width: u32,
934	        wrapping_s: TextureWrapping,
935	        has_mipmap: bool,
936	        mag_filter: SamplerMagFilter,
937			min_filter: SamplerFilter,
938			buffering: bool,
939			buffer_channel_type: ChannelType,
940			buffer_component_type: ComponentType,
941			initial_data: Option<*const c_void>,
942		) -> Result<Self, TextureError> {
943		Self::new(glcore, TextureDimension::Tex1d, format, width, 1, 1, wrapping_s, TextureWrapping::Repeat, TextureWrapping::Repeat, has_mipmap, mag_filter, min_filter, buffering, buffer_channel_type, buffer_component_type, initial_data)
944	}
945
946	/// Create an 2D texture
947	pub fn new_2d(
948	        glcore: Rc<GLCore>,
949	        format: TextureFormat,
950	        width: u32,
951	        height: u32,
952	        wrapping_s: TextureWrapping,
953	        wrapping_t: TextureWrapping,
954	        has_mipmap: bool,
955	        mag_filter: SamplerMagFilter,
956			min_filter: SamplerFilter,
957			buffering: bool,
958			buffer_channel_type: ChannelType,
959			buffer_component_type: ComponentType,
960			initial_data: Option<*const c_void>,
961		) -> Result<Self, TextureError> {
962		Self::new(glcore, TextureDimension::Tex2d, format, width, height, 1, wrapping_s, wrapping_t, TextureWrapping::Repeat, has_mipmap, mag_filter, min_filter, buffering, buffer_channel_type, buffer_component_type, initial_data)
963	}
964
965	/// Create an 3D texture
966	pub fn new_3d(
967	        glcore: Rc<GLCore>,
968	        format: TextureFormat,
969	        width: u32,
970	        height: u32,
971	        depth: u32,
972	        wrapping_s: TextureWrapping,
973	        wrapping_t: TextureWrapping,
974	        wrapping_r: TextureWrapping,
975	        has_mipmap: bool,
976	        mag_filter: SamplerMagFilter,
977			min_filter: SamplerFilter,
978			buffering: bool,
979			buffer_channel_type: ChannelType,
980			buffer_component_type: ComponentType,
981			initial_data: Option<*const c_void>,
982		) -> Result<Self, TextureError> {
983		Self::new(glcore, TextureDimension::Tex3d, format, width, height, depth, wrapping_s, wrapping_t, wrapping_r, has_mipmap, mag_filter, min_filter, buffering, buffer_channel_type, buffer_component_type, initial_data)
984	}
985
986	/// Create an cube map texture
987	pub fn new_cube(
988	        glcore: Rc<GLCore>,
989	        format: TextureFormat,
990	        size: u32,
991	        has_mipmap: bool,
992	        mag_filter: SamplerMagFilter,
993			min_filter: SamplerFilter,
994			buffering: bool,
995			buffer_channel_type: ChannelType,
996			buffer_component_type: ComponentType,
997			initial_data: Option<*const c_void>,
998		) -> Result<Self, TextureError> {
999		Self::new(glcore, TextureDimension::TexCube, format, size, size, 1, TextureWrapping::ClampToEdge, TextureWrapping::ClampToEdge, TextureWrapping::ClampToEdge, has_mipmap, mag_filter, min_filter, buffering, buffer_channel_type, buffer_component_type, initial_data)
1000	}
1001
1002	/// Create a texture from an image
1003	pub fn from_image<P: Pixel>(
1004			glcore: Rc<GLCore>,
1005			dim: TextureDimension,
1006			img: &ImageBuffer<P, Vec<P::Subpixel>>,
1007			wrapping_s: TextureWrapping,
1008			wrapping_t: TextureWrapping,
1009			has_mipmap: bool,
1010			mag_filter: SamplerMagFilter,
1011			min_filter: SamplerFilter,
1012		) -> Result<Self, TextureError> {
1013		let mut buffer_channel_type = ChannelType::Rgb;
1014		let mut buffer_component_type = ComponentType::U8;
1015		get_channel_type_and_component_type_from_image_pixel::<P>(&mut buffer_channel_type, &mut buffer_component_type).unwrap();
1016		let format = TextureFormat::from_channel_type_and_component_type(buffer_channel_type, buffer_component_type).unwrap();
1017		let pixel_buffer = PixelBuffer::from_image(glcore.clone(), img)?;
1018		match dim {
1019			TextureDimension::Tex1d => {
1020				assert_eq!(img.height(), 1);
1021				Self::new_from_pixel_buffer(glcore, dim, format, img.width(), 1, 1, wrapping_s, wrapping_t, TextureWrapping::Repeat, has_mipmap, mag_filter, min_filter, pixel_buffer)
1022			}
1023			TextureDimension::Tex2d => {
1024				Self::new_from_pixel_buffer(glcore, dim, format, img.width(), img.height(), 1, wrapping_s, wrapping_t, TextureWrapping::Repeat, has_mipmap, mag_filter, min_filter, pixel_buffer)
1025			}
1026			TextureDimension::TexCube => {
1027				assert_eq!(img.width() * 6, img.height());
1028				Self::new_from_pixel_buffer(glcore, dim, format, img.width(), img.width(), 1, TextureWrapping::ClampToEdge, TextureWrapping::ClampToEdge, TextureWrapping::ClampToEdge, has_mipmap, mag_filter, min_filter, pixel_buffer)
1029			}
1030			other => panic!("Could not create a {other:?} texture from a `ImageBuffer`")
1031		}
1032	}
1033
1034	/// Create a texture from a file
1035	pub fn from_file(
1036			glcore: Rc<GLCore>,
1037			path: &Path,
1038			dim: TextureDimension,
1039			wrapping_s: TextureWrapping,
1040			wrapping_t: TextureWrapping,
1041			has_mipmap: bool,
1042			mag_filter: SamplerMagFilter,
1043			min_filter: SamplerFilter,
1044		) -> Result<Self, TextureError> {
1045		let ext = path.extension().map_or_else(String::new, |ext| OsStr::to_str(ext).unwrap().to_lowercase());
1046		match &ext[..] {
1047			"jpg" | "jpeg" => {
1048				let image_data = std::fs::read(path)?;
1049				let img: RgbImage = turbojpeg::decompress_image(&image_data)?;
1050				Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?)
1051			}
1052			_ => {
1053				match ImageReader::open(path)?.decode()? {
1054					DynamicImage::ImageLuma8(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1055					DynamicImage::ImageLumaA8(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1056					DynamicImage::ImageRgb8(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1057					DynamicImage::ImageRgba8(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1058					DynamicImage::ImageLuma16(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1059					DynamicImage::ImageLumaA16(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1060					DynamicImage::ImageRgb16(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1061					DynamicImage::ImageRgba16(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1062					DynamicImage::ImageRgb32F(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1063					DynamicImage::ImageRgba32F(img) => Ok(Self::from_image(glcore, dim, &img, wrapping_s, wrapping_t, has_mipmap, mag_filter, min_filter)?),
1064					_ => Err(LoadImageError::UnsupportedImageType(format!("Unsupported image type when loading texture from {path:?}")))?,
1065				}
1066			}
1067		}
1068	}
1069}
1070
1071impl<B, BP> GenericTexture for Texture<B, BP>
1072where
1073	B: BufferVec<BP>,
1074	BP: BufferVecItem {
1075	fn get_glcore(&self) -> &GLCore {
1076		&self.glcore
1077	}
1078
1079	fn get_name(&self) -> u32 {
1080		self.name
1081	}
1082
1083	fn get_dim(&self) -> TextureDimension {
1084		self.dim
1085	}
1086
1087	fn get_width(&self) -> u32 {
1088		self.width
1089	}
1090
1091	fn get_height(&self) -> u32 {
1092		self.height
1093	}
1094
1095	fn get_depth(&self) -> u32 {
1096		self.depth
1097	}
1098
1099	fn get_format(&self) -> TextureFormat {
1100		self.format
1101	}
1102
1103	fn get_bytes_of_face(&self) -> usize {
1104		self.bytes_of_face
1105	}
1106
1107	fn get_bytes_of_texture(&self) -> usize {
1108		self.bytes_of_texture
1109	}
1110
1111	fn has_mipmap(&self) -> bool {
1112		self.has_mipmap
1113	}
1114
1115	fn get_pixel_buffer(&self) -> Option<&dyn GenericPixelBuffer> {
1116		if let Some(pixel_buffer) = &self.pixel_buffer {
1117			Some(pixel_buffer)
1118		} else {
1119			None
1120		}
1121	}
1122
1123	fn create_pixel_buffer(&mut self, buffer_channel_type: ChannelType, buffer_component_type: ComponentType, initial_data: Option<*const c_void>) -> Result<(), TextureError> {
1124		self.pixel_buffer = Some(PixelBuffer::new(self.glcore.clone(), self.width, self.height, self.depth, self.bytes_of_texture, buffer_channel_type, buffer_component_type, initial_data)?);
1125		Ok(())
1126	}
1127
1128	fn drop_pixel_buffer(&mut self) {
1129		self.pixel_buffer = None
1130	}
1131
1132	fn bind<'a>(&'a self) -> Result<TextureBind<'a>, TextureError> {
1133		match self.get_dim() {
1134			TextureDimension::Tex1d => TextureBind::new(self, TextureTarget::Tex1d),
1135			TextureDimension::Tex2d => TextureBind::new(self, TextureTarget::Tex2d),
1136			TextureDimension::Tex3d => TextureBind::new(self, TextureTarget::Tex3d),
1137			TextureDimension::TexCube => panic!("Please use `bind_face()` to bind a cube map."),
1138		}
1139	}
1140
1141	fn bind_face<'a>(&'a self, face: CubeMapFaces) -> Result<TextureBind<'a>, TextureError> {
1142		match self.get_dim() {
1143			TextureDimension::TexCube => {
1144				match face {
1145					CubeMapFaces::TexCubePosX => TextureBind::new(self, TextureTarget::TexCubePosX),
1146					CubeMapFaces::TexCubeNegX => TextureBind::new(self, TextureTarget::TexCubeNegX),
1147					CubeMapFaces::TexCubePosY => TextureBind::new(self, TextureTarget::TexCubePosY),
1148					CubeMapFaces::TexCubeNegY => TextureBind::new(self, TextureTarget::TexCubeNegY),
1149					CubeMapFaces::TexCubePosZ => TextureBind::new(self, TextureTarget::TexCubePosZ),
1150					CubeMapFaces::TexCubeNegZ => TextureBind::new(self, TextureTarget::TexCubeNegZ),
1151				}
1152			}
1153			_ => panic!("Please use `bind()` to bind an non-cube-map texture."),
1154		}
1155	}
1156}
1157
1158impl<B, BP> Drop for Texture<B, BP>
1159where
1160	B: BufferVec<BP>,
1161	BP: BufferVecItem {
1162	fn drop(&mut self) {
1163		self.glcore.glDeleteTextures(1, &self.name as *const u32).unwrap();
1164	}
1165}
1166
1167impl<'a> TextureBind<'a> {
1168	/// Create a binding state to the texture, utilizing the RAII rules to manage the binding state
1169	fn new(texture: &'a dyn GenericTexture, target: TextureTarget) -> Result<Self, TextureError> {
1170		texture.get_glcore().glBindTexture(target as u32, texture.get_name())?;
1171		Ok(Self {
1172			texture,
1173			target,
1174		})
1175	}
1176
1177	/// Explicitly unbind the texture.
1178	pub fn unbind(self) {}
1179}
1180
1181impl Drop for TextureBind<'_> {
1182	fn drop(&mut self) {
1183		self.texture.get_glcore().glBindTexture(self.target as u32, 0).unwrap();
1184	}
1185}
1186
1187impl<B, BP> Debug for Texture<B, BP>
1188where
1189	B: BufferVec<BP>,
1190	BP: BufferVecItem {
1191	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1192		f.debug_struct("Texture")
1193		.field("name", &self.name)
1194		.field("dim", &self.dim)
1195		.field("format", &self.format)
1196		.field("width", &self.width)
1197		.field("height", &self.height)
1198		.field("depth", &self.depth)
1199		.field("has_mipmap", &self.has_mipmap)
1200		.field("pixel_buffer", &self.pixel_buffer)
1201		.finish()
1202	}
1203}
1204
1205impl Debug for TextureDimension {
1206	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1207		match self {
1208			Self::Tex1d => write!(f, "1D"),
1209			Self::Tex2d => write!(f, "2D"),
1210			Self::Tex3d => write!(f, "3D"),
1211			Self::TexCube => write!(f, "CubeMap"),
1212		}
1213	}
1214}
1215
1216impl Debug for TextureFormat {
1217	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1218		match self {
1219			Self::Depth => write!(f, "DEPTH"),
1220			Self::DepthStencil => write!(f, "DEPTH_STENCIL"),
1221			Self::Red => write!(f, "RED"),
1222			Self::Rg => write!(f, "RG"),
1223			Self::Rgb => write!(f, "RGB"),
1224			Self::Rgba => write!(f, "RGBA"),
1225			Self::Red8 => write!(f, "R8"),
1226			Self::Red8Snorm => write!(f, "R8_SNORM"),
1227			Self::Red16 => write!(f, "R16"),
1228			Self::Red16Snorm => write!(f, "R16_SNORM"),
1229			Self::Rg8 => write!(f, "RG8"),
1230			Self::Rg8Snorm => write!(f, "RG8_SNORM"),
1231			Self::Rg16 => write!(f, "RG16"),
1232			Self::Rg16Snorm => write!(f, "RG16_SNORM"),
1233			Self::R3g3b2 => write!(f, "R3_G3_B2"),
1234			Self::Rgb4 => write!(f, "RGB4"),
1235			Self::Rgb5 => write!(f, "RGB5"),
1236			Self::Rgb8 => write!(f, "RGB8"),
1237			Self::Rgb8Snorm => write!(f, "RGB8_SNORM"),
1238			Self::Rgb10 => write!(f, "RGB10"),
1239			Self::Rgb12 => write!(f, "RGB12"),
1240			Self::Rgb16Snorm => write!(f, "RGB16_SNORM"),
1241			Self::Rgba2 => write!(f, "RGBA2"),
1242			Self::Rgba4 => write!(f, "RGBA4"),
1243			Self::Rgb5a1 => write!(f, "RGB5_A1"),
1244			Self::Rgba8 => write!(f, "RGBA8"),
1245			Self::Rgba8Snorm => write!(f, "RGBA8_SNORM"),
1246			Self::Rgb10a2 => write!(f, "RGB10_A2"),
1247			Self::Rgb10a2ui => write!(f, "RGB10_A2UI"),
1248			Self::Rgba12 => write!(f, "RGBA12"),
1249			Self::Rgba16 => write!(f, "RGBA16"),
1250			Self::R32f => write!(f, "R32F"),
1251			Self::Rg32f => write!(f, "RG32F"),
1252			Self::Rgb32f => write!(f, "RGB32F"),
1253			Self::Rgba32f => write!(f, "RGBA32F"),
1254			Self::R11fg11fb10f => write!(f, "R11F_G11F_B10F"),
1255			Self::Rgb9e5 => write!(f, "RGB9_E5"),
1256			Self::R8i => write!(f, "R8I"),
1257			Self::R8ui => write!(f, "R8UI"),
1258			Self::R16i => write!(f, "R16I"),
1259			Self::R16ui => write!(f, "R16UI"),
1260			Self::R32i => write!(f, "R32I"),
1261			Self::R32ui => write!(f, "R32UI"),
1262			Self::Rg8i => write!(f, "RG8I"),
1263			Self::Rg8ui => write!(f, "RG8UI"),
1264			Self::Rg16i => write!(f, "RG16I"),
1265			Self::Rg16ui => write!(f, "RG16UI"),
1266			Self::Rg32i => write!(f, "RG32I"),
1267			Self::Rg32ui => write!(f, "RG32UI"),
1268			Self::Rgb8i => write!(f, "RGB8I"),
1269			Self::Rgb8ui => write!(f, "RGB8UI"),
1270			Self::Rgb16i => write!(f, "RGB16I"),
1271			Self::Rgb16ui => write!(f, "RGB16UI"),
1272			Self::Rgb32i => write!(f, "RGB32I"),
1273			Self::Rgb32ui => write!(f, "RGB32UI"),
1274			Self::Rgba8i => write!(f, "RGBA8I"),
1275			Self::Rgba8ui => write!(f, "RGBA8UI"),
1276			Self::Rgba16i => write!(f, "RGBA16I"),
1277			Self::Rgba16ui => write!(f, "RGBA16UI"),
1278			Self::Rgba32i => write!(f, "RGBA32I"),
1279			Self::Rgba32ui => write!(f, "RGBA32UI"),
1280		}
1281	}
1282}
1283
1284impl Debug for CubeMapFaces {
1285	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1286		match self {
1287			Self::TexCubePosX => write!(f, "Positive X"),
1288			Self::TexCubeNegX => write!(f, "Negative X"),
1289			Self::TexCubePosY => write!(f, "Positive Y"),
1290			Self::TexCubeNegY => write!(f, "Negative Y"),
1291			Self::TexCubePosZ => write!(f, "Positive Z"),
1292			Self::TexCubeNegZ => write!(f, "Negative Z"),
1293		}
1294	}
1295}
1296
1297impl Debug for ChannelType {
1298	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1299		match self {
1300			Self::Red => write!(f, "RED"),
1301			Self::Rg => write!(f, "RG"),
1302			Self::Rgb => write!(f, "RGB"),
1303			Self::Bgr => write!(f, "BGR"),
1304			Self::Rgba => write!(f, "RGBA"),
1305			Self::Bgra => write!(f, "BGRA"),
1306			Self::RedInteger => write!(f, "RED_INTEGER"),
1307			Self::RgInteger => write!(f, "RG_INTEGER"),
1308			Self::RgbInteger => write!(f, "RGB_INTEGER"),
1309			Self::BgrInteger => write!(f, "BGR_INTEGER"),
1310			Self::RgbaInteger => write!(f, "RGBA_INTEGER"),
1311			Self::BgraInteger => write!(f, "BGRA_INTEGER"),
1312			Self::StencilIndex => write!(f, "STENCIL_INDEX"),
1313			Self::Depth => write!(f, "DEPTH_COMPONENT"),
1314			Self::DepthStencil => write!(f, "DEPTH_STENCIL"),
1315		}
1316	}
1317}
1318
1319impl Debug for ComponentType {
1320	fn fmt(&self, f: &mut Formatter) -> fmt::Result {
1321		match self {
1322			Self::U8 => write!(f, "UNSIGNED_BYTE"),
1323			Self::I8 => write!(f, "BYTE"),
1324			Self::U16 => write!(f, "UNSIGNED_SHORT"),
1325			Self::I16 => write!(f, "SHORT"),
1326			Self::U32 => write!(f, "UNSIGNED_INT"),
1327			Self::I32 => write!(f, "INT"),
1328			Self::F16 => write!(f, "HALF_FLOAT"),
1329			Self::F32 => write!(f, "FLOAT"),
1330			Self::U8_332 => write!(f, "UNSIGNED_BYTE_3_3_2"),
1331			Self::U8_233Rev => write!(f, "UNSIGNED_BYTE_2_3_3_REV"),
1332			Self::U16_565 => write!(f, "UNSIGNED_SHORT_5_6_5"),
1333			Self::U16_565Rev => write!(f, "UNSIGNED_SHORT_5_6_5_REV"),
1334			Self::U16_4444 => write!(f, "UNSIGNED_SHORT_4_4_4_4"),
1335			Self::U16_4444Rev => write!(f, "UNSIGNED_SHORT_4_4_4_4_REV"),
1336			Self::U16_5551 => write!(f, "UNSIGNED_SHORT_5_5_5_1"),
1337			Self::U16_1555Rev => write!(f, "UNSIGNED_SHORT_1_5_5_5_REV"),
1338			Self::U32_8888 => write!(f, "UNSIGNED_INT_8_8_8_8"),
1339			Self::U32_8888Rev => write!(f, "UNSIGNED_INT_8_8_8_8_REV"),
1340			Self::U32_10_10_10_2 => write!(f, "UNSIGNED_INT_10_10_10_2"),
1341			Self::U32_2_10_10_10Rev => write!(f, "UNSIGNED_INT_2_10_10_10_REV"),
1342		}
1343	}
1344}