1use crate::{
22 core::color::Color,
23 error::FrameworkError,
24 gl::{server::GlGraphicsServer, ToGlConstant},
25 gpu_texture::{
26 image_1d_size_bytes, image_2d_size_bytes, image_3d_size_bytes, Coordinate, CubeMapFace,
27 GpuTexture, GpuTextureDescriptor, GpuTextureKind, MagnificationFilter, MinificationFilter,
28 PixelKind, WrapMode,
29 },
30};
31use glow::{HasContext, PixelPackData, PixelUnpackData, COMPRESSED_RED_RGTC1, COMPRESSED_RG_RGTC2};
32use std::{
33 marker::PhantomData,
34 rc::{Rc, Weak},
35};
36
37impl GpuTextureKind {
38 pub fn gl_texture_target(&self) -> u32 {
39 match self {
40 Self::Line { .. } => glow::TEXTURE_1D,
41 Self::Rectangle { .. } => glow::TEXTURE_2D,
42 Self::Cube { .. } => glow::TEXTURE_CUBE_MAP,
43 Self::Volume { .. } => glow::TEXTURE_3D,
44 }
45 }
46}
47
48impl ToGlConstant for MinificationFilter {
49 fn into_gl(self) -> u32 {
50 match self {
51 Self::Nearest => glow::NEAREST,
52 Self::NearestMipMapNearest => glow::NEAREST_MIPMAP_NEAREST,
53 Self::NearestMipMapLinear => glow::NEAREST_MIPMAP_LINEAR,
54 Self::Linear => glow::LINEAR,
55 Self::LinearMipMapNearest => glow::LINEAR_MIPMAP_NEAREST,
56 Self::LinearMipMapLinear => glow::LINEAR_MIPMAP_LINEAR,
57 }
58 }
59}
60
61impl ToGlConstant for MagnificationFilter {
62 fn into_gl(self) -> u32 {
63 match self {
64 Self::Nearest => glow::NEAREST,
65 Self::Linear => glow::LINEAR,
66 }
67 }
68}
69
70impl ToGlConstant for WrapMode {
71 fn into_gl(self) -> u32 {
72 match self {
73 Self::Repeat => glow::REPEAT,
74 Self::ClampToEdge => glow::CLAMP_TO_EDGE,
75 Self::ClampToBorder => glow::CLAMP_TO_BORDER,
76 Self::MirroredRepeat => glow::MIRRORED_REPEAT,
77 Self::MirrorClampToEdge => glow::MIRROR_CLAMP_TO_EDGE,
78 }
79 }
80}
81
82impl ToGlConstant for Coordinate {
83 fn into_gl(self) -> u32 {
84 match self {
85 Self::S => glow::TEXTURE_WRAP_S,
86 Self::T => glow::TEXTURE_WRAP_T,
87 Self::R => glow::TEXTURE_WRAP_R,
88 }
89 }
90}
91
92impl ToGlConstant for CubeMapFace {
93 fn into_gl(self) -> u32 {
94 match self {
95 Self::PositiveX => glow::TEXTURE_CUBE_MAP_POSITIVE_X,
96 Self::NegativeX => glow::TEXTURE_CUBE_MAP_NEGATIVE_X,
97 Self::PositiveY => glow::TEXTURE_CUBE_MAP_POSITIVE_Y,
98 Self::NegativeY => glow::TEXTURE_CUBE_MAP_NEGATIVE_Y,
99 Self::PositiveZ => glow::TEXTURE_CUBE_MAP_POSITIVE_Z,
100 Self::NegativeZ => glow::TEXTURE_CUBE_MAP_NEGATIVE_Z,
101 }
102 }
103}
104
105pub struct GlTexture {
106 state: Weak<GlGraphicsServer>,
107 texture: glow::Texture,
108 kind: GpuTextureKind,
109 min_filter: MinificationFilter,
110 mag_filter: MagnificationFilter,
111 s_wrap_mode: WrapMode,
112 t_wrap_mode: WrapMode,
113 r_wrap_mode: WrapMode,
114 anisotropy: f32,
115 pixel_kind: PixelKind,
116 base_level: usize,
117 max_level: usize,
118 min_lod: f32,
119 max_lod: f32,
120 lod_bias: f32,
121 thread_mark: PhantomData<*const u8>,
123}
124
125const GL_COMPRESSED_RGB_S3TC_DXT1_EXT: u32 = 0x83F0;
126const GL_COMPRESSED_RGBA_S3TC_DXT1_EXT: u32 = 0x83F1;
127const GL_COMPRESSED_RGBA_S3TC_DXT3_EXT: u32 = 0x83F2;
128const GL_COMPRESSED_RGBA_S3TC_DXT5_EXT: u32 = 0x83F3;
129
130pub struct PixelDescriptor {
131 pub data_type: u32,
132 pub format: u32,
133 pub internal_format: u32,
134 pub swizzle_mask: Option<[i32; 4]>,
135}
136
137impl PixelKind {
138 pub(crate) fn pixel_descriptor(self) -> PixelDescriptor {
139 let (data_type, format, internal_format, swizzle_mask) = match self {
140 PixelKind::R32F => (glow::FLOAT, glow::RED, glow::R32F, None),
141 PixelKind::R32UI => (glow::UNSIGNED_INT, glow::RED_INTEGER, glow::R32UI, None),
142 PixelKind::R16F => (glow::FLOAT, glow::RED, glow::R16F, None),
143 PixelKind::D32F => (
144 glow::FLOAT,
145 glow::DEPTH_COMPONENT,
146 glow::DEPTH_COMPONENT32F,
147 None,
148 ),
149 PixelKind::D16 => (
150 glow::UNSIGNED_SHORT,
151 glow::DEPTH_COMPONENT,
152 glow::DEPTH_COMPONENT16,
153 None,
154 ),
155 PixelKind::D24S8 => (
156 glow::UNSIGNED_INT_24_8,
157 glow::DEPTH_STENCIL,
158 glow::DEPTH24_STENCIL8,
159 None,
160 ),
161 PixelKind::RGBA8 => (glow::UNSIGNED_BYTE, glow::RGBA, glow::RGBA8, None),
162 PixelKind::SRGBA8 => (glow::UNSIGNED_BYTE, glow::RGBA, glow::SRGB8_ALPHA8, None),
163 PixelKind::RGB8 => (glow::UNSIGNED_BYTE, glow::RGB, glow::RGB8, None),
164 PixelKind::SRGB8 => (glow::UNSIGNED_BYTE, glow::RGB, glow::SRGB8, None),
165 PixelKind::RG8 => (glow::UNSIGNED_BYTE, glow::RG, glow::RG8, None),
166 PixelKind::R8 => (glow::UNSIGNED_BYTE, glow::RED, glow::R8, None),
167 PixelKind::R8UI => (glow::UNSIGNED_BYTE, glow::RED_INTEGER, glow::R8UI, None),
168 PixelKind::BGRA8 => (glow::UNSIGNED_BYTE, glow::BGRA, glow::RGBA8, None),
169 PixelKind::BGR8 => (glow::UNSIGNED_BYTE, glow::BGR, glow::RGB8, None),
170 PixelKind::RG16 => (glow::UNSIGNED_SHORT, glow::RG, glow::RG16, None),
171 PixelKind::R16 => (glow::UNSIGNED_SHORT, glow::RED, glow::R16, None),
172 PixelKind::RGB16 => (glow::UNSIGNED_SHORT, glow::RGB, glow::RGB16, None),
173 PixelKind::RGBA16 => (glow::UNSIGNED_SHORT, glow::RGBA, glow::RGBA16, None),
174 PixelKind::RGB10A2 => (
175 glow::UNSIGNED_INT_2_10_10_10_REV,
176 glow::RGBA,
177 glow::RGB10_A2,
178 None,
179 ),
180 PixelKind::DXT1RGB => (0, 0, GL_COMPRESSED_RGB_S3TC_DXT1_EXT, None),
181 PixelKind::DXT1RGBA => (0, 0, GL_COMPRESSED_RGBA_S3TC_DXT1_EXT, None),
182 PixelKind::DXT3RGBA => (0, 0, GL_COMPRESSED_RGBA_S3TC_DXT3_EXT, None),
183 PixelKind::DXT5RGBA => (0, 0, GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, None),
184 PixelKind::R8RGTC => (0, 0, COMPRESSED_RED_RGTC1, None),
185 PixelKind::RG8RGTC => (0, 0, COMPRESSED_RG_RGTC2, None),
186 PixelKind::RGB32F => (glow::FLOAT, glow::RGB, glow::RGB32F, None),
187 PixelKind::RGBA32F => (glow::FLOAT, glow::RGBA, glow::RGBA32F, None),
188 PixelKind::RGBA16F => (glow::HALF_FLOAT, glow::RGBA, glow::RGBA16F, None),
189 PixelKind::RGB16F => (glow::HALF_FLOAT, glow::RGB, glow::RGB16F, None),
190 PixelKind::R11G11B10F => (glow::FLOAT, glow::RGB, glow::R11F_G11F_B10F, None),
191 PixelKind::L8 => (
192 glow::UNSIGNED_BYTE,
193 glow::RED,
194 glow::R8,
195 Some([
196 glow::RED as i32,
197 glow::RED as i32,
198 glow::RED as i32,
199 glow::ONE as i32,
200 ]),
201 ),
202 PixelKind::LA8 => (
203 glow::UNSIGNED_BYTE,
204 glow::RG,
205 glow::RG8,
206 Some([
207 glow::RED as i32,
208 glow::RED as i32,
209 glow::RED as i32,
210 glow::GREEN as i32,
211 ]),
212 ),
213 PixelKind::LA16 => (
214 glow::UNSIGNED_SHORT,
215 glow::RG,
216 glow::RG16,
217 Some([
218 glow::RED as i32,
219 glow::RED as i32,
220 glow::RED as i32,
221 glow::GREEN as i32,
222 ]),
223 ),
224 PixelKind::L16 => (
225 glow::UNSIGNED_SHORT,
226 glow::RED,
227 glow::R16,
228 Some([
229 glow::RED as i32,
230 glow::RED as i32,
231 glow::RED as i32,
232 glow::ONE as i32,
233 ]),
234 ),
235 };
236
237 PixelDescriptor {
238 data_type,
239 format,
240 internal_format,
241 swizzle_mask,
242 }
243 }
244}
245
246struct TempBinding {
247 server: Rc<GlGraphicsServer>,
248 unit: u32,
249 target: u32,
250}
251
252impl TempBinding {
253 fn new(server: Rc<GlGraphicsServer>, texture: &GlTexture) -> Self {
254 let unit = server
255 .free_texture_unit()
256 .expect("Texture units limit exceeded!");
257 let target = texture.kind.gl_texture_target();
258 server.set_texture(unit, target, Some(texture.texture));
259 Self {
260 server,
261 unit,
262 target,
263 }
264 }
265
266 fn set_minification_filter(&mut self, min_filter: MinificationFilter) {
267 unsafe {
268 self.server.gl.tex_parameter_i32(
269 self.target,
270 glow::TEXTURE_MIN_FILTER,
271 min_filter.into_gl() as i32,
272 );
273 }
274 }
275
276 fn set_magnification_filter(&mut self, mag_filter: MagnificationFilter) {
277 unsafe {
278 self.server.gl.tex_parameter_i32(
279 self.target,
280 glow::TEXTURE_MAG_FILTER,
281 mag_filter.into_gl() as i32,
282 );
283 }
284 }
285
286 fn set_anisotropy(&mut self, anisotropy: f32) {
287 unsafe {
288 let max = self
289 .server
290 .gl
291 .get_parameter_f32(glow::MAX_TEXTURE_MAX_ANISOTROPY_EXT);
292 self.server.gl.tex_parameter_f32(
293 self.target,
294 glow::TEXTURE_MAX_ANISOTROPY_EXT,
295 anisotropy.clamp(1.0, max),
296 );
297 }
298 }
299
300 fn set_wrap(&mut self, coordinate: Coordinate, wrap: WrapMode) {
301 unsafe {
302 self.server.gl.tex_parameter_i32(
303 self.target,
304 coordinate.into_gl(),
305 wrap.into_gl() as i32,
306 );
307 }
308 }
309
310 fn set_base_level(&mut self, level: usize) {
311 unsafe {
312 self.server
313 .gl
314 .tex_parameter_i32(self.target, glow::TEXTURE_BASE_LEVEL, level as i32);
315 }
316 }
317
318 fn set_max_level(&mut self, level: usize) {
319 unsafe {
320 self.server
321 .gl
322 .tex_parameter_i32(self.target, glow::TEXTURE_MAX_LEVEL, level as i32);
323 }
324 }
325
326 fn set_min_lod(&mut self, min_lod: f32) {
327 unsafe {
328 self.server
329 .gl
330 .tex_parameter_f32(self.target, glow::TEXTURE_MIN_LOD, min_lod);
331 }
332 }
333
334 fn set_max_lod(&mut self, max_lod: f32) {
335 unsafe {
336 self.server
337 .gl
338 .tex_parameter_f32(self.target, glow::TEXTURE_MAX_LOD, max_lod);
339 }
340 }
341
342 fn set_lod_bias(&mut self, bias: f32) {
343 unsafe {
344 self.server
345 .gl
346 .tex_parameter_f32(self.target, glow::TEXTURE_LOD_BIAS, bias);
347 }
348 }
349}
350
351impl Drop for TempBinding {
352 fn drop(&mut self) {
353 self.server.set_texture(self.unit, self.target, None);
354 }
355}
356
357impl GlTexture {
358 pub fn new(
374 server: &GlGraphicsServer,
375 mut desc: GpuTextureDescriptor,
376 ) -> Result<Self, FrameworkError> {
377 let actual_max_level = desc.mip_count.saturating_sub(1);
379 if desc.max_level > actual_max_level {
380 desc.max_level = actual_max_level;
381 }
382 if desc.base_level > desc.max_level {
383 desc.base_level = desc.max_level;
384 }
385 if desc.base_level > actual_max_level {
386 desc.base_level = actual_max_level;
387 }
388
389 unsafe {
390 let texture = server.gl.create_texture()?;
391
392 let mut result = Self {
393 state: server.weak(),
394 texture,
395 kind: desc.kind,
396 min_filter: desc.min_filter,
397 mag_filter: desc.mag_filter,
398 s_wrap_mode: desc.s_wrap_mode,
399 t_wrap_mode: desc.t_wrap_mode,
400 r_wrap_mode: desc.r_wrap_mode,
401 anisotropy: desc.anisotropy,
402 pixel_kind: desc.pixel_kind,
403 base_level: desc.base_level,
404 max_level: desc.max_level,
405 min_lod: desc.min_lod,
406 max_lod: desc.max_lod,
407 lod_bias: desc.lod_bias,
408 thread_mark: PhantomData,
409 };
410
411 result.set_data(desc.kind, desc.pixel_kind, desc.mip_count, desc.data)?;
412
413 let mut binding = result.make_temp_binding();
414 binding.set_magnification_filter(desc.mag_filter);
415 binding.set_minification_filter(desc.min_filter);
416 binding.set_wrap(Coordinate::S, desc.s_wrap_mode);
417 binding.set_wrap(Coordinate::T, desc.t_wrap_mode);
418 binding.set_wrap(Coordinate::R, desc.r_wrap_mode);
419 binding.set_anisotropy(desc.anisotropy);
420 binding.set_base_level(desc.base_level);
421 binding.set_max_level(desc.max_level);
422 binding.set_min_lod(desc.min_lod);
423 binding.set_max_lod(desc.max_lod);
424 binding.set_lod_bias(desc.lod_bias);
425
426 Ok(result)
427 }
428 }
429
430 pub fn bind(&self, server: &GlGraphicsServer, sampler_index: u32) {
431 server.set_texture(
432 sampler_index,
433 self.kind.gl_texture_target(),
434 Some(self.texture),
435 );
436 }
437
438 fn make_temp_binding(&self) -> TempBinding {
439 let server = self.state.upgrade().unwrap();
440 TempBinding::new(server, self)
441 }
442
443 pub fn id(&self) -> glow::Texture {
444 self.texture
445 }
446}
447
448impl Drop for GlTexture {
449 fn drop(&mut self) {
450 if let Some(state) = self.state.upgrade() {
451 unsafe {
452 state.gl.delete_texture(self.texture);
453 }
454 }
455 }
456}
457
458impl GpuTexture for GlTexture {
459 fn set_anisotropy(&mut self, anisotropy: f32) {
460 self.make_temp_binding().set_anisotropy(anisotropy);
461 self.anisotropy = anisotropy;
462 }
463
464 fn anisotropy(&self) -> f32 {
465 self.anisotropy
466 }
467
468 fn set_minification_filter(&mut self, filter: MinificationFilter) {
469 self.make_temp_binding().set_minification_filter(filter);
470 self.min_filter = filter;
471 }
472
473 fn minification_filter(&self) -> MinificationFilter {
474 self.min_filter
475 }
476
477 fn set_magnification_filter(&mut self, filter: MagnificationFilter) {
478 self.make_temp_binding().set_magnification_filter(filter);
479 self.mag_filter = filter;
480 }
481
482 fn magnification_filter(&self) -> MagnificationFilter {
483 self.mag_filter
484 }
485
486 fn set_wrap(&mut self, coordinate: Coordinate, wrap: WrapMode) {
487 self.make_temp_binding().set_wrap(coordinate, wrap);
488 match coordinate {
489 Coordinate::S => self.s_wrap_mode = wrap,
490 Coordinate::T => self.t_wrap_mode = wrap,
491 Coordinate::R => self.r_wrap_mode = wrap,
492 }
493 }
494
495 fn wrap_mode(&self, coordinate: Coordinate) -> WrapMode {
496 match coordinate {
497 Coordinate::S => self.s_wrap_mode,
498 Coordinate::T => self.t_wrap_mode,
499 Coordinate::R => self.r_wrap_mode,
500 }
501 }
502
503 fn set_border_color(&mut self, #[allow(unused_variables)] color: Color) {
504 #[cfg(not(target_arch = "wasm32"))]
505 unsafe {
506 let temp_binding = self.make_temp_binding();
507 let color = color.as_frgba();
508 let color = [color.x, color.y, color.z, color.w];
509
510 temp_binding.server.gl.tex_parameter_f32_slice(
511 self.kind.gl_texture_target(),
512 glow::TEXTURE_BORDER_COLOR,
513 &color,
514 );
515 }
516 }
517
518 fn set_data(
519 &mut self,
520 kind: GpuTextureKind,
521 pixel_kind: PixelKind,
522 mip_count: usize,
523 data: Option<&[u8]>,
524 ) -> Result<(), FrameworkError> {
525 let mip_count = mip_count.max(1);
526
527 let mut desired_byte_count = 0;
528
529 'mip_loop: for mip in 0..mip_count {
530 match kind {
531 GpuTextureKind::Line { length } => {
532 if let Some(length) = length.checked_shr(mip as u32) {
533 desired_byte_count += image_1d_size_bytes(pixel_kind, length);
534 } else {
535 break 'mip_loop;
536 }
537 }
538 GpuTextureKind::Rectangle { width, height } => {
539 if let (Some(width), Some(height)) = (
540 width.checked_shr(mip as u32),
541 height.checked_shr(mip as u32),
542 ) {
543 desired_byte_count += image_2d_size_bytes(pixel_kind, width, height);
544 } else {
545 break 'mip_loop;
546 }
547 }
548 GpuTextureKind::Cube { width, height } => {
549 if let (Some(width), Some(height)) = (
550 width.checked_shr(mip as u32),
551 height.checked_shr(mip as u32),
552 ) {
553 desired_byte_count += 6 * image_2d_size_bytes(pixel_kind, width, height);
554 } else {
555 break 'mip_loop;
556 }
557 }
558 GpuTextureKind::Volume {
559 width,
560 height,
561 depth,
562 } => {
563 if let (Some(width), Some(height), Some(depth)) = (
564 width.checked_shr(mip as u32),
565 height.checked_shr(mip as u32),
566 depth.checked_shr(mip as u32),
567 ) {
568 desired_byte_count += image_3d_size_bytes(pixel_kind, width, height, depth);
569 } else {
570 break 'mip_loop;
571 }
572 }
573 };
574 }
575
576 if let Some(data) = data {
577 let actual_data_size = data.len();
578 if actual_data_size != desired_byte_count {
579 return Err(FrameworkError::InvalidTextureData {
580 expected_data_size: desired_byte_count,
581 actual_data_size,
582 });
583 }
584 }
585
586 self.kind = kind;
587 self.pixel_kind = pixel_kind;
588
589 let mut temp_binding = self.make_temp_binding();
590 temp_binding.set_max_level(mip_count.saturating_sub(1));
591 let target = kind.gl_texture_target();
592
593 unsafe {
594 let PixelDescriptor {
595 data_type,
596 format,
597 internal_format,
598 swizzle_mask,
599 } = pixel_kind.pixel_descriptor();
600
601 let is_compressed = pixel_kind.is_compressed();
602
603 if let Some(alignment) = pixel_kind.unpack_alignment() {
604 temp_binding
605 .server
606 .gl
607 .pixel_store_i32(glow::UNPACK_ALIGNMENT, alignment);
608 }
609
610 if let Some(swizzle_mask) = swizzle_mask {
611 if temp_binding
612 .server
613 .gl
614 .supported_extensions()
615 .contains("GL_ARB_texture_swizzle")
616 {
617 temp_binding.server.gl.tex_parameter_i32_slice(
618 target,
619 glow::TEXTURE_SWIZZLE_RGBA,
620 &swizzle_mask,
621 );
622 }
623 }
624
625 let mut mip_byte_offset = 0;
626 'mip_loop2: for mip in 0..mip_count {
627 match kind {
628 GpuTextureKind::Line { length } => {
629 if let Some(length) = length.checked_shr(mip as u32) {
630 let size = image_1d_size_bytes(pixel_kind, length) as i32;
631 let pixels = data.map(|data| {
632 &data[mip_byte_offset..(mip_byte_offset + size as usize)]
633 });
634
635 if is_compressed {
636 temp_binding.server.gl.compressed_tex_image_1d(
637 glow::TEXTURE_1D,
638 mip as i32,
639 internal_format as i32,
640 length as i32,
641 0,
642 size,
643 pixels.ok_or(FrameworkError::EmptyTextureData)?,
644 );
645 } else {
646 temp_binding.server.gl.tex_image_1d(
647 glow::TEXTURE_1D,
648 mip as i32,
649 internal_format as i32,
650 length as i32,
651 0,
652 format,
653 data_type,
654 PixelUnpackData::Slice(pixels),
655 );
656 }
657
658 mip_byte_offset += size as usize;
659 } else {
660 break 'mip_loop2;
662 }
663 }
664 GpuTextureKind::Rectangle { width, height } => {
665 if let (Some(width), Some(height)) = (
666 width.checked_shr(mip as u32),
667 height.checked_shr(mip as u32),
668 ) {
669 let size = image_2d_size_bytes(pixel_kind, width, height) as i32;
670 let pixels = data.map(|data| {
671 &data[mip_byte_offset..(mip_byte_offset + size as usize)]
672 });
673
674 if is_compressed {
675 temp_binding.server.gl.compressed_tex_image_2d(
676 glow::TEXTURE_2D,
677 mip as i32,
678 internal_format as i32,
679 width as i32,
680 height as i32,
681 0,
682 size,
683 pixels.ok_or(FrameworkError::EmptyTextureData)?,
684 );
685 } else {
686 temp_binding.server.gl.tex_image_2d(
687 glow::TEXTURE_2D,
688 mip as i32,
689 internal_format as i32,
690 width as i32,
691 height as i32,
692 0,
693 format,
694 data_type,
695 PixelUnpackData::Slice(pixels),
696 );
697 }
698
699 mip_byte_offset += size as usize;
700 } else {
701 break 'mip_loop2;
703 }
704 }
705 GpuTextureKind::Cube { width, height } => {
706 if let (Some(width), Some(height)) = (
707 width.checked_shr(mip as u32),
708 height.checked_shr(mip as u32),
709 ) {
710 let bytes_per_face = image_2d_size_bytes(pixel_kind, width, height);
711
712 for face in 0..6 {
713 let begin = mip_byte_offset + face * bytes_per_face;
714 let end = mip_byte_offset + (face + 1) * bytes_per_face;
715 let face_pixels = data.map(|data| &data[begin..end]);
716
717 if is_compressed {
718 temp_binding.server.gl.compressed_tex_image_2d(
719 glow::TEXTURE_CUBE_MAP_POSITIVE_X + face as u32,
720 mip as i32,
721 internal_format as i32,
722 width as i32,
723 height as i32,
724 0,
725 bytes_per_face as i32,
726 face_pixels.ok_or(FrameworkError::EmptyTextureData)?,
727 );
728 } else {
729 temp_binding.server.gl.tex_image_2d(
730 glow::TEXTURE_CUBE_MAP_POSITIVE_X + face as u32,
731 mip as i32,
732 internal_format as i32,
733 width as i32,
734 height as i32,
735 0,
736 format,
737 data_type,
738 PixelUnpackData::Slice(face_pixels),
739 );
740 }
741 }
742
743 mip_byte_offset += 6 * bytes_per_face;
744 } else {
745 break 'mip_loop2;
747 }
748 }
749 GpuTextureKind::Volume {
750 width,
751 height,
752 depth,
753 } => {
754 if let (Some(width), Some(height), Some(depth)) = (
755 width.checked_shr(mip as u32),
756 height.checked_shr(mip as u32),
757 depth.checked_shr(mip as u32),
758 ) {
759 let size = image_3d_size_bytes(pixel_kind, width, height, depth) as i32;
760 let pixels = data.map(|data| {
761 &data[mip_byte_offset..(mip_byte_offset + size as usize)]
762 });
763
764 if is_compressed {
765 temp_binding.server.gl.compressed_tex_image_3d(
766 glow::TEXTURE_3D,
767 mip as i32,
768 internal_format as i32,
769 width as i32,
770 height as i32,
771 depth as i32,
772 0,
773 size,
774 pixels.ok_or(FrameworkError::EmptyTextureData)?,
775 );
776 } else {
777 temp_binding.server.gl.tex_image_3d(
778 glow::TEXTURE_3D,
779 mip as i32,
780 internal_format as i32,
781 width as i32,
782 height as i32,
783 depth as i32,
784 0,
785 format,
786 data_type,
787 PixelUnpackData::Slice(pixels),
788 );
789 }
790
791 mip_byte_offset += size as usize;
792 } else {
793 break 'mip_loop2;
795 }
796 }
797 }
798 }
799 }
800
801 Ok(())
802 }
803
804 fn get_image(&self, level: usize) -> Vec<u8> {
805 let temp_binding = self.make_temp_binding();
806 unsafe {
807 let desc = self.pixel_kind.pixel_descriptor();
808 let (kind, buffer_size) = match self.kind {
809 GpuTextureKind::Line { length } => (
810 glow::TEXTURE_1D,
811 image_1d_size_bytes(self.pixel_kind, length),
812 ),
813 GpuTextureKind::Rectangle { width, height } => (
814 glow::TEXTURE_2D,
815 image_2d_size_bytes(self.pixel_kind, width, height),
816 ),
817 GpuTextureKind::Cube { width, height } => (
818 glow::TEXTURE_CUBE_MAP,
819 6 * image_2d_size_bytes(self.pixel_kind, width, height),
820 ),
821 GpuTextureKind::Volume {
822 width,
823 height,
824 depth,
825 } => (
826 glow::TEXTURE_3D,
827 image_3d_size_bytes(self.pixel_kind, width, height, depth),
828 ),
829 };
830
831 let mut bytes = vec![0; buffer_size];
832 temp_binding.server.gl.get_tex_image(
833 kind,
834 level as i32,
835 desc.format,
836 desc.data_type,
837 PixelPackData::Slice(Some(bytes.as_mut_slice())),
838 );
839 bytes
840 }
841 }
842
843 fn read_pixels(&self) -> Vec<u8> {
844 let temp_binding = self.make_temp_binding();
845 unsafe {
846 if let GpuTextureKind::Rectangle { width, height } = self.kind {
847 let pixel_info = self.pixel_kind.pixel_descriptor();
848 let mut buffer = vec![0; image_2d_size_bytes(self.pixel_kind, width, height)];
849 temp_binding.server.gl.read_pixels(
850 0,
851 0,
852 width as i32,
853 height as i32,
854 pixel_info.format,
855 pixel_info.data_type,
856 PixelPackData::Slice(Some(buffer.as_mut_slice())),
857 );
858 buffer
859 } else {
860 Default::default()
861 }
862 }
863 }
864
865 fn kind(&self) -> GpuTextureKind {
866 self.kind
867 }
868
869 fn pixel_kind(&self) -> PixelKind {
870 self.pixel_kind
871 }
872
873 fn set_base_level(&mut self, level: usize) {
874 self.make_temp_binding().set_base_level(level);
875 self.base_level = level;
876 }
877
878 fn base_level(&self) -> usize {
879 self.base_level
880 }
881
882 fn set_max_level(&mut self, level: usize) {
883 self.make_temp_binding().set_max_level(level);
884 self.max_level = level;
885 }
886
887 fn max_level(&self) -> usize {
888 self.max_level
889 }
890
891 fn set_min_lod(&mut self, min_lod: f32) {
892 self.make_temp_binding().set_min_lod(min_lod);
893 self.min_lod = min_lod;
894 }
895
896 fn min_lod(&self) -> f32 {
897 self.min_lod
898 }
899
900 fn set_max_lod(&mut self, max_lod: f32) {
901 self.make_temp_binding().set_max_lod(max_lod);
902 self.max_lod = max_lod;
903 }
904
905 fn max_lod(&self) -> f32 {
906 self.max_lod
907 }
908
909 fn set_lod_bias(&mut self, bias: f32) {
910 self.make_temp_binding().set_lod_bias(bias);
911 self.lod_bias = bias;
912 }
913
914 fn lod_bias(&self) -> f32 {
915 self.lod_bias
916 }
917}