1 | use std::rc::Rc; |
2 | |
3 | use glow::HasContext; |
4 | |
5 | use crate::{ErrorKind, ImageFlags, ImageInfo, ImageSource, PixelFormat}; |
6 | |
7 | pub struct GlTexture { |
8 | id: <glow::Context as glow::HasContext>::Texture, |
9 | info: ImageInfo, |
10 | owned: bool, |
11 | } |
12 | |
13 | impl GlTexture { |
14 | pub fn new_from_native_texture(texture: <glow::Context as glow::HasContext>::Texture, info: ImageInfo) -> Self { |
15 | Self { |
16 | id: texture, |
17 | info, |
18 | owned: false, |
19 | } |
20 | } |
21 | pub fn new(context: &Rc<glow::Context>, info: ImageInfo, opengles_2_0: bool) -> Result<Self, ErrorKind> { |
22 | //let size = src.dimensions(); |
23 | |
24 | let id = unsafe { |
25 | let id = context.create_texture().unwrap(); |
26 | context.bind_texture(glow::TEXTURE_2D, Some(id)); |
27 | context.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); |
28 | if !opengles_2_0 { |
29 | context.pixel_store_i32(glow::UNPACK_ROW_LENGTH, info.width() as i32); |
30 | context.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, 0); |
31 | context.pixel_store_i32(glow::UNPACK_SKIP_ROWS, 0); |
32 | } |
33 | id |
34 | }; |
35 | |
36 | let texture = Self { id, info, owned: true }; |
37 | |
38 | match info.format() { |
39 | PixelFormat::Gray8 => unsafe { |
40 | let internal_format = if opengles_2_0 { glow::LUMINANCE } else { glow::R8 }; |
41 | let format = if opengles_2_0 { internal_format } else { glow::RED }; |
42 | |
43 | context.tex_image_2d( |
44 | glow::TEXTURE_2D, |
45 | 0, |
46 | internal_format as i32, |
47 | texture.info.width() as i32, |
48 | texture.info.height() as i32, |
49 | 0, |
50 | format, |
51 | glow::UNSIGNED_BYTE, |
52 | None, //data.buf().as_ptr() as *const GLvoid |
53 | ); |
54 | }, |
55 | PixelFormat::Rgb8 => unsafe { |
56 | context.tex_image_2d( |
57 | glow::TEXTURE_2D, |
58 | 0, |
59 | glow::RGB as i32, |
60 | texture.info.width() as i32, |
61 | texture.info.height() as i32, |
62 | 0, |
63 | glow::RGB, |
64 | glow::UNSIGNED_BYTE, |
65 | None, |
66 | //data.buf().as_ptr() as *const GLvoid |
67 | ); |
68 | }, |
69 | PixelFormat::Rgba8 => unsafe { |
70 | context.tex_image_2d( |
71 | glow::TEXTURE_2D, |
72 | 0, |
73 | glow::RGBA as i32, |
74 | texture.info.width() as i32, |
75 | texture.info.height() as i32, |
76 | 0, |
77 | glow::RGBA, |
78 | glow::UNSIGNED_BYTE, |
79 | None, |
80 | //data.buf().as_ptr() as *const GLvoid |
81 | ); |
82 | }, |
83 | } |
84 | |
85 | let flags = texture.info.flags(); |
86 | |
87 | if flags.contains(ImageFlags::GENERATE_MIPMAPS) { |
88 | if flags.contains(ImageFlags::NEAREST) { |
89 | unsafe { |
90 | context.tex_parameter_i32( |
91 | glow::TEXTURE_2D, |
92 | glow::TEXTURE_MIN_FILTER, |
93 | glow::NEAREST_MIPMAP_NEAREST as i32, |
94 | ); |
95 | } |
96 | } else { |
97 | unsafe { |
98 | context.tex_parameter_i32( |
99 | glow::TEXTURE_2D, |
100 | glow::TEXTURE_MIN_FILTER, |
101 | glow::LINEAR_MIPMAP_LINEAR as i32, |
102 | ); |
103 | } |
104 | } |
105 | } else if flags.contains(ImageFlags::NEAREST) { |
106 | unsafe { |
107 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::NEAREST as i32); |
108 | } |
109 | } else { |
110 | unsafe { |
111 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MIN_FILTER, glow::LINEAR as i32); |
112 | } |
113 | } |
114 | |
115 | if flags.contains(ImageFlags::NEAREST) { |
116 | unsafe { |
117 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::NEAREST as i32); |
118 | } |
119 | } else { |
120 | unsafe { |
121 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_MAG_FILTER, glow::LINEAR as i32); |
122 | } |
123 | } |
124 | |
125 | if flags.contains(ImageFlags::REPEAT_X) { |
126 | unsafe { |
127 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::REPEAT as i32); |
128 | } |
129 | } else { |
130 | unsafe { |
131 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_S, glow::CLAMP_TO_EDGE as i32); |
132 | } |
133 | } |
134 | |
135 | if flags.contains(ImageFlags::REPEAT_Y) { |
136 | unsafe { |
137 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::REPEAT as i32); |
138 | } |
139 | } else { |
140 | unsafe { |
141 | context.tex_parameter_i32(glow::TEXTURE_2D, glow::TEXTURE_WRAP_T, glow::CLAMP_TO_EDGE as i32); |
142 | } |
143 | } |
144 | |
145 | unsafe { |
146 | context.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4); |
147 | if !opengles_2_0 { |
148 | context.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0); |
149 | context.pixel_store_i32(glow::UNPACK_SKIP_PIXELS, 0); |
150 | context.pixel_store_i32(glow::UNPACK_SKIP_ROWS, 0); |
151 | } |
152 | } |
153 | |
154 | if flags.contains(ImageFlags::GENERATE_MIPMAPS) { |
155 | unsafe { |
156 | context.generate_mipmap(glow::TEXTURE_2D); |
157 | //glow::TexParameteri(glow::TEXTURE_2D, glow::GENERATE_MIPMAP, glow::TRUE); |
158 | } |
159 | } |
160 | |
161 | unsafe { |
162 | context.bind_texture(glow::TEXTURE_2D, None); |
163 | } |
164 | |
165 | Ok(texture) |
166 | } |
167 | |
168 | pub fn id(&self) -> <glow::Context as glow::HasContext>::Texture { |
169 | self.id |
170 | } |
171 | |
172 | pub fn update( |
173 | &mut self, |
174 | context: &Rc<glow::Context>, |
175 | src: ImageSource, |
176 | x: usize, |
177 | y: usize, |
178 | opengles_2_0: bool, |
179 | ) -> Result<(), ErrorKind> { |
180 | let size = src.dimensions(); |
181 | |
182 | if x + size.width > self.info.width() { |
183 | return Err(ErrorKind::ImageUpdateOutOfBounds); |
184 | } |
185 | |
186 | if y + size.height > self.info.height() { |
187 | return Err(ErrorKind::ImageUpdateOutOfBounds); |
188 | } |
189 | |
190 | if self.info.format() != src.format() { |
191 | return Err(ErrorKind::ImageUpdateWithDifferentFormat); |
192 | } |
193 | |
194 | unsafe { |
195 | context.bind_texture(glow::TEXTURE_2D, Some(self.id)); |
196 | context.pixel_store_i32(glow::UNPACK_ALIGNMENT, 1); |
197 | if !opengles_2_0 { |
198 | context.pixel_store_i32(glow::UNPACK_ROW_LENGTH, size.width as i32); |
199 | } |
200 | } |
201 | |
202 | match src { |
203 | ImageSource::Gray(data) => unsafe { |
204 | let format = if opengles_2_0 { glow::LUMINANCE } else { glow::R8 }; |
205 | |
206 | context.tex_sub_image_2d( |
207 | glow::TEXTURE_2D, |
208 | 0, |
209 | x as i32, |
210 | y as i32, |
211 | size.width as i32, |
212 | size.height as i32, |
213 | format, |
214 | glow::UNSIGNED_BYTE, |
215 | glow::PixelUnpackData::Slice(data.buf().align_to().1), |
216 | ); |
217 | }, |
218 | ImageSource::Rgb(data) => unsafe { |
219 | context.tex_sub_image_2d( |
220 | glow::TEXTURE_2D, |
221 | 0, |
222 | x as i32, |
223 | y as i32, |
224 | size.width as i32, |
225 | size.height as i32, |
226 | glow::RGB, |
227 | glow::UNSIGNED_BYTE, |
228 | glow::PixelUnpackData::Slice(data.buf().align_to().1), |
229 | ); |
230 | }, |
231 | ImageSource::Rgba(data) => unsafe { |
232 | context.tex_sub_image_2d( |
233 | glow::TEXTURE_2D, |
234 | 0, |
235 | x as i32, |
236 | y as i32, |
237 | size.width as i32, |
238 | size.height as i32, |
239 | glow::RGBA, |
240 | glow::UNSIGNED_BYTE, |
241 | glow::PixelUnpackData::Slice(data.buf().align_to().1), |
242 | ); |
243 | }, |
244 | #[cfg (target_arch = "wasm32" )] |
245 | ImageSource::HtmlImageElement(image_element) => unsafe { |
246 | context.tex_sub_image_2d_with_html_image( |
247 | glow::TEXTURE_2D, |
248 | 0, |
249 | x as i32, |
250 | y as i32, |
251 | glow::RGBA, |
252 | glow::UNSIGNED_BYTE, |
253 | image_element, |
254 | ) |
255 | }, |
256 | } |
257 | |
258 | if self.info.flags().contains(ImageFlags::GENERATE_MIPMAPS) { |
259 | unsafe { |
260 | context.generate_mipmap(glow::TEXTURE_2D); |
261 | //glow::TexParameteri(glow::TEXTURE_2D, glow::GENERATE_MIPMAP, glow::TRUE); |
262 | } |
263 | } |
264 | |
265 | unsafe { |
266 | context.pixel_store_i32(glow::UNPACK_ALIGNMENT, 4); |
267 | if !opengles_2_0 { |
268 | context.pixel_store_i32(glow::UNPACK_ROW_LENGTH, 0); |
269 | } |
270 | //glow::PixelStorei(glow::UNPACK_SKIP_PIXELS, 0); |
271 | //glow::PixelStorei(glow::UNPACK_SKIP_ROWS, 0); |
272 | context.bind_texture(glow::TEXTURE_2D, None); |
273 | } |
274 | |
275 | Ok(()) |
276 | } |
277 | |
278 | pub fn delete(self, context: &Rc<glow::Context>) { |
279 | if self.owned { |
280 | unsafe { |
281 | context.delete_texture(self.id); |
282 | } |
283 | } |
284 | } |
285 | |
286 | pub fn info(&self) -> ImageInfo { |
287 | self.info |
288 | } |
289 | } |
290 | |