mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Initial support of payload composition
This commit is contained in:
@@ -14,7 +14,7 @@ struct CompositionFeatures {
|
||||
bool inherits{true};
|
||||
bool variantSets{true};
|
||||
bool references{true};
|
||||
bool payloads{true};
|
||||
bool payload{true}; // Not 'payloads'
|
||||
bool specializes{true};
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ static std::string GetFileExtension(const std::string &filename) {
|
||||
|
||||
static std::string str_tolower(std::string s) {
|
||||
std::transform(s.begin(), s.end(), s.begin(),
|
||||
[](unsigned char c) { return std::tolower(c); }
|
||||
[](unsigned char c) { return std::tolower(c); }
|
||||
);
|
||||
return s;
|
||||
}
|
||||
@@ -34,12 +34,12 @@ static std::string str_tolower(std::string s) {
|
||||
int main(int argc, char **argv) {
|
||||
if (argc < 2) {
|
||||
std::cout << "Usage tusdcat [--flatten] [--composition=STRLIST] [--relative] input.usda/usdc/usdz\n";
|
||||
std::cout << "\n --flatten (not implemented yet) Do composition(load sublayers, refences, payloads, evaluate `over`, inherit, variants..)";
|
||||
std::cout << "\n --flatten (not implemented yet) Do composition(load sublayers, refences, payload, evaluate `over`, inherit, variants..)";
|
||||
std::cout << " --composition: Specify which composition feature to be "
|
||||
"enabled(valid when `--flatten` is supplied). Comma separated "
|
||||
"list. \n l "
|
||||
"`subLayers`, i `inherits`, v `variantSets`, r `references`, "
|
||||
"p `payloads`, s `specializes`. \n Example: "
|
||||
"p `payload`, s `specializes`. \n Example: "
|
||||
"--composition=r,p --composition=references,subLayers\n";
|
||||
std::cout << "\n --relative (not implemented yet) Print Path as relative Path\n";
|
||||
return EXIT_FAILURE;
|
||||
@@ -71,7 +71,7 @@ int main(int argc, char **argv) {
|
||||
comp_features.inherits = false;
|
||||
comp_features.variantSets = false;
|
||||
comp_features.references = false;
|
||||
comp_features.payloads = false;
|
||||
comp_features.payload = false;
|
||||
comp_features.specializes = false;
|
||||
|
||||
for (const auto &item : items) {
|
||||
@@ -83,8 +83,8 @@ int main(int argc, char **argv) {
|
||||
comp_features.variantSets = true;
|
||||
} else if ((item == "r") || (item == "references")) {
|
||||
comp_features.references = true;
|
||||
} else if ((item == "p") || (item == "payloads")) {
|
||||
comp_features.payloads = true;
|
||||
} else if ((item == "p") || (item == "payload")) {
|
||||
comp_features.payload = true;
|
||||
} else if ((item == "s") || (item == "specializes")) {
|
||||
comp_features.specializes = true;
|
||||
} else {
|
||||
@@ -168,7 +168,7 @@ int main(int argc, char **argv) {
|
||||
// - [ ] Inherits
|
||||
// - [ ] VariantSets
|
||||
// - [x] References
|
||||
// - [ ] Payload
|
||||
// - [x] Payload
|
||||
// - [ ] Specializes
|
||||
//
|
||||
|
||||
@@ -184,12 +184,12 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `subLayers` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
}
|
||||
|
||||
|
||||
if (comp_features.references) {
|
||||
tinyusdz::Layer composited_layer;
|
||||
if (!tinyusdz::CompositeReferences(resolver, src_layer, &composited_layer, &warn, &err)) {
|
||||
@@ -201,7 +201,24 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `references` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
}
|
||||
|
||||
if (comp_features.payload) {
|
||||
tinyusdz::Layer composited_layer;
|
||||
if (!tinyusdz::CompositePayload(resolver, src_layer, &composited_layer, &warn, &err)) {
|
||||
std::cerr << "Failed to composite `payload`: " << err << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (warn.size()) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# `payload` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
|
||||
@@ -14,7 +14,7 @@ struct CompositionFeatures {
|
||||
bool inherits{true};
|
||||
bool variantSets{true};
|
||||
bool references{true};
|
||||
bool payloads{true};
|
||||
bool payload{true};
|
||||
bool specializes{true};
|
||||
};
|
||||
|
||||
@@ -27,7 +27,7 @@ int main(int argc, char **argv) {
|
||||
"enabled(valid when `--flatten` is supplied). Comma separated "
|
||||
"list. \n l "
|
||||
"`subLayers`, i `inherits`, v `variantSets`, r `references`, "
|
||||
"p `payloads`, s `specializes`. \n Example: "
|
||||
"p `payload`, s `specializes`. \n Example: "
|
||||
"--composition=r,p --composition=references,subLayers\n";
|
||||
exit(-1);
|
||||
}
|
||||
@@ -56,7 +56,7 @@ int main(int argc, char **argv) {
|
||||
comp_features.inherits = false;
|
||||
comp_features.variantSets = false;
|
||||
comp_features.references = false;
|
||||
comp_features.payloads = false;
|
||||
comp_features.payload = false;
|
||||
comp_features.specializes = false;
|
||||
|
||||
for (const auto &item : items) {
|
||||
@@ -68,8 +68,8 @@ int main(int argc, char **argv) {
|
||||
comp_features.variantSets = true;
|
||||
} else if ((item == "r") || (item == "references")) {
|
||||
comp_features.references = true;
|
||||
} else if ((item == "p") || (item == "payloads")) {
|
||||
comp_features.payloads = true;
|
||||
} else if ((item == "p") || (item == "payload")) {
|
||||
comp_features.payload = true;
|
||||
} else if ((item == "s") || (item == "specializes")) {
|
||||
comp_features.specializes = true;
|
||||
} else {
|
||||
@@ -180,7 +180,7 @@ int main(int argc, char **argv) {
|
||||
// - [ ] Inherits
|
||||
// - [ ] VariantSets
|
||||
// - [x] References
|
||||
// - [ ] Payload
|
||||
// - [x] Payload
|
||||
// - [ ] Specializes
|
||||
//
|
||||
|
||||
@@ -196,7 +196,7 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `subLayers` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
@@ -213,7 +213,24 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `references` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
}
|
||||
|
||||
if (comp_features.payload) {
|
||||
tinyusdz::Layer composited_layer;
|
||||
if (!tinyusdz::CompositePayload(resolver, src_layer, &composited_layer, &warn, &err)) {
|
||||
std::cerr << "Failed to composite `payload`: " << err << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (warn.size()) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# `payload` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
|
||||
@@ -13,7 +13,7 @@ struct CompositionFeatures {
|
||||
bool inherits{true};
|
||||
bool variantSets{true};
|
||||
bool references{true};
|
||||
bool payloads{true};
|
||||
bool payload{true};
|
||||
bool specializes{true};
|
||||
};
|
||||
|
||||
@@ -26,7 +26,7 @@ int main(int argc, char **argv) {
|
||||
"enabled(valid when `--flatten` is supplied). Comma separated "
|
||||
"list. \n l "
|
||||
"`subLayers`, i `inherits`, v `variantSets`, r `references`, "
|
||||
"p `payloads`, s `specializes`. \n Example: "
|
||||
"p `payload`, s `specializes`. \n Example: "
|
||||
"--composition=r,p --composition=references,subLayers\n";
|
||||
exit(-1);
|
||||
}
|
||||
@@ -55,7 +55,7 @@ int main(int argc, char **argv) {
|
||||
comp_features.inherits = false;
|
||||
comp_features.variantSets = false;
|
||||
comp_features.references = false;
|
||||
comp_features.payloads = false;
|
||||
comp_features.payload = false;
|
||||
comp_features.specializes = false;
|
||||
|
||||
for (const auto &item : items) {
|
||||
@@ -67,8 +67,8 @@ int main(int argc, char **argv) {
|
||||
comp_features.variantSets = true;
|
||||
} else if ((item == "r") || (item == "references")) {
|
||||
comp_features.references = true;
|
||||
} else if ((item == "p") || (item == "payloads")) {
|
||||
comp_features.payloads = true;
|
||||
} else if ((item == "p") || (item == "payload")) {
|
||||
comp_features.payload = true;
|
||||
} else if ((item == "s") || (item == "specializes")) {
|
||||
comp_features.specializes = true;
|
||||
} else {
|
||||
@@ -151,7 +151,7 @@ int main(int argc, char **argv) {
|
||||
// - [ ] Inherits
|
||||
// - [ ] VariantSets
|
||||
// - [x] References
|
||||
// - [ ] Payload
|
||||
// - [x] Payload
|
||||
// - [ ] Specializes
|
||||
//
|
||||
|
||||
@@ -167,7 +167,7 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `subLayers` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
@@ -184,7 +184,24 @@ int main(int argc, char **argv) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# composited\n";
|
||||
std::cout << "# `references` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
}
|
||||
|
||||
if (comp_features.payload) {
|
||||
tinyusdz::Layer composited_layer;
|
||||
if (!tinyusdz::CompositePayload(resolver, src_layer, &composited_layer, &warn, &err)) {
|
||||
std::cerr << "Failed to composite `payload`: " << err << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (warn.size()) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
}
|
||||
|
||||
std::cout << "# `payload` composited\n";
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
src_layer = std::move(composited_layer);
|
||||
|
||||
@@ -468,6 +468,189 @@ bool CompositeReferencesRec(uint32_t depth,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompositePayloadRec(uint32_t depth,
|
||||
const AssetResolutionResolver &resolver,
|
||||
PrimSpec &primspec /* [inout] */, std::string *warn,
|
||||
std::string *err,
|
||||
PayloadCompositionOptions options) {
|
||||
if (depth > options.max_depth) {
|
||||
PUSH_ERROR_AND_RETURN("Too deep.");
|
||||
}
|
||||
|
||||
// Traverse children first.
|
||||
for (auto &child : primspec.children()) {
|
||||
if (!CompositePayloadRec(depth + 1, resolver, child, warn, err,
|
||||
options)) {
|
||||
}
|
||||
}
|
||||
|
||||
if (primspec.metas().payload) {
|
||||
const ListEditQual &qual = primspec.metas().payload.value().first;
|
||||
const auto &payloads = primspec.metas().payload.value().second;
|
||||
|
||||
if ((qual == ListEditQual::ResetToExplicit) ||
|
||||
(qual == ListEditQual::Prepend)) {
|
||||
for (const auto &pl : payloads) {
|
||||
std::string asset_path = pl.asset_path.GetAssetPath();
|
||||
|
||||
if (asset_path.empty()) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
"TODO: Prim path(e.g. </xform>) in references.");
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
std::string _warn;
|
||||
std::string _err;
|
||||
|
||||
// resolve path
|
||||
// TODO: Store resolved path to Reference?
|
||||
std::string resolved_path = resolver.resolve(asset_path);
|
||||
|
||||
DCOUT("Loading payload: " << resolved_path << ", asset_path: " << asset_path);
|
||||
if (!LoadLayerFromFile(resolved_path, &layer, &_warn, &_err)) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("Failed to open `{}` as Layer: {}",
|
||||
asset_path, _err));
|
||||
}
|
||||
|
||||
DCOUT("layer = " << print_layer(layer, 0));
|
||||
|
||||
// TODO: Recursively resolve `payload`
|
||||
|
||||
if (_warn.size()) {
|
||||
if (warn) {
|
||||
(*warn) += _warn;
|
||||
}
|
||||
}
|
||||
|
||||
if (layer.primspecs().empty()) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("No prims in `{}`", asset_path));
|
||||
}
|
||||
|
||||
std::string default_prim;
|
||||
if (pl.prim_path.is_valid()) {
|
||||
default_prim = pl.prim_path.prim_part();
|
||||
} else {
|
||||
// Use `defaultPrim` metadatum
|
||||
if (layer.metas().defaultPrim.valid()) {
|
||||
default_prim = "/" + layer.metas().defaultPrim.str();
|
||||
} else {
|
||||
// Use the first Prim in the layer.
|
||||
default_prim = "/" + layer.primspecs().begin()->first;
|
||||
}
|
||||
}
|
||||
|
||||
const PrimSpec *src_ps{nullptr};
|
||||
if (!layer.find_primspec_at(Path(default_prim, ""), &src_ps, err)) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("Failed to find PrimSpec `{}` in layer `{}`", default_prim, asset_path));
|
||||
}
|
||||
|
||||
if (!src_ps) {
|
||||
PUSH_ERROR_AND_RETURN("Internal error: PrimSpec pointer is nullptr.");
|
||||
}
|
||||
|
||||
// `inherits` op
|
||||
if (!InheritPrimSpec(primspec, *src_ps, warn, err)) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Failed to reference layer `{}`", asset_path));
|
||||
}
|
||||
|
||||
// Modify Prim type if this PrimSpec is Model type.
|
||||
if (primspec.typeName().empty() || primspec.typeName() == "Model") {
|
||||
if (src_ps->typeName().empty() || src_ps->typeName() == "Model") {
|
||||
// pass
|
||||
} else {
|
||||
primspec.typeName() = src_ps->typeName();
|
||||
}
|
||||
}
|
||||
|
||||
DCOUT("inherit done: primspec = " << primspec.name());
|
||||
}
|
||||
|
||||
} else if (qual == ListEditQual::Delete) {
|
||||
PUSH_ERROR_AND_RETURN("`delete` references are not supported yet.");
|
||||
} else if (qual == ListEditQual::Add) {
|
||||
PUSH_ERROR_AND_RETURN("`add` references are not supported yet.");
|
||||
} else if (qual == ListEditQual::Order) {
|
||||
PUSH_ERROR_AND_RETURN("`order` references are not supported yet.");
|
||||
} else if (qual == ListEditQual::Invalid) {
|
||||
PUSH_ERROR_AND_RETURN("Invalid listedit qualifier to for `references`.");
|
||||
} else if (qual == ListEditQual::Append) {
|
||||
for (const auto &pl : payloads) {
|
||||
std::string asset_path = pl.asset_path.GetAssetPath();
|
||||
|
||||
if (asset_path.empty()) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
"TODO: Prim path(e.g. </xform>) in references.");
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
std::string _warn;
|
||||
std::string _err;
|
||||
|
||||
// resolve path
|
||||
// TODO: Store resolved path to Reference?
|
||||
std::string resolved_path = resolver.resolve(asset_path);
|
||||
|
||||
DCOUT("Loading payload: " << resolved_path << ", asset_path " << asset_path);
|
||||
if (!LoadLayerFromFile(asset_path, &layer, &_warn, &_err)) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("Failed to open `{}` as Layer: {}",
|
||||
asset_path, _err));
|
||||
}
|
||||
|
||||
if (_warn.size()) {
|
||||
if (warn) {
|
||||
(*warn) += _warn;
|
||||
}
|
||||
}
|
||||
|
||||
std::string default_prim;
|
||||
if (pl.prim_path.is_valid()) {
|
||||
default_prim = pl.prim_path.prim_part();
|
||||
} else {
|
||||
// Use `defaultPrim` metadatum
|
||||
if (layer.metas().defaultPrim.valid()) {
|
||||
default_prim = "/" + layer.metas().defaultPrim.str();
|
||||
} else {
|
||||
// Use the first Prim in the layer.
|
||||
default_prim = "/" + layer.primspecs().begin()->first;
|
||||
}
|
||||
}
|
||||
|
||||
const PrimSpec *src_ps{nullptr};
|
||||
if (!layer.find_primspec_at(Path(default_prim, ""), &src_ps, err)) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("Failed to find PrimSpec `{}` in layer `{}`", default_prim, asset_path));
|
||||
}
|
||||
|
||||
if (!src_ps) {
|
||||
PUSH_ERROR_AND_RETURN("Internal error: PrimSpec pointer is nullptr.");
|
||||
}
|
||||
|
||||
// `over` op
|
||||
if (!OverridePrimSpec(primspec, *src_ps, warn, err)) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Failed to reference layer `{}`", asset_path));
|
||||
}
|
||||
|
||||
// Modify Prim type if this PrimSpec is Model type.
|
||||
if (primspec.typeName().empty() || primspec.typeName() == "Model") {
|
||||
|
||||
if (src_ps->typeName().empty() || src_ps->typeName() == "Model") {
|
||||
// pass
|
||||
} else {
|
||||
primspec.typeName() = src_ps->typeName();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove `payload`.
|
||||
primspec.metas().payload = nonstd::nullopt;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
bool CompositeReferences(const AssetResolutionResolver &resolver,
|
||||
@@ -493,6 +676,29 @@ bool CompositeReferences(const AssetResolutionResolver &resolver,
|
||||
return true;
|
||||
}
|
||||
|
||||
bool CompositePayload(const AssetResolutionResolver &resolver,
|
||||
const Layer &in_layer, Layer *composited_layer,
|
||||
std::string *warn, std::string *err,
|
||||
PayloadCompositionOptions options) {
|
||||
if (!composited_layer) {
|
||||
return false;
|
||||
}
|
||||
|
||||
Layer dst = in_layer; // deep copy
|
||||
|
||||
for (auto &item : dst.primspecs()) {
|
||||
|
||||
if (!CompositePayloadRec(/* depth */0, resolver, item.second, warn, err, options)) {
|
||||
PUSH_ERROR_AND_RETURN("Composite `payload` failed.");
|
||||
}
|
||||
}
|
||||
|
||||
(*composited_layer) = dst;
|
||||
|
||||
DCOUT("Composite `payload` ok.");
|
||||
return true;
|
||||
}
|
||||
|
||||
namespace detail {
|
||||
|
||||
static nonstd::optional<Prim> ReconstructPrimFromPrimSpec(
|
||||
|
||||
Reference in New Issue
Block a user