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