1use crate::*;
2pub use glow;
3use glow::*;
4
5pub struct ImageTexture<T: Type, C: Color> {
7 pub framebuffer: Framebuffer,
9
10 pub texture: Texture,
12 _t: std::marker::PhantomData<(T, C)>,
13}
14
15impl<T: Type, C: Color> ImageTexture<T, C> {
16 pub fn new(framebuffer: Framebuffer, texture: Texture) -> Self {
18 ImageTexture {
19 framebuffer,
20 texture,
21 _t: std::marker::PhantomData,
22 }
23 }
24}
25
26pub trait ToTexture<T: Type, C: Color> {
28 const COLOR: u32;
30
31 const KIND: u32;
33
34 fn get_meta(&self) -> &Meta<T, C>;
36
37 fn get_data(&self) -> &[u8];
39
40 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 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 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 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 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 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 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);