1use ddsfile::{Caps2, D3DFormat};
44use fast_image_resize as fr;
45use fast_image_resize::ResizeOptions;
46use fxhash::FxHasher;
47use fyrox_core::{
48 algebra::{Vector2, Vector3},
49 futures::io::Error,
50 io::FileLoadError,
51 num_traits::Bounded,
52 reflect::prelude::*,
53 sparse::AtomicIndex,
54 uuid::Uuid,
55 uuid_provider,
56 visitor::{PodVecView, Visit, VisitError, VisitResult, Visitor},
57 TypeUuidProvider,
58};
59use fyrox_resource::{
60 embedded_data_source, io::ResourceIo, manager::BuiltInResource, options::ImportOptions,
61 untyped::ResourceKind, Resource, ResourceData, TEXTURE_RESOURCE_UUID,
62};
63use image::{ColorType, DynamicImage, ImageError, ImageFormat, Pixel};
64use lazy_static::lazy_static;
65use serde::{Deserialize, Serialize};
66use std::{
67 fmt::{Debug, Display, Formatter},
68 hash::{Hash, Hasher},
69 io::Cursor,
70 ops::{Deref, DerefMut, Shr},
71 path::Path,
72 sync::Arc,
73};
74use strum_macros::{AsRefStr, EnumString, VariantNames};
75
76pub mod loader;
77
78#[derive(Copy, Clone, Debug, Reflect)]
80pub enum TextureKind {
81 Line {
83 length: u32,
85 },
86 Rectangle {
88 width: u32,
90 height: u32,
92 },
93 Cube {
95 width: u32,
97 height: u32,
99 },
100 Volume {
102 width: u32,
104 height: u32,
106 depth: u32,
108 },
109}
110
111impl TextureKind {
112 #[inline]
114 pub fn line_length(&self) -> Option<u32> {
115 if let Self::Line { length } = self {
116 Some(*length)
117 } else {
118 None
119 }
120 }
121
122 #[inline]
124 pub fn rectangle_size(&self) -> Option<Vector2<u32>> {
125 if let Self::Rectangle { width, height } = self {
126 Some(Vector2::new(*width, *height))
127 } else {
128 None
129 }
130 }
131
132 #[inline]
134 pub fn cube_size(&self) -> Option<Vector2<u32>> {
135 if let Self::Cube { width, height } = self {
136 Some(Vector2::new(*width, *height))
137 } else {
138 None
139 }
140 }
141
142 #[inline]
144 pub fn volume_size(&self) -> Option<Vector3<u32>> {
145 if let Self::Volume {
146 width,
147 height,
148 depth,
149 } = self
150 {
151 Some(Vector3::new(*width, *height, *depth))
152 } else {
153 None
154 }
155 }
156}
157
158impl Default for TextureKind {
159 fn default() -> Self {
160 Self::Rectangle {
161 width: 0,
162 height: 0,
163 }
164 }
165}
166
167impl Visit for TextureKind {
168 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
169 let mut region = visitor.enter_region(name)?;
170
171 let mut id = match self {
172 TextureKind::Line { .. } => 0,
173 TextureKind::Rectangle { .. } => 1,
174 TextureKind::Cube { .. } => 2,
175 TextureKind::Volume { .. } => 3,
176 };
177 id.visit("Id", &mut region)?;
178 if region.is_reading() {
179 *self = match id {
180 0 => TextureKind::Line { length: 0 },
181 1 => TextureKind::Rectangle {
182 width: 0,
183 height: 0,
184 },
185 2 => TextureKind::Cube {
186 width: 0,
187 height: 0,
188 },
189 3 => TextureKind::Volume {
190 width: 0,
191 height: 0,
192 depth: 0,
193 },
194 _ => {
195 return VisitResult::Err(VisitError::User(format!(
196 "Invalid texture kind {id}!"
197 )))
198 }
199 };
200 }
201 match self {
202 TextureKind::Line { length } => {
203 length.visit("Length", &mut region)?;
204 }
205 TextureKind::Rectangle { width, height } => {
206 width.visit("Width", &mut region)?;
207 height.visit("Height", &mut region)?;
208 }
209 TextureKind::Cube { width, height } => {
210 width.visit("Width", &mut region)?;
211 height.visit("Height", &mut region)?;
212 }
213 TextureKind::Volume {
214 width,
215 height,
216 depth,
217 } => {
218 width.visit("Width", &mut region)?;
219 height.visit("Height", &mut region)?;
220 depth.visit("Depth", &mut region)?;
221 }
222 }
223
224 Ok(())
225 }
226}
227
228#[derive(Default, Clone, Reflect)]
230pub struct TextureBytes(Vec<u8>);
231
232impl Visit for TextureBytes {
233 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
234 self.0.visit(name, visitor)
235 }
236}
237
238impl Debug for TextureBytes {
239 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
240 write!(f, "Texture has {} bytes", self.0.len())
241 }
242}
243
244impl From<Vec<u8>> for TextureBytes {
245 fn from(bytes: Vec<u8>) -> Self {
246 Self(bytes)
247 }
248}
249
250impl Deref for TextureBytes {
251 type Target = Vec<u8>;
252
253 fn deref(&self) -> &Self::Target {
254 &self.0
255 }
256}
257
258impl DerefMut for TextureBytes {
259 fn deref_mut(&mut self) -> &mut Self::Target {
260 &mut self.0
261 }
262}
263
264#[derive(Debug, Clone, Reflect)]
266pub struct Texture {
267 kind: TextureKind,
268 bytes: TextureBytes,
269 pixel_kind: TexturePixelKind,
270 minification_filter: TextureMinificationFilter,
271 magnification_filter: TextureMagnificationFilter,
272 s_wrap_mode: TextureWrapMode,
273 t_wrap_mode: TextureWrapMode,
274 r_wrap_mode: TextureWrapMode,
275 base_level: usize,
276 max_level: usize,
277 min_lod: f32,
278 max_lod: f32,
279 lod_bias: f32,
280 mip_count: u32,
281 anisotropy: f32,
282 modifications_counter: u64,
283 is_render_target: bool,
284 #[doc(hidden)]
285 #[reflect(hidden)]
286 pub cache_index: Arc<AtomicIndex>,
287}
288
289impl TypeUuidProvider for Texture {
290 fn type_uuid() -> Uuid {
291 TEXTURE_RESOURCE_UUID
292 }
293}
294
295impl ResourceData for Texture {
296 fn type_uuid(&self) -> Uuid {
297 <Self as TypeUuidProvider>::type_uuid()
298 }
299
300 fn save(&mut self, path: &Path) -> Result<(), Box<dyn std::error::Error>> {
301 let color_type = match self.pixel_kind {
302 TexturePixelKind::R8 => ColorType::L8,
303 TexturePixelKind::Luminance8 => ColorType::L8,
304 TexturePixelKind::RGB8 => ColorType::Rgb8,
305 TexturePixelKind::RGBA8 => ColorType::Rgba8,
306 TexturePixelKind::RG8 => ColorType::La8,
307 TexturePixelKind::LuminanceAlpha8 => ColorType::La8,
308 TexturePixelKind::R16 => ColorType::L16,
309 TexturePixelKind::Luminance16 => ColorType::L16,
310 TexturePixelKind::RG16 => ColorType::La16,
311 TexturePixelKind::LuminanceAlpha16 => ColorType::La16,
312 TexturePixelKind::RGB16 => ColorType::Rgb16,
313 TexturePixelKind::RGBA16 => ColorType::Rgba16,
314 TexturePixelKind::RGB32F => ColorType::Rgb32F,
315 TexturePixelKind::RGBA32F => ColorType::Rgba32F,
316 TexturePixelKind::DXT1RGB
317 | TexturePixelKind::DXT1RGBA
318 | TexturePixelKind::DXT3RGBA
319 | TexturePixelKind::DXT5RGBA
320 | TexturePixelKind::R8RGTC
321 | TexturePixelKind::RG8RGTC
322 | TexturePixelKind::BGR8
323 | TexturePixelKind::BGRA8
324 | TexturePixelKind::RGB16F
325 | TexturePixelKind::R32F
326 | TexturePixelKind::R16F => return Err(Box::new(TextureError::UnsupportedFormat)),
327 };
328 if let TextureKind::Rectangle { width, height } = self.kind {
329 Ok(image::save_buffer(
330 path,
331 self.bytes.as_ref(),
332 width,
333 height,
334 color_type,
335 )?)
336 } else {
337 Err(Box::new(TextureError::UnsupportedFormat))
338 }
339 }
340
341 fn can_be_saved(&self) -> bool {
342 true
343 }
344}
345
346impl Visit for Texture {
347 fn visit(&mut self, name: &str, visitor: &mut Visitor) -> VisitResult {
348 let mut region = visitor.enter_region(name)?;
349
350 let mut kind = self.pixel_kind.id();
351 kind.visit("KindId", &mut region)?;
352 if region.is_reading() {
353 self.pixel_kind = TexturePixelKind::new(kind)?;
354 }
355
356 self.minification_filter
357 .visit("MinificationFilter", &mut region)?;
358 self.magnification_filter
359 .visit("MagnificationFilter", &mut region)?;
360 self.anisotropy.visit("Anisotropy", &mut region)?;
361 self.s_wrap_mode.visit("SWrapMode", &mut region)?;
362 self.t_wrap_mode.visit("TWrapMode", &mut region)?;
363 let _ = self.t_wrap_mode.visit("RWrapMode", &mut region);
364 self.mip_count.visit("MipCount", &mut region)?;
365 self.kind.visit("Kind", &mut region)?;
366 let mut bytes_view = PodVecView::from_pod_vec(&mut self.bytes);
367 let _ = bytes_view.visit("Data", &mut region);
368
369 let _ = self.base_level.visit("BaseLevel", &mut region);
370 let _ = self.max_level.visit("MaxLevel", &mut region);
371 let _ = self.min_lod.visit("MinLod", &mut region);
372 let _ = self.max_lod.visit("MaxLod", &mut region);
373 let _ = self.lod_bias.visit("LodBias", &mut region);
374
375 Ok(())
376 }
377}
378
379impl Default for Texture {
380 fn default() -> Self {
384 Self {
385 kind: TextureKind::Rectangle {
386 width: 0,
387 height: 0,
388 },
389 bytes: Default::default(),
390 pixel_kind: TexturePixelKind::RGBA8,
391 minification_filter: TextureMinificationFilter::LinearMipMapLinear,
392 magnification_filter: TextureMagnificationFilter::Linear,
393 s_wrap_mode: TextureWrapMode::Repeat,
394 t_wrap_mode: TextureWrapMode::Repeat,
395 r_wrap_mode: TextureWrapMode::Repeat,
396 base_level: 0,
397 max_level: default_max_level(),
398 min_lod: default_min_lod(),
399 max_lod: default_max_lod(),
400 lod_bias: 0.0,
401 mip_count: 1,
402 anisotropy: 16.0,
403 modifications_counter: 0,
404 is_render_target: false,
405 cache_index: Default::default(),
406 }
407 }
408}
409
410#[derive(
412 Default, Copy, Clone, Deserialize, Serialize, Debug, Reflect, AsRefStr, EnumString, VariantNames,
413)]
414pub enum MipFilter {
415 Nearest,
418 #[default]
421 Bilinear,
422 Hamming,
424 CatmullRom,
427 Lanczos,
430}
431
432uuid_provider!(MipFilter = "8fa17c0e-6889-4540-b396-97db4dc952aa");
433
434impl MipFilter {
435 fn into_filter_type(self) -> fr::FilterType {
436 match self {
437 MipFilter::Nearest => fr::FilterType::Box,
438 MipFilter::Bilinear => fr::FilterType::Bilinear,
439 MipFilter::CatmullRom => fr::FilterType::CatmullRom,
440 MipFilter::Hamming => fr::FilterType::Hamming,
441 MipFilter::Lanczos => fr::FilterType::Lanczos3,
442 }
443 }
444}
445
446#[derive(Clone, Deserialize, Serialize, Debug, Reflect)]
464pub struct TextureImportOptions {
465 #[serde(default)]
466 pub(crate) minification_filter: TextureMinificationFilter,
467 #[serde(default)]
468 pub(crate) magnification_filter: TextureMagnificationFilter,
469 #[serde(default)]
470 pub(crate) s_wrap_mode: TextureWrapMode,
471 #[serde(default)]
472 pub(crate) t_wrap_mode: TextureWrapMode,
473 #[serde(default)]
474 pub(crate) r_wrap_mode: TextureWrapMode,
475 #[serde(default)]
476 pub(crate) anisotropy: f32,
477 #[serde(default)]
478 pub(crate) compression: CompressionOptions,
479 #[serde(default)]
480 pub(crate) mip_filter: MipFilter,
481 #[serde(default)]
482 pub(crate) flip_green_channel: bool,
483 #[serde(default)]
484 pub(crate) base_level: usize,
485 #[serde(default = "default_max_level")]
486 pub(crate) max_level: usize,
487 #[serde(default = "default_min_lod")]
488 pub(crate) min_lod: f32,
489 #[serde(default = "default_max_lod")]
490 pub(crate) max_lod: f32,
491 #[serde(default)]
492 pub(crate) lod_bias: f32,
493}
494
495fn default_max_level() -> usize {
496 1000
497}
498
499fn default_min_lod() -> f32 {
500 -1000.0
501}
502
503fn default_max_lod() -> f32 {
504 1000.0
505}
506
507impl Default for TextureImportOptions {
508 fn default() -> Self {
509 Self {
510 minification_filter: TextureMinificationFilter::LinearMipMapLinear,
511 magnification_filter: TextureMagnificationFilter::Linear,
512 s_wrap_mode: TextureWrapMode::Repeat,
513 t_wrap_mode: TextureWrapMode::Repeat,
514 r_wrap_mode: TextureWrapMode::Repeat,
515 anisotropy: 16.0,
516 compression: CompressionOptions::default(),
517 mip_filter: Default::default(),
518 flip_green_channel: false,
519 base_level: 0,
520 max_level: default_max_level(),
521 min_lod: default_min_lod(),
522 max_lod: default_max_lod(),
523 lod_bias: 0.0,
524 }
525 }
526}
527
528impl ImportOptions for TextureImportOptions {}
529
530impl TextureImportOptions {
531 pub fn with_minification_filter(
534 mut self,
535 minification_filter: TextureMinificationFilter,
536 ) -> Self {
537 self.minification_filter = minification_filter;
538 self
539 }
540
541 pub fn set_minification_filter(&mut self, minification_filter: TextureMinificationFilter) {
544 self.minification_filter = minification_filter;
545 }
546
547 pub fn with_magnification_filter(
550 mut self,
551 magnification_filter: TextureMagnificationFilter,
552 ) -> Self {
553 self.magnification_filter = magnification_filter;
554 self
555 }
556
557 pub fn set_magnification_filter(&mut self, magnification_filter: TextureMagnificationFilter) {
560 self.magnification_filter = magnification_filter;
561 }
562
563 pub fn with_s_wrap_mode(mut self, s_wrap_mode: TextureWrapMode) -> Self {
566 self.s_wrap_mode = s_wrap_mode;
567 self
568 }
569
570 pub fn set_s_wrap_mode(&mut self, s_wrap_mode: TextureWrapMode) {
573 self.s_wrap_mode = s_wrap_mode;
574 }
575
576 pub fn with_t_wrap_mode(mut self, t_wrap_mode: TextureWrapMode) -> Self {
579 self.t_wrap_mode = t_wrap_mode;
580 self
581 }
582
583 pub fn set_t_wrap_mode(&mut self, t_wrap_mode: TextureWrapMode) {
586 self.t_wrap_mode = t_wrap_mode;
587 }
588
589 pub fn with_anisotropy(mut self, anisotropy: f32) -> Self {
592 self.anisotropy = anisotropy.min(1.0);
593 self
594 }
595
596 pub fn set_anisotropy(&mut self, anisotropy: f32) {
599 self.anisotropy = anisotropy.min(1.0);
600 }
601
602 pub fn with_compression(mut self, compression: CompressionOptions) -> Self {
604 self.compression = compression;
605 self
606 }
607
608 pub fn set_compression(&mut self, compression: CompressionOptions) {
610 self.compression = compression;
611 }
612
613 pub fn with_base_level(mut self, base_level: usize) -> Self {
615 self.base_level = base_level;
616 self
617 }
618
619 pub fn set_base_level(&mut self, base_level: usize) {
621 self.base_level = base_level;
622 }
623
624 pub fn with_max_level(mut self, max_level: usize) -> Self {
626 self.max_level = max_level;
627 self
628 }
629
630 pub fn set_max_level(&mut self, max_level: usize) {
632 self.max_level = max_level;
633 }
634
635 pub fn with_min_lod(mut self, min_lod: f32) -> Self {
637 self.min_lod = min_lod;
638 self
639 }
640
641 pub fn set_min_lod(&mut self, min_lod: f32) {
643 self.min_lod = min_lod;
644 }
645
646 pub fn with_max_lod(mut self, max_lod: f32) -> Self {
648 self.max_lod = max_lod;
649 self
650 }
651
652 pub fn set_max_lod(&mut self, max_lod: f32) {
654 self.max_lod = max_lod;
655 }
656
657 pub fn with_lod_bias(mut self, lod_bias: f32) -> Self {
659 self.lod_bias = lod_bias;
660 self
661 }
662
663 pub fn set_lod_bias(&mut self, lod_bias: f32) {
665 self.lod_bias = lod_bias;
666 }
667}
668
669lazy_static! {
670 pub static ref PLACEHOLDER: BuiltInResource<Texture> = BuiltInResource::new(embedded_data_source!("default.png"),
672 |data| {
673 TextureResource::load_from_memory(
674 ResourceKind::External("__PlaceholderTexture".into()),
675 data,
676 Default::default()
677 )
678 .unwrap()
679 });
680}
681
682pub type TextureResource = Resource<Texture>;
684
685pub trait TextureResourceExtension: Sized {
687 fn new_render_target(width: u32, height: u32) -> Self;
691
692 fn load_from_memory(
710 kind: ResourceKind,
711 data: &[u8],
712 import_options: TextureImportOptions,
713 ) -> Result<Self, TextureError>;
714
715 fn from_bytes(
718 kind: TextureKind,
719 pixel_kind: TexturePixelKind,
720 bytes: Vec<u8>,
721 resource_kind: ResourceKind,
722 ) -> Option<Self>;
723
724 fn deep_clone(&self) -> Self;
727}
728
729impl TextureResourceExtension for TextureResource {
730 fn new_render_target(width: u32, height: u32) -> Self {
731 Resource::new_ok(
732 Default::default(),
733 Texture {
734 kind: TextureKind::Rectangle { width, height },
736 bytes: Default::default(),
737 pixel_kind: TexturePixelKind::RGBA8,
738 minification_filter: TextureMinificationFilter::Linear,
739 magnification_filter: TextureMagnificationFilter::Linear,
740 s_wrap_mode: TextureWrapMode::Repeat,
741 t_wrap_mode: TextureWrapMode::Repeat,
742 r_wrap_mode: TextureWrapMode::Repeat,
743 base_level: 0,
744 max_level: 1000,
745 min_lod: -1000.0,
746 max_lod: 1000.0,
747 lod_bias: 0.0,
748 mip_count: 1,
749 anisotropy: 1.0,
750 modifications_counter: 0,
751 is_render_target: true,
752 cache_index: Default::default(),
753 },
754 )
755 }
756
757 fn load_from_memory(
758 kind: ResourceKind,
759 data: &[u8],
760 import_options: TextureImportOptions,
761 ) -> Result<Self, TextureError> {
762 Ok(Resource::new_ok(
763 kind,
764 Texture::load_from_memory(data, import_options)?,
765 ))
766 }
767
768 fn from_bytes(
769 kind: TextureKind,
770 pixel_kind: TexturePixelKind,
771 bytes: Vec<u8>,
772 resource_kind: ResourceKind,
773 ) -> Option<Self> {
774 Some(Resource::new_ok(
775 resource_kind,
776 Texture::from_bytes(kind, pixel_kind, bytes)?,
777 ))
778 }
779
780 fn deep_clone(&self) -> Self {
781 let kind = self.header().kind.clone();
782 let data = self.data_ref().clone();
783 Resource::new_ok(kind, data)
784 }
785}
786
787#[derive(
790 Copy,
791 Clone,
792 Debug,
793 Hash,
794 PartialOrd,
795 PartialEq,
796 Deserialize,
797 Serialize,
798 Reflect,
799 VariantNames,
800 EnumString,
801 AsRefStr,
802 Visit,
803 Eq,
804)]
805#[repr(u32)]
806pub enum TextureMagnificationFilter {
807 Nearest = 0,
810
811 Linear = 1,
814}
815
816uuid_provider!(TextureMagnificationFilter = "824f5b6c-8957-42db-9ebc-ef2a5dece5ab");
817
818impl Default for TextureMagnificationFilter {
819 fn default() -> Self {
820 Self::Linear
821 }
822}
823
824#[derive(
827 Copy,
828 Clone,
829 Debug,
830 Hash,
831 PartialOrd,
832 PartialEq,
833 Deserialize,
834 Serialize,
835 Reflect,
836 VariantNames,
837 EnumString,
838 AsRefStr,
839 Visit,
840 Eq,
841)]
842#[repr(u32)]
843pub enum TextureMinificationFilter {
844 Nearest = 0,
847
848 NearestMipMapNearest = 1,
852
853 NearestMipMapLinear = 2,
858
859 Linear = 3,
862
863 LinearMipMapNearest = 4,
867
868 LinearMipMapLinear = 5,
873}
874
875uuid_provider!(TextureMinificationFilter = "0ec9e072-6d0a-47b2-a9c2-498cac4de22b");
876
877impl TextureMinificationFilter {
878 pub fn is_using_mip_mapping(self) -> bool {
880 match self {
881 TextureMinificationFilter::Nearest | TextureMinificationFilter::Linear => false,
882 TextureMinificationFilter::NearestMipMapNearest
883 | TextureMinificationFilter::LinearMipMapLinear
884 | TextureMinificationFilter::NearestMipMapLinear
885 | TextureMinificationFilter::LinearMipMapNearest => true,
886 }
887 }
888}
889
890impl Default for TextureMinificationFilter {
891 fn default() -> Self {
892 Self::LinearMipMapLinear
893 }
894}
895
896#[derive(
898 Copy,
899 Clone,
900 Debug,
901 Hash,
902 PartialOrd,
903 PartialEq,
904 Deserialize,
905 Serialize,
906 Reflect,
907 VariantNames,
908 EnumString,
909 AsRefStr,
910 Visit,
911 Eq,
912)]
913#[repr(u32)]
914pub enum TextureWrapMode {
915 Repeat = 0,
918
919 ClampToEdge = 1,
922
923 ClampToBorder = 2,
927
928 MirroredRepeat = 3,
932
933 MirrorClampToEdge = 4,
936}
937
938uuid_provider!(TextureWrapMode = "e360d139-4374-4323-a66d-d192809d9d87");
939
940impl Default for TextureWrapMode {
941 fn default() -> Self {
942 Self::Repeat
943 }
944}
945
946#[derive(Copy, Clone, PartialEq, Eq, Debug, Reflect)]
948#[repr(u32)]
949pub enum TexturePixelKind {
950 R8 = 0,
952
953 RGB8 = 1,
955
956 RGBA8 = 2,
958
959 RG8 = 3,
961
962 R16 = 4,
964
965 RG16 = 5,
967
968 BGR8 = 6,
970
971 BGRA8 = 7,
973
974 RGB16 = 8,
976
977 RGBA16 = 9,
979
980 DXT1RGB = 10,
982
983 DXT1RGBA = 11,
985
986 DXT3RGBA = 12,
988
989 DXT5RGBA = 13,
991
992 R8RGTC = 14,
994
995 RG8RGTC = 15,
997
998 RGB32F = 16,
1000
1001 RGBA32F = 17,
1003
1004 Luminance8 = 18,
1011
1012 LuminanceAlpha8 = 19,
1019
1020 Luminance16 = 20,
1027
1028 LuminanceAlpha16 = 21,
1035
1036 RGB16F = 22,
1038
1039 R32F = 23,
1041
1042 R16F = 24,
1044}
1045
1046impl TexturePixelKind {
1047 fn new(id: u32) -> Result<Self, String> {
1048 match id {
1049 0 => Ok(Self::R8),
1050 1 => Ok(Self::RGB8),
1051 2 => Ok(Self::RGBA8),
1052 3 => Ok(Self::RG8),
1053 4 => Ok(Self::R16),
1054 5 => Ok(Self::RG16),
1055 6 => Ok(Self::BGR8),
1056 7 => Ok(Self::BGRA8),
1057 8 => Ok(Self::RGB16),
1058 9 => Ok(Self::RGBA16),
1059 10 => Ok(Self::DXT1RGB),
1060 11 => Ok(Self::DXT1RGBA),
1061 12 => Ok(Self::DXT3RGBA),
1062 13 => Ok(Self::DXT5RGBA),
1063 14 => Ok(Self::R8RGTC),
1064 15 => Ok(Self::RG8RGTC),
1065 16 => Ok(Self::RGB32F),
1066 17 => Ok(Self::RGBA32F),
1067 18 => Ok(Self::Luminance8),
1068 19 => Ok(Self::LuminanceAlpha8),
1069 20 => Ok(Self::Luminance16),
1070 21 => Ok(Self::LuminanceAlpha16),
1071 22 => Ok(Self::RGB16F),
1072 23 => Ok(Self::R32F),
1073 24 => Ok(Self::R16F),
1074 _ => Err(format!("Invalid texture kind {id}!")),
1075 }
1076 }
1077
1078 fn id(self) -> u32 {
1079 self as u32
1080 }
1081
1082 pub fn size_in_bytes(&self) -> Option<usize> {
1085 match self {
1086 Self::R8 | Self::Luminance8 => Some(1),
1087 Self::RGB8 | Self::BGR8 => Some(3),
1088 Self::RGBA8 | Self::RG16 | Self::BGRA8 | Self::LuminanceAlpha16 | Self::R32F => Some(4),
1089 Self::RG8 | Self::R16 | Self::LuminanceAlpha8 | Self::Luminance16 | Self::R16F => {
1090 Some(2)
1091 }
1092 Self::RGB16 | Self::RGB16F => Some(6),
1093 Self::RGBA16 => Some(8),
1094 Self::RGB32F => Some(12),
1095 Self::RGBA32F => Some(16),
1096 Self::DXT1RGB
1099 | Self::DXT1RGBA
1100 | Self::DXT3RGBA
1101 | Self::DXT5RGBA
1102 | Self::R8RGTC
1103 | Self::RG8RGTC => None,
1104 }
1105 }
1106}
1107
1108#[derive(Debug)]
1110pub enum TextureError {
1111 UnsupportedFormat,
1113 Io(std::io::Error),
1115 Image(image::ImageError),
1117 FileLoadError(FileLoadError),
1119}
1120
1121impl Display for TextureError {
1122 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
1123 match self {
1124 TextureError::UnsupportedFormat => {
1125 write!(f, "Unsupported format!")
1126 }
1127 TextureError::Io(v) => {
1128 write!(f, "An i/o error has occurred: {v}")
1129 }
1130 TextureError::Image(v) => {
1131 write!(f, "Image loading error {v}")
1132 }
1133 TextureError::FileLoadError(v) => {
1134 write!(f, "A file load error has occurred {v:?}")
1135 }
1136 }
1137 }
1138}
1139
1140impl std::error::Error for TextureError {}
1141
1142impl From<FileLoadError> for TextureError {
1143 fn from(v: FileLoadError) -> Self {
1144 Self::FileLoadError(v)
1145 }
1146}
1147
1148impl From<image::ImageError> for TextureError {
1149 fn from(v: ImageError) -> Self {
1150 Self::Image(v)
1151 }
1152}
1153
1154impl From<std::io::Error> for TextureError {
1155 fn from(v: Error) -> Self {
1156 Self::Io(v)
1157 }
1158}
1159
1160fn ceil_div_4(x: u32) -> u32 {
1161 (x + 3) / 4
1162}
1163
1164#[derive(
1172 Copy,
1173 Clone,
1174 Deserialize,
1175 Serialize,
1176 PartialEq,
1177 Eq,
1178 Debug,
1179 Reflect,
1180 VariantNames,
1181 EnumString,
1182 AsRefStr,
1183)]
1184#[repr(u32)]
1185pub enum CompressionOptions {
1186 NoCompression = 0,
1188
1189 Speed = 1,
1195
1196 Quality = 2,
1202}
1203
1204uuid_provider!(CompressionOptions = "fbdcc081-d0b8-4b62-9925-2de6c013fbf5");
1205
1206impl Default for CompressionOptions {
1207 fn default() -> Self {
1208 Self::NoCompression
1209 }
1210}
1211
1212fn transmute_slice<T>(bytes: &[u8]) -> &'_ [T] {
1213 unsafe {
1216 std::slice::from_raw_parts(
1217 bytes.as_ptr() as *const T,
1218 bytes.len() / std::mem::size_of::<T>(),
1219 )
1220 }
1221}
1222
1223fn transmute_slice_mut<T>(bytes: &mut [u8]) -> &'_ mut [T] {
1224 unsafe {
1227 std::slice::from_raw_parts_mut(
1228 bytes.as_ptr() as *mut T,
1229 bytes.len() / std::mem::size_of::<T>(),
1230 )
1231 }
1232}
1233
1234fn compress_bc1<T: tbc::color::ColorRgba8>(bytes: &[u8], width: usize, height: usize) -> Vec<u8> {
1235 tbc::encode_image_bc1_conv_u8::<T>(transmute_slice::<T>(bytes), width, height)
1236}
1237
1238fn compress_bc3<T: tbc::color::ColorRgba8>(bytes: &[u8], width: usize, height: usize) -> Vec<u8> {
1239 tbc::encode_image_bc3_conv_u8::<T>(transmute_slice::<T>(bytes), width, height)
1240}
1241
1242fn compress_r8_bc4<T: tbc::color::ColorRed8>(bytes: &[u8], width: usize, height: usize) -> Vec<u8> {
1243 tbc::encode_image_bc4_r8_conv_u8::<T>(transmute_slice::<T>(bytes), width, height)
1244}
1245
1246fn compress_rg8_bc4<T: tbc::color::ColorRedGreen8>(
1247 bytes: &[u8],
1248 width: usize,
1249 height: usize,
1250) -> Vec<u8> {
1251 tbc::encode_image_bc4_rg8_conv_u8::<T>(transmute_slice::<T>(bytes), width, height)
1252}
1253
1254fn data_hash(data: &[u8]) -> u64 {
1255 let mut hasher = FxHasher::default();
1256 data.hash(&mut hasher);
1257 hasher.finish()
1258}
1259
1260fn try_compress(
1261 pixel_kind: TexturePixelKind,
1262 bytes: &[u8],
1263 w: usize,
1264 h: usize,
1265 compression: CompressionOptions,
1266) -> Option<(Vec<u8>, TexturePixelKind)> {
1267 match (pixel_kind, compression) {
1268 (TexturePixelKind::RGB8, CompressionOptions::Speed) => Some((
1269 compress_bc1::<tbc::color::Rgb8>(bytes, w, h),
1270 TexturePixelKind::DXT1RGB,
1271 )),
1272 (TexturePixelKind::RGB8, CompressionOptions::Quality) => Some((
1273 compress_bc3::<tbc::color::Rgb8>(bytes, w, h),
1274 TexturePixelKind::DXT5RGBA,
1275 )),
1276 (TexturePixelKind::RGBA8, CompressionOptions::Speed) => Some((
1277 compress_bc1::<tbc::color::Rgba8>(bytes, w, h),
1278 TexturePixelKind::DXT1RGBA,
1279 )),
1280 (TexturePixelKind::RGBA8, CompressionOptions::Quality) => Some((
1281 compress_bc3::<tbc::color::Rgba8>(bytes, w, h),
1282 TexturePixelKind::DXT5RGBA,
1283 )),
1284 (TexturePixelKind::R8, CompressionOptions::Speed)
1285 | (TexturePixelKind::R8, CompressionOptions::Quality)
1286 | (TexturePixelKind::Luminance8, CompressionOptions::Speed)
1287 | (TexturePixelKind::Luminance8, CompressionOptions::Quality) => Some((
1288 compress_r8_bc4::<tbc::color::Red8>(bytes, w, h),
1289 TexturePixelKind::R8RGTC,
1290 )),
1291 (TexturePixelKind::RG8, CompressionOptions::Speed)
1292 | (TexturePixelKind::RG8, CompressionOptions::Quality)
1293 | (TexturePixelKind::LuminanceAlpha8, CompressionOptions::Speed)
1294 | (TexturePixelKind::LuminanceAlpha8, CompressionOptions::Quality) => Some((
1295 compress_rg8_bc4::<tbc::color::RedGreen8>(bytes, w, h),
1296 TexturePixelKind::RG8RGTC,
1297 )),
1298 _ => None,
1299 }
1300}
1301
1302fn bytes_in_mip_level(kind: TextureKind, pixel_kind: TexturePixelKind, mip: usize) -> u32 {
1303 let pixel_count = match kind {
1304 TextureKind::Line { length } => length.shr(mip),
1305 TextureKind::Rectangle { width, height } => width.shr(mip) * height.shr(mip),
1306 TextureKind::Cube { width, height } => 6 * width.shr(mip) * height.shr(mip),
1307 TextureKind::Volume {
1308 width,
1309 height,
1310 depth,
1311 } => width.shr(mip) * height.shr(mip) * depth.shr(mip),
1312 };
1313 match pixel_kind {
1314 TexturePixelKind::R8 | TexturePixelKind::Luminance8 => pixel_count,
1316 TexturePixelKind::R16
1317 | TexturePixelKind::LuminanceAlpha8
1318 | TexturePixelKind::Luminance16
1319 | TexturePixelKind::RG8
1320 | TexturePixelKind::R16F => 2 * pixel_count,
1321 TexturePixelKind::RGB8 | TexturePixelKind::BGR8 => 3 * pixel_count,
1322 TexturePixelKind::RGBA8
1323 | TexturePixelKind::BGRA8
1324 | TexturePixelKind::RG16
1325 | TexturePixelKind::LuminanceAlpha16
1326 | TexturePixelKind::R32F => 4 * pixel_count,
1327 TexturePixelKind::RGB16 | TexturePixelKind::RGB16F => 6 * pixel_count,
1328 TexturePixelKind::RGBA16 => 8 * pixel_count,
1329 TexturePixelKind::RGB32F => 12 * pixel_count,
1330 TexturePixelKind::RGBA32F => 16 * pixel_count,
1331
1332 TexturePixelKind::DXT1RGB
1334 | TexturePixelKind::DXT1RGBA
1335 | TexturePixelKind::DXT3RGBA
1336 | TexturePixelKind::DXT5RGBA
1337 | TexturePixelKind::R8RGTC
1338 | TexturePixelKind::RG8RGTC => {
1339 let block_size = match pixel_kind {
1340 TexturePixelKind::DXT1RGB
1341 | TexturePixelKind::DXT1RGBA
1342 | TexturePixelKind::R8RGTC => 8,
1343 TexturePixelKind::DXT3RGBA
1344 | TexturePixelKind::DXT5RGBA
1345 | TexturePixelKind::RG8RGTC => 16,
1346 _ => unreachable!(),
1347 };
1348 match kind {
1349 TextureKind::Line { length } => ceil_div_4(length) * block_size,
1350 TextureKind::Rectangle { width, height } => {
1351 ceil_div_4(width) * ceil_div_4(height) * block_size
1352 }
1353 TextureKind::Cube { width, height } => {
1354 6 * ceil_div_4(width) * ceil_div_4(height) * block_size
1355 }
1356 TextureKind::Volume {
1357 width,
1358 height,
1359 depth,
1360 } => ceil_div_4(width) * ceil_div_4(height) * ceil_div_4(depth) * block_size,
1361 }
1362 }
1363 }
1364}
1365
1366fn mip_byte_offset(kind: TextureKind, pixel_kind: TexturePixelKind, mut mip: usize) -> usize {
1367 let mut offset = 0;
1369 loop {
1370 offset += bytes_in_mip_level(kind, pixel_kind, mip) as usize;
1371 mip = mip.saturating_sub(1);
1372 if mip == 0 {
1373 break;
1374 }
1375 }
1376 offset
1377}
1378
1379fn convert_pixel_type_enum(pixel_kind: TexturePixelKind) -> fr::PixelType {
1380 match pixel_kind {
1381 TexturePixelKind::R8 | TexturePixelKind::Luminance8 => fr::PixelType::U8,
1382 TexturePixelKind::RGB8 | TexturePixelKind::BGR8 => fr::PixelType::U8x3,
1383 TexturePixelKind::RGBA8 | TexturePixelKind::BGRA8 => fr::PixelType::U8x4,
1384 TexturePixelKind::RG8 | TexturePixelKind::LuminanceAlpha8 => fr::PixelType::U8x2,
1385 TexturePixelKind::R16 | TexturePixelKind::Luminance16 => fr::PixelType::U16,
1386 TexturePixelKind::RG16 | TexturePixelKind::LuminanceAlpha16 => fr::PixelType::U16x2,
1387 TexturePixelKind::RGB16 => fr::PixelType::U16x3,
1388 TexturePixelKind::RGBA16 => fr::PixelType::U16x4,
1389 TexturePixelKind::R32F => fr::PixelType::F32,
1390 _ => unreachable!(),
1391 }
1392}
1393
1394fn flip_green_channel<'a, P>(pixels: impl Iterator<Item = &'a mut P>)
1395where
1396 P: Pixel + 'a,
1397{
1398 for pixel in pixels {
1399 let green = &mut pixel.channels_mut()[1];
1400 let inverted = P::Subpixel::max_value() - *green;
1401 *green = inverted;
1402 }
1403}
1404
1405impl Texture {
1406 pub fn load_from_memory(
1428 data: &[u8],
1429 import_options: TextureImportOptions,
1430 ) -> Result<Self, TextureError> {
1431 if let Ok(dds) = ddsfile::Dds::read(&mut Cursor::new(data)) {
1436 let d3dformat = dds
1437 .get_d3d_format()
1438 .ok_or(TextureError::UnsupportedFormat)?;
1439 let mip_count = dds.get_num_mipmap_levels();
1440 let mut bytes = dds.data;
1441
1442 let pixel_kind = match d3dformat {
1444 D3DFormat::DXT1 => TexturePixelKind::DXT1RGBA,
1445 D3DFormat::DXT3 => TexturePixelKind::DXT3RGBA,
1446 D3DFormat::DXT5 => TexturePixelKind::DXT5RGBA,
1447 D3DFormat::L8 | D3DFormat::A8 => TexturePixelKind::R8,
1448 D3DFormat::L16 => TexturePixelKind::R16,
1449 D3DFormat::R8G8B8 => TexturePixelKind::RGB8,
1450 D3DFormat::A8L8 => TexturePixelKind::RG8,
1451 D3DFormat::A8R8G8B8 => {
1452 TexturePixelKind::RGBA8
1465 }
1466 D3DFormat::G16R16 => {
1467 assert_eq!(bytes.len() % 4, 0);
1469 for chunk in bytes.chunks_exact_mut(4) {
1470 let gh = chunk[0];
1472 let gl = chunk[1];
1473 let rh = chunk[2];
1475 let rl = chunk[3];
1476 chunk[0] = rh;
1478 chunk[1] = rl;
1479 chunk[2] = gh;
1480 chunk[3] = gl;
1481 }
1482 TexturePixelKind::RG16
1483 }
1484 _ => return Err(TextureError::UnsupportedFormat),
1485 };
1486
1487 Ok(Self {
1488 pixel_kind,
1489 modifications_counter: 0,
1490 minification_filter: import_options.minification_filter,
1491 magnification_filter: import_options.magnification_filter,
1492 s_wrap_mode: import_options.s_wrap_mode,
1493 t_wrap_mode: import_options.t_wrap_mode,
1494 r_wrap_mode: import_options.r_wrap_mode,
1495 base_level: import_options.base_level,
1496 max_level: import_options.max_level,
1497 min_lod: import_options.min_lod,
1498 max_lod: import_options.max_lod,
1499 anisotropy: import_options.anisotropy,
1500 mip_count,
1501 bytes: bytes.into(),
1502 kind: if dds.header.caps2 & Caps2::CUBEMAP == Caps2::CUBEMAP {
1503 TextureKind::Cube {
1504 width: dds.header.width,
1505 height: dds.header.height,
1506 }
1507 } else if dds.header.caps2 & Caps2::VOLUME == Caps2::VOLUME {
1508 TextureKind::Volume {
1509 width: dds.header.width,
1510 height: dds.header.height,
1511 depth: dds.header.depth.unwrap(),
1512 }
1513 } else {
1514 TextureKind::Rectangle {
1515 width: dds.header.width,
1516 height: dds.header.height,
1517 }
1518 },
1519 is_render_target: false,
1520 cache_index: Default::default(),
1521 lod_bias: import_options.lod_bias,
1522 })
1523 } else {
1524 let mut dyn_img = image::load_from_memory(data)
1526 .or_else(|_| image::load_from_memory_with_format(data, ImageFormat::Tga))?;
1530
1531 let width = dyn_img.width();
1532 let height = dyn_img.height();
1533
1534 if import_options.flip_green_channel {
1535 match dyn_img {
1536 DynamicImage::ImageRgb8(ref mut img) => flip_green_channel(img.pixels_mut()),
1537 DynamicImage::ImageRgba8(ref mut img) => flip_green_channel(img.pixels_mut()),
1538 DynamicImage::ImageRgb16(ref mut img) => flip_green_channel(img.pixels_mut()),
1539 DynamicImage::ImageRgba16(ref mut img) => flip_green_channel(img.pixels_mut()),
1540 DynamicImage::ImageRgb32F(ref mut img) => flip_green_channel(img.pixels_mut()),
1541 DynamicImage::ImageRgba32F(ref mut img) => flip_green_channel(img.pixels_mut()),
1542 _ => (),
1543 }
1544 }
1545
1546 let src_pixel_kind = match dyn_img {
1547 DynamicImage::ImageLuma8(_) => TexturePixelKind::Luminance8,
1548 DynamicImage::ImageLumaA8(_) => TexturePixelKind::LuminanceAlpha8,
1549 DynamicImage::ImageRgb8(_) => TexturePixelKind::RGB8,
1550 DynamicImage::ImageRgba8(_) => TexturePixelKind::RGBA8,
1551 DynamicImage::ImageLuma16(_) => TexturePixelKind::Luminance16,
1552 DynamicImage::ImageLumaA16(_) => TexturePixelKind::LuminanceAlpha16,
1553 DynamicImage::ImageRgb16(_) => TexturePixelKind::RGB16,
1554 DynamicImage::ImageRgba16(_) => TexturePixelKind::RGBA16,
1555 DynamicImage::ImageRgb32F(_) => TexturePixelKind::RGB32F,
1556 DynamicImage::ImageRgba32F(_) => TexturePixelKind::RGBA32F,
1557 _ => return Err(TextureError::UnsupportedFormat),
1558 };
1559 let mut final_pixel_kind = src_pixel_kind;
1560
1561 let mut mip_count = 0;
1562 let mut bytes = Vec::with_capacity(
1563 width as usize * height as usize * src_pixel_kind.size_in_bytes().unwrap_or(4),
1564 );
1565
1566 if import_options.minification_filter.is_using_mip_mapping() {
1567 let src_pixel_type = convert_pixel_type_enum(src_pixel_kind);
1568 let mut level_width = width;
1569 let mut level_height = height;
1570 let mut current_level = fr::images::Image::from_vec_u8(
1571 level_width,
1572 level_height,
1573 dyn_img.as_bytes().to_vec(),
1574 src_pixel_type,
1575 )
1576 .map_err(|_| TextureError::UnsupportedFormat)?;
1577
1578 while level_width != 0 && level_height != 0 {
1579 if mip_count != 0 {
1580 let mut dst_img =
1581 fr::images::Image::new(level_width, level_height, src_pixel_type);
1582
1583 let mut resizer = fr::Resizer::new();
1584
1585 resizer
1586 .resize(
1587 ¤t_level,
1588 &mut dst_img,
1589 Some(&ResizeOptions {
1590 algorithm: fr::ResizeAlg::Convolution(
1591 import_options.mip_filter.into_filter_type(),
1592 ),
1593 cropping: Default::default(),
1594 mul_div_alpha: true,
1595 }),
1596 )
1597 .expect("Pixel types must match!");
1598
1599 current_level = dst_img;
1600 }
1601
1602 mip_count += 1;
1603
1604 if import_options.compression == CompressionOptions::NoCompression {
1605 bytes.extend_from_slice(current_level.buffer())
1606 } else if let Some((compressed_data, new_pixel_kind)) = try_compress(
1607 src_pixel_kind,
1608 current_level.buffer(),
1609 level_width as usize,
1610 level_height as usize,
1611 import_options.compression,
1612 ) {
1613 final_pixel_kind = new_pixel_kind;
1614 bytes.extend_from_slice(&compressed_data);
1615 } else {
1616 bytes.extend_from_slice(current_level.buffer())
1617 }
1618
1619 level_width = level_width.checked_shr(1).unwrap_or_default();
1620 level_height = level_height.checked_shr(1).unwrap_or_default();
1621 }
1622 } else {
1623 mip_count = 1;
1624
1625 if import_options.compression == CompressionOptions::NoCompression {
1626 bytes.extend_from_slice(dyn_img.as_bytes());
1627 } else if let Some((compressed_data, new_pixel_kind)) = try_compress(
1628 src_pixel_kind,
1629 dyn_img.as_bytes(),
1630 width as usize,
1631 height as usize,
1632 import_options.compression,
1633 ) {
1634 final_pixel_kind = new_pixel_kind;
1635 bytes.extend_from_slice(&compressed_data);
1636 } else {
1637 bytes.extend_from_slice(dyn_img.as_bytes())
1638 }
1639 }
1640
1641 Ok(Self {
1642 pixel_kind: final_pixel_kind,
1643 kind: TextureKind::Rectangle { width, height },
1644 modifications_counter: 0,
1645 bytes: bytes.into(),
1646 mip_count,
1647 minification_filter: import_options.minification_filter,
1648 magnification_filter: import_options.magnification_filter,
1649 s_wrap_mode: import_options.s_wrap_mode,
1650 t_wrap_mode: import_options.t_wrap_mode,
1651 r_wrap_mode: import_options.r_wrap_mode,
1652 base_level: import_options.base_level,
1653 max_level: import_options.max_level,
1654 min_lod: import_options.min_lod,
1655 max_lod: import_options.max_lod,
1656 anisotropy: import_options.anisotropy,
1657 is_render_target: false,
1658 cache_index: Default::default(),
1659 lod_bias: import_options.lod_bias,
1660 })
1661 }
1662 }
1663
1664 pub(crate) async fn load_from_file<P: AsRef<Path>>(
1671 path: P,
1672 io: &dyn ResourceIo,
1673 import_options: TextureImportOptions,
1674 ) -> Result<Self, TextureError> {
1675 let data = io.load_file(path.as_ref()).await?;
1676 Self::load_from_memory(&data, import_options)
1677 }
1678
1679 pub fn from_bytes(
1685 kind: TextureKind,
1686 pixel_kind: TexturePixelKind,
1687 bytes: Vec<u8>,
1688 ) -> Option<Self> {
1689 if bytes_in_mip_level(kind, pixel_kind, 0) != bytes.len() as u32 {
1690 None
1691 } else {
1692 Some(Self {
1693 kind,
1694 modifications_counter: 0,
1695 bytes: bytes.into(),
1696 pixel_kind,
1697 ..Default::default()
1698 })
1699 }
1700 }
1701
1702 #[inline]
1704 pub fn set_minification_filter(&mut self, filter: TextureMinificationFilter) {
1705 self.minification_filter = filter;
1706 }
1707
1708 #[inline]
1710 pub fn minification_filter(&self) -> TextureMinificationFilter {
1711 self.minification_filter
1712 }
1713
1714 #[inline]
1716 pub fn set_magnification_filter(&mut self, filter: TextureMagnificationFilter) {
1717 self.magnification_filter = filter;
1718 }
1719
1720 #[inline]
1722 pub fn magnification_filter(&self) -> TextureMagnificationFilter {
1723 self.magnification_filter
1724 }
1725
1726 #[inline]
1728 pub fn set_s_wrap_mode(&mut self, s_wrap_mode: TextureWrapMode) {
1729 self.s_wrap_mode = s_wrap_mode;
1730 }
1731
1732 #[inline]
1734 pub fn s_wrap_mode(&self) -> TextureWrapMode {
1735 self.s_wrap_mode
1736 }
1737
1738 #[inline]
1740 pub fn set_t_wrap_mode(&mut self, t_wrap_mode: TextureWrapMode) {
1741 self.t_wrap_mode = t_wrap_mode;
1742 }
1743
1744 #[inline]
1746 pub fn t_wrap_mode(&self) -> TextureWrapMode {
1747 self.t_wrap_mode
1748 }
1749
1750 #[inline]
1752 pub fn set_r_wrap_mode(&mut self, r_wrap_mode: TextureWrapMode) {
1753 self.r_wrap_mode = r_wrap_mode;
1754 }
1755
1756 #[inline]
1758 pub fn r_wrap_mode(&self) -> TextureWrapMode {
1759 self.r_wrap_mode
1760 }
1761
1762 #[inline]
1764 pub fn mip_count(&self) -> u32 {
1765 self.mip_count
1766 }
1767
1768 #[inline]
1770 pub fn kind(&self) -> TextureKind {
1771 self.kind
1772 }
1773
1774 #[inline]
1776 pub fn modifications_count(&self) -> u64 {
1777 self.modifications_counter
1778 }
1779
1780 #[inline]
1782 pub fn calculate_data_hash(&self) -> u64 {
1783 data_hash(&self.bytes.0)
1784 }
1785
1786 #[inline]
1788 pub fn pixel_kind(&self) -> TexturePixelKind {
1789 self.pixel_kind
1790 }
1791
1792 #[inline]
1794 pub fn base_level(&self) -> usize {
1795 self.base_level
1796 }
1797
1798 #[inline]
1802 pub fn set_base_level(&mut self, base_level: usize) {
1803 self.base_level = base_level;
1804 }
1805
1806 #[inline]
1808 pub fn max_level(&self) -> usize {
1809 self.max_level
1810 }
1811
1812 #[inline]
1816 pub fn set_max_level(&mut self, max_level: usize) {
1817 self.max_level = max_level;
1818 }
1819
1820 #[inline]
1822 pub fn min_lod(&self) -> f32 {
1823 self.min_lod
1824 }
1825
1826 #[inline]
1829 pub fn set_min_lod(&mut self, min_lod: f32) {
1830 self.min_lod = min_lod;
1831 }
1832
1833 #[inline]
1835 pub fn max_lod(&self) -> f32 {
1836 self.max_lod
1837 }
1838
1839 #[inline]
1842 pub fn set_max_lod(&mut self, max_lod: f32) {
1843 self.max_lod = max_lod;
1844 }
1845
1846 #[inline]
1849 pub fn lod_bias(&self) -> f32 {
1850 self.lod_bias
1851 }
1852
1853 #[inline]
1859 pub fn set_lod_bias(&mut self, lod_bias: f32) {
1860 self.lod_bias = lod_bias;
1861 }
1862
1863 pub fn data(&self) -> &[u8] {
1865 &self.bytes
1866 }
1867
1868 pub fn data_of_type<T: Sized>(&self) -> Option<&[T]> {
1882 if let Some(pixel_size) = self.pixel_kind.size_in_bytes() {
1883 if pixel_size == std::mem::size_of::<T>() {
1884 return Some(transmute_slice(&self.bytes));
1885 }
1886 }
1887 None
1888 }
1889
1890 #[inline]
1892 pub fn mip_level_data(&self, mip: usize) -> &[u8] {
1893 let mip_begin = mip
1894 .checked_sub(1)
1895 .map(|prev| mip_byte_offset(self.kind, self.pixel_kind, prev))
1896 .unwrap_or_default();
1897 let mip_end = mip_byte_offset(self.kind, self.pixel_kind, mip);
1898 &self.bytes[mip_begin..mip_end]
1899 }
1900
1901 pub fn mip_level_data_of_type<T: Sized>(&self, mip: usize) -> Option<&[T]> {
1912 if let Some(pixel_size) = self.pixel_kind.size_in_bytes() {
1913 if pixel_size == std::mem::size_of::<T>() {
1914 return Some(transmute_slice(self.mip_level_data(mip)));
1915 }
1916 }
1917 None
1918 }
1919
1920 #[inline]
1922 pub fn is_render_target(&self) -> bool {
1923 self.is_render_target
1924 }
1925
1926 #[inline]
1931 pub fn set_anisotropy_level(&mut self, anisotropy: f32) {
1932 self.anisotropy = anisotropy.max(1.0);
1933 }
1934
1935 #[inline]
1937 pub fn anisotropy_level(&self) -> f32 {
1938 self.anisotropy
1939 }
1940
1941 #[inline]
1944 pub fn modify(&mut self) -> TextureDataRefMut<'_> {
1945 TextureDataRefMut { texture: self }
1946 }
1947}
1948
1949pub struct TextureDataRefMut<'a> {
1952 texture: &'a mut Texture,
1953}
1954
1955impl Drop for TextureDataRefMut<'_> {
1956 fn drop(&mut self) {
1957 self.texture.modifications_counter += 1;
1958 }
1959}
1960
1961impl Deref for TextureDataRefMut<'_> {
1962 type Target = Texture;
1963
1964 fn deref(&self) -> &Self::Target {
1965 self.texture
1966 }
1967}
1968
1969impl DerefMut for TextureDataRefMut<'_> {
1970 fn deref_mut(&mut self) -> &mut Self::Target {
1971 self.texture
1972 }
1973}
1974
1975impl TextureDataRefMut<'_> {
1976 pub fn data_mut(&mut self) -> &mut [u8] {
1978 &mut self.texture.bytes
1979 }
1980
1981 pub fn data_mut_of_type<T: Sized>(&mut self) -> Option<&mut [T]> {
1988 if let Some(pixel_size) = self.texture.pixel_kind.size_in_bytes() {
1989 if pixel_size == std::mem::size_of::<T>() {
1990 return Some(transmute_slice_mut(&mut self.texture.bytes));
1991 }
1992 }
1993 None
1994 }
1995}