Revision control
++ // Copyright (C) 2026 The Qt Company Ltd.
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
++ // Qt-Security score:significant reason:default
++
++ #ifndef QSSGGLTFDOCUMENT_P_H
++ #define QSSGGLTFDOCUMENT_P_H
++
++ //
++ // W A R N I N G
++ // -------------
++ //
++ // This file is not part of the Qt API. It exists purely as an
++ // implementation detail. This header file may change from version to
++ // version without notice, or even be removed.
++ //
++ // We mean it.
++ //
++
++ #include <QtQuick3DGltf/qtquick3dgltfexports.h>
++
++ #include <QtCore/qbytearray.h>
++ #include <QtCore/qhash.h>
++ #include <QtCore/qjsonobject.h>
++ #include <QtCore/qlist.h>
++ #include <QtCore/qmath.h>
++ #include <QtCore/qstring.h>
++ #include <QtCore/qstringlist.h>
++ #include <QtGui/qmatrix4x4.h>
++ #include <QtGui/qquaternion.h>
++ #include <QtGui/qvector2d.h>
++ #include <QtGui/qvector3d.h>
++ #include <QtGui/qvector4d.h>
++
++ #include <optional>
++
++ QT_BEGIN_NAMESPACE
++
++ // A value-struct representation of a glTF 2.0 document, mirroring the JSON
++ // schema. Object references are integer indices into the document-level
++ // arrays, exactly as in the format; -1 means "not set". Data specific to
++ // supported extensions is parsed into typed members; anything else stays
++ // available through the raw extension objects.
++ namespace QSSGGltf {
++
++ struct Asset
++ {
++ QString version;
++ QString minVersion;
++ QString generator;
++ QString copyright;
++ };
++
++ struct Buffer
++ {
++ QString uri;
++ qint64 byteLength = 0;
++ QByteArray data; // resolved contents (GLB BIN chunk, data: URI, or external file)
++ bool meshoptFallback = false; // EXT_meshopt_compression fallback, never loaded
++ };
++
++ struct BufferView
++ {
++ int buffer = -1;
++ qint64 byteOffset = 0;
++ qint64 byteLength = 0;
++ int byteStride = 0; // 0 = tightly packed
++ int target = 0;
++ QString name;
++ };
++
++ struct Accessor
++ {
++ // Values match the glTF componentType constants
++ enum class ComponentType {
++ Byte = 5120,
++ UnsignedByte = 5121,
++ Short = 5122,
++ UnsignedShort = 5123,
++ UnsignedInt = 5125,
++ Float = 5126
++ };
++ enum class Type {
++ Scalar,
++ Vec2,
++ Vec3,
++ Vec4,
++ Mat2,
++ Mat3,
++ Mat4
++ };
++
++ struct Sparse
++ {
++ qint64 count = 0;
++ int indicesBufferView = -1;
++ qint64 indicesByteOffset = 0;
++ ComponentType indicesComponentType = ComponentType::UnsignedInt;
++ int valuesBufferView = -1;
++ qint64 valuesByteOffset = 0;
++ };
++
++ int bufferView = -1; // -1 = all zeros (unless sparse)
++ qint64 byteOffset = 0;
++ ComponentType componentType = ComponentType::Float;
++ Type type = Type::Scalar;
++ qint64 count = 0;
++ bool normalized = false;
++ QList<double> min;
++ QList<double> max;
++ std::optional<Sparse> sparse;
++ QString name;
++
++ static int componentByteSize(ComponentType componentType)
++ {
++ switch (componentType) {
++ case ComponentType::Byte:
++ case ComponentType::UnsignedByte:
++ return 1;
++ case ComponentType::Short:
++ case ComponentType::UnsignedShort:
++ return 2;
++ case ComponentType::UnsignedInt:
++ case ComponentType::Float:
++ return 4;
++ }
++ return 0;
++ }
++
++ static int componentCount(Type type)
++ {
++ switch (type) {
++ case Type::Scalar: return 1;
++ case Type::Vec2: return 2;
++ case Type::Vec3: return 3;
++ case Type::Vec4: return 4;
++ case Type::Mat2: return 4;
++ case Type::Mat3: return 9;
++ case Type::Mat4: return 16;
++ }
++ return 0;
++ }
++
++ int elementByteSize() const
++ {
++ return componentByteSize(componentType) * componentCount(type);
++ }
++ };
++
++ struct Image
++ {
++ QString uri;
++ int bufferView = -1;
++ QString mimeType;
++ QString name;
++ };
++
++ struct Sampler
++ {
++ // Values match the glTF/GL filter and wrap constants; 0 = unspecified
++ enum Filter {
++ Nearest = 9728,
++ Linear = 9729,
++ NearestMipMapNearest = 9984,
++ LinearMipMapNearest = 9985,
++ NearestMipMapLinear = 9986,
++ LinearMipMapLinear = 9987
++ };
++ enum WrapMode {
++ ClampToEdge = 33071,
++ MirroredRepeat = 33648,
++ Repeat = 10497
++ };
++
++ int magFilter = 0;
++ int minFilter = 0;
++ int wrapS = Repeat;
++ int wrapT = Repeat;
++ QString name;
++ };
++
++ struct Texture
++ {
++ int sampler = -1;
++ int source = -1;
++ int webpSource = -1; // EXT_texture_webp; preferred over source when set
++ QString name;
++ QJsonObject extensions;
++ };
++
++ struct TextureTransform // KHR_texture_transform
++ {
++ QVector2D offset { 0.0f, 0.0f };
++ QVector2D scale { 1.0f, 1.0f };
++ float rotation = 0.0f;
++ int texCoord = -1; // -1 = keep the TextureInfo texCoord
++ };
++
++ struct TextureInfo
++ {
++ int index = -1;
++ int texCoord = 0;
++ // scale for normalTexture, strength for occlusionTexture; 1.0 otherwise
++ float scaleOrStrength = 1.0f;
++ std::optional<TextureTransform> transform;
++
++ bool isSet() const { return index >= 0; }
++ };
++
++ struct Material
++ {
++ enum class AlphaMode {
++ Opaque,
++ Mask,
++ Blend
++ };
++
++ struct SpecularGlossiness // KHR_materials_pbrSpecularGlossiness
++ {
++ QVector4D diffuseFactor { 1.0f, 1.0f, 1.0f, 1.0f };
++ TextureInfo diffuseTexture;
++ QVector3D specularFactor { 1.0f, 1.0f, 1.0f };
++ float glossinessFactor = 1.0f;
++ TextureInfo specularGlossinessTexture;
++ };
++
++ struct Clearcoat // KHR_materials_clearcoat
++ {
++ float clearcoatFactor = 0.0f;
++ TextureInfo clearcoatTexture;
++ float clearcoatRoughnessFactor = 0.0f;
++ TextureInfo clearcoatRoughnessTexture;
++ TextureInfo clearcoatNormalTexture; // scaleOrStrength = normal scale
++ };
++
++ struct Transmission // KHR_materials_transmission
++ {
++ float transmissionFactor = 0.0f;
++ TextureInfo transmissionTexture;
++ };
++
++ struct Volume // KHR_materials_volume
++ {
++ float thicknessFactor = 0.0f;
++ TextureInfo thicknessTexture;
++ float attenuationDistance = 0.0f; // 0 = +infinity per spec default
++ QVector3D attenuationColor { 1.0f, 1.0f, 1.0f };
++ };
++
++ struct Specular // KHR_materials_specular
++ {
++ float specularFactor = 1.0f;
++ TextureInfo specularTexture;
++ QVector3D specularColorFactor { 1.0f, 1.0f, 1.0f };
++ TextureInfo specularColorTexture;
++ };
++
++ struct Sheen // KHR_materials_sheen
++ {
++ QVector3D sheenColorFactor { 0.0f, 0.0f, 0.0f };
++ TextureInfo sheenColorTexture;
++ float sheenRoughnessFactor = 0.0f;
++ TextureInfo sheenRoughnessTexture;
++ };
++
++ struct Anisotropy // KHR_materials_anisotropy
++ {
++ float anisotropyStrength = 0.0f;
++ float anisotropyRotation = 0.0f; // radians
++ TextureInfo anisotropyTexture;
++ };
++
++ struct Iridescence // KHR_materials_iridescence
++ {
++ float iridescenceFactor = 0.0f;
++ TextureInfo iridescenceTexture;
++ float iridescenceIor = 1.3f;
++ float iridescenceThicknessMinimum = 100.0f; // nanometers
++ float iridescenceThicknessMaximum = 400.0f; // nanometers
++ TextureInfo iridescenceThicknessTexture;
++ };
++
++ QString name;
++
++ // pbrMetallicRoughness
++ QVector4D baseColorFactor { 1.0f, 1.0f, 1.0f, 1.0f };
++ TextureInfo baseColorTexture;
++ float metallicFactor = 1.0f;
++ float roughnessFactor = 1.0f;
++ TextureInfo metallicRoughnessTexture;
++
++ TextureInfo normalTexture; // scaleOrStrength = scale
++ TextureInfo occlusionTexture; // scaleOrStrength = strength
++ TextureInfo emissiveTexture;
++ QVector3D emissiveFactor { 0.0f, 0.0f, 0.0f };
++
++ AlphaMode alphaMode = AlphaMode::Opaque;
++ float alphaCutoff = 0.5f;
++ bool doubleSided = false;
++
++ // Extensions
++ bool unlit = false; // KHR_materials_unlit
++ std::optional<SpecularGlossiness> specularGlossiness;
++ std::optional<Clearcoat> clearcoat;
++ std::optional<Transmission> transmission;
++ std::optional<Volume> volume;
++ std::optional<float> ior; // KHR_materials_ior
++ std::optional<float> emissiveStrength; // KHR_materials_emissive_strength
++ std::optional<Specular> specular;
++ std::optional<Sheen> sheen;
++ std::optional<Anisotropy> anisotropy;
++ std::optional<Iridescence> iridescence;
++ std::optional<float> dispersion; // KHR_materials_dispersion
++
++ QJsonObject extensions; // raw, including any we do not support
++ };
++
++ struct MeshPrimitive
++ {
++ // Values match the glTF primitive.mode constants
++ enum Mode {
++ Points = 0,
++ Lines = 1,
++ LineLoop = 2,
++ LineStrip = 3,
++ Triangles = 4,
++ TriangleStrip = 5,
++ TriangleFan = 6
++ };
++
++ struct VariantMapping // KHR_materials_variants
++ {
++ int material = -1;
++ QList<int> variants; // indices into QSSGGltfDocument::materialVariants
++ };
++
++ QHash<QByteArray, int> attributes; // semantic (POSITION, NORMAL, ...) -> accessor
++ int indices = -1;
++ int material = -1;
++ int mode = Triangles;
++ QList<QHash<QByteArray, int>> targets; // morph targets
++ QList<VariantMapping> variantMappings; // KHR_materials_variants
++ QJsonObject extensions;
++
++ // -1 or an unmapped variant selects the default; the first match wins
++ int effectiveMaterial(int variantIndex) const
++ {
++ if (variantIndex >= 0) {
++ for (const VariantMapping &mapping : variantMappings) {
++ if (mapping.variants.contains(variantIndex))
++ return mapping.material;
++ }
++ }
++ return material;
++ }
++ };
++
++ struct Mesh
++ {
++ QList<MeshPrimitive> primitives;
++ QList<float> weights; // default morph target weights
++ QString name;
++ };
++
++ struct Node
++ {
++ QList<int> children;
++ int mesh = -1;
++ int skin = -1;
++ int camera = -1;
++ int light = -1; // KHR_lights_punctual
++ bool hasMatrix = false;
++ QMatrix4x4 matrix;
++ QVector3D translation { 0.0f, 0.0f, 0.0f };
++ QQuaternion rotation;
++ QVector3D scale { 1.0f, 1.0f, 1.0f };
++ QList<float> weights; // overrides mesh.weights
++ bool visible = true; // KHR_node_visibility; applies to the node's subtree
++ // EXT_mesh_gpu_instancing accessors
++ bool hasInstancing = false;
++ int instanceTranslation = -1;
++ int instanceRotation = -1;
++ int instanceScale = -1;
++ QString name;
++ QJsonObject extensions;
++ };
++
++ struct Skin
++ {
++ int inverseBindMatrices = -1; // -1 = identity matrices
++ int skeleton = -1;
++ QList<int> joints;
++ QString name;
++ };
++
++ struct AnimationSampler
++ {
++ enum class Interpolation {
++ Linear,
++ Step,
++ CubicSpline
++ };
++
++ int input = -1; // accessor with key times (seconds)
++ int output = -1; // accessor with key values
++ Interpolation interpolation = Interpolation::Linear;
++ };
++
++ struct AnimationChannel
++ {
++ enum class Path {
++ Translation,
++ Rotation,
++ Scale,
++ Weights
++ };
++
++ int sampler = -1;
++ int targetNode = -1;
++ Path path = Path::Translation;
++ };
++
++ struct Animation
++ {
++ QList<AnimationSampler> samplers;
++ QList<AnimationChannel> channels;
++ QString name;
++ };
++
++ struct Camera
++ {
++ enum class Type {
++ Perspective,
++ Orthographic
++ };
++
++ Type type = Type::Perspective;
++ // perspective
++ float aspectRatio = 0.0f; // 0 = unspecified
++ float yfov = 0.0f; // radians
++ // orthographic
++ float xmag = 0.0f;
++ float ymag = 0.0f;
++ // shared
++ float znear = 0.0f;
++ float zfar = 0.0f; // 0 = infinite for perspective
++ QString name;
++ };
++
++ struct Light // KHR_lights_punctual
++ {
++ enum class Type {
++ Directional,
++ Point,
++ Spot
++ };
++
++ Type type = Type::Directional;
++ QVector3D color { 1.0f, 1.0f, 1.0f };
++ float intensity = 1.0f; // candela for point/spot, lux for directional
++ float range = 0.0f; // 0 = +infinity per spec default
++ // spot only
++ float innerConeAngle = 0.0f; // radians
++ float outerConeAngle = qDegreesToRadians(45.0f);
++ QString name;
++ };
++
++ struct Scene
++ {
++ QList<int> nodes;
++ QString name;
++ };
++
++ } // namespace QSSGGltf
++
++ class Q_QUICK3DGLTF_EXPORT QSSGGltfDocument
++ {
++ public:
++ QSSGGltf::Asset asset;
++ QList<QSSGGltf::Buffer> buffers;
++ QList<QSSGGltf::BufferView> bufferViews;
++ QList<QSSGGltf::Accessor> accessors;
++ QList<QSSGGltf::Image> images;
++ QList<QSSGGltf::Sampler> samplers;
++ QList<QSSGGltf::Texture> textures;
++ QList<QSSGGltf::Material> materials;
++ QList<QSSGGltf::Mesh> meshes;
++ QList<QSSGGltf::Node> nodes;
++ QList<QSSGGltf::Skin> skins;
++ QList<QSSGGltf::Animation> animations;
++ QList<QSSGGltf::Camera> cameras;
++ QList<QSSGGltf::Light> lights; // KHR_lights_punctual
++ QList<QSSGGltf::Scene> scenes;
++ int scene = -1;
++
++ QStringList extensionsUsed;
++ QStringList extensionsRequired;
++ QStringList materialVariants; // KHR_materials_variants variant names
++ QJsonObject rootExtensions;
++
++ // Directory the document was loaded from, used to resolve relative URIs.
++ // Local filesystem or qrc (":/...") path.
++ QString baseDir;
++ };
++
++ QT_END_NAMESPACE
++
++ #endif // QSSGGLTFDOCUMENT_P_H