scene/reference.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // SPDX-License-Identifier: BSD-3-Clause | ||
| 2 | /// @file reference.cpp | ||
| 3 | /// @brief The reference families, the JSON Schema of scene files and the reference pages. | ||
| 4 | #include "ernie/scene/reference.h" | ||
| 5 | |||
| 6 | #include "ernie/scene/json_value.h" | ||
| 7 | #include "ernie/util/text.h" | ||
| 8 | |||
| 9 | #include <algorithm> | ||
| 10 | #include <array> | ||
| 11 | #include <optional> | ||
| 12 | #include <stdexcept> | ||
| 13 | |||
| 14 | namespace ernie { | ||
| 15 | namespace { | ||
| 16 | |||
| 17 | constexpr std::string_view kInstancePattern = "[A-Za-z_][A-Za-z0-9_]*"; | ||
| 18 | constexpr std::string_view kExampleInstance = "example"; | ||
| 19 | |||
| 20 | /// @return Text as a regular expression matching it literally. | ||
| 21 | 72 | std::string Literal(std::string_view text) { | |
| 22 | 72 | std::string out; | |
| 23 | 808 | for (const char c : text) { | |
| 24 | 736 | if (std::string_view("\\^$.|?*+()[]{}").find(c) != std::string_view::npos) { | |
| 25 | 1 | out += '\\'; | |
| 26 | } | ||
| 27 | 1472 | out += c; | |
| 28 | } | ||
| 29 | 72 | return out; | |
| 30 | ✗ | } | |
| 31 | |||
| 32 | 1477 | std::optional<Json> JsonValue(const Value& value) { | |
| 33 | 1477 | if (value.Empty()) { | |
| 34 | 198 | return std::nullopt; | |
| 35 | } | ||
| 36 | 1279 | try { | |
| 37 | 2558 | return ToJson(value); | |
| 38 | ✗ | } catch (const std::invalid_argument&) { | |
| 39 | ✗ | return std::nullopt; | |
| 40 | ✗ | } | |
| 41 | } | ||
| 42 | |||
| 43 | /// @return A type's fallback for an attribute as scene files write it; none if it has none. | ||
| 44 | 1466 | std::optional<Json> JsonFallback(const SchemaDef& schema, const AttributeDef& def) { | |
| 45 | 2932 | return JsonValue(schema.Fallback(def)); | |
| 46 | } | ||
| 47 | |||
| 48 | 625 | bool IsInstanced(std::string_view name) { | |
| 49 | 625 | return name.find(kInstanceName) != std::string_view::npos; | |
| 50 | } | ||
| 51 | |||
| 52 | 65 | std::vector<std::string_view> OpenNamespaces(const SchemaDef& schema) { | |
| 53 | 65 | std::vector<std::string_view> namespaces; | |
| 54 | 275 | for (const SchemaDef* type = &schema; type != nullptr; type = type->base) { | |
| 55 | 210 | namespaces.insert(namespaces.end(), type->openNamespaces.begin(), | |
| 56 | type->openNamespaces.end()); | ||
| 57 | } | ||
| 58 | 65 | return namespaces; | |
| 59 | ✗ | } | |
| 60 | |||
| 61 | 3 | std::vector<std::string> Names(SchemaKind kind) { | |
| 62 | 3 | std::vector<std::string> names; | |
| 63 | 198 | for (const SchemaDef* schema : Schemas()) { | |
| 64 | 195 | if (schema->kind == kind) { | |
| 65 | 54 | names.emplace_back(schema->name); | |
| 66 | } | ||
| 67 | } | ||
| 68 | 3 | return names; | |
| 69 | ✗ | } | |
| 70 | |||
| 71 | // The JSON Schema. | ||
| 72 | |||
| 73 | 73 | Json Ref(std::string_view name) { | |
| 74 | 438 | return {{"$ref", "#/$defs/" + std::string(name)}}; | |
| 75 | 438 | } | |
| 76 | |||
| 77 | 284 | Json Number(const AttributeMeta& meta, bool integer) { | |
| 78 | 1420 | Json number{{"type", integer ? "integer" : "number"}}; | |
| 79 | 284 | if (meta.lower) { | |
| 80 | 406 | number[meta.lower->exclusive ? "exclusiveMinimum" : "minimum"] = meta.lower->value; | |
| 81 | } | ||
| 82 | 284 | if (meta.upper) { | |
| 83 | 66 | number[meta.upper->exclusive ? "exclusiveMaximum" : "maximum"] = meta.upper->value; | |
| 84 | } | ||
| 85 | 284 | return number; | |
| 86 | 1420 | } | |
| 87 | |||
| 88 | 126 | Json Array(Json items, std::optional<std::size_t> count = std::nullopt) { | |
| 89 | 882 | Json array{{"type", "array"}, {"items", std::move(items)}}; | |
| 90 | 126 | if (count) { | |
| 91 | 39 | array["minItems"] = *count; | |
| 92 | 39 | array["maxItems"] = *count; | |
| 93 | } | ||
| 94 | 126 | return array; | |
| 95 | 756 | } | |
| 96 | |||
| 97 | 243 | Json String() { | |
| 98 | 972 | return {{"type", "string"}}; | |
| 99 | 972 | } | |
| 100 | |||
| 101 | 625 | Json ValueSchema(const AttributeDef& def) { | |
| 102 | 625 | const AttributeMeta& meta = def.meta; | |
| 103 | 625 | switch (def.type) { | |
| 104 | 35 | case ColumnType::Bool: | |
| 105 | 140 | return {{"type", "boolean"}}; | |
| 106 | 72 | case ColumnType::Int: | |
| 107 | 72 | return Number(meta, true); | |
| 108 | 136 | case ColumnType::Double: | |
| 109 | 136 | return Number(meta, false); | |
| 110 | 11 | case ColumnType::Vec2: | |
| 111 | 11 | return Array(Number(meta, false), 2); | |
| 112 | 23 | case ColumnType::Vec3: | |
| 113 | 23 | return Array(Number(meta, false), 3); | |
| 114 | 3 | case ColumnType::Vec4: | |
| 115 | 3 | return Array(Number(meta, false), 4); | |
| 116 | ✗ | case ColumnType::Quat: | |
| 117 | ✗ | return Array(Number({}, false), 4); | |
| 118 | ✗ | case ColumnType::Matrix: | |
| 119 | ✗ | return Array(Array(Number({}, false), 4), 4); | |
| 120 | 178 | case ColumnType::TokenValue: { | |
| 121 | 178 | Json token = String(); | |
| 122 | 178 | if (!meta.options.empty()) { | |
| 123 | 149 | token["enum"] = meta.options; | |
| 124 | } | ||
| 125 | 178 | return token; | |
| 126 | 178 | } | |
| 127 | 6 | case ColumnType::Relationship: | |
| 128 | 6 | return String(); | |
| 129 | 8 | case ColumnType::Relationships: | |
| 130 | 72 | return {{"anyOf", Json::array({String(), Array(String())})}}; | |
| 131 | 36 | case ColumnType::FloatArray: | |
| 132 | 36 | return Array(Number(meta, false)); | |
| 133 | 42 | case ColumnType::TokenArray: | |
| 134 | 42 | return Array(String()); | |
| 135 | case ColumnType::Tensor: | ||
| 136 | break; | ||
| 137 | } | ||
| 138 | 75 | const Json shared{{"type", "object"}, | |
| 139 | 225 | {"required", Json::array({"$array"})}, | |
| 140 | 1425 | {"properties", {{"$array", {{"type", "integer"}, {"minimum", 0}}}}}}; | |
| 141 | 825 | return {{"anyOf", Json::array({{{"type", "array"}}, shared})}}; | |
| 142 | 2229 | } | |
| 143 | |||
| 144 | 65 | Json SchemaDefinition(const SchemaDef& schema) { | |
| 145 | 65 | Json properties = Json::object(); | |
| 146 | 65 | Json patterns = Json::object(); | |
| 147 | 690 | for (const AttributeDef* def : schema.AllAttributes()) { | |
| 148 | 625 | Json attribute = ValueSchema(*def); | |
| 149 | 625 | attribute["description"] = def->meta.doc; | |
| 150 | 625 | if (const std::optional<Json> fallback = JsonFallback(schema, *def)) { | |
| 151 | 550 | attribute["default"] = *fallback; | |
| 152 | ✗ | } | |
| 153 | 625 | if (IsInstanced(def->name)) { | |
| 154 | 12 | patterns["^" + Replace(Literal(def->name), kInstanceName, kInstancePattern) + "$"] = | |
| 155 | 12 | std::move(attribute); | |
| 156 | } else { | ||
| 157 | 621 | properties[std::string(def->name)] = std::move(attribute); | |
| 158 | } | ||
| 159 | 625 | } | |
| 160 | 132 | for (const std::string_view space : OpenNamespaces(schema)) { | |
| 161 | 132 | patterns[space == "*" ? std::string(".*") : "^" + Literal(space)] = Json::object(); | |
| 162 | 65 | } | |
| 163 | 260 | Json definition{{"description", schema.doc}}; | |
| 164 | 65 | if (!properties.empty()) { | |
| 165 | 60 | definition["properties"] = std::move(properties); | |
| 166 | } | ||
| 167 | 65 | if (!patterns.empty()) { | |
| 168 | 45 | definition["patternProperties"] = std::move(patterns); | |
| 169 | } | ||
| 170 | 65 | Json builtins = Json::array(); | |
| 171 | 82 | for (const std::string_view api : schema.AllBuiltinApis()) { | |
| 172 | 17 | builtins.push_back(Ref(ApiName::Parse(api).schema->name)); | |
| 173 | 65 | } | |
| 174 | 65 | if (!builtins.empty()) { | |
| 175 | 15 | definition["allOf"] = std::move(builtins); | |
| 176 | } | ||
| 177 | 65 | return definition; | |
| 178 | 325 | } | |
| 179 | |||
| 180 | 1 | Json XformOpsSchema() { | |
| 181 | 1 | const Json vector = Array(Number({}, false), 3); | |
| 182 | 1 | return {{"type", "object"}, | |
| 183 | {"description", "The prim's transform ops, as SetXform authors them."}, | ||
| 184 | {"properties", | ||
| 185 | {{"translate", vector}, | ||
| 186 | {"rotate", vector}, | ||
| 187 | {"rotationOrder", {{"enum", {"XYZ", "XZY", "YXZ", "YZX", "ZXY", "ZYX"}}}}, | ||
| 188 | 2 | {"orient", Array(Number({}, false), 4)}, | |
| 189 | 4 | {"scale", {{"anyOf", Json::array({Number({}, false), vector})}}}}}, | |
| 190 | 41 | {"additionalProperties", false}}; | |
| 191 | 50 | } | |
| 192 | |||
| 193 | /// @return When the prim's type is `name`, or it applies the API schema `name`, check it so. | ||
| 194 | 54 | Json Condition(const SchemaDef& schema) { | |
| 195 | 54 | Json test; | |
| 196 | 54 | if (schema.kind == SchemaKind::Concrete) { | |
| 197 | 117 | test = {{"required", Json::array({kTypeName})}, | |
| 198 | 507 | {"properties", {{kTypeName, {{"const", schema.name}}}}}}; | |
| 199 | } else { | ||
| 200 | 15 | const Json item = schema.kind == SchemaKind::SingleApply | |
| 201 | 57 | ? Json{{"const", schema.name}} | |
| 202 | 65 | : Json{{"pattern", "^" + Literal(schema.name) + ":"}}; | |
| 203 | 45 | test = {{"required", Json::array({kApis})}, | |
| 204 | 195 | {"properties", {{kApis, {{"contains", item}}}}}}; | |
| 205 | ✗ | } | |
| 206 | 486 | return {{"if", test}, {"then", Ref(schema.name)}}; | |
| 207 | 1441 | } | |
| 208 | |||
| 209 | 1 | Json PrimSchema() { | |
| 210 | 1 | const std::string instanced = Join(Names(SchemaKind::MultipleApply), "|", Literal); | |
| 211 | 1 | const Json api{ | |
| 212 | 11 | {"anyOf", Json::array({{{"enum", Names(SchemaKind::SingleApply)}}, | |
| 213 | 2 | {{"pattern", "^(" + instanced + | |
| 214 | 8 | "):" + std::string(kInstancePattern) + "$"}}})}}; | |
| 215 | 2 | Json conditions = Json::array(); | |
| 216 | // A prim without a type takes attributes of any name. | ||
| 217 | 22 | conditions.push_back({{"if", {{"not", {{"required", Json::array({kTypeName})}}}}}, | |
| 218 | 2 | {"then", {{"patternProperties", {{".*", Json::object()}}}}}}); | |
| 219 | 66 | for (const SchemaDef* schema : Schemas()) { | |
| 220 | 65 | if (schema->kind != SchemaKind::Abstract) { | |
| 221 | 54 | conditions.push_back(Condition(*schema)); | |
| 222 | } | ||
| 223 | } | ||
| 224 | 1 | return {{"type", "object"}, | |
| 225 | {"description", "A prim: its type, applied API schemas, transform and attributes."}, | ||
| 226 | {"properties", | ||
| 227 | 1 | {{kTypeName, {{"enum", Names(SchemaKind::Concrete)}}}, | |
| 228 | 2 | {kApis, Array(api)}, | |
| 229 | 2 | {kXform, Ref("XformOps")}}}, | |
| 230 | {"patternProperties", | ||
| 231 | 2 | {{Literal(kTimeSamples) + "$", | |
| 232 | {{"type", "object"}, | ||
| 233 | {"description", "The attribute's values by time code."}, | ||
| 234 | {"propertyNames", {{"pattern", "^-?[0-9]+(\\.[0-9]+)?([eE][-+]?[0-9]+)?$"}}}}}}}, | ||
| 235 | {"allOf", std::move(conditions)}, | ||
| 236 | 46 | {"unevaluatedProperties", false}}; | |
| 237 | 106 | } | |
| 238 | |||
| 239 | // The reference pages. | ||
| 240 | |||
| 241 | 53 | std::string Anchor(std::string_view schema) { | |
| 242 | 53 | return ToLower(schema); | |
| 243 | } | ||
| 244 | |||
| 245 | 53 | std::string Link(std::string_view schema, const SchemaFamily& from) { | |
| 246 | 53 | const SchemaFamily* family = FindFamily(schema); | |
| 247 | 53 | const std::string page = | |
| 248 | 68 | family == nullptr || family == &from ? std::string() : std::string(family->name) + ".md"; | |
| 249 | 212 | return "[" + std::string(schema) + "](" + page + "#" + Anchor(schema) + ")"; | |
| 250 | 53 | } | |
| 251 | |||
| 252 | /// @return The type a reference page shows: USD's, with relationship lists and array shapes | ||
| 253 | /// spelt out. | ||
| 254 | 305 | std::string TypeText(const AttributeDef& def) { | |
| 255 | 305 | const AttributeMeta& meta = def.meta; | |
| 256 | 305 | if (def.type == ColumnType::Relationships) { | |
| 257 | 8 | return "rel[]"; | |
| 258 | } | ||
| 259 | 297 | if (def.type != ColumnType::Tensor || (meta.components == 0 && meta.ranks.empty())) { | |
| 260 | 278 | return UsdTypeName(def); | |
| 261 | } | ||
| 262 | 38 | const std::string element = meta.bytes ? "uchar" : meta.integer ? "int" : "float"; | |
| 263 | 19 | if (meta.components != 0) { | |
| 264 | 28 | return element + "[n, " + std::to_string(meta.components) + "]"; | |
| 265 | } | ||
| 266 | 10 | return element + " tensor, rank " + | |
| 267 | 21 | Join(meta.ranks, " or ", [](std::int64_t rank) { return std::to_string(rank); }); | |
| 268 | 19 | } | |
| 269 | |||
| 270 | 305 | std::string ValuesText(const AttributeMeta& meta) { | |
| 271 | 305 | std::vector<std::string> values; | |
| 272 | 463 | for (const std::string_view option : meta.options) { | |
| 273 | 316 | values.push_back("`" + std::string(option) + "`"); | |
| 274 | } | ||
| 275 | 305 | if (meta.lower) { | |
| 276 | 346 | values.push_back((meta.lower->exclusive ? "> " : "≥ ") + ToText(meta.lower->value)); | |
| 277 | } | ||
| 278 | 305 | if (meta.upper) { | |
| 279 | 52 | values.push_back((meta.upper->exclusive ? "< " : "≤ ") + ToText(meta.upper->value)); | |
| 280 | } | ||
| 281 | 610 | return Join(values, ", "); | |
| 282 | 305 | } | |
| 283 | |||
| 284 | 576 | std::string Cell(std::string_view text) { | |
| 285 | 1152 | return Replace(Replace(text, "|", "\\|"), "\n", " "); | |
| 286 | } | ||
| 287 | |||
| 288 | 316 | std::string Code(const std::optional<Json>& json) { | |
| 289 | 1129 | return json ? "`" + Cell(json->dump()) + "`" : ""; | |
| 290 | } | ||
| 291 | |||
| 292 | 65 | std::string KindText(const SchemaDef& schema) { | |
| 293 | 65 | switch (schema.kind) { | |
| 294 | 11 | case SchemaKind::Abstract: | |
| 295 | 11 | return "Abstract base"; | |
| 296 | 39 | case SchemaKind::Concrete: | |
| 297 | 39 | return "Prim type"; | |
| 298 | 14 | case SchemaKind::SingleApply: | |
| 299 | 14 | return "API schema"; | |
| 300 | case SchemaKind::MultipleApply: | ||
| 301 | break; | ||
| 302 | } | ||
| 303 | 2 | return "Multiple-apply API schema, applied as `" + std::string(schema.name) + ":<name>`"; | |
| 304 | } | ||
| 305 | |||
| 306 | 65 | std::string SchemaSection(const SchemaDef& schema, const SchemaFamily& family) { | |
| 307 | 195 | std::string out = "## " + std::string(schema.name) + "\n\n" + std::string(schema.doc) + "\n\n"; | |
| 308 | 65 | std::string facts = KindText(schema); | |
| 309 | 65 | if (schema.base != nullptr) { | |
| 310 | 86 | facts += " · Inherits " + Link(schema.base->name, family); | |
| 311 | } | ||
| 312 | 73 | for (const std::string_view api : schema.builtinApis) { | |
| 313 | 16 | facts += " · Built in: " + Link(ApiName::Parse(api).schema->name, family); | |
| 314 | } | ||
| 315 | 67 | for (const std::string_view type : schema.appliesTo) { | |
| 316 | 4 | facts += " · Applies to " + Link(type, family); | |
| 317 | } | ||
| 318 | 65 | out += facts + "\n\n"; | |
| 319 | 65 | if (!schema.attributes.empty()) { | |
| 320 | 56 | out += "| Attribute | Type | Description | Fallback | Values | Source |\n" | |
| 321 | 56 | "|---|---|---|---|---|---|\n"; | |
| 322 | 56 | const std::string usd = | |
| 323 | 168 | "[" + std::string(family.usdModule) + "](" + std::string(family.usdUrl) + ")"; | |
| 324 | 361 | for (const AttributeDef& def : schema.attributes) { | |
| 325 | 305 | const bool ernie = IsErnieSchema(schema.name) || def.name.starts_with("ernie:"); | |
| 326 | 1357 | out += "| `" + std::string(def.name) + "` | " + TypeText(def) + " | " + | |
| 327 | 1525 | Cell(def.meta.doc) + " | " + Code(JsonFallback(schema, def)) + " | " + | |
| 328 | 1525 | ValuesText(def.meta) + " | " + (ernie ? std::string("Ernie") : usd) + " |\n"; | |
| 329 | } | ||
| 330 | 56 | out += "\n"; | |
| 331 | 56 | } | |
| 332 | 65 | if (!schema.fallbackOverrides.empty()) { | |
| 333 | 6 | out += | |
| 334 | 12 | "Fallbacks it changes: " + | |
| 335 | 6 | Join(schema.fallbackOverrides, "; ", | |
| 336 | 17 | [](const auto& entry) { | |
| 337 | 33 | return "`" + std::string(entry.first) + "` " + Code(JsonValue(entry.second)); | |
| 338 | 18 | }) + | |
| 339 | 6 | ".\n\n"; | |
| 340 | } | ||
| 341 | 65 | if (const std::string example = ExampleScene(schema); !example.empty()) { | |
| 342 | 108 | out += "```json\n" + example + "```\n\n"; | |
| 343 | ✗ | } | |
| 344 | 65 | return out; | |
| 345 | 184 | } | |
| 346 | |||
| 347 | } // namespace | ||
| 348 | |||
| 349 | 516 | const SchemaFamily* FindFamily(std::string_view schema) { | |
| 350 | 3637 | const auto in = [&](const std::vector<const SchemaDef*>& schemas) { | |
| 351 | 3121 | return std::ranges::find(schemas, schema, &SchemaDef::name) != schemas.end(); | |
| 352 | 516 | }; | |
| 353 | 1744 | for (const SchemaFamily& family : SchemaFamilies()) { | |
| 354 | 1744 | if (in(family.usd) || in(family.ernie)) { | |
| 355 | 516 | return &family; | |
| 356 | } | ||
| 357 | } | ||
| 358 | ✗ | return nullptr; | |
| 359 | } | ||
| 360 | |||
| 361 | 456 | bool IsErnieSchema(std::string_view schema) { | |
| 362 | 456 | const SchemaFamily* family = FindFamily(schema); | |
| 363 | 912 | return family != nullptr && | |
| 364 | 456 | std::ranges::find(family->ernie, schema, &SchemaDef::name) != family->ernie.end(); | |
| 365 | } | ||
| 366 | |||
| 367 | 1 | std::string SceneJsonSchema() { | |
| 368 | 1 | Json defs = Json::object(); | |
| 369 | 1 | defs["Prim"] = PrimSchema(); | |
| 370 | 1 | defs["XformOps"] = XformOpsSchema(); | |
| 371 | 66 | for (const SchemaDef* schema : Schemas()) { | |
| 372 | 65 | defs[std::string(schema->name)] = SchemaDefinition(*schema); | |
| 373 | } | ||
| 374 | 1 | Json root{{"$schema", "https://json-schema.org/draft/2020-12/schema"}, | |
| 375 | {"$id", kSceneSchemaUrl}, | ||
| 376 | {"title", "Ernie scene"}, | ||
| 377 | {"description", "A scene file: prims by path, each with its type, API schemas and " | ||
| 378 | "attributes by USD name."}, | ||
| 379 | {"type", "object"}, | ||
| 380 | 3 | {"required", Json::array({"prims"})}, | |
| 381 | {"properties", | ||
| 382 | 1 | {{"$schema", String()}, | |
| 383 | {"prims", | ||
| 384 | {{"type", "object"}, | ||
| 385 | {"propertyNames", {{"pattern", "^/"}}}, | ||
| 386 | 2 | {"additionalProperties", Ref("Prim")}}}}}, | |
| 387 | {"additionalProperties", false}, | ||
| 388 | 46 | {"$defs", std::move(defs)}}; | |
| 389 | 1 | return PrintJson(root); | |
| 390 | 50 | } | |
| 391 | |||
| 392 | 8 | std::string ReferencePage(const SchemaFamily& family) { | |
| 393 | 24 | std::string out = "# " + std::string(family.title) + "\n\n" + | |
| 394 | 8 | "Generated from the schema registry by `ernie schema --markdown`.\n\n"; | |
| 395 | 24 | for (const auto* schemas : {&family.usd, &family.ernie}) { | |
| 396 | 81 | for (const SchemaDef* schema : *schemas) { | |
| 397 | 130 | out += SchemaSection(*schema, family); | |
| 398 | } | ||
| 399 | } | ||
| 400 | 8 | return out; | |
| 401 | ✗ | } | |
| 402 | |||
| 403 | 130 | std::string ExampleScene(const SchemaDef& schema) { | |
| 404 | 130 | if (schema.kind == SchemaKind::Abstract) { | |
| 405 | 22 | return {}; | |
| 406 | } | ||
| 407 | 108 | const bool api = schema.kind != SchemaKind::Concrete; | |
| 408 | 108 | const ApiName name{&schema, schema.kind == SchemaKind::MultipleApply ? kExampleInstance : ""}; | |
| 409 | 108 | Json prim = Json::object(); | |
| 410 | 108 | prim[kTypeName] = | |
| 411 | 216 | api ? (schema.appliesTo.empty() ? "Xform" : schema.appliesTo.front()) : schema.name; | |
| 412 | 108 | if (api) { | |
| 413 | 120 | prim[kApis] = Json::array({name.ToString()}); | |
| 414 | } | ||
| 415 | 644 | for (const AttributeDef& def : schema.attributes) { | |
| 416 | 536 | const std::optional<Json> fallback = JsonFallback(schema, def); | |
| 417 | // Arrays, targets and empty tokens have nothing to show. | ||
| 418 | 458 | const bool shown = fallback && def.type != ColumnType::Tensor && | |
| 419 | def.type != ColumnType::Relationship && | ||
| 420 | 1360 | def.type != ColumnType::Relationships && *fallback != Json(""); | |
| 421 | 536 | if (shown) { | |
| 422 | 388 | prim[name.Attribute(def.name)] = *fallback; | |
| 423 | } | ||
| 424 | 536 | } | |
| 425 | 108 | Json prims = Json::object(); | |
| 426 | 108 | prims["/World/" + std::string(schema.name)] = std::move(prim); | |
| 427 | 108 | return PrintJson(SceneFile(std::move(prims))); | |
| 428 | 138 | } | |
| 429 | |||
| 430 | 425 | std::string UsdTypeName(const AttributeDef& def) { | |
| 431 | 425 | static constexpr std::array<std::string_view, 14> kTypes{ | |
| 432 | "bool", "int", "double", "double2", "double3", "double4", "quatd", | ||
| 433 | "matrix4d", "token", "rel", "rel", "float[]", "token[]", ""}; | ||
| 434 | 425 | const AttributeMeta& meta = def.meta; | |
| 435 | 425 | switch (def.type) { | |
| 436 | 11 | case ColumnType::Vec3: | |
| 437 | 11 | return meta.color ? "color3d" : "double3"; | |
| 438 | 97 | case ColumnType::TokenValue: | |
| 439 | 178 | return meta.asset ? "asset" : "token"; | |
| 440 | 37 | case ColumnType::Tensor: { | |
| 441 | 58 | const std::string element = meta.bytes ? "uchar" : meta.integer ? "int" : "float"; | |
| 442 | 74 | return element + (meta.components > 1 ? std::to_string(meta.components) : "") + "[]"; | |
| 443 | 37 | } | |
| 444 | 280 | default: | |
| 445 | 280 | return std::string(kTypes[static_cast<std::size_t>(def.type)]); | |
| 446 | } | ||
| 447 | } | ||
| 448 | |||
| 449 | } // namespace ernie | ||
| 450 |