Initial support of payload composition

This commit is contained in:
Syoyo Fujita
2023-07-21 23:33:22 +09:00
parent 30b098fb6c
commit 13a4839e3b
4 changed files with 284 additions and 27 deletions

View File

@@ -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);

View File

@@ -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);

View File

@@ -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);

View File

@@ -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(