Vendor dependencies for 0.3.0 release

This commit is contained in:
2025-09-27 10:29:08 -05:00
parent 0c8d39d483
commit 82ab7f317b
26803 changed files with 16134934 additions and 0 deletions

1
vendor/gltf-json/.cargo-checksum.json vendored Normal file
View File

@@ -0,0 +1 @@
{"files":{"Cargo.toml":"111962f25283be97ac1d7e23df377a2f75bcc118d3604336c31a25e0904cd973","LICENSE-APACHE":"3708458dee7f359ac6c9c5558023ed481be87e5372c43ebd7f2ca7ad23c12026","LICENSE-MIT":"0e6c282dfcb08a031c37b8f851fe5813fad63612e88a29dbe5121d727d67bbf2","src/accessor.rs":"97cfe9f774a292abc443c32cea810ac2403415487af24c6aa304fa99a4f1378a","src/animation.rs":"f42b916dafd2e9f023567dfe494bac9d2f7343a13bcccd25a2ba9ea308f120d8","src/asset.rs":"732098569f12c23dd5e485a75a5967e1c3f5a112b0c1928b30f8a27fe1a0f5ad","src/buffer.rs":"c23fc2c5359664c768a50fb578a171a5af42e1eb77a2d79ee7a9cfea2e3a6006","src/camera.rs":"f9a44e7cf0048b3c87e7a131ef473dd83646db3043d2e99a8891ce92ff56828d","src/extensions/accessor.rs":"4e3dc2a9c056b4b9a20bfb66997018ae2b4ac548fdd879634bcd33157e009ac5","src/extensions/animation.rs":"125434b3c7c59a05d087f890e68b031508c7ba19000920099070a5f8fc4ab0e0","src/extensions/asset.rs":"bac398d09c75d0e8b54de1cc2fb8b9440bf06bd77d4c767b313ce29a106a9581","src/extensions/buffer.rs":"0fa09d502fb76bff3c41fd8b896d9e08823b4ef503a145d7a68dd6d19dd7ea2b","src/extensions/camera.rs":"9c2672c34a91f961d4251795f03dbd54410d784923f08628b674db6bc67b21cb","src/extensions/image.rs":"9efe5ba8055304edee1e29771955be4a491d842aee6d91925c8d9f73570f8af2","src/extensions/material.rs":"9c6e6d972a93f40e0a9587111733ff5d7b7dbe3b527f0bb6657049067d2562d5","src/extensions/mesh.rs":"e79e027e0699c071bc53074676fcb6e54b15a7569576998d300ebfda2f9b6180","src/extensions/mod.rs":"b676e86d30094d6a0ceacf17b19921818008c29d1d6d300099c8587e1b5da66d","src/extensions/root.rs":"8a225d3f5186e9be6371a84606e3657521cbe4e0f10c265a6a76cfc9236071d8","src/extensions/scene.rs":"16dacefbf7e3eb64c69cb47faf1cedcf5042acd6e4aa586a3b86a81440274dcb","src/extensions/skin.rs":"4ec0aa67a4067fc70c83335bc93839a8447edecfeba071416633b4bf939dbae9","src/extensions/texture.rs":"50674d05e6b0e369b6c1050f0437654243686e1dc180f5576273f9afd53d9ea2","src/extras.rs":"df7fa225aa0d646c73d2d5b648df910633110615f459bbd98fbd4fe2688f34aa","src/image.rs":"035494246a856adad3ffb79c3d8fabad55bf5c9f3dc132f6e57ff7fa29d6667c","src/lib.rs":"5acbbf5e73ccd85011d4a17316bb55ec29b949b6e4f1f168af5ebebc0c28fd58","src/material.rs":"8f3c236581f082e95f46958c40de3373bd0a2761d496f890d358dfc759c43786","src/mesh.rs":"c83141a98271b5a08b11eaa4de72a39bc4dcf6efb5091882f71db02e1b0113c1","src/path.rs":"084052509ee4f4fb23c57eda104bd0cd6da1f0120dc4908b84f2cbb6d64b3aa0","src/root.rs":"dc2ab6e0d96b9b3a16c3cf99630d919dc415495c180afaa405d16cd97623e6cf","src/scene.rs":"e4cb09ffcd08b9c02b1ce0fae5452fc46a9058e7a341255a6587f5ee9f45f13f","src/skin.rs":"9b4edc4672e99f54f91e14b0d4bfea63d4ecdb496c7957fcc66eb70dcbb8ad8c","src/texture.rs":"a8026ba6c77d2647aef98aee821d11c130b76804fbea4c7b6e2b39dd052b45f1","src/validation.rs":"efda43d3371d995dab67fa5b41a0fd83fe9466169565d6f6a202eaaa62cdcb4f","tests/minimal_accessor_invalid.gltf":"a723016163c75a905f128b0b16994d1d72424cbc6b1332ed77f5797fc04d74c7","tests/non_sparse_accessor_without_buffer_view.gltf":"f28cf8bec4e6a3db981573ca3fd72feb3af8f386c404a43a852018909fca22c5","tests/test_validation.rs":"7ed7ac327a6d9c10d32e301cd127daa04db3b57884edd6e500202cfe39e61767"},"package":"e6176f9d60a7eab0a877e8e96548605dedbde9190a7ae1e80bbcc1c9af03ab14"}

50
vendor/gltf-json/Cargo.toml vendored Normal file
View File

@@ -0,0 +1,50 @@
# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO
#
# When uploading crates to the registry Cargo will automatically
# "normalize" Cargo.toml files for maximal compatibility
# with all versions of Cargo and also rewrite `path` dependencies
# to registry (e.g., crates.io) dependencies.
#
# If you are reading this file be aware that the original Cargo.toml
# will likely look very different (and much more reasonable).
# See Cargo.toml.orig for the original contents.
[package]
edition = "2021"
rust-version = "1.61"
name = "gltf-json"
version = "1.4.1"
authors = ["David Harvey-Macaulay <alteous@outlook.com>"]
description = "JSON parsing for the gltf crate"
license = "MIT OR Apache-2.0"
repository = "https://github.com/gltf-rs/gltf"
[dependencies.gltf-derive]
version = "=1.4.1"
[dependencies.serde]
version = "1.0"
[dependencies.serde_derive]
version = "1.0"
[dependencies.serde_json]
version = "1.0"
features = ["raw_value"]
[features]
KHR_lights_punctual = []
KHR_materials_emissive_strength = []
KHR_materials_ior = []
KHR_materials_pbrSpecularGlossiness = []
KHR_materials_specular = []
KHR_materials_transmission = []
KHR_materials_unlit = []
KHR_materials_variants = []
KHR_materials_volume = []
KHR_texture_transform = []
allow_empty_texture = []
default = []
extensions = []
extras = []
names = []

202
vendor/gltf-json/LICENSE-APACHE vendored Normal file
View File

@@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

26
vendor/gltf-json/LICENSE-MIT vendored Normal file
View File

@@ -0,0 +1,26 @@
Copyright (c) 2017 The gltf Library Developers
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

423
vendor/gltf-json/src/accessor.rs vendored Normal file
View File

@@ -0,0 +1,423 @@
use crate::validation::{Checked, Error, USize64};
use crate::{buffer, extensions, Extras, Index, Path, Root};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use serde_json::Value;
use std::fmt;
/// The component data type.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
pub enum ComponentType {
/// Corresponds to `GL_BYTE`.
I8 = 1,
/// Corresponds to `GL_UNSIGNED_BYTE`.
U8,
/// Corresponds to `GL_SHORT`.
I16,
/// Corresponds to `GL_UNSIGNED_SHORT`.
U16,
/// Corresponds to `GL_UNSIGNED_INT`.
U32,
/// Corresponds to `GL_FLOAT`.
F32,
}
/// Specifies whether an attribute, vector, or matrix.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
pub enum Type {
/// Scalar quantity.
Scalar = 1,
/// 2D vector.
Vec2,
/// 3D vector.
Vec3,
/// 4D vector.
Vec4,
/// 2x2 matrix.
Mat2,
/// 3x3 matrix.
Mat3,
/// 4x4 matrix.
Mat4,
}
/// Corresponds to `GL_BYTE`.
pub const BYTE: u32 = 5120;
/// Corresponds to `GL_UNSIGNED_BYTE`.
pub const UNSIGNED_BYTE: u32 = 5121;
/// Corresponds to `GL_SHORT`.
pub const SHORT: u32 = 5122;
/// Corresponds to `GL_UNSIGNED_SHORT`.
pub const UNSIGNED_SHORT: u32 = 5123;
/// Corresponds to `GL_UNSIGNED_INT`.
pub const UNSIGNED_INT: u32 = 5125;
/// Corresponds to `GL_FLOAT`.
pub const FLOAT: u32 = 5126;
/// All valid generic vertex attribute component types.
pub const VALID_COMPONENT_TYPES: &[u32] = &[
BYTE,
UNSIGNED_BYTE,
SHORT,
UNSIGNED_SHORT,
UNSIGNED_INT,
FLOAT,
];
/// All valid index component types.
pub const VALID_INDEX_TYPES: &[u32] = &[UNSIGNED_BYTE, UNSIGNED_SHORT, UNSIGNED_INT];
/// All valid accessor types.
pub const VALID_ACCESSOR_TYPES: &[&str] =
&["SCALAR", "VEC2", "VEC3", "VEC4", "MAT2", "MAT3", "MAT4"];
/// Contains data structures for sparse storage.
pub mod sparse {
use super::*;
use crate::extensions;
/// Indices of those attributes that deviate from their initialization value.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Indices {
/// The parent buffer view containing the sparse indices.
///
/// The referenced buffer view must not have `ARRAY_BUFFER` nor
/// `ELEMENT_ARRAY_BUFFER` as its target.
#[serde(rename = "bufferView")]
pub buffer_view: Index<buffer::View>,
/// The offset relative to the start of the parent `BufferView` in bytes.
#[serde(default, rename = "byteOffset")]
pub byte_offset: USize64,
/// The data type of each index.
#[serde(rename = "componentType")]
pub component_type: Checked<IndexComponentType>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::accessor::sparse::Indices>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// Sparse storage of attributes that deviate from their initialization value.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Sparse {
/// The number of attributes encoded in this sparse accessor.
pub count: USize64,
/// Index array of size `count` that points to those accessor attributes
/// that deviate from their initialization value.
///
/// Indices must strictly increase.
pub indices: Indices,
/// Array of size `count * number_of_components` storing the displaced
/// accessor attributes pointed by `indices`.
///
/// Substituted values must have the same `component_type` and number of
/// components as the base `Accessor`.
pub values: Values,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::accessor::sparse::Sparse>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// Array of size `count * number_of_components` storing the displaced
/// accessor attributes pointed by `accessor::sparse::Indices`.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Values {
/// The parent buffer view containing the sparse indices.
///
/// The referenced buffer view must not have `ARRAY_BUFFER` nor
/// `ELEMENT_ARRAY_BUFFER` as its target.
#[serde(rename = "bufferView")]
pub buffer_view: Index<buffer::View>,
/// The offset relative to the start of the parent buffer view in bytes.
#[serde(default, rename = "byteOffset")]
pub byte_offset: USize64,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::accessor::sparse::Values>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
}
/// A typed view into a buffer view.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[gltf(validate_hook = "accessor_validate_hook")]
pub struct Accessor {
/// The parent buffer view this accessor reads from.
///
/// This field can be omitted in sparse accessors.
#[serde(rename = "bufferView")]
#[serde(skip_serializing_if = "Option::is_none")]
pub buffer_view: Option<Index<buffer::View>>,
/// The offset relative to the start of the parent `BufferView` in bytes.
///
/// This field can be omitted in sparse accessors.
#[serde(default, rename = "byteOffset")]
#[serde(skip_serializing_if = "Option::is_none")]
pub byte_offset: Option<USize64>,
/// The number of components within the buffer view - not to be confused
/// with the number of bytes in the buffer view.
pub count: USize64,
/// The data type of components in the attribute.
#[serde(rename = "componentType")]
pub component_type: Checked<GenericComponentType>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::accessor::Accessor>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Specifies if the attribute is a scalar, vector, or matrix.
#[serde(rename = "type")]
pub type_: Checked<Type>,
/// Minimum value of each component in this attribute.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub min: Option<Value>,
/// Maximum value of each component in this attribute.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub max: Option<Value>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// Specifies whether integer data values should be normalized.
#[serde(default, skip_serializing_if = "is_normalized_default")]
pub normalized: bool,
/// Sparse storage of attributes that deviate from their initialization
/// value.
#[serde(default)]
#[serde(skip_serializing_if = "Option::is_none")]
pub sparse: Option<sparse::Sparse>,
}
fn accessor_validate_hook<P, R>(accessor: &Accessor, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if accessor.sparse.is_none() && accessor.buffer_view.is_none() {
// If sparse is missing, then bufferView must be present. Report that bufferView is
// missing since it is the more common one to require.
report(&|| path().field("bufferView"), Error::Missing);
}
}
// Help serde avoid serializing this glTF 2.0 default value.
fn is_normalized_default(b: &bool) -> bool {
!*b
}
/// The data type of an index.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct IndexComponentType(pub ComponentType);
/// The data type of a generic vertex attribute.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct GenericComponentType(pub ComponentType);
impl<'de> de::Deserialize<'de> for Checked<GenericComponentType> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<GenericComponentType>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_COMPONENT_TYPES)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::ComponentType::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
BYTE => Valid(GenericComponentType(I8)),
UNSIGNED_BYTE => Valid(GenericComponentType(U8)),
SHORT => Valid(GenericComponentType(I16)),
UNSIGNED_SHORT => Valid(GenericComponentType(U16)),
UNSIGNED_INT => Valid(GenericComponentType(U32)),
FLOAT => Valid(GenericComponentType(F32)),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl<'de> de::Deserialize<'de> for Checked<IndexComponentType> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<IndexComponentType>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_INDEX_TYPES)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::ComponentType::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
UNSIGNED_BYTE => Valid(IndexComponentType(U8)),
UNSIGNED_SHORT => Valid(IndexComponentType(U16)),
UNSIGNED_INT => Valid(IndexComponentType(U32)),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl<'de> de::Deserialize<'de> for Checked<Type> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Type>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_ACCESSOR_TYPES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Type::*;
use crate::validation::Checked::*;
Ok(match value {
"SCALAR" => Valid(Scalar),
"VEC2" => Valid(Vec2),
"VEC3" => Valid(Vec3),
"VEC4" => Valid(Vec4),
"MAT2" => Valid(Mat2),
"MAT3" => Valid(Mat3),
"MAT4" => Valid(Mat4),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_str(match *self {
Type::Scalar => "SCALAR",
Type::Vec2 => "VEC2",
Type::Vec3 => "VEC3",
Type::Vec4 => "VEC4",
Type::Mat2 => "MAT2",
Type::Mat3 => "MAT3",
Type::Mat4 => "MAT4",
})
}
}
impl ComponentType {
/// Returns the number of bytes this value represents.
pub fn size(&self) -> usize {
use self::ComponentType::*;
match *self {
I8 | U8 => 1,
I16 | U16 => 2,
F32 | U32 => 4,
}
}
/// Returns the corresponding `GLenum`.
pub fn as_gl_enum(self) -> u32 {
match self {
ComponentType::I8 => BYTE,
ComponentType::U8 => UNSIGNED_BYTE,
ComponentType::I16 => SHORT,
ComponentType::U16 => UNSIGNED_SHORT,
ComponentType::U32 => UNSIGNED_INT,
ComponentType::F32 => FLOAT,
}
}
}
impl ser::Serialize for ComponentType {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u32(self.as_gl_enum())
}
}
impl Type {
/// Returns the equivalent number of scalar quantities this type represents.
pub fn multiplicity(&self) -> usize {
use self::Type::*;
match *self {
Scalar => 1,
Vec2 => 2,
Vec3 => 3,
Vec4 | Mat2 => 4,
Mat3 => 9,
Mat4 => 16,
}
}
}

263
vendor/gltf-json/src/animation.rs vendored Normal file
View File

@@ -0,0 +1,263 @@
use crate::validation::{Checked, Error, Validate};
use crate::{accessor, extensions, scene, Extras, Index, Path, Root};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// All valid animation interpolation algorithms.
pub const VALID_INTERPOLATIONS: &[&str] = &["LINEAR", "STEP", "CUBICSPLINE"];
/// All valid animation property names.
pub const VALID_PROPERTIES: &[&str] = &["translation", "rotation", "scale", "weights"];
/// Specifies an interpolation algorithm.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
pub enum Interpolation {
/// Linear interpolation.
///
/// The animated values are linearly interpolated between keyframes.
/// When targeting a rotation, spherical linear interpolation (slerp) should be
/// used to interpolate quaternions. The number output of elements must equal
/// the number of input elements.
Linear = 1,
/// Step interpolation.
///
/// The animated values remain constant to the output of the first keyframe,
/// until the next keyframe. The number of output elements must equal the number
/// of input elements.
Step,
/// Cubic spline interpolation.
///
/// The animation's interpolation is computed using a cubic spline with specified
/// tangents. The number of output elements must equal three times the number of
/// input elements. For each input element, the output stores three elements, an
/// in-tangent, a spline vertex, and an out-tangent. There must be at least two
/// keyframes when using this interpolation
CubicSpline,
}
/// Specifies a property to animate.
#[derive(Clone, Copy, Debug, Eq, PartialEq, Deserialize)]
pub enum Property {
/// XYZ translation vector.
Translation = 1,
/// XYZW rotation quaternion.
Rotation,
/// XYZ scale vector.
Scale,
/// Weights of morph targets.
MorphTargetWeights,
}
/// A keyframe animation.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Animation {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::animation::Animation>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// An array of channels, each of which targets an animation's sampler at a
/// node's property.
///
/// Different channels of the same animation must not have equal targets.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub channels: Vec<Channel>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// An array of samplers that combine input and output accessors with an
/// interpolation algorithm to define a keyframe graph (but not its target).
#[serde(skip_serializing_if = "Vec::is_empty")]
pub samplers: Vec<Sampler>,
}
/// Targets an animation's sampler at a node's property.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Channel {
/// The index of a sampler in this animation used to compute the value for the
/// target.
pub sampler: Index<Sampler>,
/// The index of the node and TRS property to target.
pub target: Target,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::animation::Channel>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// The index of the node and TRS property that an animation channel targets.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Target {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::animation::Target>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// The index of the node to target.
pub node: Index<scene::Node>,
/// The name of the node's property to modify or the 'weights' of the
/// morph targets it instantiates.
pub path: Checked<Property>,
}
/// Defines a keyframe graph but not its target.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Sampler {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::animation::Sampler>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// The index of an accessor containing keyframe input values, e.g., time.
pub input: Index<accessor::Accessor>,
/// The interpolation algorithm.
#[serde(default)]
pub interpolation: Checked<Interpolation>,
/// The index of an accessor containing keyframe output values.
pub output: Index<accessor::Accessor>,
}
impl Validate for Animation {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
self.samplers
.validate(root, || path().field("samplers"), report);
for (index, channel) in self.channels.iter().enumerate() {
if channel.sampler.value() >= self.samplers.len() {
let path = || path().field("channels").index(index).field("sampler");
report(&path, Error::IndexOutOfBounds);
}
}
}
}
impl Default for Interpolation {
fn default() -> Self {
Interpolation::Linear
}
}
impl<'de> de::Deserialize<'de> for Checked<Interpolation> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Interpolation>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_INTERPOLATIONS)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Interpolation::*;
use crate::validation::Checked::*;
Ok(match value {
"LINEAR" => Valid(Linear),
"STEP" => Valid(Step),
"CUBICSPLINE" => Valid(CubicSpline),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Interpolation {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_str(match *self {
Interpolation::Linear => "LINEAR",
Interpolation::Step => "STEP",
Interpolation::CubicSpline => "CUBICSPLINE",
})
}
}
impl<'de> de::Deserialize<'de> for Checked<Property> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Property>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_PROPERTIES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Property::*;
use crate::validation::Checked::*;
Ok(match value {
"translation" => Valid(Translation),
"rotation" => Valid(Rotation),
"scale" => Valid(Scale),
"weights" => Valid(MorphTargetWeights),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Property {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_str(match *self {
Property::Translation => "translation",
Property::Rotation => "rotation",
Property::Scale => "scale",
Property::MorphTargetWeights => "weights",
})
}
}

46
vendor/gltf-json/src/asset.rs vendored Normal file
View File

@@ -0,0 +1,46 @@
use crate::{extensions, Extras};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
/// Metadata about the glTF asset.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Asset {
/// A copyright message suitable for display to credit the content creator.
#[serde(skip_serializing_if = "Option::is_none")]
pub copyright: Option<String>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::asset::Asset>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Tool that generated this glTF model.
#[serde(skip_serializing_if = "Option::is_none")]
pub generator: Option<String>,
/// The minimum glTF version that this asset targets.
#[serde(rename = "minVersion")]
#[serde(skip_serializing_if = "Option::is_none")]
pub min_version: Option<String>,
/// The glTF version of this asset.
pub version: String,
}
impl Default for Asset {
fn default() -> Self {
Self {
copyright: None,
extensions: Default::default(),
extras: Default::default(),
generator: None,
min_version: None,
version: "2.0".to_string(),
}
}
}

165
vendor/gltf-json/src/buffer.rs vendored Normal file
View File

@@ -0,0 +1,165 @@
use crate::validation::{Checked, Error, USize64, Validate};
use crate::{extensions, Extras, Index, Path, Root};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// Corresponds to `GL_ARRAY_BUFFER`.
pub const ARRAY_BUFFER: u32 = 34_962;
/// Corresponds to `GL_ELEMENT_ARRAY_BUFFER`.
pub const ELEMENT_ARRAY_BUFFER: u32 = 34_963;
/// The minimum byte stride.
pub const MIN_BYTE_STRIDE: usize = 4;
/// The maximum byte stride.
pub const MAX_BYTE_STRIDE: usize = 252;
/// All valid GPU buffer targets.
pub const VALID_TARGETS: &[u32] = &[ARRAY_BUFFER, ELEMENT_ARRAY_BUFFER];
/// Specifies the target a GPU buffer should be bound to.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Target {
/// Corresponds to `GL_ARRAY_BUFFER`.
ArrayBuffer = 1,
/// Corresponds to `GL_ELEMENT_ARRAY_BUFFER`.
ElementArrayBuffer,
}
impl ser::Serialize for Target {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
Target::ArrayBuffer => serializer.serialize_u32(ARRAY_BUFFER),
Target::ElementArrayBuffer => serializer.serialize_u32(ELEMENT_ARRAY_BUFFER),
}
}
}
/// Distance between individual items in a buffer view, measured in bytes.
#[derive(Clone, Copy, Debug, Default, Deserialize, Eq, Hash, PartialEq, Serialize)]
pub struct Stride(pub usize);
impl Validate for Stride {
fn validate<P, R>(&self, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if self.0 < MIN_BYTE_STRIDE || self.0 > MAX_BYTE_STRIDE {
report(&path, Error::Invalid);
}
}
}
/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Buffer {
/// The length of the buffer in bytes.
#[serde(default, rename = "byteLength")]
pub byte_length: USize64,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The uri of the buffer. Relative paths are relative to the .gltf file.
/// Instead of referencing an external file, the uri can also be a data-uri.
#[serde(skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::buffer::Buffer>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// A view into a buffer generally representing a subset of the buffer.
///
/// <https://github.com/KhronosGroup/glTF/tree/master/specification/2.0#reference-bufferview>
///
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct View {
/// The parent `Buffer`.
pub buffer: Index<Buffer>,
/// The length of the `BufferView` in bytes.
#[serde(rename = "byteLength")]
pub byte_length: USize64,
/// Offset into the parent buffer in bytes.
#[serde(
default,
rename = "byteOffset",
skip_serializing_if = "Option::is_none"
)]
pub byte_offset: Option<USize64>,
/// The stride in bytes between vertex attributes or other interleavable data.
///
/// When zero, data is assumed to be tightly packed.
#[serde(rename = "byteStride")]
#[serde(skip_serializing_if = "Option::is_none")]
pub byte_stride: Option<Stride>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// Optional target the buffer should be bound to.
#[serde(skip_serializing_if = "Option::is_none")]
pub target: Option<Checked<Target>>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::buffer::View>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
impl<'de> de::Deserialize<'de> for Checked<Target> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Target>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_TARGETS)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Target::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
ARRAY_BUFFER => Valid(ArrayBuffer),
ELEMENT_ARRAY_BUFFER => Valid(ElementArrayBuffer),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}

163
vendor/gltf-json/src/camera.rs vendored Normal file
View File

@@ -0,0 +1,163 @@
use crate::validation::{Checked, Error};
use crate::{extensions, Extras, Path, Root};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// All valid camera types.
pub const VALID_CAMERA_TYPES: &[&str] = &["perspective", "orthographic"];
/// Specifies the camera type.
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Type {
/// A perspective projection.
Perspective = 1,
/// An orthographic projection.
Orthographic,
}
/// A camera's projection.
///
/// A node can reference a camera to apply a transform to place the camera in the
/// scene.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[gltf(validate_hook = "camera_validate_hook")]
pub struct Camera {
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// An orthographic camera containing properties to create an orthographic
/// projection matrix.
#[serde(skip_serializing_if = "Option::is_none")]
pub orthographic: Option<Orthographic>,
/// A perspective camera containing properties to create a perspective
/// projection matrix.
#[serde(skip_serializing_if = "Option::is_none")]
pub perspective: Option<Perspective>,
/// Specifies if the camera uses a perspective or orthographic projection.
#[serde(rename = "type")]
pub type_: Checked<Type>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::camera::Camera>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
fn camera_validate_hook<P, R>(camera: &Camera, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if camera.orthographic.is_none() && camera.perspective.is_none() {
report(&path, Error::Missing);
}
}
/// Values for an orthographic camera.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Orthographic {
/// The horizontal magnification of the view.
pub xmag: f32,
/// The vertical magnification of the view.
pub ymag: f32,
/// The distance to the far clipping plane.
pub zfar: f32,
/// The distance to the near clipping plane.
pub znear: f32,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::camera::Orthographic>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// Values for a perspective camera.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Perspective {
/// Aspect ratio of the field of view.
#[serde(rename = "aspectRatio")]
#[serde(skip_serializing_if = "Option::is_none")]
pub aspect_ratio: Option<f32>,
/// The vertical field of view in radians.
pub yfov: f32,
/// The distance to the far clipping plane.
#[serde(skip_serializing_if = "Option::is_none")]
pub zfar: Option<f32>,
/// The distance to the near clipping plane.
pub znear: f32,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::camera::Perspective>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
impl<'de> de::Deserialize<'de> for Checked<Type> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Type>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_CAMERA_TYPES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Type::*;
use crate::validation::Checked::*;
Ok(match value {
"perspective" => Valid(Perspective),
"orthographic" => Valid(Orthographic),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
Type::Perspective => serializer.serialize_str("perspective"),
Type::Orthographic => serializer.serialize_str("orthographic"),
}
}
}

View File

@@ -0,0 +1,30 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// Contains data structures for sparse storage.
pub mod sparse {
use super::*;
/// Indices of those attributes that deviate from their initialization value.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Indices {}
/// Sparse storage of attributes that deviate from their initialization value.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Sparse {}
/// Array of size `count * number_of_components` storing the displaced
/// accessor attributes pointed by `accessor::sparse::Indices`.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Values {}
}
/// A typed view into a buffer view.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Accessor {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

View File

@@ -0,0 +1,24 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// A keyframe animation.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Animation {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Targets an animation's sampler at a node's property.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Channel {}
/// The index of the node and TRS property that an animation channel targets.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Target {}
/// Defines a keyframe graph but not its target.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Sampler {}

View File

@@ -0,0 +1,6 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
/// Metadata about the glTF asset.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Asset {}

View File

@@ -0,0 +1,20 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// A buffer points to binary data representing geometry, animations, or skins.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Buffer {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// A view into a buffer generally representing a subset of the buffer.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct View {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

View File

@@ -0,0 +1,31 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// A camera's projection.
///
/// A node can reference a camera to apply a transform to place the camera in the
/// scene.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Camera {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Values for an orthographic camera.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Orthographic {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Values for a perspective camera.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Perspective {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

View File

@@ -0,0 +1,12 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// Image data used to create a texture.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Image {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

View File

@@ -0,0 +1,417 @@
#[allow(unused_imports)] // different features use different imports
use crate::{material::StrengthFactor, texture, validation::Validate, Extras};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// The material appearance of a primitive.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Material {
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
#[serde(
default,
rename = "KHR_materials_pbrSpecularGlossiness",
skip_serializing_if = "Option::is_none"
)]
pub pbr_specular_glossiness: Option<PbrSpecularGlossiness>,
#[cfg(feature = "KHR_materials_unlit")]
#[serde(
default,
rename = "KHR_materials_unlit",
skip_serializing_if = "Option::is_none"
)]
pub unlit: Option<Unlit>,
#[cfg(feature = "KHR_materials_transmission")]
#[serde(
default,
rename = "KHR_materials_transmission",
skip_serializing_if = "Option::is_none"
)]
pub transmission: Option<Transmission>,
#[cfg(feature = "KHR_materials_volume")]
#[serde(
default,
rename = "KHR_materials_volume",
skip_serializing_if = "Option::is_none"
)]
pub volume: Option<Volume>,
#[cfg(feature = "KHR_materials_specular")]
#[serde(
default,
rename = "KHR_materials_specular",
skip_serializing_if = "Option::is_none"
)]
pub specular: Option<Specular>,
#[cfg(feature = "KHR_materials_ior")]
#[serde(
default,
rename = "KHR_materials_ior",
skip_serializing_if = "Option::is_none"
)]
pub ior: Option<Ior>,
#[cfg(feature = "KHR_materials_emissive_strength")]
#[serde(
default,
rename = "KHR_materials_emissive_strength",
skip_serializing_if = "Option::is_none"
)]
pub emissive_strength: Option<EmissiveStrength>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct PbrMetallicRoughness {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// A set of parameter values that are used to define the specular-glossiness
/// material model from Physically-Based Rendering (PBR) methodology.
///
/// This model supports more materials than metallic-roughness, at the cost of
/// increased memory use. When both are available, specular-glossiness should be
/// preferred.
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct PbrSpecularGlossiness {
/// The material's diffuse factor.
///
/// The RGBA components of the reflected diffuse color of the
/// material. Metals have a diffuse value of `[0.0, 0.0, 0.0]`. The fourth
/// component (A) is the alpha coverage of the material. The `alphaMode`
/// property specifies how alpha is interpreted. The values are linear.
pub diffuse_factor: PbrDiffuseFactor,
/// The diffuse texture.
///
/// This texture contains RGB(A) components of the reflected diffuse color
/// of the material in sRGB color space. If the fourth component (A) is
/// present, it represents the alpha coverage of the material. Otherwise, an
/// alpha of 1.0 is assumed. The `alphaMode` property specifies how alpha is
/// interpreted. The stored texels must not be premultiplied.
#[serde(skip_serializing_if = "Option::is_none")]
pub diffuse_texture: Option<texture::Info>,
/// The material's specular factor.
pub specular_factor: PbrSpecularFactor,
/// The glossiness or smoothness of the material.
///
/// A value of 1.0 means the material has full glossiness or is perfectly
/// smooth. A value of 0.0 means the material has no glossiness or is
/// completely rough. This value is linear.
pub glossiness_factor: StrengthFactor,
/// The specular-glossiness texture.
///
/// A RGBA texture, containing the specular color of the material (RGB
/// components) and its glossiness (A component). The values are in sRGB
/// space.
#[serde(skip_serializing_if = "Option::is_none")]
pub specular_glossiness_texture: Option<texture::Info>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// Defines the normal texture of a material.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct NormalTexture {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Defines the occlusion texture of a material.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct OcclusionTexture {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// The diffuse factor of a material.
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrDiffuseFactor(pub [f32; 4]);
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl Default for PbrDiffuseFactor {
fn default() -> Self {
PbrDiffuseFactor([1.0, 1.0, 1.0, 1.0])
}
}
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl Validate for PbrDiffuseFactor {}
/// The specular factor of a material.
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrSpecularFactor(pub [f32; 3]);
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl Default for PbrSpecularFactor {
fn default() -> Self {
PbrSpecularFactor([1.0, 1.0, 1.0])
}
}
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
impl Validate for PbrSpecularFactor {}
/// Empty struct that should be present for primitives which should not be shaded with the PBR shading model.
#[cfg(feature = "KHR_materials_unlit")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Unlit {}
/// A number in the inclusive range [0.0, 1.0] with a default value of 0.0.
#[cfg(feature = "KHR_materials_transmission")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct TransmissionFactor(pub f32);
#[cfg(feature = "KHR_materials_transmission")]
impl Default for TransmissionFactor {
fn default() -> Self {
TransmissionFactor(0.0)
}
}
#[cfg(feature = "KHR_materials_transmission")]
impl Validate for TransmissionFactor {}
#[cfg(feature = "KHR_materials_transmission")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct Transmission {
/// The base percentage of light that is transmitted through the surface.
///
/// The amount of light that is transmitted by the surface rather than diffusely re-emitted.
/// This is a percentage of all the light that penetrates a surface (i.e. isnt specularly reflected)
/// rather than a percentage of the total light that hits a surface.
/// A value of 1.0 means that 100% of the light that penetrates the surface is transmitted through.
pub transmission_factor: TransmissionFactor,
/// The transmission texture.
///
/// The R channel of this texture defines the amount of light that is transmitted by the surface
/// rather than diffusely re-emitted. A value of 1.0 in the red channel means that 100% of the light
/// that penetrates the surface (i.e. isnt specularly reflected) is transmitted through.
/// The value is linear and is multiplied by the transmissionFactor to determine the total transmission value.
#[serde(skip_serializing_if = "Option::is_none")]
pub transmission_texture: Option<texture::Info>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// A positive number with default value of 1.5
#[cfg(feature = "KHR_materials_ior")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct IndexOfRefraction(pub f32);
#[cfg(feature = "KHR_materials_ior")]
impl Default for IndexOfRefraction {
fn default() -> Self {
IndexOfRefraction(1.5)
}
}
#[cfg(feature = "KHR_materials_ior")]
impl Validate for IndexOfRefraction {}
#[cfg(feature = "KHR_materials_ior")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct Ior {
/// The index of refraction.
///
/// Typical values for the index of refraction range from 1 to 2.
/// In rare cases values greater than 2 are possible.
/// For example, the ior of water is 1.33, and diamond is 2.42
pub ior: IndexOfRefraction,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// A positive number with 1.0 as the default value.
#[cfg(feature = "KHR_materials_emissive_strength")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct EmissiveStrengthFactor(pub f32);
#[cfg(feature = "KHR_materials_emissive_strength")]
impl Default for EmissiveStrengthFactor {
fn default() -> Self {
EmissiveStrengthFactor(1.0)
}
}
#[cfg(feature = "KHR_materials_emissive_strength")]
impl Validate for EmissiveStrengthFactor {}
#[cfg(feature = "KHR_materials_emissive_strength")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct EmissiveStrength {
/// The factor by which to scale the emissive factor or emissive texture.
pub emissive_strength: EmissiveStrengthFactor,
}
/// A number in the inclusive range [0.0, +inf] with a default value of 0.0.
#[cfg(feature = "KHR_materials_volume")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct ThicknessFactor(pub f32);
#[cfg(feature = "KHR_materials_volume")]
impl Default for ThicknessFactor {
fn default() -> Self {
ThicknessFactor(0.0)
}
}
#[cfg(feature = "KHR_materials_volume")]
impl Validate for ThicknessFactor {}
/// A number in the inclusive range [0.0, +inf] with a default value of +inf.
#[cfg(feature = "KHR_materials_volume")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AttenuationDistance(pub f32);
#[cfg(feature = "KHR_materials_volume")]
impl Default for AttenuationDistance {
fn default() -> Self {
AttenuationDistance(f32::INFINITY)
}
}
#[cfg(feature = "KHR_materials_volume")]
impl Validate for AttenuationDistance {}
/// A colour in the inclusive range [[0.0; 3], [1.0; 3]] with a default value of [1.0; 3].
#[cfg(feature = "KHR_materials_volume")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AttenuationColor(pub [f32; 3]);
#[cfg(feature = "KHR_materials_volume")]
impl Default for AttenuationColor {
fn default() -> Self {
AttenuationColor([1.0, 1.0, 1.0])
}
}
#[cfg(feature = "KHR_materials_volume")]
impl Validate for AttenuationColor {}
#[cfg(feature = "KHR_materials_volume")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct Volume {
/// The thickness of the volume beneath the surface. The value is
/// given in the coordinate space of the mesh. If the value is 0
/// the material is thin-walled. Otherwise the material is a
/// volume boundary. The `doubleSided` property has no effect on
/// volume boundaries. Range is [0, +inf).
pub thickness_factor: ThicknessFactor,
/// A texture that defines the thickness, stored in the G channel.
/// This will be multiplied by `thickness_factor`. Range is [0, 1].
#[serde(skip_serializing_if = "Option::is_none")]
pub thickness_texture: Option<texture::Info>,
/// Density of the medium given as the average distance that light
/// travels in the medium before interacting with a particle. The
/// value is given in world space. Range is (0, +inf).
pub attenuation_distance: AttenuationDistance,
/// The color that white light turns into due to absorption when
/// reaching the attenuation distance.
pub attenuation_color: AttenuationColor,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// A number in the inclusive range [0.0, +inf] with a default value of 1.0.
#[cfg(feature = "KHR_materials_specular")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct SpecularFactor(pub f32);
#[cfg(feature = "KHR_materials_specular")]
impl Default for SpecularFactor {
fn default() -> Self {
SpecularFactor(1.0)
}
}
#[cfg(feature = "KHR_materials_specular")]
impl Validate for SpecularFactor {}
/// A colour in the inclusive range [[0.0; 3], [1.0; 3]] with a default value of [1.0; 3].
#[cfg(feature = "KHR_materials_specular")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct SpecularColorFactor(pub [f32; 3]);
#[cfg(feature = "KHR_materials_specular")]
impl Default for SpecularColorFactor {
fn default() -> Self {
SpecularColorFactor([1.0, 1.0, 1.0])
}
}
#[cfg(feature = "KHR_materials_specular")]
impl Validate for SpecularColorFactor {}
#[cfg(feature = "KHR_materials_specular")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct Specular {
/// The strength of the specular reflection.
pub specular_factor: SpecularFactor,
/// A texture that defines the strength of the specular reflection,
/// stored in the alpha (`A`) channel. This will be multiplied by
/// `specular_factor`.
#[serde(skip_serializing_if = "Option::is_none")]
pub specular_texture: Option<texture::Info>,
/// The F0 color of the specular reflection (linear RGB).
pub specular_color_factor: SpecularColorFactor,
/// A texture that defines the F0 color of the specular reflection,
/// stored in the `RGB` channels and encoded in sRGB. This texture
/// will be multiplied by `specular_color_factor`.
#[serde(skip_serializing_if = "Option::is_none")]
pub specular_color_texture: Option<texture::Info>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}

43
vendor/gltf-json/src/extensions/mesh.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// A set of primitives to be rendered.
///
/// A node can contain one or more meshes and its transform places the meshes in
/// the scene.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Mesh {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Geometry to be rendered with the given material.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Primitive {
#[cfg(feature = "KHR_materials_variants")]
#[serde(
default,
rename = "KHR_materials_variants",
skip_serializing_if = "Option::is_none"
)]
pub khr_materials_variants: Option<KhrMaterialsVariants>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
#[cfg(feature = "KHR_materials_variants")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct KhrMaterialsVariants {
pub mappings: Vec<Mapping>,
}
#[cfg(feature = "KHR_materials_variants")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Mapping {
pub material: u32,
pub variants: Vec<u32>,
}

73
vendor/gltf-json/src/extensions/mod.rs vendored Normal file
View File

@@ -0,0 +1,73 @@
/// Contains `Accessor` and other related data structures.
pub mod accessor;
/// Contains `Animation` and other related data structures.
pub mod animation;
/// Contains `Asset` metadata.
pub mod asset;
/// Contains `Buffer`, `View`, and other related data structures.
pub mod buffer;
/// Contains `Camera` and other related data structures.
pub mod camera;
/// Contains `Image` and other related data structures.
pub mod image;
/// Contains `Material` and other related data structures.
pub mod material;
/// Contains `Mesh` and other related data structures.
pub mod mesh;
/// Contains `Root`.
pub mod root;
/// Contains `Scene`, `Node`, and other related data structures.
pub mod scene;
/// Contains `Skin` and other related data structures.
pub mod skin;
/// Contains `Texture`, `Sampler`, and other related data structures.
pub mod texture;
pub use self::root::Root;
/// Names of glTF 2.0 extensions enabled by the user.
pub const ENABLED_EXTENSIONS: &[&str] = &[
#[cfg(feature = "KHR_lights_punctual")]
"KHR_lights_punctual",
#[cfg(feature = "KHR_materials_pbrSpecularGlossiness")]
"KHR_materials_pbrSpecularGlossiness",
#[cfg(feature = "KHR_materials_unlit")]
"KHR_materials_unlit",
#[cfg(feature = "KHR_texture_transform")]
"KHR_texture_transform",
#[cfg(feature = "KHR_materials_transmission")]
"KHR_materials_transmission",
#[cfg(feature = "KHR_materials_ior")]
"KHR_materials_ior",
#[cfg(feature = "KHR_materials_emissive_strength")]
"KHR_materials_emissive_strength",
// Allowlisted texture extensions. Processing is delegated to the user.
#[cfg(feature = "allow_empty_texture")]
"KHR_texture_basisu",
#[cfg(feature = "allow_empty_texture")]
"EXT_texture_webp",
#[cfg(feature = "allow_empty_texture")]
"MSFT_texture_dds",
];
/// Names of glTF 2.0 extensions supported by the library.
pub const SUPPORTED_EXTENSIONS: &[&str] = &[
"KHR_lights_punctual",
"KHR_materials_pbrSpecularGlossiness",
"KHR_materials_unlit",
"KHR_texture_transform",
"KHR_materials_transmission",
"KHR_materials_ior",
"KHR_materials_emissive_strength",
];

118
vendor/gltf-json/src/extensions/root.rs vendored Normal file
View File

@@ -0,0 +1,118 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// The root object of a glTF 2.0 asset.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Root {
#[cfg(feature = "KHR_lights_punctual")]
#[serde(
default,
rename = "KHR_lights_punctual",
skip_serializing_if = "Option::is_none"
)]
pub khr_lights_punctual: Option<KhrLightsPunctual>,
#[cfg(feature = "KHR_materials_variants")]
#[serde(
default,
rename = "KHR_materials_variants",
skip_serializing_if = "Option::is_none"
)]
pub khr_materials_variants: Option<KhrMaterialsVariants>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
#[cfg(feature = "KHR_lights_punctual")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct KhrLightsPunctual {
/// Lights at this node.
pub lights: Vec<crate::extensions::scene::khr_lights_punctual::Light>,
}
#[cfg(feature = "KHR_lights_punctual")]
impl crate::root::Get<crate::extensions::scene::khr_lights_punctual::Light> for crate::Root {
fn get(
&self,
id: crate::Index<crate::extensions::scene::khr_lights_punctual::Light>,
) -> Option<&crate::extensions::scene::khr_lights_punctual::Light> {
if let Some(extensions) = self.extensions.as_ref() {
if let Some(khr_lights_punctual) = extensions.khr_lights_punctual.as_ref() {
khr_lights_punctual.lights.get(id.value())
} else {
None
}
} else {
None
}
}
}
#[cfg(feature = "KHR_lights_punctual")]
impl AsRef<[crate::extensions::scene::khr_lights_punctual::Light]> for crate::Root {
fn as_ref(&self) -> &[crate::extensions::scene::khr_lights_punctual::Light] {
self.extensions
.as_ref()
.and_then(|extensions| extensions.khr_lights_punctual.as_ref())
.map(|khr_lights_punctual| khr_lights_punctual.lights.as_slice())
.unwrap_or(&[])
}
}
#[cfg(feature = "KHR_lights_punctual")]
impl AsMut<Vec<crate::extensions::scene::khr_lights_punctual::Light>> for crate::Root {
fn as_mut(&mut self) -> &mut Vec<crate::extensions::scene::khr_lights_punctual::Light> {
&mut self
.extensions
.get_or_insert_with(Default::default)
.khr_lights_punctual
.get_or_insert_with(Default::default)
.lights
}
}
#[cfg(feature = "KHR_materials_variants")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct KhrMaterialsVariants {
pub variants: Vec<crate::extensions::scene::khr_materials_variants::Variant>,
}
#[cfg(feature = "KHR_materials_variants")]
impl crate::root::Get<crate::extensions::scene::khr_materials_variants::Variant> for crate::Root {
fn get(
&self,
id: crate::Index<crate::extensions::scene::khr_materials_variants::Variant>,
) -> Option<&crate::extensions::scene::khr_materials_variants::Variant> {
self.extensions
.as_ref()?
.khr_materials_variants
.as_ref()?
.variants
.get(id.value())
}
}
#[cfg(feature = "KHR_materials_variants")]
impl AsRef<[crate::extensions::scene::khr_materials_variants::Variant]> for crate::Root {
fn as_ref(&self) -> &[crate::extensions::scene::khr_materials_variants::Variant] {
self.extensions
.as_ref()
.and_then(|extensions| extensions.khr_materials_variants.as_ref())
.map(|khr_materials_variants| khr_materials_variants.variants.as_slice())
.unwrap_or(&[])
}
}
#[cfg(feature = "KHR_materials_variants")]
impl AsMut<Vec<crate::extensions::scene::khr_materials_variants::Variant>> for crate::Root {
fn as_mut(&mut self) -> &mut Vec<crate::extensions::scene::khr_materials_variants::Variant> {
&mut self
.extensions
.get_or_insert_with(Default::default)
.khr_materials_variants
.get_or_insert_with(Default::default)
.variants
}
}

230
vendor/gltf-json/src/extensions/scene.rs vendored Normal file
View File

@@ -0,0 +1,230 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// A node in the node hierarchy. When the node contains `skin`, all
/// `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes.
/// A node can have either a `matrix` or any combination of
/// `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted
/// to matrices and postmultiplied in the `T * R * S` order to compose the
/// transformation matrix; first the scale is applied to the vertices, then the
/// rotation, and then the translation. If none are provided, the transform is the
/// identity. When a node is targeted for animation (referenced by an
/// animation.channel.target), only TRS properties may be present; `matrix` will not
/// be present.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Node {
#[cfg(feature = "KHR_lights_punctual")]
#[serde(
default,
rename = "KHR_lights_punctual",
skip_serializing_if = "Option::is_none"
)]
pub khr_lights_punctual: Option<khr_lights_punctual::KhrLightsPunctual>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
#[cfg(feature = "KHR_lights_punctual")]
pub mod khr_lights_punctual {
use crate::validation::{Checked, Error};
use crate::{Extras, Index, Path, Root};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// All valid light types.
pub const VALID_TYPES: &[&str] = &["directional", "point", "spot"];
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct KhrLightsPunctual {
pub light: Index<Light>,
}
/// Specifies the light type.
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum Type {
/// Directional lights act as though they are infinitely far away and emit light in
/// the direction of the local -z axis. This light type inherits the orientation of
/// the node that it belongs to; position and scale are ignored except for their
/// effect on the inherited node orientation. Because it is at an infinite distance,
/// the light is not attenuated. Its intensity is defined in lumens per metre squared,
/// or lux (lm/m^2).
Directional = 1,
/// Point lights emit light in all directions from their position in space; rotation
/// and scale are ignored except for their effect on the inherited node position. The
/// brightness of the light attenuates in a physically correct manner as distance
/// increases from the light's position (i.e. brightness goes like the inverse square
/// of the distance). Point light intensity is defined in candela, which is lumens per
/// square radian (lm/sr)."
Point,
/// Spot lights emit light in a cone in the direction of the local -z axis. The angle
/// and falloff of the cone is defined using two numbers, the innerConeAngle and outer
/// ConeAngle. As with point lights, the brightness also attenuates in a physically
/// correct manner as distance increases from the light's position (i.e. brightness
/// goes like the inverse square of the distance). Spot light intensity refers to the
/// brightness inside the innerConeAngle (and at the location of the light) and is
/// defined in candela, which is lumens per square radian (lm/sr). Engines that don't
/// support two angles for spotlights should use outerConeAngle as the spotlight angle
/// (leaving innerConeAngle to implicitly be 0).
Spot,
}
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[gltf(validate_hook = "light_validate_hook")]
pub struct Light {
/// Color of the light source.
#[serde(default = "color_default")]
pub color: [f32; 3],
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<std::boxed::Box<serde_json::value::RawValue>>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Intensity of the light source. `point` and `spot` lights use luminous intensity
/// in candela (lm/sr) while `directional` lights use illuminance in lux (lm/m^2).
#[serde(default = "intensity_default")]
pub intensity: f32,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// A distance cutoff at which the light's intensity may be considered to have reached
/// zero.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub range: Option<f32>,
/// Spot light parameters.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub spot: Option<Spot>,
/// Specifies the light type.
#[serde(rename = "type")]
pub type_: Checked<Type>,
}
fn light_validate_hook<P, R>(light: &Light, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if let Checked::Valid(ty) = light.type_.as_ref() {
if *ty == Type::Spot && light.spot.is_none() {
report(&|| path().field("spot"), Error::Missing);
}
}
}
fn color_default() -> [f32; 3] {
[1.0, 1.0, 1.0]
}
fn intensity_default() -> f32 {
1.0
}
/// Spot light parameters.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(rename_all = "camelCase")]
pub struct Spot {
/// Angle in radians from centre of spotlight where falloff begins.
#[serde(default)]
pub inner_cone_angle: f32,
/// Angle in radians from centre of spotlight where falloff ends.
#[serde(default = "outer_cone_angle_default")]
pub outer_cone_angle: f32,
}
fn outer_cone_angle_default() -> f32 {
std::f32::consts::FRAC_PI_4
}
impl<'de> de::Deserialize<'de> for Checked<Type> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Type>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_TYPES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Type::*;
use crate::validation::Checked::*;
Ok(match value {
"directional" => Valid(Directional),
"point" => Valid(Point),
"spot" => Valid(Spot),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl ser::Serialize for Type {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_str(match *self {
Type::Directional => "directional",
Type::Point => "point",
Type::Spot => "spot",
})
}
}
}
#[cfg(feature = "KHR_materials_variants")]
pub mod khr_materials_variants {
use crate::validation::{Error, Validate};
use crate::{Path, Root};
use serde_derive::{Deserialize, Serialize};
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Variant {
pub name: String,
}
impl Validate for Variant {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
self.name.validate(root, || path().field("name"), report);
}
}
}
/// The root `Node`s of a scene.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Scene {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

12
vendor/gltf-json/src/extensions/skin.rs vendored Normal file
View File

@@ -0,0 +1,12 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// Joints and matrices defining a skin.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Skin {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}

View File

@@ -0,0 +1,114 @@
#[cfg(feature = "KHR_texture_transform")]
use crate::{extras::Extras, validation::Validate};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
#[cfg(feature = "extensions")]
use serde_json::{Map, Value};
/// Texture sampler properties for filtering and wrapping modes.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Sampler {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// A texture and its sampler.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Texture {
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
/// Reference to a `Texture`.
pub struct Info {
#[cfg(feature = "KHR_texture_transform")]
#[serde(
default,
rename = "KHR_texture_transform",
skip_serializing_if = "Option::is_none"
)]
pub texture_transform: Option<TextureTransform>,
#[cfg(feature = "extensions")]
#[serde(default, flatten)]
pub others: Map<String, Value>,
}
/// Many techniques can be used to optimize resource usage for a 3d scene.
/// Chief among them is the ability to minimize the number of textures the GPU must load.
/// To achieve this, many engines encourage packing many objects' low-resolution textures into a single large texture atlas.
/// The region of the resulting atlas that corresponds with each object is then defined by vertical and horizontal offsets,
/// and the width and height of the region.
///
/// To support this use case, this extension adds `offset`, `rotation`, and `scale` properties to textureInfo structures.
/// These properties would typically be implemented as an affine transform on the UV coordinates.
#[cfg(feature = "KHR_texture_transform")]
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default, rename_all = "camelCase")]
pub struct TextureTransform {
// The offset of the UV coordinate origin as a factor of the texture dimensions.
pub offset: TextureTransformOffset,
/// Rotate the UVs by this many radians counter-clockwise around the origin.
/// This is equivalent to a similar rotation of the image clockwise.
pub rotation: TextureTransformRotation,
/// The scale factor applied to the components of the UV coordinates.
pub scale: TextureTransformScale,
/// Overrides the textureInfo texCoord value if supplied, and if this extension is supported.
pub tex_coord: Option<u32>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// The offset of the UV coordinate origin as a factor of the texture dimensions.
#[cfg(feature = "KHR_texture_transform")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct TextureTransformOffset(pub [f32; 2]);
#[cfg(feature = "KHR_texture_transform")]
impl Default for TextureTransformOffset {
fn default() -> Self {
Self([0.0, 0.0])
}
}
#[cfg(feature = "KHR_texture_transform")]
impl Validate for TextureTransformOffset {}
/// Rotate the UVs by this many radians counter-clockwise around the origin.
/// This is equivalent to a similar rotation of the image clockwise.
#[cfg(feature = "KHR_texture_transform")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct TextureTransformRotation(pub f32);
#[cfg(feature = "KHR_texture_transform")]
impl Default for TextureTransformRotation {
fn default() -> Self {
Self(0.0)
}
}
#[cfg(feature = "KHR_texture_transform")]
impl Validate for TextureTransformRotation {}
/// The scale factor applied to the components of the UV coordinates.
#[cfg(feature = "KHR_texture_transform")]
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct TextureTransformScale(pub [f32; 2]);
#[cfg(feature = "KHR_texture_transform")]
impl Default for TextureTransformScale {
fn default() -> Self {
Self([1.0, 1.0])
}
}
#[cfg(feature = "KHR_texture_transform")]
impl Validate for TextureTransformScale {}

33
vendor/gltf-json/src/extras.rs vendored Normal file
View File

@@ -0,0 +1,33 @@
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
use std::fmt;
#[cfg(feature = "extras")]
pub use serde_json::value::RawValue;
/// Data type of the `extras` attribute on all glTF objects.
#[cfg(feature = "extras")]
pub type Extras = Option<::std::boxed::Box<RawValue>>;
/// Data type of the `extras` attribute on all glTF objects.
#[cfg(not(feature = "extras"))]
pub type Extras = Void;
/// Type representing no user-defined data.
#[derive(Clone, Default, Serialize, Deserialize, Validate)]
pub struct Void {
#[serde(default, skip_serializing)]
_allow_unknown_fields: (),
}
impl fmt::Debug for Void {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{}}")
}
}
impl fmt::Display for Void {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{{}}")
}
}

49
vendor/gltf-json/src/image.rs vendored Normal file
View File

@@ -0,0 +1,49 @@
use crate::validation::Validate;
use crate::{buffer, extensions, Extras, Index};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
/// All valid MIME types.
pub const VALID_MIME_TYPES: &[&str] = &["image/jpeg", "image/png"];
/// Image data used to create a texture.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Image {
/// The index of the buffer view that contains the image. Use this instead of
/// the image's uri property.
#[serde(rename = "bufferView")]
#[serde(skip_serializing_if = "Option::is_none")]
pub buffer_view: Option<Index<buffer::View>>,
/// The image's MIME type.
#[serde(rename = "mimeType")]
#[serde(skip_serializing_if = "Option::is_none")]
pub mime_type: Option<MimeType>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The uri of the image. Relative paths are relative to the .gltf file.
/// Instead of referencing an external file, the uri can also be a data-uri.
/// The image format must be jpg or png.
#[serde(skip_serializing_if = "Option::is_none")]
pub uri: Option<String>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::image::Image>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// An image MIME type.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct MimeType(pub String);
impl Validate for MimeType {}

107
vendor/gltf-json/src/lib.rs vendored Normal file
View File

@@ -0,0 +1,107 @@
/// Contains `Accessor` and other related data structures.
pub mod accessor;
/// Contains `Animation` and other related data structures.
pub mod animation;
/// Contains `Asset` metadata.
pub mod asset;
/// Contains `Buffer`, `View`, and other related data structures.
pub mod buffer;
/// Contains `Camera` and other related data structures.
pub mod camera;
/// Contains extension specific data structures and the names of all
/// 2.0 extensions supported by the library.
pub mod extensions;
/// Contains `Extras`.
pub mod extras;
/// Contains `Image` and other related data structures.
pub mod image;
/// Contains `Material` and other related data structures.
pub mod material;
/// Contains `Mesh` and other related data structures.
pub mod mesh;
/// Contains `Path`.
pub mod path;
/// Contains `Root`.
pub mod root;
/// Contains `Scene`, `Node`, and other related data structures.
pub mod scene;
/// Contains `Skin` and other related data structures.
pub mod skin;
/// Contains `Texture`, `Sampler`, and other related data structures.
pub mod texture;
/// Contains functions that validate glTF JSON data against the specification.
pub mod validation;
#[doc(inline)]
pub use accessor::Accessor;
#[doc(inline)]
pub use animation::Animation;
#[doc(inline)]
pub use asset::Asset;
#[doc(inline)]
pub use buffer::Buffer;
#[doc(inline)]
pub use camera::Camera;
#[doc(inline)]
pub use image::Image;
#[doc(inline)]
pub use material::Material;
#[doc(inline)]
pub use mesh::Mesh;
#[doc(inline)]
pub use scene::Node;
#[doc(inline)]
pub use scene::Scene;
#[doc(inline)]
pub use skin::Skin;
#[doc(inline)]
pub use texture::Texture;
#[doc(inline)]
pub use self::extras::Extras;
#[doc(inline)]
pub use self::path::Path;
#[doc(inline)]
pub use self::root::Index;
#[doc(inline)]
pub use self::root::Root;
#[doc(inline)]
pub use serde_json::Error;
#[doc(inline)]
pub use serde_json::Value;
/// Re-exports of `serde_json` deserialization functions.
///
/// This module re-exports the generic serde deserialization functions
/// so that one can deserialize data structures other than `Root` without
/// being bound to a specific version of `serde_json`.
pub mod deserialize {
pub use serde_json::{from_reader, from_slice, from_str, from_value};
}
/// Re-exports of `serde_json` serialization functions.
///
/// This module re-exports the generic serde serialization functions
/// so that one can serialize data structures other than `Root` without
/// being bound to a specific version of `serde_json`.
pub mod serialize {
pub use serde_json::{
to_string, to_string_pretty, to_value, to_vec, to_vec_pretty, to_writer, to_writer_pretty,
};
}

311
vendor/gltf-json/src/material.rs vendored Normal file
View File

@@ -0,0 +1,311 @@
use crate::validation::{Checked, Validate};
use crate::{extensions, texture, Extras, Index};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// All valid alpha modes.
pub const VALID_ALPHA_MODES: &[&str] = &["OPAQUE", "MASK", "BLEND"];
/// The alpha rendering mode of a material.
#[derive(Clone, Copy, Eq, PartialEq, Debug)]
pub enum AlphaMode {
/// The alpha value is ignored and the rendered output is fully opaque.
Opaque = 1,
/// The rendered output is either fully opaque or fully transparent depending on
/// the alpha value and the specified alpha cutoff value.
Mask,
/// The alpha value is used, to determine the transparency of the rendered output.
/// The alpha cutoff value is ignored.
Blend,
}
impl ser::Serialize for AlphaMode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
match *self {
AlphaMode::Opaque => serializer.serialize_str("OPAQUE"),
AlphaMode::Mask => serializer.serialize_str("MASK"),
AlphaMode::Blend => serializer.serialize_str("BLEND"),
}
}
}
/// The material appearance of a primitive.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Material {
/// The alpha cutoff value of the material.
#[serde(rename = "alphaCutoff")]
//#[cfg_attr(feature = "alphaCutoff", serde(skip_serializing_if = "Option::is_none"))]
#[serde(skip_serializing_if = "Option::is_none")]
pub alpha_cutoff: Option<AlphaCutoff>,
/// The alpha rendering mode of the material.
///
/// The material's alpha rendering mode enumeration specifying the
/// interpretation of the alpha value of the main factor and texture.
///
/// * In `Opaque` mode (default) the alpha value is ignored and the rendered
/// output is fully opaque.
///
/// * In `Mask` mode, the rendered output is either fully opaque or fully
/// transparent depending on the alpha value and the specified alpha cutoff
/// value.
///
/// * In `Blend` mode, the alpha value is used to composite the source and
/// destination areas and the rendered output is combined with the
/// background using the normal painting operation (i.e. the Porter and
/// Duff over operator).
#[serde(rename = "alphaMode")]
pub alpha_mode: Checked<AlphaMode>,
/// Specifies whether the material is double-sided.
///
/// * When this value is false, back-face culling is enabled.
///
/// * When this value is true, back-face culling is disabled and double sided
/// lighting is enabled.
///
/// The back-face must have its normals reversed before the lighting
/// equation is evaluated.
#[serde(rename = "doubleSided")]
pub double_sided: bool,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology. When not
/// specified, all the default values of `pbrMetallicRoughness` apply.
#[serde(default, rename = "pbrMetallicRoughness")]
pub pbr_metallic_roughness: PbrMetallicRoughness,
/// A tangent space normal map. The texture contains RGB components in linear
/// space. Each texel represents the XYZ components of a normal vector in
/// tangent space. Red [0 to 255] maps to X [-1 to 1]. Green [0 to 255] maps to
/// Y [-1 to 1]. Blue [128 to 255] maps to Z [1/255 to 1]. The normal vectors
/// use OpenGL conventions where +X is right and +Y is up. +Z points toward the
/// viewer.
#[serde(rename = "normalTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub normal_texture: Option<NormalTexture>,
/// The occlusion map texture. The occlusion values are sampled from the R
/// channel. Higher values indicate areas that should receive full indirect
/// lighting and lower values indicate no indirect lighting. These values are
/// linear. If other channels are present (GBA), they are ignored for occlusion
/// calculations.
#[serde(rename = "occlusionTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub occlusion_texture: Option<OcclusionTexture>,
/// The emissive map controls the color and intensity of the light being emitted
/// by the material. This texture contains RGB components in sRGB color space.
/// If a fourth component (A) is present, it is ignored.
#[serde(rename = "emissiveTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub emissive_texture: Option<texture::Info>,
/// The emissive color of the material.
#[serde(rename = "emissiveFactor")]
pub emissive_factor: EmissiveFactor,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::Material>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// A set of parameter values that are used to define the metallic-roughness
/// material model from Physically-Based Rendering (PBR) methodology.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct PbrMetallicRoughness {
/// The material's base color factor.
#[serde(rename = "baseColorFactor")]
pub base_color_factor: PbrBaseColorFactor,
/// The base color texture.
#[serde(rename = "baseColorTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub base_color_texture: Option<texture::Info>,
/// The metalness of the material.
#[serde(rename = "metallicFactor")]
pub metallic_factor: StrengthFactor,
/// The roughness of the material.
///
/// * A value of 1.0 means the material is completely rough.
/// * A value of 0.0 means the material is completely smooth.
#[serde(rename = "roughnessFactor")]
pub roughness_factor: StrengthFactor,
/// The metallic-roughness texture.
///
/// This texture has two components:
///
/// The metalness values are sampled from the B channel.
/// The roughness values are sampled from the G channel.
/// These values are linear. If other channels are present (R or A),
/// they are ignored for metallic-roughness calculations.
#[serde(rename = "metallicRoughnessTexture")]
#[serde(skip_serializing_if = "Option::is_none")]
pub metallic_roughness_texture: Option<texture::Info>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::PbrMetallicRoughness>,
/// Optional application specific data.
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// Defines the normal texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct NormalTexture {
/// The index of the texture.
pub index: Index<texture::Texture>,
/// The scalar multiplier applied to each normal vector of the texture.
///
/// This value is ignored if normalTexture is not specified.
#[serde(default = "material_normal_texture_scale_default")]
pub scale: f32,
/// The set index of the texture's `TEXCOORD` attribute.
#[serde(default, rename = "texCoord")]
pub tex_coord: u32,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::NormalTexture>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
fn material_normal_texture_scale_default() -> f32 {
1.0
}
/// Defines the occlusion texture of a material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct OcclusionTexture {
/// The index of the texture.
pub index: Index<texture::Texture>,
/// The scalar multiplier controlling the amount of occlusion applied.
#[serde(default)]
pub strength: StrengthFactor,
/// The set index of the texture's `TEXCOORD` attribute.
#[serde(default, rename = "texCoord")]
pub tex_coord: u32,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::material::OcclusionTexture>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
/// The alpha cutoff value of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct AlphaCutoff(pub f32);
/// The emissive color of a material.
#[derive(Clone, Copy, Debug, Default, Deserialize, Serialize)]
pub struct EmissiveFactor(pub [f32; 3]);
/// The base color factor of a material.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct PbrBaseColorFactor(pub [f32; 4]);
/// A number in the inclusive range [0.0, 1.0] with a default value of 1.0.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct StrengthFactor(pub f32);
impl Default for AlphaCutoff {
fn default() -> Self {
AlphaCutoff(0.5)
}
}
impl Validate for AlphaCutoff {}
impl Default for AlphaMode {
fn default() -> Self {
AlphaMode::Opaque
}
}
impl<'de> de::Deserialize<'de> for Checked<AlphaMode> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<AlphaMode>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_ALPHA_MODES)
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::AlphaMode::*;
use crate::validation::Checked::*;
Ok(match value {
"OPAQUE" => Valid(Opaque),
"MASK" => Valid(Mask),
"BLEND" => Valid(Blend),
_ => Invalid,
})
}
}
deserializer.deserialize_str(Visitor)
}
}
impl Validate for EmissiveFactor {}
impl Default for PbrBaseColorFactor {
fn default() -> Self {
PbrBaseColorFactor([1.0, 1.0, 1.0, 1.0])
}
}
impl Validate for PbrBaseColorFactor {}
impl Default for StrengthFactor {
fn default() -> Self {
StrengthFactor(1.0)
}
}
impl Validate for StrengthFactor {}

377
vendor/gltf-json/src/mesh.rs vendored Normal file
View File

@@ -0,0 +1,377 @@
use crate::validation::{Checked, Error};
use crate::{accessor, extensions, material, Extras, Index};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use serde_json::from_value;
use std::collections::BTreeMap;
use std::fmt;
/// Corresponds to `GL_POINTS`.
pub const POINTS: u32 = 0;
/// Corresponds to `GL_LINES`.
pub const LINES: u32 = 1;
/// Corresponds to `GL_LINE_LOOP`.
pub const LINE_LOOP: u32 = 2;
/// Corresponds to `GL_LINE_STRIP`.
pub const LINE_STRIP: u32 = 3;
/// Corresponds to `GL_TRIANGLES`.
pub const TRIANGLES: u32 = 4;
/// Corresponds to `GL_TRIANGLE_STRIP`.
pub const TRIANGLE_STRIP: u32 = 5;
/// Corresponds to `GL_TRIANGLE_FAN`.
pub const TRIANGLE_FAN: u32 = 6;
/// All valid primitive rendering modes.
pub const VALID_MODES: &[u32] = &[
POINTS,
LINES,
LINE_LOOP,
LINE_STRIP,
TRIANGLES,
TRIANGLE_STRIP,
TRIANGLE_FAN,
];
/// All valid semantic names for Morph targets.
pub const VALID_MORPH_TARGETS: &[&str] = &["POSITION", "NORMAL", "TANGENT"];
/// The type of primitives to render.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
pub enum Mode {
/// Corresponds to `GL_POINTS`.
Points = 1,
/// Corresponds to `GL_LINES`.
Lines,
/// Corresponds to `GL_LINE_LOOP`.
LineLoop,
/// Corresponds to `GL_LINE_STRIP`.
LineStrip,
/// Corresponds to `GL_TRIANGLES`.
Triangles,
/// Corresponds to `GL_TRIANGLE_STRIP`.
TriangleStrip,
/// Corresponds to `GL_TRIANGLE_FAN`.
TriangleFan,
}
/// A set of primitives to be rendered.
///
/// A node can contain one or more meshes and its transform places the meshes in
/// the scene.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Mesh {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::mesh::Mesh>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// Defines the geometry to be renderered with a material.
pub primitives: Vec<Primitive>,
/// Defines the weights to be applied to the morph targets.
#[serde(skip_serializing_if = "Option::is_none")]
pub weights: Option<Vec<f32>>,
}
/// Geometry to be rendered with the given material.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
#[gltf(validate_hook = "primitive_validate_hook")]
pub struct Primitive {
/// Maps attribute semantic names to the `Accessor`s containing the
/// corresponding attribute data.
pub attributes: BTreeMap<Checked<Semantic>, Index<accessor::Accessor>>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::mesh::Primitive>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// The index of the accessor that contains the indices.
#[serde(skip_serializing_if = "Option::is_none")]
pub indices: Option<Index<accessor::Accessor>>,
/// The index of the material to apply to this primitive when rendering
#[serde(skip_serializing_if = "Option::is_none")]
pub material: Option<Index<material::Material>>,
/// The type of primitives to render.
#[serde(default, skip_serializing_if = "is_primitive_mode_default")]
pub mode: Checked<Mode>,
/// An array of Morph Targets, each Morph Target is a dictionary mapping
/// attributes (only `POSITION`, `NORMAL`, and `TANGENT` supported) to their
/// deviations in the Morph Target.
#[serde(skip_serializing_if = "Option::is_none")]
pub targets: Option<Vec<MorphTarget>>,
}
fn is_primitive_mode_default(mode: &Checked<Mode>) -> bool {
*mode == Checked::Valid(Mode::Triangles)
}
fn primitive_validate_hook<P, R>(primitive: &Primitive, root: &crate::Root, path: P, report: &mut R)
where
P: Fn() -> crate::Path,
R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
{
let position_path = &|| path().field("attributes").key("POSITION");
if let Some(pos_accessor_index) = primitive
.attributes
.get(&Checked::Valid(Semantic::Positions))
{
// spec: POSITION accessor **must** have `min` and `max` properties defined.
let pos_accessor = &root.accessors[pos_accessor_index.value()];
let min_path = &|| position_path().field("min");
if let Some(ref min) = pos_accessor.min {
if from_value::<[f32; 3]>(min.clone()).is_err() {
report(min_path, Error::Invalid);
}
} else {
report(min_path, Error::Missing);
}
let max_path = &|| position_path().field("max");
if let Some(ref max) = pos_accessor.max {
if from_value::<[f32; 3]>(max.clone()).is_err() {
report(max_path, Error::Invalid);
}
} else {
report(max_path, Error::Missing);
}
} else {
report(position_path, Error::Missing);
}
}
/// A dictionary mapping attributes to their deviations in the Morph Target.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct MorphTarget {
/// XYZ vertex position displacements of type `[f32; 3]`.
#[serde(rename = "POSITION")]
#[serde(skip_serializing_if = "Option::is_none")]
pub positions: Option<Index<accessor::Accessor>>,
/// XYZ vertex normal displacements of type `[f32; 3]`.
#[serde(rename = "NORMAL")]
#[serde(skip_serializing_if = "Option::is_none")]
pub normals: Option<Index<accessor::Accessor>>,
/// XYZ vertex tangent displacements of type `[f32; 3]`.
#[serde(rename = "TANGENT")]
#[serde(skip_serializing_if = "Option::is_none")]
pub tangents: Option<Index<accessor::Accessor>>,
}
/// Vertex attribute semantic name.
#[derive(Clone, Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub enum Semantic {
/// Extra attribute name.
#[cfg(feature = "extras")]
Extras(String),
/// XYZ vertex positions.
Positions,
/// XYZ vertex normals.
Normals,
/// XYZW vertex tangents where the `w` component is a sign value indicating the
/// handedness of the tangent basis.
Tangents,
/// RGB or RGBA vertex color.
Colors(u32),
/// UV texture co-ordinates.
TexCoords(u32),
/// Joint indices.
Joints(u32),
/// Joint weights.
Weights(u32),
}
impl Default for Mode {
fn default() -> Mode {
Mode::Triangles
}
}
impl Mode {
/// Returns the equivalent `GLenum`.
pub fn as_gl_enum(self) -> u32 {
match self {
Mode::Points => POINTS,
Mode::Lines => LINES,
Mode::LineLoop => LINE_LOOP,
Mode::LineStrip => LINE_STRIP,
Mode::Triangles => TRIANGLES,
Mode::TriangleStrip => TRIANGLE_STRIP,
Mode::TriangleFan => TRIANGLE_FAN,
}
}
}
impl<'de> de::Deserialize<'de> for Checked<Mode> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Mode>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_MODES)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::Mode::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
POINTS => Valid(Points),
LINES => Valid(Lines),
LINE_LOOP => Valid(LineLoop),
LINE_STRIP => Valid(LineStrip),
TRIANGLES => Valid(Triangles),
TRIANGLE_STRIP => Valid(TriangleStrip),
TRIANGLE_FAN => Valid(TriangleFan),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl ser::Serialize for Mode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u32(self.as_gl_enum())
}
}
impl Semantic {
fn checked(s: &str) -> Checked<Self> {
use self::Semantic::*;
use crate::validation::Checked::*;
match s {
"NORMAL" => Valid(Normals),
"POSITION" => Valid(Positions),
"TANGENT" => Valid(Tangents),
#[cfg(feature = "extras")]
_ if s.starts_with('_') => Valid(Extras(s[1..].to_string())),
_ if s.starts_with("COLOR_") => match s["COLOR_".len()..].parse() {
Ok(set) => Valid(Colors(set)),
Err(_) => Invalid,
},
_ if s.starts_with("TEXCOORD_") => match s["TEXCOORD_".len()..].parse() {
Ok(set) => Valid(TexCoords(set)),
Err(_) => Invalid,
},
_ if s.starts_with("JOINTS_") => match s["JOINTS_".len()..].parse() {
Ok(set) => Valid(Joints(set)),
Err(_) => Invalid,
},
_ if s.starts_with("WEIGHTS_") => match s["WEIGHTS_".len()..].parse() {
Ok(set) => Valid(Weights(set)),
Err(_) => Invalid,
},
_ => Invalid,
}
}
}
impl ser::Serialize for Semantic {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_str(&self.to_string())
}
}
impl ToString for Semantic {
fn to_string(&self) -> String {
use self::Semantic::*;
match *self {
Positions => "POSITION".into(),
Normals => "NORMAL".into(),
Tangents => "TANGENT".into(),
Colors(set) => format!("COLOR_{}", set),
TexCoords(set) => format!("TEXCOORD_{}", set),
Joints(set) => format!("JOINTS_{}", set),
Weights(set) => format!("WEIGHTS_{}", set),
#[cfg(feature = "extras")]
Extras(ref name) => format!("_{}", name),
}
}
}
impl ToString for Checked<Semantic> {
fn to_string(&self) -> String {
match *self {
Checked::Valid(ref semantic) => semantic.to_string(),
Checked::Invalid => "<invalid semantic name>".into(),
}
}
}
impl<'de> de::Deserialize<'de> for Checked<Semantic> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<Semantic>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "semantic name")
}
fn visit_str<E>(self, value: &str) -> Result<Self::Value, E>
where
E: de::Error,
{
Ok(Semantic::checked(value))
}
}
deserializer.deserialize_str(Visitor)
}
}

98
vendor/gltf-json/src/path.rs vendored Normal file
View File

@@ -0,0 +1,98 @@
use std::fmt;
/// An immutable JSON source path.
#[derive(Default, Clone, Debug, PartialEq)]
pub struct Path(pub String);
impl Path {
/// Creates an empty JSON source path.
///
/// # Examples
///
/// Basic usage
///
/// ```rust
/// # use gltf_json::Path;
/// let path = Path::new();
/// assert_eq!("", path.as_str());
/// ```
pub fn new() -> Self {
Path(String::new())
}
/// Returns a new path ending with the given field.
///
/// # Examples
///
/// Basic usage
///
/// ```rust
/// # use gltf_json::Path;
/// let path = Path::new().field("foo");
/// assert_eq!("foo", path.as_str());
/// assert_eq!("foo.bar", path.field("bar").as_str());
/// ```
pub fn field(&self, name: &str) -> Self {
if self.0.is_empty() {
Path(name.to_string())
} else {
Path(format!("{}.{}", self.0, name))
}
}
/// Returns a new path ending with the given array index.
///
/// # Examples
///
/// Basic usage
///
/// ```rust
/// # use gltf_json::Path;
/// let path = Path::new().field("foo");
/// assert_eq!("foo[123]", path.index(123).as_str());
/// ```
pub fn index(&self, index: usize) -> Self {
Path(format!("{}[{}]", self.0, index))
}
/// Returns a new path ending with the given object key.
///
/// # Examples
///
/// Basic usage
///
/// ```rust
/// # use gltf_json::Path;
/// let path = Path::new().field("foo");
/// assert_eq!("foo[\"bar\"]", path.key("bar").as_str());
/// ```
pub fn key(&self, key: &str) -> Self {
Path(format!("{}[\"{}\"]", self.0, key))
}
/// Provides a string value for a JSON path.
///
/// # Examples
///
/// Basic usage
///
/// ```rust
/// # use gltf_json::Path;
/// let path = Path::new().field("foo").index(0).value_str("baz");
/// assert_eq!("foo[0] = \"baz\"", path.as_str());
/// ```
pub fn value_str(&self, value: &str) -> Self {
Path(format!("{} = \"{}\"", self.0, value))
}
/// Returns a view into the internal representation.
pub fn as_str(&self) -> &str {
&self.0
}
}
impl fmt::Display for Path {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}

502
vendor/gltf-json/src/root.rs vendored Normal file
View File

@@ -0,0 +1,502 @@
use crate::buffer;
use crate::extensions;
use crate::texture;
use crate::validation;
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
use std::{self, fmt, io, marker};
use crate::path::Path;
use crate::{
Accessor, Animation, Asset, Buffer, Camera, Error, Extras, Image, Material, Mesh, Node, Scene,
Skin, Texture, Value,
};
use validation::Validate;
// TODO: As a breaking change, simplify by replacing uses of `Get<T>` with `AsRef<[T]>`.
/// Helper trait for retrieving top-level objects by a universal identifier.
pub trait Get<T> {
/// Retrieves a single value at the given index.
fn get(&self, id: Index<T>) -> Option<&T>;
}
/// Represents an offset into a vector of type `T` owned by the root glTF object.
///
/// This type may be used with the following functions:
///
/// * [`Root::get()`] to retrieve objects from [`Root`].
/// * [`Root::push()`] to add new objects to [`Root`].
pub struct Index<T>(u32, marker::PhantomData<fn() -> T>);
impl<T> Index<T> {
/// Given a vector of glTF objects, call [`Vec::push()`] to insert it into the vector,
/// then return an [`Index`] for it.
///
/// This allows you to easily obtain [`Index`] values with the correct index and type when
/// creating a glTF asset. Note that for [`Root`], you can call [`Root::push()`] without
/// needing to retrieve the correct vector first.
///
/// # Panics
///
/// Panics if the vector has [`u32::MAX`] or more elements, in which case an `Index` cannot be
/// created.
pub fn push(vec: &mut Vec<T>, value: T) -> Index<T> {
let len = vec.len();
let Ok(index): Result<u32, _> = len.try_into() else {
panic!(
"glTF vector of {ty} has {len} elements, which exceeds the Index limit",
ty = std::any::type_name::<T>(),
);
};
vec.push(value);
Index::new(index)
}
}
/// The root object of a glTF 2.0 asset.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[gltf(validate_hook = "root_validate_hook")]
pub struct Root {
/// An array of accessors.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub accessors: Vec<Accessor>,
/// An array of keyframe animations.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub animations: Vec<Animation>,
/// Metadata about the glTF asset.
pub asset: Asset,
/// An array of buffers.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub buffers: Vec<Buffer>,
/// An array of buffer views.
#[serde(default, rename = "bufferViews")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub buffer_views: Vec<buffer::View>,
/// The default scene.
#[serde(skip_serializing_if = "Option::is_none")]
pub scene: Option<Index<Scene>>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::root::Root>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Names of glTF extensions used somewhere in this asset.
#[serde(default, rename = "extensionsUsed")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub extensions_used: Vec<String>,
/// Names of glTF extensions required to properly load this asset.
#[serde(default, rename = "extensionsRequired")]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub extensions_required: Vec<String>,
/// An array of cameras.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub cameras: Vec<Camera>,
/// An array of images.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub images: Vec<Image>,
/// An array of materials.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub materials: Vec<Material>,
/// An array of meshes.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub meshes: Vec<Mesh>,
/// An array of nodes.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub nodes: Vec<Node>,
/// An array of samplers.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub samplers: Vec<texture::Sampler>,
/// An array of scenes.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub scenes: Vec<Scene>,
/// An array of skins.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub skins: Vec<Skin>,
/// An array of textures.
#[serde(default)]
#[serde(skip_serializing_if = "Vec::is_empty")]
pub textures: Vec<Texture>,
}
fn root_validate_hook<P, R>(root: &Root, _also_root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, crate::validation::Error),
{
for (i, ext) in root.extensions_required.iter().enumerate() {
if !crate::extensions::ENABLED_EXTENSIONS.contains(&ext.as_str()) {
report(
&|| {
path()
.field("extensionsRequired")
.index(i)
.value_str(ext.as_str())
},
crate::validation::Error::Unsupported,
);
}
}
}
impl Root {
/// Returns a single item from the root object.
pub fn get<T>(&self, index: Index<T>) -> Option<&T>
where
Self: Get<T>,
{
(self as &dyn Get<T>).get(index)
}
/// Insert the given value into this (as via [`Vec::push()`]), then return the [`Index`] to it.
///
/// This allows you to easily obtain [`Index`] values with the correct index and type when
/// creating a glTF asset.
///
/// If you have a mutable borrow conflict when using this method, consider using the more
/// explicit [`Index::push()`] method, passing it only the necessary vector.
///
/// # Panics
///
/// Panics if there are already [`u32::MAX`] or more elements of this type,
/// in which case an `Index` cannot be created.
#[track_caller]
pub fn push<T>(&mut self, value: T) -> Index<T>
where
Self: AsMut<Vec<T>>,
{
Index::push(self.as_mut(), value)
}
/// Deserialize from a JSON string slice.
#[allow(clippy::should_implement_trait)]
pub fn from_str(str_: &str) -> Result<Self, Error> {
serde_json::from_str(str_)
}
/// Deserialize from a JSON byte slice.
pub fn from_slice(slice: &[u8]) -> Result<Self, Error> {
serde_json::from_slice(slice)
}
/// Deserialize from a stream of JSON.
pub fn from_reader<R>(reader: R) -> Result<Self, Error>
where
R: io::Read,
{
serde_json::from_reader(reader)
}
/// Serialize as a `String` of JSON.
pub fn to_string(&self) -> Result<String, Error> {
serde_json::to_string(self)
}
/// Serialize as a pretty-printed `String` of JSON.
pub fn to_string_pretty(&self) -> Result<String, Error> {
serde_json::to_string_pretty(self)
}
/// Serialize as a generic JSON value.
pub fn to_value(&self) -> Result<Value, Error> {
serde_json::to_value(self)
}
/// Serialize as a JSON byte vector.
pub fn to_vec(&self) -> Result<Vec<u8>, Error> {
serde_json::to_vec(self)
}
/// Serialize as a pretty-printed JSON byte vector.
pub fn to_vec_pretty(&self) -> Result<Vec<u8>, Error> {
serde_json::to_vec_pretty(self)
}
/// Serialize as a JSON byte writertor.
pub fn to_writer<W>(&self, writer: W) -> Result<(), Error>
where
W: io::Write,
{
serde_json::to_writer(writer, self)
}
/// Serialize as a pretty-printed JSON byte writertor.
pub fn to_writer_pretty<W>(&self, writer: W) -> Result<(), Error>
where
W: io::Write,
{
serde_json::to_writer_pretty(writer, self)
}
}
impl<T> Index<T> {
/// Creates a new `Index` representing an offset into an array containing `T`.
pub fn new(value: u32) -> Self {
Index(value, std::marker::PhantomData)
}
/// Returns the internal offset value.
pub fn value(&self) -> usize {
self.0 as usize
}
}
impl<T> serde::Serialize for Index<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ::serde::Serializer,
{
serializer.serialize_u64(self.value() as u64)
}
}
impl<'de, T> serde::Deserialize<'de> for Index<T> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
struct Visitor<T>(marker::PhantomData<T>);
impl<'de, T> serde::de::Visitor<'de> for Visitor<T> {
type Value = Index<T>;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("index into child of root")
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: serde::de::Error,
{
Ok(Index::new(value as u32))
}
}
deserializer.deserialize_u64(Visitor::<T>(marker::PhantomData))
}
}
impl<T> Clone for Index<T> {
fn clone(&self) -> Self {
*self
}
}
impl<T> Copy for Index<T> {}
impl<T> Ord for Index<T> {
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
self.0.cmp(&other.0)
}
}
impl<T> PartialOrd for Index<T> {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
Some(self.cmp(other))
}
}
impl<T> Eq for Index<T> {}
impl<T> PartialEq for Index<T> {
fn eq(&self, other: &Self) -> bool {
self.0 == other.0
}
}
impl<T> std::hash::Hash for Index<T> {
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
self.0.hash(state);
}
}
impl<T> fmt::Debug for Index<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T> fmt::Display for Index<T> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl<T: Validate> Validate for Index<T>
where
Root: Get<T>,
{
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, validation::Error),
{
if root.get(*self).is_none() {
report(&path, validation::Error::IndexOutOfBounds);
}
}
}
macro_rules! impl_get {
($ty:ty, $field:ident) => {
impl<'a> Get<$ty> for Root {
fn get(&self, index: Index<$ty>) -> Option<&$ty> {
self.$field.get(index.value())
}
}
impl AsRef<[$ty]> for Root {
fn as_ref(&self) -> &[$ty] {
&self.$field
}
}
impl AsMut<Vec<$ty>> for Root {
fn as_mut(&mut self) -> &mut Vec<$ty> {
&mut self.$field
}
}
};
}
impl_get!(Accessor, accessors);
impl_get!(Animation, animations);
impl_get!(Buffer, buffers);
impl_get!(buffer::View, buffer_views);
impl_get!(Camera, cameras);
impl_get!(Image, images);
impl_get!(Material, materials);
impl_get!(Mesh, meshes);
impl_get!(Node, nodes);
impl_get!(texture::Sampler, samplers);
impl_get!(Scene, scenes);
impl_get!(Skin, skins);
impl_get!(Texture, textures);
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashSet;
#[test]
fn index_is_partialeq() {
assert_eq!(Index::<Node>::new(1), Index::new(1));
assert_ne!(Index::<Node>::new(1), Index::new(2));
}
#[test]
fn index_is_hash() {
let set = HashSet::from([Index::<Node>::new(1), Index::new(1234)]);
assert!(set.contains(&Index::new(1234)));
assert!(!set.contains(&Index::new(999)));
assert_eq!(set.len(), 2);
}
#[test]
fn index_is_ord() {
assert!(Index::<Node>::new(1) < Index::new(1234));
}
fn _index_is_send_sync()
where
Index<Material>: Send + Sync,
{
}
#[test]
fn index_push() {
let some_object = "hello";
let mut vec = Vec::new();
assert_eq!(Index::push(&mut vec, some_object), Index::new(0));
assert_eq!(Index::push(&mut vec, some_object), Index::new(1));
}
#[test]
fn root_push() {
let some_object = Buffer {
byte_length: validation::USize64(1),
#[cfg(feature = "names")]
name: None,
uri: None,
extensions: None,
extras: Default::default(),
};
let mut root = Root::default();
assert_eq!(root.push(some_object.clone()), Index::new(0));
assert_eq!(root.push(some_object), Index::new(1));
}
#[test]
fn root_extensions() {
use crate::validation::Error;
use crate::Path;
let mut root = super::Root {
extensions_required: vec!["KHR_lights_punctual".to_owned()],
..Default::default()
};
let mut errors = Vec::new();
root.validate(&root, Path::new, &mut |path, error| {
errors.push((path(), error));
});
#[cfg(feature = "KHR_lights_punctual")]
{
assert!(errors.is_empty());
}
#[cfg(not(feature = "KHR_lights_punctual"))]
{
assert_eq!(1, errors.len());
let (path, error) = errors.get(0).unwrap();
assert_eq!(
path.as_str(),
"extensionsRequired[0] = \"KHR_lights_punctual\""
);
assert_eq!(*error, Error::Unsupported);
}
root.extensions_required = vec!["KHR_mesh_quantization".to_owned()];
errors.clear();
root.validate(&root, Path::new, &mut |path, error| {
errors.push((path(), error));
});
assert_eq!(1, errors.len());
let (path, error) = errors.get(0).unwrap();
assert_eq!(
path.as_str(),
"extensionsRequired[0] = \"KHR_mesh_quantization\""
);
assert_eq!(*error, Error::Unsupported);
}
}

114
vendor/gltf-json/src/scene.rs vendored Normal file
View File

@@ -0,0 +1,114 @@
use crate::validation::Validate;
use crate::{camera, extensions, mesh, scene, skin, Extras, Index};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
/// A node in the node hierarchy. When the node contains `skin`, all
/// `mesh.primitives` must contain `JOINTS_0` and `WEIGHTS_0` attributes.
/// A node can have either a `matrix` or any combination of
/// `translation`/`rotation`/`scale` (TRS) properties. TRS properties are converted
/// to matrices and postmultiplied in the `T * R * S` order to compose the
/// transformation matrix; first the scale is applied to the vertices, then the
/// rotation, and then the translation. If none are provided, the transform is the
/// identity. When a node is targeted for animation (referenced by an
/// animation.channel.target), only TRS properties may be present; `matrix` will not
/// be present.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
pub struct Node {
/// The index of the camera referenced by this node.
#[serde(skip_serializing_if = "Option::is_none")]
pub camera: Option<Index<camera::Camera>>,
/// The indices of this node's children.
#[serde(skip_serializing_if = "Option::is_none")]
pub children: Option<Vec<Index<scene::Node>>>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::scene::Node>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// 4x4 column-major transformation matrix.
///
/// glTF 2.0 specification:
/// When a node is targeted for animation (referenced by an
/// animation.channel.target), only TRS properties may be present;
/// matrix will not be present.
///
/// TODO: Ensure that .matrix is set to None or otherwise skipped during
/// serialization, if the node is targeted for animation.
///
#[serde(skip_serializing_if = "Option::is_none")]
pub matrix: Option<[f32; 16]>,
/// The index of the mesh in this node.
#[serde(skip_serializing_if = "Option::is_none")]
pub mesh: Option<Index<mesh::Mesh>>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The node's unit quaternion rotation in the order (x, y, z, w), where w is
/// the scalar.
#[serde(skip_serializing_if = "Option::is_none")]
pub rotation: Option<UnitQuaternion>,
/// The node's non-uniform scale.
#[serde(skip_serializing_if = "Option::is_none")]
pub scale: Option<[f32; 3]>,
/// The node's translation.
#[serde(skip_serializing_if = "Option::is_none")]
pub translation: Option<[f32; 3]>,
/// The index of the skin referenced by this node.
#[serde(skip_serializing_if = "Option::is_none")]
pub skin: Option<Index<skin::Skin>>,
/// The weights of the instantiated Morph Target. Number of elements must match
/// the number of Morph Targets of used mesh.
#[serde(skip_serializing_if = "Option::is_none")]
pub weights: Option<Vec<f32>>,
}
/// The root `Node`s of a scene.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Scene {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::scene::Scene>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The indices of each root node.
#[serde(skip_serializing_if = "Vec::is_empty")]
pub nodes: Vec<Index<Node>>,
}
/// Unit quaternion rotation in the order (x, y, z, w), where w is the scalar.
#[derive(Clone, Copy, Debug, Deserialize, Serialize)]
pub struct UnitQuaternion(pub [f32; 4]);
impl Default for UnitQuaternion {
fn default() -> Self {
UnitQuaternion([0.0, 0.0, 0.0, 1.0])
}
}
impl Validate for UnitQuaternion {}

43
vendor/gltf-json/src/skin.rs vendored Normal file
View File

@@ -0,0 +1,43 @@
use crate::{accessor, extensions, scene, Extras, Index};
use gltf_derive::Validate;
use serde_derive::{Deserialize, Serialize};
/// Joints and matrices defining a skin.
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
pub struct Skin {
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::skin::Skin>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
/// The index of the accessor containing the 4x4 inverse-bind matrices.
///
/// When `None`,each matrix is assumed to be the 4x4 identity matrix
/// which implies that the inverse-bind matrices were pre-applied.
#[serde(rename = "inverseBindMatrices")]
#[serde(skip_serializing_if = "Option::is_none")]
pub inverse_bind_matrices: Option<Index<accessor::Accessor>>,
/// Indices of skeleton nodes used as joints in this skin.
///
/// The array length must be the same as the `count` property of the
/// `inverse_bind_matrices` `Accessor` (when defined).
#[serde(skip_serializing_if = "Vec::is_empty")]
pub joints: Vec<Index<scene::Node>>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The index of the node used as a skeleton root.
///
/// When `None`, joints transforms resolve to scene root.
#[serde(skip_serializing_if = "Option::is_none")]
pub skeleton: Option<Index<scene::Node>>,
}

479
vendor/gltf-json/src/texture.rs vendored Normal file
View File

@@ -0,0 +1,479 @@
use crate::validation::{Checked, Validate};
use crate::{extensions, image, Extras, Index};
use gltf_derive::Validate;
use serde::{de, ser};
use serde_derive::{Deserialize, Serialize};
use std::fmt;
/// Corresponds to `GL_NEAREST`.
pub const NEAREST: u32 = 9728;
/// Corresponds to `GL_LINEAR`.
pub const LINEAR: u32 = 9729;
/// Corresponds to `GL_NEAREST_MIPMAP_NEAREST`.
pub const NEAREST_MIPMAP_NEAREST: u32 = 9984;
/// Corresponds to `GL_LINEAR_MIPMAP_NEAREST`.
pub const LINEAR_MIPMAP_NEAREST: u32 = 9985;
/// Corresponds to `GL_NEAREST_MIPMAP_LINEAR`.
pub const NEAREST_MIPMAP_LINEAR: u32 = 9986;
/// Corresponds to `GL_LINEAR_MIPMAP_LINEAR`.
pub const LINEAR_MIPMAP_LINEAR: u32 = 9987;
/// Corresponds to `GL_CLAMP_TO_EDGE`.
pub const CLAMP_TO_EDGE: u32 = 33_071;
/// Corresponds to `GL_MIRRORED_REPEAT`.
pub const MIRRORED_REPEAT: u32 = 33_648;
/// Corresponds to `GL_REPEAT`.
pub const REPEAT: u32 = 10_497;
/// All valid magnification filters.
pub const VALID_MAG_FILTERS: &[u32] = &[NEAREST, LINEAR];
/// All valid minification filters.
pub const VALID_MIN_FILTERS: &[u32] = &[
NEAREST,
LINEAR,
NEAREST_MIPMAP_NEAREST,
LINEAR_MIPMAP_NEAREST,
NEAREST_MIPMAP_LINEAR,
LINEAR_MIPMAP_LINEAR,
];
/// All valid wrapping modes.
pub const VALID_WRAPPING_MODES: &[u32] = &[CLAMP_TO_EDGE, MIRRORED_REPEAT, REPEAT];
/// Magnification filter.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
pub enum MagFilter {
/// Corresponds to `GL_NEAREST`.
Nearest = 1,
/// Corresponds to `GL_LINEAR`.
Linear,
}
impl MagFilter {
/// OpenGL enum
pub fn as_gl_enum(&self) -> u32 {
match *self {
MagFilter::Nearest => NEAREST,
MagFilter::Linear => LINEAR,
}
}
}
/// Minification filter.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
pub enum MinFilter {
/// Corresponds to `GL_NEAREST`.
Nearest = 1,
/// Corresponds to `GL_LINEAR`.
Linear,
/// Corresponds to `GL_NEAREST_MIPMAP_NEAREST`.
NearestMipmapNearest,
/// Corresponds to `GL_LINEAR_MIPMAP_NEAREST`.
LinearMipmapNearest,
/// Corresponds to `GL_NEAREST_MIPMAP_LINEAR`.
NearestMipmapLinear,
/// Corresponds to `GL_LINEAR_MIPMAP_LINEAR`.
LinearMipmapLinear,
}
impl MinFilter {
/// Returns the corresponding OpenGL enum value.
pub fn as_gl_enum(&self) -> u32 {
match *self {
MinFilter::Nearest => NEAREST,
MinFilter::Linear => LINEAR,
MinFilter::NearestMipmapNearest => NEAREST_MIPMAP_NEAREST,
MinFilter::LinearMipmapNearest => LINEAR_MIPMAP_NEAREST,
MinFilter::NearestMipmapLinear => NEAREST_MIPMAP_LINEAR,
MinFilter::LinearMipmapLinear => LINEAR_MIPMAP_LINEAR,
}
}
}
/// Texture co-ordinate wrapping mode.
#[derive(Clone, Copy, Debug, Deserialize, Eq, PartialEq)]
pub enum WrappingMode {
/// Corresponds to `GL_CLAMP_TO_EDGE`.
ClampToEdge = 1,
/// Corresponds to `GL_MIRRORED_REPEAT`.
MirroredRepeat,
/// Corresponds to `GL_REPEAT`.
Repeat,
}
impl WrappingMode {
/// Returns the corresponding OpenGL enum value.
pub fn as_gl_enum(&self) -> u32 {
match *self {
WrappingMode::ClampToEdge => CLAMP_TO_EDGE,
WrappingMode::MirroredRepeat => MIRRORED_REPEAT,
WrappingMode::Repeat => REPEAT,
}
}
}
/// Texture sampler properties for filtering and wrapping modes.
#[derive(Clone, Debug, Default, Deserialize, Serialize, Validate)]
#[serde(default)]
pub struct Sampler {
/// Magnification filter.
#[serde(rename = "magFilter")]
#[serde(skip_serializing_if = "Option::is_none")]
pub mag_filter: Option<Checked<MagFilter>>,
/// Minification filter.
#[serde(rename = "minFilter")]
#[serde(skip_serializing_if = "Option::is_none")]
pub min_filter: Option<Checked<MinFilter>>,
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// `s` wrapping mode.
#[serde(default, rename = "wrapS")]
pub wrap_s: Checked<WrappingMode>,
/// `t` wrapping mode.
#[serde(default, rename = "wrapT")]
pub wrap_t: Checked<WrappingMode>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::texture::Sampler>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
fn source_default() -> Index<image::Image> {
Index::new(u32::MAX)
}
fn source_is_empty(source: &Index<image::Image>) -> bool {
source.value() == u32::MAX as usize
}
fn source_validate<P, R>(source: &Index<image::Image>, root: &crate::Root, path: P, report: &mut R)
where
P: Fn() -> crate::Path,
R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
{
if cfg!(feature = "allow_empty_texture") {
if !source_is_empty(source) {
source.validate(root, path, report);
}
} else if source_is_empty(source) {
report(&path, crate::validation::Error::Missing);
} else {
source.validate(root, &path, report);
}
}
/// A texture and its sampler.
#[derive(Clone, Debug, Deserialize, Serialize)]
pub struct Texture {
/// Optional user-defined name for this object.
#[cfg(feature = "names")]
#[cfg_attr(feature = "names", serde(skip_serializing_if = "Option::is_none"))]
pub name: Option<String>,
/// The index of the sampler used by this texture.
#[serde(skip_serializing_if = "Option::is_none")]
pub sampler: Option<Index<Sampler>>,
/// The index of the image used by this texture.
#[serde(default = "source_default", skip_serializing_if = "source_is_empty")]
pub source: Index<image::Image>,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::texture::Texture>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
impl Validate for Texture {
fn validate<P, R>(&self, root: &crate::Root, path: P, report: &mut R)
where
P: Fn() -> crate::Path,
R: FnMut(&dyn Fn() -> crate::Path, crate::validation::Error),
{
self.sampler
.validate(root, || path().field("sampler"), report);
self.extensions
.validate(root, || path().field("extensions"), report);
source_validate(&self.source, root, || path().field("source"), report);
}
}
#[derive(Clone, Debug, Deserialize, Serialize, Validate)]
/// Reference to a `Texture`.
pub struct Info {
/// The index of the texture.
pub index: Index<Texture>,
/// The set index of the texture's `TEXCOORD` attribute.
#[serde(default, rename = "texCoord")]
pub tex_coord: u32,
/// Extension specific data.
#[serde(default, skip_serializing_if = "Option::is_none")]
pub extensions: Option<extensions::texture::Info>,
/// Optional application specific data.
#[serde(default)]
#[cfg_attr(feature = "extras", serde(skip_serializing_if = "Option::is_none"))]
#[cfg_attr(not(feature = "extras"), serde(skip_serializing))]
pub extras: Extras,
}
impl<'de> de::Deserialize<'de> for Checked<MagFilter> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<MagFilter>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_MAG_FILTERS)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::MagFilter::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
NEAREST => Valid(Nearest),
LINEAR => Valid(Linear),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl<'de> de::Deserialize<'de> for Checked<MinFilter> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<MinFilter>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_MIN_FILTERS)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::MinFilter::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
NEAREST => Valid(Nearest),
LINEAR => Valid(Linear),
NEAREST_MIPMAP_NEAREST => Valid(NearestMipmapNearest),
LINEAR_MIPMAP_NEAREST => Valid(LinearMipmapNearest),
NEAREST_MIPMAP_LINEAR => Valid(NearestMipmapLinear),
LINEAR_MIPMAP_LINEAR => Valid(LinearMipmapLinear),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl ser::Serialize for MinFilter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u32(self.as_gl_enum())
}
}
impl<'de> de::Deserialize<'de> for Checked<WrappingMode> {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: de::Deserializer<'de>,
{
struct Visitor;
impl<'de> de::Visitor<'de> for Visitor {
type Value = Checked<WrappingMode>;
fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "any of: {:?}", VALID_WRAPPING_MODES)
}
fn visit_u64<E>(self, value: u64) -> Result<Self::Value, E>
where
E: de::Error,
{
use self::WrappingMode::*;
use crate::validation::Checked::*;
Ok(match value as u32 {
CLAMP_TO_EDGE => Valid(ClampToEdge),
MIRRORED_REPEAT => Valid(MirroredRepeat),
REPEAT => Valid(Repeat),
_ => Invalid,
})
}
}
deserializer.deserialize_u64(Visitor)
}
}
impl ser::Serialize for MagFilter {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u32(self.as_gl_enum())
}
}
impl Default for WrappingMode {
fn default() -> Self {
WrappingMode::Repeat
}
}
impl ser::Serialize for WrappingMode {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: ser::Serializer,
{
serializer.serialize_u32(self.as_gl_enum())
}
}
#[cfg(test)]
mod tests {
#[test]
fn deserialize_source() {
let json = r#"{"asset":{"version":"2.0"},"textures":[{"source": 0}]}"#;
let root = serde_json::from_str::<crate::Root>(json).unwrap();
assert_eq!(0, root.textures[0].source.value());
}
#[test]
fn deserialize_empty_source() {
let json = r#"{"asset":{"version":"2.0"},"textures":[{}]}"#;
let root = serde_json::from_str::<crate::Root>(json).unwrap();
assert_eq!(u32::MAX as usize, root.textures[0].source.value());
}
#[test]
fn serialize_source() {
let root = crate::Root {
textures: vec![crate::Texture {
#[cfg(feature = "names")]
name: None,
sampler: None,
source: crate::Index::new(0),
extensions: None,
extras: Default::default(),
}],
..Default::default()
};
let json = serde_json::to_string(&root).unwrap();
assert_eq!(
r#"{"asset":{"version":"2.0"},"textures":[{"source":0}]}"#,
&json
);
}
#[test]
fn serialize_empty_source() {
let root = crate::Root {
textures: vec![crate::Texture {
#[cfg(feature = "names")]
name: None,
sampler: None,
source: crate::Index::new(u32::MAX),
extensions: None,
extras: Default::default(),
}],
..Default::default()
};
let json = serde_json::to_string(&root).unwrap();
assert_eq!(r#"{"asset":{"version":"2.0"},"textures":[{}]}"#, &json);
}
#[test]
fn validate_source() {
use crate::validation::{Error, Validate};
use crate::Path;
let json = r#"{"asset":{"version":"2.0"},"textures":[{"source":0}]}"#;
let root = serde_json::from_str::<crate::Root>(json).unwrap();
let mut errors = Vec::new();
root.textures[0].validate(
&root,
|| Path::new().field("textures").index(0),
&mut |path, error| {
errors.push((path(), error));
},
);
assert_eq!(1, errors.len());
let (path, error) = &errors[0];
assert_eq!("textures[0].source", path.as_str());
assert_eq!(Error::IndexOutOfBounds, *error);
}
#[test]
fn validate_empty_source() {
use crate::validation::{Error, Validate};
use crate::Path;
let json = r#"{"asset":{"version":"2.0"},"textures":[{}]}"#;
let root = serde_json::from_str::<crate::Root>(json).unwrap();
let mut errors = Vec::new();
root.textures[0].validate(
&root,
|| Path::new().field("textures").index(0),
&mut |path, error| {
errors.push((path(), error));
},
);
if cfg!(feature = "allow_empty_texture") {
assert!(errors.is_empty());
} else {
assert_eq!(1, errors.len());
let (path, error) = &errors[0];
assert_eq!("textures[0].source", path.as_str());
assert_eq!(Error::Missing, *error);
}
}
}

238
vendor/gltf-json/src/validation.rs vendored Normal file
View File

@@ -0,0 +1,238 @@
use serde::{ser, Serialize, Serializer};
use std::collections::BTreeMap;
use std::hash::Hash;
use crate::{Path, Root};
/// Trait for validating glTF JSON data so that the library can function without panicking.
pub trait Validate {
/// Validates the invariants required for the library to function safely.
fn validate<P, R>(&self, _root: &Root, _path: P, _report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
// nop
}
}
/// Specifies what kind of error occured during validation.
#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub enum Error {
/// An index was found to be out of bounds.
IndexOutOfBounds,
/// An invalid value was identified.
Invalid,
/// Some required data has been omitted.
Missing,
/// A memory size or offset exceeds the system limits.
Oversize,
/// One of more required extensions is not supported by this crate version.
Unsupported,
}
/// Specifies a type that has been pre-validated during deserialization or otherwise.
#[derive(Debug, Eq, Hash, PartialEq, Ord, PartialOrd)]
pub enum Checked<T> {
/// The item is valid.
Valid(T),
/// The item is invalid.
Invalid,
}
impl<T> Checked<T> {
/// Converts from `Checked<T>` to `Checked<&T>`.
pub fn as_ref(&self) -> Checked<&T> {
match *self {
Checked::Valid(ref item) => Checked::Valid(item),
Checked::Invalid => Checked::Invalid,
}
}
/// Takes ownership of the contained item if it is `Valid`.
///
/// # Panics
///
/// Panics if called on an `Invalid` item.
pub fn unwrap(self) -> T {
match self {
Checked::Valid(item) => item,
Checked::Invalid => panic!("attempted to unwrap an invalid item"),
}
}
}
impl<T: Serialize> Serialize for Checked<T> {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
match *self {
Checked::Valid(ref item) => item.serialize(serializer),
Checked::Invalid => Err(ser::Error::custom("invalid item")),
}
}
}
impl<T: Clone> Clone for Checked<T> {
fn clone(&self) -> Self {
match *self {
Checked::Valid(ref item) => Checked::Valid(item.clone()),
Checked::Invalid => Checked::Invalid,
}
}
}
impl<T: Copy> Copy for Checked<T> {}
impl<T: Default> Default for Checked<T> {
fn default() -> Self {
Checked::Valid(T::default())
}
}
impl<T> Validate for Checked<T> {
fn validate<P, R>(&self, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
match *self {
Checked::Valid(_) => {}
Checked::Invalid => report(&path, Error::Invalid),
}
}
}
/// Validates the suitability of 64-bit byte offsets/sizes on 32-bit systems.
#[derive(
Clone,
Copy,
Debug,
Default,
Eq,
Hash,
PartialEq,
serde_derive::Deserialize,
serde_derive::Serialize,
)]
pub struct USize64(pub u64);
impl From<u64> for USize64 {
fn from(value: u64) -> Self {
Self(value)
}
}
impl From<usize> for USize64 {
fn from(value: usize) -> Self {
Self(value as u64)
}
}
impl Validate for USize64 {
fn validate<P, R>(&self, _root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if usize::try_from(self.0).is_err() {
report(&path, Error::Oversize);
}
}
}
impl<K: ToString + Validate, V: Validate> Validate for BTreeMap<K, V> {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
for (key, value) in self.iter() {
key.validate(root, || path().key(&key.to_string()), report);
value.validate(root, || path().key(&key.to_string()), report);
}
}
}
impl Validate for serde_json::Map<String, serde_json::Value> {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
for (key, value) in self.iter() {
key.validate(root, || path().key(&key.to_string()), report);
value.validate(root, || path().key(&key.to_string()), report);
}
}
}
impl<T: Validate> Validate for Option<T> {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
if let Some(value) = self.as_ref() {
value.validate(root, path, report);
}
}
}
impl<T: Validate> Validate for Vec<T> {
fn validate<P, R>(&self, root: &Root, path: P, report: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
for (index, value) in self.iter().enumerate() {
value.validate(root, || path().index(index), report);
}
}
}
impl Validate for std::boxed::Box<serde_json::value::RawValue> {
fn validate<P, R>(&self, _: &Root, _: P, _: &mut R)
where
P: Fn() -> Path,
R: FnMut(&dyn Fn() -> Path, Error),
{
// nop
}
}
impl std::error::Error for Error {}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
write!(
f,
"{}",
match *self {
Error::IndexOutOfBounds => "Index out of bounds",
Error::Invalid => "Invalid value",
Error::Missing => "Missing data",
Error::Oversize => "Size exceeds system limits",
Error::Unsupported => "Unsupported extension",
}
)
}
}
// These types are assumed to be always valid.
impl Validate for bool {}
impl Validate for u32 {}
impl Validate for i32 {}
impl Validate for f32 {}
impl Validate for [f32; 3] {}
impl Validate for [f32; 4] {}
impl Validate for [f32; 16] {}
impl Validate for () {}
impl Validate for String {}
impl Validate for serde_json::Value {}

View File

@@ -0,0 +1,53 @@
{
"scenes" : [ { "nodes" : [ 0 ] } ],
"nodes" : [ { "mesh" : 0 } ],
"meshes" : [
{
"primitives" : [ {
"attributes" : { "POSITION" : 1 },
"indices" : 0
} ]
}
],
"buffers" : [
{
"uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
"byteLength" : 44
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteOffset" : 0,
"byteLength" : 6,
"target" : 34963
},
{
"buffer" : 0,
"byteOffset" : 8,
"byteLength" : 36,
"target" : 34962
}
],
"accessors" : [
{
"bufferView" : 0,
"byteOffset" : 0,
"componentType" : 5123,
"count" : 3,
"type" : "SCALAR"
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"type" : "VEC3",
"max" : [ 1.0, 1.0 ]
}
],
"asset" : {
"version" : "2.0"
}
}

View File

@@ -0,0 +1,53 @@
{
"scenes" : [ { "nodes" : [ 0 ] } ],
"nodes" : [ { "mesh" : 0 } ],
"meshes" : [
{
"primitives" : [ {
"attributes" : { "POSITION" : 1 },
"indices" : 0
} ]
}
],
"buffers" : [
{
"uri" : "data:application/octet-stream;base64,AAABAAIAAAAAAAAAAAAAAAAAAAAAAIA/AAAAAAAAAAAAAAAAAACAPwAAAAA=",
"byteLength" : 44
}
],
"bufferViews" : [
{
"buffer" : 0,
"byteOffset" : 0,
"byteLength" : 6,
"target" : 34963
},
{
"buffer" : 0,
"byteOffset" : 8,
"byteLength" : 36,
"target" : 34962
}
],
"accessors" : [
{
"byteOffset" : 0,
"componentType" : 5123,
"count" : 3,
"type" : "SCALAR"
},
{
"bufferView" : 1,
"byteOffset" : 0,
"componentType" : 5126,
"count" : 3,
"type" : "VEC3",
"min" : [ 0.0, 0.0, 0.0 ],
"max" : [ 1.0, 1.0, 1.0 ]
}
],
"asset" : {
"version" : "2.0"
}
}

View File

@@ -0,0 +1,46 @@
use std::{fs, io};
use gltf_json::validation::{Error, Validate};
use gltf_json::Path;
fn import_json(filename: &str) -> gltf_json::Root {
let file = fs::File::open(filename).unwrap();
let reader = io::BufReader::new(file);
gltf_json::Root::from_reader(reader).unwrap()
}
#[test]
fn test_accessor_bounds_validate() {
// file with missing min/max values
let json = import_json("tests/minimal_accessor_invalid.gltf");
let mut errs = vec![];
json.validate(&json, gltf_json::Path::new, &mut |path, err| {
errs.push((path(), err))
});
assert_eq!(
errs,
[
(
Path("meshes[0].primitives[0].attributes[\"POSITION\"].min".into()),
Error::Missing
),
(
Path("meshes[0].primitives[0].attributes[\"POSITION\"].max".into()),
Error::Invalid
)
]
);
}
#[test]
fn test_non_sparse_accessor_without_buffer_view_validate() {
let json = import_json("tests/non_sparse_accessor_without_buffer_view.gltf");
let mut errs = vec![];
json.validate(&json, gltf_json::Path::new, &mut |path, err| {
errs.push((path(), err))
});
assert_eq!(
errs,
[(Path("accessors[0].bufferView".into()), Error::Missing)]
);
}