1use std::rc::Rc;
2
3use glow::HasContext;
4
5use crate::{ErrorKind, ImageFlags, ImageInfo, ImageSource, PixelFormat};
6
7pub struct GlTexture {
8 id: <glow::Context as glow::HasContext>::Texture,
9 info: ImageInfo,
10 owned: bool,
11}
12
13impl 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