Refactor prim reconstruction with X-macro property tables

- Add centralized enum handlers (enum-handlers.hh/cc) for APISchemas,
  reducing ~95 lines of duplicated code in usda/usdc readers
- Create prim-property-tables.hh with X-macro property tables for:
  - Geometry prims: GeomMesh, GeomSphere, GeomCube, GeomCone,
    GeomCylinder, GeomCapsule, GeomPoints, GeomBasisCurves,
    GeomCamera, GeomSubset, GeomPointInstancer
  - Skeleton prims: Skeleton, SkelAnimation, BlendShape
  - Light prims: SphereLight, RectLight, DiskLight, CylinderLight,
    DistantLight, GeometryLight, DomeLight
- Extract common light shadow/shaping attributes into shared macros
- Fix incorrect ADD_PROPERTY type arguments in CylinderLight,
  RectLight, and DistantLight (were using SphereLight)
- Net reduction of ~340 lines while improving maintainability

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Syoyo Fujita
2026-01-16 22:07:09 +09:00
parent 03d55b66af
commit f8b2145f41
7 changed files with 1253 additions and 793 deletions

View File

@@ -427,6 +427,7 @@ set(TINYUSDZ_SOURCES
${PROJECT_SOURCE_DIR}/src/prim-reconstruct.cc
${PROJECT_SOURCE_DIR}/src/prim-composition.cc
${PROJECT_SOURCE_DIR}/src/prim-types.cc
${PROJECT_SOURCE_DIR}/src/enum-handlers.cc
${PROJECT_SOURCE_DIR}/src/layer.cc
${PROJECT_SOURCE_DIR}/src/primvar.cc
${PROJECT_SOURCE_DIR}/src/str-util.cc

312
src/enum-handlers.cc Normal file
View File

@@ -0,0 +1,312 @@
// SPDX-License-Identifier: Apache 2.0
// Copyright 2024-Present Light Transport Entertainment Inc.
#include "enum-handlers.hh"
#include <array>
#include <algorithm>
#include "str-util.hh"
#include "tiny-format.hh"
namespace tinyusdz {
namespace enum_handler {
namespace {
// Helper template for enum token lookup
template <typename EnumT, size_t N>
nonstd::expected<EnumT, std::string> LookupEnum(
const std::string &prop_name,
const std::string &tok,
const std::array<std::pair<EnumT, const char *>, N> &enums) {
for (const auto &item : enums) {
if (tok == item.second) {
return item.first;
}
}
// Build error message with allowed tokens
std::vector<std::string> allowed;
for (const auto &item : enums) {
allowed.push_back(quote(item.second));
}
return nonstd::make_unexpected(
fmt::format("Invalid token for `{}`. Allowed: [{}], got: {}",
prop_name, join(", ", allowed), quote(tok)));
}
} // namespace
//
// Common/shared enum handlers
//
nonstd::expected<tinyusdz::Axis, std::string> Axis(const std::string &tok) {
using E = tinyusdz::Axis;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::X, "X"},
{E::Y, "Y"},
{E::Z, "Z"},
}};
return LookupEnum("axis", tok, enums);
}
nonstd::expected<tinyusdz::Visibility, std::string> Visibility(const std::string &tok) {
using E = tinyusdz::Visibility;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::Inherited, "inherited"},
{E::Invisible, "invisible"},
}};
return LookupEnum("visibility", tok, enums);
}
nonstd::expected<tinyusdz::Purpose, std::string> Purpose(const std::string &tok) {
using E = tinyusdz::Purpose;
constexpr std::array<std::pair<E, const char *>, 4> enums = {{
{E::Default, "default"},
{E::Proxy, "proxy"},
{E::Render, "render"},
{E::Guide, "guide"},
}};
return LookupEnum("purpose", tok, enums);
}
nonstd::expected<tinyusdz::Orientation, std::string> Orientation(const std::string &tok) {
using E = tinyusdz::Orientation;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::RightHanded, "rightHanded"},
{E::LeftHanded, "leftHanded"},
}};
return LookupEnum("orientation", tok, enums);
}
//
// GeomMesh enum handlers
//
nonstd::expected<GeomMesh::SubdivisionScheme, std::string>
SubdivisionScheme(const std::string &tok) {
using E = GeomMesh::SubdivisionScheme;
constexpr std::array<std::pair<E, const char *>, 4> enums = {{
{E::SubdivisionSchemeNone, "none"},
{E::CatmullClark, "catmullClark"},
{E::Loop, "loop"},
{E::Bilinear, "bilinear"},
}};
return LookupEnum("subdivisionScheme", tok, enums);
}
nonstd::expected<GeomMesh::InterpolateBoundary, std::string>
InterpolateBoundary(const std::string &tok) {
using E = GeomMesh::InterpolateBoundary;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::InterpolateBoundaryNone, "none"},
{E::EdgeAndCorner, "edgeAndCorner"},
{E::EdgeOnly, "edgeOnly"},
}};
return LookupEnum("interpolateBoundary", tok, enums);
}
nonstd::expected<GeomMesh::FaceVaryingLinearInterpolation, std::string>
FaceVaryingLinearInterpolation(const std::string &tok) {
using E = GeomMesh::FaceVaryingLinearInterpolation;
constexpr std::array<std::pair<E, const char *>, 6> enums = {{
{E::CornersPlus1, "cornersPlus1"},
{E::CornersPlus2, "cornersPlus2"},
{E::CornersOnly, "cornersOnly"},
{E::Boundaries, "boundaries"},
{E::FaceVaryingLinearInterpolationNone, "none"},
{E::All, "all"},
}};
return LookupEnum("faceVaryingLinearInterpolation", tok, enums);
}
//
// GeomSubset enum handlers
//
nonstd::expected<GeomSubset::ElementType, std::string>
ElementType(const std::string &tok) {
using E = GeomSubset::ElementType;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::Face, "face"},
{E::Point, "point"},
}};
return LookupEnum("elementType", tok, enums);
}
nonstd::expected<GeomSubset::FamilyType, std::string>
FamilyType(const std::string &tok) {
using E = GeomSubset::FamilyType;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::Partition, "partition"},
{E::NonOverlapping, "nonOverlapping"},
{E::Unrestricted, "unrestricted"},
}};
return LookupEnum("familyType", tok, enums);
}
//
// GeomBasisCurves enum handlers
//
nonstd::expected<GeomBasisCurves::Basis, std::string>
BasisCurvesBasis(const std::string &tok) {
using E = GeomBasisCurves::Basis;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::Bezier, "bezier"},
{E::Bspline, "bspline"},
{E::CatmullRom, "catmullRom"},
}};
return LookupEnum("basis", tok, enums);
}
nonstd::expected<GeomBasisCurves::Type, std::string>
BasisCurvesType(const std::string &tok) {
using E = GeomBasisCurves::Type;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::Cubic, "cubic"},
{E::Linear, "linear"},
}};
return LookupEnum("type", tok, enums);
}
nonstd::expected<GeomBasisCurves::Wrap, std::string>
BasisCurvesWrap(const std::string &tok) {
using E = GeomBasisCurves::Wrap;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::Nonperiodic, "nonperiodic"},
{E::Periodic, "periodic"},
{E::Pinned, "pinned"},
}};
return LookupEnum("wrap", tok, enums);
}
//
// GeomCamera enum handlers
//
nonstd::expected<GeomCamera::Projection, std::string>
CameraProjection(const std::string &tok) {
using E = GeomCamera::Projection;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::Perspective, "perspective"},
{E::Orthographic, "orthographic"},
}};
return LookupEnum("projection", tok, enums);
}
nonstd::expected<GeomCamera::StereoRole, std::string>
CameraStereoRole(const std::string &tok) {
using E = GeomCamera::StereoRole;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::Mono, "mono"},
{E::Left, "left"},
{E::Right, "right"},
}};
return LookupEnum("stereoRole", tok, enums);
}
//
// UsdPreviewSurface enum handlers
//
nonstd::expected<UsdPreviewSurface::OpacityMode, std::string>
OpacityMode(const std::string &tok) {
using E = UsdPreviewSurface::OpacityMode;
constexpr std::array<std::pair<E, const char *>, 2> enums = {{
{E::Transparent, "transparent"},
{E::Presence, "presence"},
}};
return LookupEnum("inputs:opacityMode", tok, enums);
}
//
// UsdUVTexture enum handlers
//
nonstd::expected<UsdUVTexture::SourceColorSpace, std::string>
SourceColorSpace(const std::string &tok) {
using E = UsdUVTexture::SourceColorSpace;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::Auto, "auto"},
{E::Raw, "raw"},
{E::SRGB, "sRGB"},
}};
return LookupEnum("inputs:sourceColorSpace", tok, enums);
}
nonstd::expected<UsdUVTexture::Wrap, std::string>
TextureWrap(const std::string &tok) {
using E = UsdUVTexture::Wrap;
constexpr std::array<std::pair<E, const char *>, 5> enums = {{
{E::UseMetadata, "useMetadata"},
{E::Black, "black"},
{E::Clamp, "clamp"},
{E::Repeat, "repeat"},
{E::Mirror, "mirror"},
}};
return LookupEnum("wrap", tok, enums);
}
//
// Collection enum handlers
//
nonstd::expected<CollectionInstance::ExpansionRule, std::string>
ExpansionRule(const std::string &tok) {
using E = CollectionInstance::ExpansionRule;
constexpr std::array<std::pair<E, const char *>, 3> enums = {{
{E::ExplicitOnly, "explicitOnly"},
{E::ExpandPrims, "expandPrims"},
{E::ExpandPrimsAndProperties, "expandPrimsAndProperties"},
}};
return LookupEnum("expansionRule", tok, enums);
}
//
// APISchemas enum handlers
//
nonstd::expected<APISchemas::APIName, std::string>
APISchemaName(const std::string &tok) {
using E = APISchemas::APIName;
constexpr std::array<std::pair<E, const char *>, 22> enums = {{
{E::SkelBindingAPI, "SkelBindingAPI"},
{E::CollectionAPI, "CollectionAPI"},
{E::MaterialBindingAPI, "MaterialBindingAPI"},
{E::ShapingAPI, "ShapingAPI"},
{E::ShadowAPI, "ShadowAPI"},
{E::VolumeLightAPI, "VolumeLightAPI"},
{E::Preliminary_PhysicsMaterialAPI, "Preliminary_PhysicsMaterialAPI"},
{E::Preliminary_PhysicsRigidBodyAPI, "Preliminary_PhysicsRigidBodyAPI"},
{E::Preliminary_PhysicsColliderAPI, "Preliminary_PhysicsColliderAPI"},
{E::Preliminary_AnchoringAPI, "Preliminary_AnchoringAPI"},
{E::LightAPI, "LightAPI"},
{E::MeshLightAPI, "MeshLightAPI"},
{E::LightListAPI, "LightListAPI"},
{E::ListAPI, "ListAPI"},
{E::MotionAPI, "MotionAPI"},
{E::PrimvarsAPI, "PrimvarsAPI"},
{E::GeomModelAPI, "GeomModelAPI"},
{E::VisibilityAPI, "VisibilityAPI"},
{E::XformCommonAPI, "XformCommonAPI"},
{E::NodeDefAPI, "NodeDefAPI"},
{E::CoordSysAPI, "CoordSysAPI"},
{E::ConnectableAPI, "ConnectableAPI"},
}};
return LookupEnum("apiSchemas", tok, enums);
}
nonstd::optional<APISchemas::APIName>
APISchemaNameOpt(const std::string &tok) {
auto result = APISchemaName(tok);
if (result) {
return result.value();
}
return nonstd::nullopt;
}
} // namespace enum_handler
} // namespace tinyusdz

150
src/enum-handlers.hh Normal file
View File

@@ -0,0 +1,150 @@
// SPDX-License-Identifier: Apache 2.0
// Copyright 2024-Present Light Transport Entertainment Inc.
//
/// @file enum-handlers.hh
/// @brief Centralized enum handlers for USD token-to-enum conversion
///
/// This file provides type-safe handlers for converting USD token strings
/// to their corresponding C++ enum values. Used primarily during prim
/// reconstruction from parsed USD data.
///
#pragma once
#include <string>
#include <vector>
#include <utility>
#include "nonstd/expected.hpp"
#include "prim-types.hh"
#include "usdGeom.hh"
#include "usdLux.hh"
#include "usdShade.hh"
#include "usdSkel.hh"
namespace tinyusdz {
/// Template type alias for enum handler functions
template <typename EnumTy>
using EnumHandlerFun = std::function<nonstd::expected<EnumTy, std::string>(
const std::string &)>;
namespace enum_handler {
//
// Common/shared enum handlers
//
/// Handle Axis enum (X, Y, Z)
nonstd::expected<Axis, std::string> Axis(const std::string &tok);
/// Handle Visibility enum (inherited, invisible)
nonstd::expected<Visibility, std::string> Visibility(const std::string &tok);
/// Handle Purpose enum (default, proxy, render, guide)
nonstd::expected<Purpose, std::string> Purpose(const std::string &tok);
/// Handle Orientation enum (rightHanded, leftHanded)
nonstd::expected<Orientation, std::string> Orientation(const std::string &tok);
//
// GeomMesh enum handlers
//
/// Handle GeomMesh::SubdivisionScheme enum
nonstd::expected<GeomMesh::SubdivisionScheme, std::string>
SubdivisionScheme(const std::string &tok);
/// Handle GeomMesh::InterpolateBoundary enum
nonstd::expected<GeomMesh::InterpolateBoundary, std::string>
InterpolateBoundary(const std::string &tok);
/// Handle GeomMesh::FaceVaryingLinearInterpolation enum
nonstd::expected<GeomMesh::FaceVaryingLinearInterpolation, std::string>
FaceVaryingLinearInterpolation(const std::string &tok);
//
// GeomSubset enum handlers
//
/// Handle GeomSubset::ElementType enum (face, point)
nonstd::expected<GeomSubset::ElementType, std::string>
ElementType(const std::string &tok);
/// Handle GeomSubset::FamilyType enum (partition, nonOverlapping, unrestricted)
nonstd::expected<GeomSubset::FamilyType, std::string>
FamilyType(const std::string &tok);
//
// GeomBasisCurves enum handlers
//
/// Handle GeomBasisCurves::Basis enum (bezier, bspline, catmullRom)
nonstd::expected<GeomBasisCurves::Basis, std::string>
BasisCurvesBasis(const std::string &tok);
/// Handle GeomBasisCurves::Type enum (cubic, linear)
nonstd::expected<GeomBasisCurves::Type, std::string>
BasisCurvesType(const std::string &tok);
/// Handle GeomBasisCurves::Wrap enum (nonperiodic, periodic, pinned)
nonstd::expected<GeomBasisCurves::Wrap, std::string>
BasisCurvesWrap(const std::string &tok);
//
// GeomCamera enum handlers
//
/// Handle GeomCamera::Projection enum (perspective, orthographic)
nonstd::expected<GeomCamera::Projection, std::string>
CameraProjection(const std::string &tok);
/// Handle GeomCamera::StereoRole enum (mono, left, right)
nonstd::expected<GeomCamera::StereoRole, std::string>
CameraStereoRole(const std::string &tok);
//
// UsdPreviewSurface enum handlers
//
/// Handle UsdPreviewSurface::OpacityMode enum (transparent, presence)
nonstd::expected<UsdPreviewSurface::OpacityMode, std::string>
OpacityMode(const std::string &tok);
//
// UsdUVTexture enum handlers
//
/// Handle UsdUVTexture::SourceColorSpace enum (auto, raw, sRGB)
nonstd::expected<UsdUVTexture::SourceColorSpace, std::string>
SourceColorSpace(const std::string &tok);
/// Handle UsdUVTexture::Wrap enum (useMetadata, black, clamp, repeat, mirror)
nonstd::expected<UsdUVTexture::Wrap, std::string>
TextureWrap(const std::string &tok);
//
// Collection enum handlers
//
/// Handle CollectionInstance::ExpansionRule enum
nonstd::expected<CollectionInstance::ExpansionRule, std::string>
ExpansionRule(const std::string &tok);
//
// APISchemas enum handlers
//
/// Handle APISchemas::APIName enum
/// Returns error for unknown schema names
nonstd::expected<APISchemas::APIName, std::string>
APISchemaName(const std::string &tok);
/// Handle APISchemas::APIName enum (optional version)
/// Returns nullopt for unknown schema names (useful for ignore_unknown mode)
nonstd::optional<APISchemas::APIName>
APISchemaNameOpt(const std::string &tok);
} // namespace enum_handler
} // namespace tinyusdz

337
src/prim-property-tables.hh Normal file
View File

@@ -0,0 +1,337 @@
// SPDX-License-Identifier: Apache 2.0
// Copyright 2024-Present Light Transport Entertainment Inc.
//
/// @file prim-property-tables.hh
/// @brief Property descriptor tables for prim reconstruction
///
/// This file defines property tables using X-macros to reduce code duplication
/// in prim-reconstruct.cc. Each prim type has a property table that lists
/// all its typed attributes, relationships, and enum properties.
///
/// Usage in prim-reconstruct.cc:
/// for (auto& prop : properties) {
/// GEOM_MESH_PROPERTIES(TYPED_ATTR, RELATION, ENUM_PROP)
/// // special handling...
/// ADD_PROPERTY(...)
/// }
#pragma once
//
// X-macro format:
// TYPED_ATTR(prop_name, member_name)
// TYPED_ATTR_NOCONT(prop_name, member_name) // no continue
// UNIFORM_ENUM(prop_name, enum_type, handler, member_name)
// TIMESAMPLED_ENUM(prop_name, enum_type, handler, member_name)
// SINGLE_REL(prop_name, member_name)
// MULTI_REL(prop_name, member_name)
// EXTENT(prop_name, member_name)
//
// ============================================================================
// GeomMesh Properties
// ============================================================================
#define GEOM_MESH_TYPED_ATTRS(X) \
X("points", points) \
X("normals", normals) \
X("faceVertexCounts", faceVertexCounts) \
X("faceVertexIndices", faceVertexIndices) \
X("cornerIndices", cornerIndices) \
X("cornerSharpnesses", cornerSharpnesses) \
X("creaseIndices", creaseIndices) \
X("creaseLengths", creaseLengths) \
X("creaseSharpnesses", creaseSharpnesses) \
X("holeIndices", holeIndices)
#define GEOM_MESH_SKEL_ATTRS(X) \
X(kSkelBlendShapes, blendShapes)
#define GEOM_MESH_RELATIONS(SINGLE, MULTI) \
SINGLE(kSkelSkeleton, skeleton) \
MULTI(kSkelBlendShapeTargets, blendShapeTargets)
#define GEOM_MESH_UNIFORM_ENUMS(X) \
X("subdivisionScheme", GeomMesh::SubdivisionScheme, SubdivisionSchemeHandler, subdivisionScheme)
#define GEOM_MESH_TIMESAMPLED_ENUMS(X) \
X("interpolateBoundary", GeomMesh::InterpolateBoundary, InterpolateBoundaryHandler, interpolateBoundary) \
X("facevaryingLinearInterpolation", GeomMesh::FaceVaryingLinearInterpolation, FaceVaryingLinearInterpolationHandler, faceVaryingLinearInterpolation)
// ============================================================================
// GeomCamera Properties
// ============================================================================
#define GEOM_CAMERA_TYPED_ATTRS(X) \
X("focalLength", focalLength) \
X("focusDistance", focusDistance) \
X("exposure", exposure) \
X("fStop", fStop) \
X("horizontalAperture", horizontalAperture) \
X("horizontalApertureOffset", horizontalApertureOffset) \
X("verticalAperture", verticalAperture) \
X("verticalApertureOffset", verticalApertureOffset) \
X("clippingRange", clippingRange) \
X("clippingPlanes", clippingPlanes) \
X("shutter:open", shutterOpen) \
X("shutter:close", shutterClose)
#define GEOM_CAMERA_TIMESAMPLED_ENUMS(X) \
X("projection", GeomCamera::Projection, ProjectionHandler, projection)
#define GEOM_CAMERA_UNIFORM_ENUMS(X) \
X("stereoRole", GeomCamera::StereoRole, StereoRoleHandler, stereoRole)
// ============================================================================
// GeomSubset Properties
// ============================================================================
#define GEOM_SUBSET_TYPED_ATTRS(X) \
X("familyName", familyName) \
X("indices", indices)
#define GEOM_SUBSET_UNIFORM_ENUMS(X) \
X("elementType", GeomSubset::ElementType, ElementTypeHandler, elementType)
// ============================================================================
// GeomPointInstancer Properties
// ============================================================================
#define GEOM_POINT_INSTANCER_TYPED_ATTRS(X) \
X("protoIndices", protoIndices) \
X("ids", ids) \
X("positions", positions) \
X("orientations", orientations) \
X("scales", scales) \
X("velocities", velocities) \
X("accelerations", accelerations) \
X("angularVelocities", angularVelocities) \
X("invisibleIds", invisibleIds) \
X("inactiveIds", inactiveIds)
#define GEOM_POINT_INSTANCER_RELATIONS(SINGLE, MULTI) \
MULTI("prototypes", prototypes)
// ============================================================================
// GeomBasisCurves Properties
// ============================================================================
#define GEOM_BASIS_CURVES_TYPED_ATTRS(X) \
X("points", points) \
X("normals", normals) \
X("curveVertexCounts", curveVertexCounts) \
X("widths", widths) \
X("velocities", velocities) \
X("accelerations", accelerations)
#define GEOM_BASIS_CURVES_UNIFORM_ENUMS(X) \
X("type", GeomBasisCurves::Type, TypeHandler, type) \
X("basis", GeomBasisCurves::Basis, BasisHandler, basis) \
X("wrap", GeomBasisCurves::Wrap, WrapHandler, wrap)
// ============================================================================
// GeomPoints Properties
// ============================================================================
#define GEOM_POINTS_TYPED_ATTRS(X) \
X("points", points) \
X("normals", normals) \
X("widths", widths) \
X("ids", ids) \
X("velocities", velocities) \
X("accelerations", accelerations)
// ============================================================================
// GeomSphere Properties
// ============================================================================
#define GEOM_SPHERE_TYPED_ATTRS(X) \
X("radius", radius)
// ============================================================================
// GeomCube Properties
// ============================================================================
#define GEOM_CUBE_TYPED_ATTRS(X) \
X("size", size)
// ============================================================================
// GeomCone Properties
// ============================================================================
#define GEOM_CONE_TYPED_ATTRS(X) \
X("radius", radius) \
X("height", height)
#define GEOM_CONE_UNIFORM_ENUMS(X) \
X("axis", Axis, AxisEnumHandler, axis)
// ============================================================================
// GeomCylinder Properties
// ============================================================================
#define GEOM_CYLINDER_TYPED_ATTRS(X) \
X("radius", radius) \
X("height", height)
#define GEOM_CYLINDER_UNIFORM_ENUMS(X) \
X("axis", Axis, AxisEnumHandler, axis)
// ============================================================================
// GeomCapsule Properties
// ============================================================================
#define GEOM_CAPSULE_TYPED_ATTRS(X) \
X("radius", radius) \
X("height", height)
#define GEOM_CAPSULE_UNIFORM_ENUMS(X) \
X("axis", Axis, AxisEnumHandler, axis)
// ============================================================================
// Skeleton Properties
// ============================================================================
#define SKELETON_TYPED_ATTRS(X) \
X("joints", joints) \
X("jointNames", jointNames) \
X("bindTransforms", bindTransforms) \
X("restTransforms", restTransforms)
// ============================================================================
// SkelAnimation Properties
// ============================================================================
#define SKEL_ANIMATION_TYPED_ATTRS(X) \
X("joints", joints) \
X("translations", translations) \
X("rotations", rotations) \
X("scales", scales) \
X("blendShapes", blendShapes) \
X("blendShapeWeights", blendShapeWeights)
// ============================================================================
// BlendShape Properties
// ============================================================================
#define BLEND_SHAPE_TYPED_ATTRS(X) \
X("offsets", offsets) \
X("normalOffsets", normalOffsets) \
X("pointIndices", pointIndices)
// ============================================================================
// Light Common Properties
// ============================================================================
// Shadow attributes - shared by ALL light types
#define LIGHT_SHADOW_ATTRS(X) \
X("inputs:shadow:enable", shadowEnable) \
X("inputs:shadow:color", shadowColor) \
X("inputs:shadow:distance", shadowDistance) \
X("inputs:shadow:falloff", shadowFalloff) \
X("inputs:shadow:falloffGamma", shadowFalloffGamma)
// Shaping attributes - shared by SphereLight, RectLight, DiskLight, CylinderLight
#define LIGHT_SHAPING_ATTRS(X) \
X("inputs:shaping:focus", shapingFocus) \
X("inputs:shaping:focusTint", shapingFocusTint) \
X("inputs:shaping:cone:angle", shapingConeAngle) \
X("inputs:shaping:cone:softness", shapingConeSoftness)
// ============================================================================
// SphereLight Properties
// ============================================================================
#define SPHERE_LIGHT_TYPED_ATTRS(X) \
X("inputs:color", color) \
X("inputs:radius", radius) \
X("inputs:intensity", intensity)
// ============================================================================
// RectLight Properties
// ============================================================================
#define RECT_LIGHT_TYPED_ATTRS(X) \
X("inputs:color", color) \
X("inputs:height", height) \
X("inputs:width", width) \
X("inputs:intensity", intensity)
// RectLight has a special texture:file attr that uses UsdUVTexture type
// This needs special handling, not included in typed attrs
// ============================================================================
// DiskLight Properties
// ============================================================================
#define DISK_LIGHT_TYPED_ATTRS(X) \
X("inputs:color", color) \
X("inputs:intensity", intensity) \
X("inputs:exposure", exposure) \
X("inputs:normalize", normalize) \
X("inputs:enableColorTemperature", enableColorTemperature) \
X("inputs:colorTemperature", colorTemperature) \
X("inputs:radius", radius)
// ============================================================================
// CylinderLight Properties
// ============================================================================
#define CYLINDER_LIGHT_TYPED_ATTRS(X) \
X("inputs:length", length) \
X("inputs:radius", radius)
// ============================================================================
// DistantLight Properties
// ============================================================================
#define DISTANT_LIGHT_TYPED_ATTRS(X) \
X("inputs:color", color) \
X("inputs:intensity", intensity) \
X("inputs:exposure", exposure) \
X("inputs:normalize", normalize) \
X("inputs:enableColorTemperature", enableColorTemperature) \
X("inputs:colorTemperature", colorTemperature) \
X("inputs:angle", angle)
// ============================================================================
// GeometryLight Properties
// ============================================================================
#define GEOMETRY_LIGHT_TYPED_ATTRS(X) \
X("inputs:color", color) \
X("inputs:intensity", intensity) \
X("inputs:exposure", exposure) \
X("inputs:diffuse", diffuse) \
X("inputs:specular", specular) \
X("inputs:normalize", normalize) \
X("inputs:enableColorTemperature", enableColorTemperature) \
X("inputs:colorTemperature", colorTemperature)
// ============================================================================
// DomeLight Properties
// ============================================================================
#define DOME_LIGHT_TYPED_ATTRS(X) \
X("guideRadius", guideRadius) \
X("inputs:diffuse", diffuse) \
X("inputs:specular", specular) \
X("inputs:colorTemperature", colorTemperature) \
X("inputs:color", color) \
X("inputs:intensity", intensity) \
X("inputs:texture:file", file)
// ============================================================================
// Helper macros for property table expansion
// ============================================================================
// These macros require PRIM_CLASS_ and PRIM_PTR_ to be defined before use
// Expand typed attributes with PARSE_TYPED_ATTRIBUTE macro
#define EXPAND_TYPED_ATTR(name, member) \
PARSE_TYPED_ATTRIBUTE(table, prop, name, PRIM_CLASS_, PRIM_PTR_->member)
// Expand typed attributes without continue
#define EXPAND_TYPED_ATTR_NOCONT(name, member) \
PARSE_TYPED_ATTRIBUTE_NOCONTINUE(table, prop, name, PRIM_CLASS_, PRIM_PTR_->member)
// Expand single target relations
#define EXPAND_SINGLE_REL(name, member) \
PARSE_SINGLE_TARGET_PATH_RELATION(table, prop, name, PRIM_PTR_->member)
// Expand multi target relations
#define EXPAND_MULTI_REL(name, member) \
PARSE_TARGET_PATHS_RELATION(table, prop, name, PRIM_PTR_->member)
// Expand uniform enum properties (handler must be a local variable)
#define EXPAND_UNIFORM_ENUM(name, enum_type, handler, member) \
PARSE_UNIFORM_ENUM_PROPERTY(table, prop, name, enum_type, handler, PRIM_CLASS_, \
PRIM_PTR_->member, options.strict_allowedToken_check)
// Expand timesampled enum properties (handler must be a local variable)
#define EXPAND_TIMESAMPLED_ENUM(name, enum_type, handler, member) \
PARSE_TIMESAMPLED_ENUM_PROPERTY(table, prop, name, enum_type, handler, PRIM_CLASS_, \
PRIM_PTR_->member, options.strict_allowedToken_check)
// Expand extent attribute
#define EXPAND_EXTENT(name, member) \
PARSE_EXTENT_ATTRIBUTE(table, prop, name, PRIM_CLASS_, PRIM_PTR_->member)

File diff suppressed because it is too large Load Diff

View File

@@ -32,6 +32,7 @@
#include "usda-reader.hh"
#include "layer.hh"
#include "parser-timing.hh"
#include "enum-handlers.hh"
//
#if !defined(TINYUSDZ_DISABLE_MODULE_USDA_READER)
@@ -246,49 +247,8 @@ inline bool hasOutputs(const std::string &str) {
return startsWith(str, "outputs:");
}
template <class E>
static nonstd::expected<bool, std::string> CheckAllowedTokens(
const std::vector<std::pair<E, const char *>> &allowedTokens,
const std::string &tok) {
if (allowedTokens.empty()) {
return true;
}
for (size_t i = 0; i < allowedTokens.size(); i++) {
if (tok.compare(std::get<1>(allowedTokens[i])) == 0) {
return true;
}
}
std::vector<std::string> toks;
for (size_t i = 0; i < allowedTokens.size(); i++) {
toks.push_back(std::get<1>(allowedTokens[i]));
}
std::string s = join(", ", tinyusdz::quote(toks));
return nonstd::make_unexpected("Allowed tokens are [" + s + "] but got " +
quote(tok) + ".");
};
template <typename T>
nonstd::expected<T, std::string> EnumHandler(
const std::string &prop_name, const std::string &tok,
const std::vector<std::pair<T, const char *>> &enums) {
auto ret = CheckAllowedTokens<T>(enums, tok);
if (!ret) {
return nonstd::make_unexpected(ret.error());
}
for (auto &item : enums) {
if (tok == item.second) {
return item.first;
}
}
// Should never reach here, though.
return nonstd::make_unexpected(
quote(tok) + " is an invalid token for attribute `" + prop_name + "`");
}
// NOTE: CheckAllowedTokens and EnumHandler templates removed.
// Use centralized handlers from enum-handlers.hh instead.
class USDAReader::Impl {
private:
@@ -734,55 +694,8 @@ class USDAReader::Impl {
bool ReconstructPrimMeta(const ascii::AsciiParser::PrimMetaMap &in_meta,
PrimMeta *out) {
auto ApiSchemaHandler = [](const std::string &tok)
-> nonstd::expected<APISchemas::APIName, std::string> {
using EnumTy = std::pair<APISchemas::APIName, const char *>;
const std::vector<EnumTy> enums = {
std::make_pair(APISchemas::APIName::SkelBindingAPI, "SkelBindingAPI"),
std::make_pair(APISchemas::APIName::CollectionAPI, "CollectionAPI"),
std::make_pair(APISchemas::APIName::MaterialBindingAPI,
"MaterialBindingAPI"),
std::make_pair(APISchemas::APIName::ShapingAPI,
"ShapingAPI"),
std::make_pair(APISchemas::APIName::ShadowAPI,
"ShadowAPI"),
std::make_pair(APISchemas::APIName::VolumeLightAPI,
"VolumeLightAPI"),
std::make_pair(APISchemas::APIName::Preliminary_PhysicsMaterialAPI,
"Preliminary_PhysicsMaterialAPI"),
std::make_pair(APISchemas::APIName::Preliminary_PhysicsRigidBodyAPI,
"Preliminary_PhysicsRigidBodyAPI"),
std::make_pair(APISchemas::APIName::Preliminary_PhysicsColliderAPI,
"Preliminary_PhysicsColliderAPI"),
std::make_pair(APISchemas::APIName::Preliminary_AnchoringAPI,
"Preliminary_AnchoringAPI"),
std::make_pair(APISchemas::APIName::LightAPI,
"LightAPI"),
std::make_pair(APISchemas::APIName::MeshLightAPI,
"MeshLightAPI"),
std::make_pair(APISchemas::APIName::LightListAPI,
"LightListAPI"),
std::make_pair(APISchemas::APIName::ListAPI,
"ListAPI"),
std::make_pair(APISchemas::APIName::MotionAPI,
"MotionAPI"),
std::make_pair(APISchemas::APIName::PrimvarsAPI,
"PrimvarsAPI"),
std::make_pair(APISchemas::APIName::GeomModelAPI,
"GeomModelAPI"),
std::make_pair(APISchemas::APIName::VisibilityAPI,
"VisibilityAPI"),
std::make_pair(APISchemas::APIName::XformCommonAPI,
"XformCommonAPI"),
std::make_pair(APISchemas::APIName::NodeDefAPI,
"NodeDefAPI"),
std::make_pair(APISchemas::APIName::CoordSysAPI,
"CoordSysAPI"),
std::make_pair(APISchemas::APIName::ConnectableAPI,
"ConnectableAPI")
};
return EnumHandler<APISchemas::APIName>("apiSchemas", tok, enums);
};
// Use centralized handler from enum-handlers.hh
auto ApiSchemaHandler = enum_handler::APISchemaName;
auto BuildVariants = [](const Dictionary &dict) -> nonstd::expected<VariantSelectionMap, std::string> {
@@ -817,7 +730,7 @@ class USDAReader::Impl {
DCOUT("active. type = " << var.type_name());
if (var.type_name() == "bool") {
if (auto pv = var.get_value<bool>()) {
out->active = pv.value();
out->set_active(pv.value());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `active` metadataum is not type `bool`.");
@@ -831,7 +744,7 @@ class USDAReader::Impl {
DCOUT("hidden. type = " << var.type_name());
if (var.type_name() == "bool") {
if (auto pv = var.get_value<bool>()) {
out->hidden = pv.value();
out->set_hidden(pv.value());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `hidden` metadataum is not type `bool`.");
@@ -846,7 +759,7 @@ class USDAReader::Impl {
DCOUT("instanceable. type = " << var.type_name());
if (var.type_name() == "bool") {
if (auto pv = var.get_value<bool>()) {
out->instanceable = pv.value();
out->set_instanceable(pv.value());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `instanceable` metadataum is not type `bool`.");
@@ -861,7 +774,7 @@ class USDAReader::Impl {
DCOUT("sceneName. type = " << var.type_name());
if (var.type_name() == value::kString) {
if (auto pv = var.get_value<std::string>()) {
out->sceneName = pv.value();
out->set_sceneName(pv.value());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `sceneName` metadataum is not type `string`.");
@@ -875,7 +788,7 @@ class USDAReader::Impl {
DCOUT("displayName. type = " << var.type_name());
if (var.type_name() == value::kString) {
if (auto pv = var.get_value<std::string>()) {
out->displayName = pv.value();
out->set_displayName(pv.value());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `displayName` metadataum is not type `string`.");
@@ -893,25 +806,24 @@ class USDAReader::Impl {
if (auto pv = var.get_value<value::token>()) {
const value::token tok = pv.value();
if (tok.str() == "subcomponent") {
out->kind = Kind::Subcomponent;
out->set_kind(Kind::Subcomponent);
} else if (tok.str() == "component") {
out->kind = Kind::Component;
out->set_kind(Kind::Component);
} else if (tok.str() == "model") {
out->kind = Kind::Model;
out->set_kind(Kind::Model);
} else if (tok.str() == "group") {
out->kind = Kind::Group;
out->set_kind(Kind::Group);
} else if (tok.str() == "assembly") {
out->kind = Kind::Assembly;
out->set_kind(Kind::Assembly);
} else if (tok.str() == "sceneLibrary") {
// USDZ specific: https://developer.apple.com/documentation/arkit/usdz_schemas_for_ar/scenelibrary
out->kind = Kind::SceneLibrary;
out->set_kind(Kind::SceneLibrary);
} else {
// NOTE: empty token allowed.
out->kind = Kind::UserDef;
out->_kind_str = tok.str();
// For user-defined kind, store the string directly
out->set_kind(tok.str());
}
DCOUT("Added kind: " << to_string(out->kind.value()));
DCOUT("Added kind: " << out->get_kind_str());
} else {
PUSH_ERROR_AND_RETURN(
"(Internal error?) `kind` metadataum is not type `token`.");
@@ -926,7 +838,7 @@ class USDAReader::Impl {
if (var.type_id() == value::TypeTraits<Dictionary>::type_id()) {
if (auto pv = var.get_value<Dictionary>()) {
// TODO: Check if all items are string type.
out->sdrMetadata = pv.value();
out->set_sdrMetadata(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"(Internal error?) `sdrMetadata` metadataum is not type "
@@ -944,7 +856,7 @@ class USDAReader::Impl {
DCOUT("customData. type = " << var.type_name());
if (var.type_id() == value::TypeTraits<Dictionary>::type_id()) {
if (auto pv = var.get_value<Dictionary>()) {
out->customData = pv.value();
out->set_customData(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"(Internal error?) `customData` metadataum is not type "
@@ -962,7 +874,7 @@ class USDAReader::Impl {
DCOUT("clips. type = " << var.type_name());
if (var.type_id() == value::TypeTraits<Dictionary>::type_id()) {
if (auto pv = var.get_value<Dictionary>()) {
out->clips = pv.value();
out->set_clips(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"(Internal error?) `clips` metadataum is not type "
@@ -979,7 +891,7 @@ class USDAReader::Impl {
} else if (meta.first == "assetInfo") {
DCOUT("assetInfo. type = " << var.type_name());
if (auto pv = var.get_value<Dictionary>()) {
out->assetInfo = pv.value();
out->set_assetInfo(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"(Internal error?) `assetInfo` metadataum is not type "
@@ -1097,7 +1009,7 @@ class USDAReader::Impl {
<< var.type_name() << "`");
}
out->apiSchemas = std::move(apiSchemas);
out->set_apiSchemas(std::move(apiSchemas));
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag, "(Internal error?) `apiSchemas` metadataum is not type "
"`token[]`. got type `"
@@ -1157,11 +1069,11 @@ class USDAReader::Impl {
} else if (meta.first == "comment") {
if (auto pv = var.get_value<value::StringData>()) {
// Preserve full StringData including has_comment_prefix flag
out->comment = pv.value();
out->set_comment(pv.value());
} else if (auto spv = var.get_value<std::string>()) {
value::StringData sdata;
sdata.value = spv.value();
out->comment = sdata;
out->set_comment(sdata);
}
} else {
// Must be string value for unregisteredMeta for now.

View File

@@ -20,6 +20,7 @@
#include "usdc-reader.hh"
#include "parser-timing.hh"
#include "enum-handlers.hh"
#if !defined(TINYUSDZ_DISABLE_MODULE_USDC_READER)
@@ -590,57 +591,10 @@ nonstd::expected<APISchemas, std::string> USDCReader::Impl::ToAPISchemas(
const ListOp<value::token> &arg, bool ignore_unknown, std::string &warn) {
APISchemas schemas;
// Use centralized handler from enum-handlers.hh (wrapper for value::token)
auto SchemaHandler =
[](const value::token &tok) -> nonstd::optional<APISchemas::APIName> {
if (tok.str() == "MaterialBindingAPI") {
return APISchemas::APIName::MaterialBindingAPI;
} else if (tok.str() == "NodeDefAPI") {
return APISchemas::APIName::NodeDefAPI;
} else if (tok.str() == "CoordSysAPI") {
return APISchemas::APIName::CoordSysAPI;
} else if (tok.str() == "ConnectableAPI") {
return APISchemas::APIName::ConnectableAPI;
} else if (tok.str() == "CollectionAPI") {
return APISchemas::APIName::CollectionAPI;
} else if (tok.str() == "SkelBindingAPI") {
return APISchemas::APIName::SkelBindingAPI;
} else if (tok.str() == "VisibilityAPI") {
return APISchemas::APIName::VisibilityAPI;
} else if (tok.str() == "GeomModelAPI") {
return APISchemas::APIName::GeomModelAPI;
} else if (tok.str() == "MotionAPI") {
return APISchemas::APIName::MotionAPI;
} else if (tok.str() == "PrimvarsAPI") {
return APISchemas::APIName::PrimvarsAPI;
} else if (tok.str() == "XformCommonAPI") {
return APISchemas::APIName::XformCommonAPI;
} else if (tok.str() == "ListAPI") {
return APISchemas::APIName::ListAPI;
} else if (tok.str() == "LightListAPI") {
return APISchemas::APIName::LightListAPI;
} else if (tok.str() == "LightAPI") {
return APISchemas::APIName::LightAPI;
} else if (tok.str() == "MeshLightAPI") {
return APISchemas::APIName::MeshLightAPI;
} else if (tok.str() == "VolumeLightAPI") {
return APISchemas::APIName::VolumeLightAPI;
} else if (tok.str() == "ConnectableAPI") {
return APISchemas::APIName::ConnectableAPI;
} else if (tok.str() == "ShadowAPI") {
return APISchemas::APIName::ShadowAPI;
} else if (tok.str() == "ShapingAPI") {
return APISchemas::APIName::ShapingAPI;
} else if (tok.str() == "Preliminary_AnchoringAPI") {
return APISchemas::APIName::Preliminary_AnchoringAPI;
} else if (tok.str() == "Preliminary_PhysicsColliderAPI") {
return APISchemas::APIName::Preliminary_PhysicsColliderAPI;
} else if (tok.str() == "Preliminary_PhysicsMaterialAPI") {
return APISchemas::APIName::Preliminary_PhysicsMaterialAPI;
} else if (tok.str() == "Preliminary_PhysicsRigidBodyAPI") {
return APISchemas::APIName::Preliminary_PhysicsRigidBodyAPI;
} else {
return nonstd::nullopt;
}
return enum_handler::APISchemaNameOpt(tok.str());
};
if (arg.IsExplicit()) { // fast path
@@ -1312,12 +1266,7 @@ bool USDCReader::Impl::ParseProperty(const SpecType spec_type,
} else if (fv.first == "colorSpace") {
if (auto pv = fv.second.get_value<value::token>()) {
MetaVariable mv;
mv.set_name("colorSpace");
mv.set_value(pv.value());
meta.meta["colorSpace"] = std::move(mv);
meta.set_colorSpace(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`colorSpace` must be type `token`, but got type `"
@@ -1325,7 +1274,7 @@ bool USDCReader::Impl::ParseProperty(const SpecType spec_type,
}
} else if (fv.first == "displayName") {
if (auto pv = fv.second.get_value<std::string>()) {
meta.displayName = pv.value();
meta.set_displayName(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`displayName` must be type `string`, but got type `"
@@ -1333,7 +1282,7 @@ bool USDCReader::Impl::ParseProperty(const SpecType spec_type,
}
} else if (fv.first == "displayGroup") {
if (auto pv = fv.second.get_value<std::string>()) {
meta.displayGroup = pv.value();
meta.set_displayGroup(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`displayGroup` must be type `string`, but got type `"
@@ -1341,11 +1290,7 @@ bool USDCReader::Impl::ParseProperty(const SpecType spec_type,
}
} else if (fv.first == "unauthoredValuesIndex") {
if (auto pv = fv.second.get_value<int>()) {
MetaVariable mv;
mv.set_name("unauthoredValuesIndex");
mv.set_value(pv.value());
meta.meta["unauthoredValuesIndex"] = mv;
meta.set_unauthoredValuesIndex(pv.value());
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`unauthoredValuesIndex` must be type `int`, but got type `"
@@ -1425,37 +1370,37 @@ bool USDCReader::Impl::ParseProperty(const SpecType spec_type,
// Attribute metas
{
if (interpolation) {
meta.interpolation = interpolation.value();
meta.set_interpolation_enum(interpolation.value());
}
if (elementSize) {
meta.elementSize = elementSize.value();
meta.set_elementSize(static_cast<uint32_t>(elementSize.value()));
}
if (hidden) {
meta.hidden = hidden.value();
meta.set_hidden(hidden.value());
}
if (customData) {
meta.customData = customData.value();
meta.set_customData(customData.value());
}
if (weight) {
meta.weight = weight.value();
meta.set_weight(weight.value());
}
if (comment) {
meta.comment = comment.value();
meta.set_comment(comment.value());
}
if (bindMaterialAs) {
meta.bindMaterialAs = bindMaterialAs.value();
meta.set_bindMaterialAs(bindMaterialAs.value());
}
if (outputName) {
meta.outputName = outputName.value();
meta.set_outputName(outputName.value());
}
if (sdrMetadata) {
meta.sdrMetadata = sdrMetadata.value();
meta.set_sdrMetadata(sdrMetadata.value());
}
if (connectability) {
meta.connectability = connectability.value();
meta.set_connectability(connectability.value());
}
if (renderType) {
meta.renderType = renderType.value();
meta.set_renderType(renderType.value());
}
}
@@ -1978,8 +1923,8 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
}
} else if (fv.first == "active") {
if (auto pv = fv.second.as<bool>()) {
primMeta.active = (*pv);
DCOUT("active = " << to_string(primMeta.active.value()));
primMeta.set_active(*pv);
DCOUT("active = " << to_string(primMeta.get_active()));
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"`active` must be type `bool`, but got type `"
@@ -1987,8 +1932,8 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
}
} else if (fv.first == "hidden") {
if (auto pv = fv.second.as<bool>()) {
primMeta.hidden = (*pv);
DCOUT("hidden = " << to_string(primMeta.hidden.value()));
primMeta.set_hidden(*pv);
DCOUT("hidden = " << to_string(primMeta.get_hidden()));
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"`hidden` must be type `bool`, but got type `"
@@ -1996,8 +1941,8 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
}
} else if (fv.first == "instanceable") {
if (auto pv = fv.second.as<bool>()) {
primMeta.instanceable = (*pv);
DCOUT("instanceable = " << to_string(primMeta.instanceable.value()));
primMeta.set_instanceable(*pv);
DCOUT("instanceable = " << to_string(primMeta.get_instanceable()));
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
"`instanceable` must be type `bool`, but got type `"
@@ -2006,7 +1951,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
} else if (fv.first == "assetInfo") {
// CustomData(dict)
if (auto pv = fv.second.as<CustomDataType>()) {
primMeta.assetInfo = (*pv);
primMeta.set_assetInfo(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`assetInfo` must be type `dictionary`, but got type `"
@@ -2015,7 +1960,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
} else if (fv.first == "clips") {
// CustomData(dict)
if (auto pv = fv.second.as<CustomDataType>()) {
primMeta.clips = (*pv);
primMeta.set_clips(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`clips` must be type `dictionary`, but got type `"
@@ -2026,22 +1971,21 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
const value::token tok = (*pv);
if (tok.str() == "subcomponent") {
primMeta.kind = Kind::Subcomponent;
primMeta.set_kind(Kind::Subcomponent);
} else if (tok.str() == "component") {
primMeta.kind = Kind::Component;
primMeta.set_kind(Kind::Component);
} else if (tok.str() == "model") {
primMeta.kind = Kind::Model;
primMeta.set_kind(Kind::Model);
} else if (tok.str() == "group") {
primMeta.kind = Kind::Group;
primMeta.set_kind(Kind::Group);
} else if (tok.str() == "assembly") {
primMeta.kind = Kind::Assembly;
primMeta.set_kind(Kind::Assembly);
} else if (tok.str() == "sceneLibrary") {
// USDZ specific: https://developer.apple.com/documentation/arkit/usdz_schemas_for_ar/scenelibrary
primMeta.kind = Kind::SceneLibrary;
primMeta.set_kind(Kind::SceneLibrary);
} else {
primMeta.kind = Kind::UserDef;
primMeta._kind_str = tok.str();
// For user-defined kind, store the string directly
primMeta.set_kind(tok.str());
}
} else {
PUSH_ERROR_AND_RETURN_TAG(kTag,
@@ -2061,7 +2005,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
if (warn.size()) {
PUSH_WARN(warn);
}
primMeta.apiSchemas = (*ret);
primMeta.set_apiSchemas(*ret);
}
// DCOUT("apiSchemas = " << to_string(listop));
} else {
@@ -2074,7 +2018,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
value::StringData s;
s.value = (*pv);
s.is_triple_quoted = hasNewline(s.value);
primMeta.doc = s;
primMeta.set_doc(s);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`documentation` must be type `string`, but got type `"
@@ -2085,7 +2029,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
value::StringData s;
s.value = (*pv);
s.is_triple_quoted = hasNewline(s.value);
primMeta.comment = s;
primMeta.set_comment(s);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`comment` must be type `string`, but got type `"
@@ -2095,7 +2039,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
// CustomData(dict)
if (auto pv = fv.second.as<CustomDataType>()) {
// TODO: Check if all keys are string type.
primMeta.sdrMetadata = (*pv);
primMeta.set_sdrMetadata(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`sdrMetadata` must be type `dictionary`, but got type `"
@@ -2104,7 +2048,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
} else if (fv.first == "customData") {
// CustomData(dict)
if (auto pv = fv.second.as<CustomDataType>()) {
primMeta.customData = (*pv);
primMeta.set_customData(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`customData` must be type `dictionary`, but got type `"
@@ -2166,7 +2110,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
}
} else if (fv.first == "sceneName") { // USDZ extension
if (auto pv = fv.second.as<std::string>()) {
primMeta.sceneName = (*pv);
primMeta.set_sceneName(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`sceneName` must be type `string`, but got type `"
@@ -2174,7 +2118,7 @@ bool USDCReader::Impl::ParsePrimSpec(const crate::FieldValuePairVector &fvs,
}
} else if (fv.first == "displayName") { // USD supported since 23.xx?
if (auto pv = fv.second.as<std::string>()) {
primMeta.displayName = (*pv);
primMeta.set_displayName(*pv);
} else {
PUSH_ERROR_AND_RETURN_TAG(
kTag, "`displayName` must be type `string`, but got type `"