image2/
texture.rs

1use crate::*;
2pub use glow;
3use glow::*;
4
5/// OpenGL texture for `Image` type
6pub struct ImageTexture<T: Type, C: Color> {
7    /// Framebuffer
8    pub framebuffer: Framebuffer,
9
10    /// Texture
11    pub texture: Texture,
12    _t: std::marker::PhantomData<(T, C)>,
13}
14
15impl<T: Type, C: Color> ImageTexture<T, C> {
16    /// Create a new `ImageTexture` from framebuffer and texture
17    pub fn new(framebuffer: Framebuffer, texture: Texture) -> Self {
18        ImageTexture {
19            framebuffer,
20            texture,
21            _t: std::marker::PhantomData,
22        }
23    }
24}
25
26/// ToTexture is defined for image types that can be converted to OpenGL textures
27pub trait ToTexture<T: Type, C: Color> {
28    /// OpenGL color
29    const COLOR: u32;
30
31    /// OpenGL type
32    const KIND: u32;
33
34    /// Get metadata
35    fn get_meta(&self) -> &Meta<T, C>;
36
37    /// Get data buffer
38    fn get_data(&self) -> &[u8];
39
40    /// Get internal color type
41    fn internal(&self) -> Result<u32, Error> {
42        let internal = match (Self::COLOR, Self::KIND) {
43            (glow::RED, glow::BYTE) => glow::R8,
44            (glow::RED, glow::SHORT) => glow::R16,
45            (glow::RED, glow::UNSIGNED_BYTE) => glow::R8,
46            (glow::RED, glow::UNSIGNED_SHORT) => glow::R16,
47            (glow::RED, glow::INT) => glow::R32I,
48            (glow::RED, glow::UNSIGNED_INT) => glow::R32UI,
49            (glow::RED, glow::FLOAT) => glow::R32F,
50            (glow::RGB, glow::BYTE) => glow::RGB8,
51            (glow::RGB, glow::SHORT) => glow::RGB16,
52            (glow::RGB, glow::UNSIGNED_BYTE) => glow::RGB,
53            (glow::RGB, glow::UNSIGNED_SHORT) => glow::RGB16,
54            (glow::RGB, glow::INT) => glow::RGB32I,
55            (glow::RGB, glow::UNSIGNED_INT) => glow::RGB32UI,
56            (glow::RGB, glow::FLOAT) => glow::RGB32F,
57            (glow::RGBA, glow::BYTE) => glow::RGBA,
58            (glow::RGBA, glow::SHORT) => glow::RGBA16,
59            (glow::RGBA, glow::UNSIGNED_BYTE) => glow::RGBA,
60            (glow::RGBA, glow::UNSIGNED_SHORT) => glow::RGBA16,
61            (glow::RGBA, glow::INT) => glow::RGBA32I,
62            (glow::RGBA, glow::UNSIGNED_INT) => glow::RGBA32UI,
63            (glow::RGBA, glow::FLOAT) => glow::RGBA32F,
64            _ => return Err(Error::InvalidType),
65        };
66        Ok(internal)
67    }
68
69    /// Create `ImageTexture`
70    fn create_image_texture(&self, gl: &glow::Context) -> Result<ImageTexture<T, C>, Error> {
71        unsafe {
72            let framebuffer = gl
73                .create_framebuffer()
74                .expect("Unable to create framebuffer");
75            let texture = gl.create_texture().expect("Unable to create texture");
76            let image_texture = ImageTexture::<T, C>::new(framebuffer, texture);
77
78            // Texture
79            gl.bind_texture(glow::TEXTURE_2D, Some(texture));
80
81            gl.tex_parameter_i32(
82                glow::TEXTURE_2D,
83                glow::TEXTURE_MAG_FILTER,
84                glow::NEAREST as i32,
85            );
86            gl.tex_parameter_i32(
87                glow::TEXTURE_2D,
88                glow::TEXTURE_MIN_FILTER,
89                glow::NEAREST as i32,
90            );
91
92            let meta = self.get_meta();
93            gl.tex_image_2d(
94                glow::TEXTURE_2D,
95                0,
96                self.internal()? as i32,
97                meta.width() as i32,
98                meta.height() as i32,
99                0,
100                Self::COLOR,
101                Self::KIND,
102                Some(self.get_data()),
103            );
104
105            gl.bind_texture(glow::TEXTURE_2D, None);
106
107            // Framebuffer
108            gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(image_texture.framebuffer));
109            gl.framebuffer_texture_2d(
110                glow::READ_FRAMEBUFFER,
111                glow::COLOR_ATTACHMENT0,
112                glow::TEXTURE_2D,
113                Some(texture),
114                0,
115            );
116            gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
117            Ok(image_texture)
118        }
119    }
120
121    /// Draw the texture on the framebuffer
122    fn draw_image_texture(
123        &self,
124        gl: &glow::Context,
125        image_texture: &ImageTexture<T, C>,
126        display_size: Size,
127        offset: Point,
128    ) -> Result<(), Error> {
129        let x = offset.x;
130        let y = offset.y;
131        let display_width = display_size.width;
132        let display_height = display_size.height;
133
134        unsafe {
135            // Texture
136            gl.bind_texture(glow::TEXTURE_2D, Some(image_texture.texture));
137            let meta = self.get_meta();
138
139            gl.tex_image_2d(
140                glow::TEXTURE_2D,
141                0,
142                self.internal()? as i32,
143                meta.width() as i32,
144                meta.height() as i32,
145                0,
146                Self::COLOR,
147                Self::KIND,
148                Some(self.get_data()),
149            );
150
151            gl.bind_texture(glow::TEXTURE_2D, None);
152
153            // Framebuffer
154            gl.bind_framebuffer(glow::READ_FRAMEBUFFER, Some(image_texture.framebuffer));
155            gl.framebuffer_texture_2d(
156                glow::READ_FRAMEBUFFER,
157                glow::COLOR_ATTACHMENT0,
158                glow::TEXTURE_2D,
159                Some(image_texture.texture),
160                0,
161            );
162
163            gl.blit_framebuffer(
164                0,
165                meta.height() as i32,
166                meta.width() as i32,
167                0,
168                x as i32,
169                y as i32,
170                x as i32 + display_width as i32,
171                y as i32 + display_height as i32,
172                glow::COLOR_BUFFER_BIT,
173                glow::NEAREST,
174            );
175            gl.bind_framebuffer(glow::READ_FRAMEBUFFER, None);
176        }
177        Ok(())
178    }
179}
180
181macro_rules! to_texture {
182    ($t:ty, $c:ty, $kind:expr, $color:expr) => {
183        impl ToTexture<$t, $c> for Image<$t, $c> {
184            const COLOR: u32 = $color;
185            const KIND: u32 = $kind;
186
187            fn get_meta(&self) -> &Meta<$t, $c> {
188                &self.meta
189            }
190
191            fn get_data(&self) -> &[u8] {
192                self.buffer()
193            }
194        }
195    };
196}
197
198to_texture!(f32, Rgb, glow::FLOAT, glow::RGB);
199to_texture!(f32, Srgb, glow::FLOAT, glow::RGB);
200to_texture!(f32, Rgba, glow::FLOAT, glow::RGBA);
201to_texture!(f32, Srgba, glow::FLOAT, glow::RGBA);
202to_texture!(u16, Rgb, glow::UNSIGNED_SHORT, glow::RGB);
203to_texture!(u16, Srgb, glow::UNSIGNED_SHORT, glow::RGB);
204to_texture!(u16, Rgba, glow::UNSIGNED_SHORT, glow::RGBA);
205to_texture!(u16, Srgba, glow::UNSIGNED_SHORT, glow::RGBA);
206to_texture!(i16, Rgb, glow::SHORT, glow::RGB);
207to_texture!(i16, Srgb, glow::SHORT, glow::RGB);
208to_texture!(i16, Rgba, glow::SHORT, glow::RGBA);
209to_texture!(i16, Srgba, glow::SHORT, glow::RGBA);
210to_texture!(u8, Rgb, glow::UNSIGNED_BYTE, glow::RGB);
211to_texture!(u8, Srgb, glow::UNSIGNED_BYTE, glow::RGB);
212to_texture!(u8, Rgba, glow::UNSIGNED_BYTE, glow::RGBA);
213to_texture!(u8, Srgba, glow::UNSIGNED_BYTE, glow::RGBA);