Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
bevyengine
GitHub Repository: bevyengine/bevy
Path: blob/main/crates/bevy_gltf/src/loader/gltf_ext/texture.rs
6598 views
1
use bevy_asset::{Handle, LoadContext};
2
use bevy_image::{Image, ImageAddressMode, ImageFilterMode, ImageSamplerDescriptor};
3
use bevy_math::Affine2;
4
5
use gltf::{
6
image::Source,
7
texture::{MagFilter, MinFilter, Texture, TextureTransform, WrappingMode},
8
};
9
10
#[cfg(any(
11
feature = "pbr_anisotropy_texture",
12
feature = "pbr_multi_layer_material_textures",
13
feature = "pbr_specular_textures"
14
))]
15
use gltf::{json::texture::Info, Document};
16
17
use crate::{loader::DataUri, GltfAssetLabel};
18
19
pub(crate) fn texture_handle(
20
texture: &Texture<'_>,
21
load_context: &mut LoadContext,
22
) -> Handle<Image> {
23
match texture.source().source() {
24
Source::View { .. } => load_context.get_label_handle(texture_label(texture).to_string()),
25
Source::Uri { uri, .. } => {
26
let uri = percent_encoding::percent_decode_str(uri)
27
.decode_utf8()
28
.unwrap();
29
let uri = uri.as_ref();
30
if let Ok(_data_uri) = DataUri::parse(uri) {
31
load_context.get_label_handle(texture_label(texture).to_string())
32
} else {
33
let parent = load_context.path().parent().unwrap();
34
let image_path = parent.join(uri);
35
load_context.load(image_path)
36
}
37
}
38
}
39
}
40
41
/// Extracts the texture sampler data from the glTF [`Texture`].
42
pub(crate) fn texture_sampler(
43
texture: &Texture<'_>,
44
default_sampler: &ImageSamplerDescriptor,
45
) -> ImageSamplerDescriptor {
46
let gltf_sampler = texture.sampler();
47
let mut sampler = default_sampler.clone();
48
49
sampler.address_mode_u = address_mode(&gltf_sampler.wrap_s());
50
sampler.address_mode_v = address_mode(&gltf_sampler.wrap_t());
51
52
// Shouldn't parse filters when anisotropic filtering is on, because trilinear is then required by wgpu.
53
// We also trust user to have provided a valid sampler.
54
if sampler.anisotropy_clamp == 1 {
55
if let Some(mag_filter) = gltf_sampler.mag_filter().map(|mf| match mf {
56
MagFilter::Nearest => ImageFilterMode::Nearest,
57
MagFilter::Linear => ImageFilterMode::Linear,
58
}) {
59
sampler.mag_filter = mag_filter;
60
}
61
if let Some(min_filter) = gltf_sampler.min_filter().map(|mf| match mf {
62
MinFilter::Nearest
63
| MinFilter::NearestMipmapNearest
64
| MinFilter::NearestMipmapLinear => ImageFilterMode::Nearest,
65
MinFilter::Linear | MinFilter::LinearMipmapNearest | MinFilter::LinearMipmapLinear => {
66
ImageFilterMode::Linear
67
}
68
}) {
69
sampler.min_filter = min_filter;
70
}
71
if let Some(mipmap_filter) = gltf_sampler.min_filter().map(|mf| match mf {
72
MinFilter::Nearest
73
| MinFilter::Linear
74
| MinFilter::NearestMipmapNearest
75
| MinFilter::LinearMipmapNearest => ImageFilterMode::Nearest,
76
MinFilter::NearestMipmapLinear | MinFilter::LinearMipmapLinear => {
77
ImageFilterMode::Linear
78
}
79
}) {
80
sampler.mipmap_filter = mipmap_filter;
81
}
82
}
83
sampler
84
}
85
86
pub(crate) fn texture_label(texture: &Texture<'_>) -> GltfAssetLabel {
87
GltfAssetLabel::Texture(texture.index())
88
}
89
90
pub(crate) fn address_mode(wrapping_mode: &WrappingMode) -> ImageAddressMode {
91
match wrapping_mode {
92
WrappingMode::ClampToEdge => ImageAddressMode::ClampToEdge,
93
WrappingMode::Repeat => ImageAddressMode::Repeat,
94
WrappingMode::MirroredRepeat => ImageAddressMode::MirrorRepeat,
95
}
96
}
97
98
pub(crate) fn texture_transform_to_affine2(texture_transform: TextureTransform) -> Affine2 {
99
Affine2::from_scale_angle_translation(
100
texture_transform.scale().into(),
101
-texture_transform.rotation(),
102
texture_transform.offset().into(),
103
)
104
}
105
106
#[cfg(any(
107
feature = "pbr_anisotropy_texture",
108
feature = "pbr_multi_layer_material_textures",
109
feature = "pbr_specular_textures"
110
))]
111
/// Given a [`Info`], returns the handle of the texture that this
112
/// refers to.
113
///
114
/// This is a low-level function only used when the [`gltf`] crate has no support
115
/// for an extension, forcing us to parse its texture references manually.
116
pub(crate) fn texture_handle_from_info(
117
info: &Info,
118
document: &Document,
119
load_context: &mut LoadContext,
120
) -> Handle<Image> {
121
let texture = document
122
.textures()
123
.nth(info.index.value())
124
.expect("Texture info references a nonexistent texture");
125
texture_handle(&texture, load_context)
126
}
127
128