Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add support for EXT_texture_webp v2 #425

Merged
merged 13 commits into from
Jul 3, 2024
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ KHR_materials_variants = ["gltf-json/KHR_materials_variants"]
KHR_materials_volume = ["gltf-json/KHR_materials_volume"]
KHR_materials_specular = ["gltf-json/KHR_materials_specular"]
KHR_materials_emissive_strength = ["gltf-json/KHR_materials_emissive_strength"]
EXT_texture_webp = ["gltf-json/EXT_texture_webp", "image/webp"]
guess_mime_type = []

[[example]]
Expand Down
1 change: 1 addition & 0 deletions gltf-json/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -30,3 +30,4 @@ KHR_materials_variants = []
KHR_materials_volume = []
KHR_texture_transform = []
KHR_materials_emissive_strength = []
EXT_texture_webp = []
3 changes: 2 additions & 1 deletion gltf-json/src/extensions/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ pub const ENABLED_EXTENSIONS: &[&str] = &[
// Allowlisted texture extensions. Processing is delegated to the user.
#[cfg(feature = "allow_empty_texture")]
"KHR_texture_basisu",
#[cfg(feature = "allow_empty_texture")]
#[cfg(feature = "EXT_texture_webp")]
"EXT_texture_webp",
#[cfg(feature = "allow_empty_texture")]
"MSFT_texture_dds",
Expand All @@ -70,4 +70,5 @@ pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"KHR_materials_transmission",
"KHR_materials_ior",
"KHR_materials_emissive_strength",
"EXT_texture_webp",
];
20 changes: 19 additions & 1 deletion gltf-json/src/extensions/texture.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
#[cfg(feature = "KHR_texture_transform")]
#[cfg(any(feature = "KHR_texture_transform", feature = "EXT_texture_webp"))]
use crate::{extras::Extras, validation::Validate};
#[cfg(feature = "EXT_texture_webp")]
use crate::{image, Index};

use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
Expand All @@ -19,6 +22,21 @@ pub struct Texture {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,

#[cfg(feature = "EXT_texture_webp")]
#[serde(
default,
rename = "EXT_texture_webp",
skip_serializing_if = "Option::is_none"
)]
pub texture_webp: Option<TextureWebp>,
}

#[cfg(feature = "EXT_texture_webp")]
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct TextureWebp {
/// The index of the webp image used by the texture.
pub source: Index<image::Image>,
}

#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
Expand Down
7 changes: 6 additions & 1 deletion gltf-json/src/image.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,12 @@ use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};

/// All valid MIME types.
pub const VALID_MIME_TYPES: &[&str] = &["image/jpeg", "image/png"];
pub const VALID_MIME_TYPES: &[&str] = &[
"image/jpeg",
"image/png",
#[cfg(feature = "EXT_texture_webp")]
"image/webp",
];

/// Image data used to create a texture.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
Expand Down
32 changes: 30 additions & 2 deletions gltf-json/src/texture.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
use crate::extensions::texture;
use crate::validation::{Checked, Validate};
use crate::{extensions, image, Extras, Index};
use gltf_derive::Validate;
Expand Down Expand Up @@ -179,7 +180,7 @@ where
P: Fn() -> crate::Path,
R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
{
if cfg!(feature = "allow_empty_texture") {
if cfg!(any(feature = "allow_empty_texture",)) {
if !source_is_empty(source) {
source.validate(root, path, report);
}
Expand Down Expand Up @@ -217,6 +218,27 @@ pub struct Texture {
pub extras: Extras,
}

impl Texture {
/// The index of the image used by this texture.
pub fn primary_source(&self) -> Index<image::Image> {
#[allow(unused_mut)]
let mut source = self.source;
#[cfg(feature = "EXT_texture_webp")]
{
if let Some(texture_webp) = &self.extensions {
if let Some(texture_webp) = &texture_webp.texture_webp {
// Only use the webp source if the source is not empty
// Otherwise, fallback to whatever was there originally
if !source_is_empty(&texture_webp.source) {
source = texture_webp.source;
}
}
}
}
source
}
}

impl Validate for Texture {
fn validate<P, R>(&self, root: &crate::Root, path: P, report: &mut R)
where
Expand All @@ -227,7 +249,13 @@ impl Validate for Texture {
.validate(root, || path().field("sampler"), report);
self.extensions
.validate(root, || path().field("extensions"), report);
source_validate(&self.source, root, || path().field("source"), report);

source_validate(
&self.primary_source(),
root,
|| path().field("source"),
report,
);
}
}

Expand Down
12 changes: 12 additions & 0 deletions src/import.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use std::borrow::Cow;
use std::{fs, io};

use crate::{Document, Error, Gltf, Result};
#[cfg(feature = "EXT_texture_webp")]
use image_crate::ImageFormat::WebP;
use image_crate::ImageFormat::{Jpeg, Png};
use std::path::Path;

Expand Down Expand Up @@ -148,6 +150,8 @@ impl image::Data {
let guess_format = |encoded_image: &[u8]| match image_crate::guess_format(encoded_image) {
Ok(image_crate::ImageFormat::Png) => Some(Png),
Ok(image_crate::ImageFormat::Jpeg) => Some(Jpeg),
#[cfg(feature = "EXT_texture_webp")]
Ok(image_crate::ImageFormat::WebP) => Some(WebP),
_ => None,
};
#[cfg(not(feature = "guess_mime_type"))]
Expand All @@ -159,6 +163,8 @@ impl image::Data {
let encoded_format = match annoying_case {
"image/png" => Png,
"image/jpeg" => Jpeg,
#[cfg(feature = "EXT_texture_webp")]
"image/webp" => WebP,
_ => match guess_format(&encoded_image) {
Some(format) => format,
None => return Err(Error::UnsupportedImageEncoding),
Expand All @@ -173,13 +179,17 @@ impl image::Data {
let encoded_format = match mime_type {
Some("image/png") => Png,
Some("image/jpeg") => Jpeg,
#[cfg(feature = "EXT_texture_webp")]
Some("image/webp") => WebP,
Some(_) => match guess_format(&encoded_image) {
Some(format) => format,
None => return Err(Error::UnsupportedImageEncoding),
},
None => match uri.rsplit('.').next() {
Some("png") => Png,
Some("jpg") | Some("jpeg") => Jpeg,
#[cfg(feature = "EXT_texture_webp")]
Some("webp") => WebP,
_ => match guess_format(&encoded_image) {
Some(format) => format,
None => return Err(Error::UnsupportedImageEncoding),
Expand All @@ -197,6 +207,8 @@ impl image::Data {
let encoded_format = match mime_type {
"image/png" => Png,
"image/jpeg" => Jpeg,
#[cfg(feature = "EXT_texture_webp")]
"image/webp" => WebP,
_ => match guess_format(encoded_image) {
Some(format) => format,
None => return Err(Error::UnsupportedImageEncoding),
Expand Down
4 changes: 2 additions & 2 deletions src/texture.rs
Original file line number Diff line number Diff line change
Expand Up @@ -160,7 +160,7 @@ impl<'a> Texture<'a> {
/// Returns the image used by this texture.
#[cfg(feature = "allow_empty_texture")]
pub fn source(&self) -> Option<image::Image<'a>> {
let index = self.json.source.value();
let index = self.json.primary_source().value();
if index == u32::MAX as usize {
None
} else {
Expand All @@ -173,7 +173,7 @@ impl<'a> Texture<'a> {
pub fn source(&self) -> image::Image<'a> {
self.document
.images()
.nth(self.json.source.value())
.nth(self.json.primary_source().value())
.unwrap()
}

Expand Down
Loading