inox2d_opengl/
texture.rs

1use glow::HasContext;
2
3use inox2d::texture::ShallowTexture;
4
5#[derive(thiserror::Error, Debug)]
6#[error("Could not create texture: {0}")]
7pub struct TextureError(String);
8
9pub struct Texture {
10	tex: glow::Texture,
11	width: u32,
12	height: u32,
13	bpp: u32,
14}
15
16impl Texture {
17	pub fn from_shallow_texture(gl: &glow::Context, shalltex: &ShallowTexture) -> Result<Self, TextureError> {
18		Self::from_raw_pixels(gl, shalltex.pixels(), shalltex.width(), shalltex.height())
19	}
20
21	pub fn from_raw_pixels(gl: &glow::Context, pixels: &[u8], width: u32, height: u32) -> Result<Self, TextureError> {
22		let bpp = 8 * (pixels.len() / (width as usize * height as usize)) as u32;
23
24		let tex = unsafe { gl.create_texture().map_err(TextureError)? };
25		unsafe {
26			gl.bind_texture(glow::TEXTURE_2D, Some(tex));
27			gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32);
28			gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32);
29			gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32);
30			gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32);
31			gl.tex_image_2d(
32				glow::TEXTURE_2D,
33				0,
34				glow::RGBA8 as i32,
35				width as i32,
36				height as i32,
37				0,
38				glow::RGBA,
39				glow::UNSIGNED_BYTE,
40				Some(pixels),
41			);
42			gl.bind_texture(glow::TEXTURE_2D, None);
43		}
44
45		Ok(Texture {
46			tex,
47			width,
48			height,
49			bpp,
50		})
51	}
52
53	pub fn bind(&self, gl: &glow::Context) {
54		self.bind_on(gl, 0);
55	}
56
57	pub fn bind_on(&self, gl: &glow::Context, slot: u32) {
58		unsafe {
59			gl.active_texture(glow::TEXTURE0 + slot);
60			gl.bind_texture(glow::TEXTURE_2D, Some(self.tex));
61		}
62	}
63
64	pub fn unbind(&self, gl: &glow::Context) {
65		unsafe { gl.bind_texture(glow::TEXTURE_2D, None) };
66	}
67
68	pub fn width(&self) -> u32 {
69		self.width
70	}
71
72	pub fn height(&self) -> u32 {
73		self.height
74	}
75
76	pub fn bpp(&self) -> u32 {
77		self.bpp
78	}
79}
80
81/// Uploads an empty texture.
82///
83/// # Safety
84///
85/// Make sure `ty` is a valid OpenGL number type
86pub unsafe fn upload_empty(gl: &glow::Context, tex: glow::Texture, width: u32, height: u32, ty: u32) {
87	let internal_format = if ty == glow::FLOAT { glow::RGBA32F } else { glow::RGBA8 } as i32;
88
89	gl.bind_texture(glow::TEXTURE_2D, Some(tex));
90	gl.tex_image_2d(
91		glow::TEXTURE_2D,
92		0,
93		internal_format,
94		width as i32,
95		height as i32,
96		0,
97		glow::RGBA,
98		ty,
99		None,
100	);
101	gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32);
102	gl.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32);
103	gl.bind_texture(glow::TEXTURE_2D, None);
104}