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
81pub 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}