mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Initial support of FileFormat handler API.
This commit is contained in:
@@ -3,50 +3,69 @@
|
||||
|
||||
// Import to_string() and operator<< features
|
||||
#include <iostream>
|
||||
|
||||
#include "pprinter.hh"
|
||||
#include "value-pprint.hh"
|
||||
#include "prim-pprint.hh"
|
||||
|
||||
// Tydra is a collection of APIs to access/convert USD Prim data
|
||||
// (e.g. Can get Attribute by name)
|
||||
// See <tinyusdz>/examples/tydra_api for more Tydra API examples.
|
||||
#include "tydra/scene-access.hh"
|
||||
|
||||
std::map<std::string, float> g_map;
|
||||
#include "value-pprint.hh"
|
||||
|
||||
//
|
||||
// To read asset in custom format(and in custom file system), this example provides
|
||||
// To read asset in custom format, this example provides
|
||||
//
|
||||
// - AssetResolution handler(for AssetResolution::open_asset)
|
||||
// - Create on-memory asset system
|
||||
// - Optional. Create on-memory asset system
|
||||
// - You can use built-in file based AssetResolution handler if you provide
|
||||
// .my file
|
||||
// - File format API(read/write data with custom format)
|
||||
// - Simple 4 byte binary(float value)
|
||||
// - Simple 4 byte binary storing a float value.
|
||||
//
|
||||
|
||||
static int MyARResolve(const char *asset_name, const std::vector<std::string> &search_paths, std::string *resolved_asset_name, std::string *err, void *userdata) {
|
||||
//
|
||||
// def "muda" ( references = @bora.my@ ) {
|
||||
// }
|
||||
//
|
||||
// =>
|
||||
//
|
||||
// def "muda" () {
|
||||
// uniform float myval = 3.14
|
||||
// }
|
||||
//
|
||||
|
||||
static std::map<std::string, float> g_map;
|
||||
|
||||
//
|
||||
// Asset resolution handlers
|
||||
//
|
||||
static int MyARResolve(const char *asset_name,
|
||||
const std::vector<std::string> &search_paths,
|
||||
std::string *resolved_asset_name, std::string *err,
|
||||
void *userdata) {
|
||||
(void)err;
|
||||
(void)userdata;
|
||||
(void)search_paths;
|
||||
|
||||
std::cout << "Resolve " << asset_name << "\n";
|
||||
|
||||
if (!asset_name) {
|
||||
return -2; // err
|
||||
return -2; // err
|
||||
}
|
||||
|
||||
if (!resolved_asset_name) {
|
||||
return -2; // err
|
||||
return -2; // err
|
||||
}
|
||||
|
||||
if (g_map.count(asset_name)) {
|
||||
(*resolved_asset_name) = asset_name;
|
||||
return 0; // OK
|
||||
std::cout << "Resolved as " << resolved_asset_name << "\n";
|
||||
return 0; // OK
|
||||
}
|
||||
std::cerr << "Can't resolve asset: " << asset_name << "\n";
|
||||
|
||||
return -1; // failed to resolve.
|
||||
return -1; // failed to resolve.
|
||||
}
|
||||
|
||||
|
||||
// AssetResoltion handlers
|
||||
static int MyARSize(const char *asset_name, uint64_t *nbytes, std::string *err, void *userdata) {
|
||||
static int MyARSize(const char *asset_name, uint64_t *nbytes, std::string *err,
|
||||
void *userdata) {
|
||||
(void)userdata;
|
||||
|
||||
if (!asset_name) {
|
||||
@@ -63,13 +82,14 @@ static int MyARSize(const char *asset_name, uint64_t *nbytes, std::string *err,
|
||||
return -1;
|
||||
}
|
||||
|
||||
std::cout << "Asset size " << sizeof(float) << "\n";
|
||||
|
||||
(*nbytes) = sizeof(float);
|
||||
return 0; // OK
|
||||
return 0; // OK
|
||||
}
|
||||
|
||||
int MyARRead(const char *asset_name, uint64_t req_nbytes, uint8_t *out_buf,
|
||||
uint64_t *nbytes, std::string *err, void *userdata) {
|
||||
|
||||
uint64_t *nbytes, std::string *err, void *userdata) {
|
||||
if (!asset_name) {
|
||||
if (err) {
|
||||
(*err) += "asset_name arg is nullptr.\n";
|
||||
@@ -101,18 +121,36 @@ int MyARRead(const char *asset_name, uint64_t req_nbytes, uint8_t *out_buf,
|
||||
}
|
||||
|
||||
//
|
||||
// custom File-format APIs.
|
||||
// custom File-format handlers
|
||||
//
|
||||
static bool MyCheck(const tinyusdz::Asset &asset, std::string *warn, std::string *err, void *user_data) {
|
||||
static bool MyCheck(const tinyusdz::Asset &asset, std::string *warn,
|
||||
std::string *err, void *user_data) {
|
||||
if (asset.size() != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool MyRead(const tinyusdz::Asset &asset, tinyusdz::PrimSpec &ps/* inout */, std::string *warn, std::string *err, void *user_data) {
|
||||
static bool MyRead(const tinyusdz::Asset &asset,
|
||||
tinyusdz::PrimSpec &ps /* inout */, std::string *warn,
|
||||
std::string *err, void *user_data) {
|
||||
//
|
||||
// `tinyusdz::Asset` is a simple buffer: data() : bytes buffer, size() :
|
||||
// buffer size
|
||||
//
|
||||
|
||||
if (asset.size() != 4) {
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// Create a PrimSpec:
|
||||
//
|
||||
// def "my01" {
|
||||
// uniform float myval = ...
|
||||
// }
|
||||
//
|
||||
|
||||
float val;
|
||||
memcpy(&val, asset.data(), 4);
|
||||
@@ -122,31 +160,34 @@ static bool MyRead(const tinyusdz::Asset &asset, tinyusdz::PrimSpec &ps/* inout
|
||||
attr.set_name("myval");
|
||||
attr.variability() = tinyusdz::Variability::Uniform;
|
||||
|
||||
ps.props()["myval"] = tinyusdz::Property(attr, /* custom */false);
|
||||
ps.props()["myval"] = tinyusdz::Property(attr, /* custom */ false);
|
||||
|
||||
ps.name() = "my01"; // must set PrimSpec name
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool MyWrite(const tinyusdz::PrimSpec &ps, tinyusdz::Asset *asset_out, std::string *warn, std::string *err, void *user_data) {
|
||||
static bool MyWrite(const tinyusdz::PrimSpec &ps, tinyusdz::Asset *asset_out,
|
||||
std::string *warn, std::string *err, void *user_data) {
|
||||
// TOOD
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
int main(int argc, char **argv) {
|
||||
g_map["bora"] = 3.14f;
|
||||
g_map["dora"] = 6.14f;
|
||||
g_map["bora.my"] = 3.14f;
|
||||
g_map["dora.my"] = 6.14f;
|
||||
|
||||
tinyusdz::FileFormatHandler my_handler;
|
||||
my_handler.extension = "my";
|
||||
my_handler.description = "Custom fileformat example.";
|
||||
my_handler.description = "Custom fileformat example.";
|
||||
my_handler.checker = MyCheck;
|
||||
my_handler.reader= MyRead;
|
||||
my_handler.reader = MyRead;
|
||||
my_handler.writer = MyWrite;
|
||||
my_handler.userdata = nullptr;
|
||||
|
||||
tinyusdz::Stage stage; // empty scene
|
||||
|
||||
// path to <tinyusdz>/data/fileformat_my.usda
|
||||
std::string input_usd_filepath = "../data/fileformat_my.usda";
|
||||
if (argc > 1) {
|
||||
input_usd_filepath = argv[1];
|
||||
@@ -155,7 +196,8 @@ int main(int argc, char **argv) {
|
||||
std::string warn, err;
|
||||
|
||||
tinyusdz::Layer layer;
|
||||
bool ret = tinyusdz::LoadLayerFromFile(input_usd_filepath, &layer, &warn, &err);
|
||||
bool ret =
|
||||
tinyusdz::LoadLayerFromFile(input_usd_filepath, &layer, &warn, &err);
|
||||
|
||||
if (warn.size()) {
|
||||
std::cout << "WARN: " << warn << "\n";
|
||||
@@ -167,13 +209,13 @@ int main(int argc, char **argv) {
|
||||
}
|
||||
|
||||
tinyusdz::AssetResolutionResolver resolver;
|
||||
// Register filesystem handler for `.my` asset.
|
||||
// Register on-memory filesystem handler for `.my` asset.
|
||||
tinyusdz::AssetResolutionHandler ar_handler;
|
||||
ar_handler.resolve_fun = MyARResolve;
|
||||
ar_handler.size_fun = MyARSize;
|
||||
ar_handler.read_fun = MyARRead;
|
||||
ar_handler.write_fun = nullptr; // not used in this example.
|
||||
ar_handler.userdata = nullptr; // not used in this example;
|
||||
ar_handler.write_fun = nullptr; // not used in this example.
|
||||
ar_handler.userdata = nullptr; // not used in this example;
|
||||
resolver.register_asset_resolution_handler("my", ar_handler);
|
||||
|
||||
tinyusdz::ReferencesCompositionOptions options;
|
||||
@@ -181,12 +223,12 @@ int main(int argc, char **argv) {
|
||||
|
||||
// Do `references` composition to materialize `references = @***.my@`
|
||||
tinyusdz::Layer composited_layer;
|
||||
if (!tinyusdz::CompositeReferences(resolver, layer, &composited_layer, &warn, &err)) {
|
||||
if (!tinyusdz::CompositeReferences(resolver, layer, &composited_layer, &warn,
|
||||
&err, options)) {
|
||||
std::cerr << "Failed to composite `references`: " << err << "\n";
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
// Print USD scene as Ascii.
|
||||
std::cout << composited_layer << "\n";
|
||||
|
||||
|
||||
@@ -97,7 +97,6 @@ std::string AssetResolutionResolver::resolve(
|
||||
bool AssetResolutionResolver::open_asset(const std::string &resolvedPath, const std::string &assetPath,
|
||||
Asset *asset_out, std::string *warn, std::string *err) {
|
||||
|
||||
|
||||
if (!asset_out) {
|
||||
if (err) {
|
||||
(*err) = "`asset` arg is nullptr.";
|
||||
@@ -132,6 +131,7 @@ bool AssetResolutionResolver::open_asset(const std::string &resolvedPath, const
|
||||
uint64_t read_size{0};
|
||||
|
||||
ret = _asset_resolution_handlers.at(ext).read_fun(resolvedPath.c_str(), /* req_size */asset.size(), asset.data(), &read_size, err, userdata);
|
||||
|
||||
if (ret != 0) {
|
||||
if (err) {
|
||||
(*err) += "Read asset through handler failed.\n";
|
||||
|
||||
@@ -300,12 +300,16 @@ typedef bool (*FileFormatCheckFunction)(const Asset &asset, std::string *warn, s
|
||||
|
||||
// Read content of data into PrimSpec(metadatum, properties, primChildren/variantChildren).
|
||||
//
|
||||
// TODO: Use `Layer` instead of `PrimSpec`?
|
||||
//
|
||||
// @param[in] asset Asset data
|
||||
// @param[inout] ps PrimSpec which references/payload this asset.
|
||||
// @param[out] warn Warning message
|
||||
// @param[out] err Error message(when the fuction returns false)
|
||||
// @param[inout] user_data Userdata. can be nullptr.
|
||||
//
|
||||
// @return true when reading data succeeds.
|
||||
//
|
||||
typedef bool (*FileFormatReadFunction)(const Asset &asset, PrimSpec &ps/* inout */, std::string *warn, std::string *err, void *user_data);
|
||||
|
||||
// Write corresponding content of PrimSpec to a binary data
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
#include "prim-types.hh"
|
||||
#include "str-util.hh"
|
||||
#include "tiny-format.hh"
|
||||
#include "tinyusdz.hh"
|
||||
#include "usdGeom.hh"
|
||||
#include "usdLux.hh"
|
||||
#include "usdShade.hh"
|
||||
@@ -141,46 +142,13 @@ bool LoadAsset(AssetResolutionResolver &resolver,
|
||||
}
|
||||
|
||||
std::string asset_path = assetPath.GetAssetPath();
|
||||
std::string ext = GetExtension(asset_path);
|
||||
|
||||
if (asset_path.empty()) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
"TODO: No assetPath but Prim path(e.g. </xform>) in references.");
|
||||
}
|
||||
|
||||
if (IsBuiltinFileFormat(asset_path)) {
|
||||
if (IsUSDFileFormat(asset_path)) {
|
||||
// ok
|
||||
} else {
|
||||
if (error_when_unsupported_fileformat) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format(
|
||||
"TODO: Unknown/unsupported asset file format: {}", asset_path));
|
||||
} else {
|
||||
PUSH_WARN(fmt::format(
|
||||
"TODO: Unknown/unsupported asset file format. Skipped: {}",
|
||||
asset_path));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::string ext = GetExtension(asset_path);
|
||||
if (fileformats.count(ext)) {
|
||||
DCOUT("Fileformat handler found for: " + ext);
|
||||
|
||||
} else {
|
||||
if (error_when_unsupported_fileformat) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Unknown/unsupported asset file format: {}", asset_path));
|
||||
} else {
|
||||
PUSH_WARN(fmt::format(
|
||||
"Unknown/unsupported asset file format. Skipped: {}", asset_path));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
std::string _warn;
|
||||
std::string _err;
|
||||
|
||||
// resolve path
|
||||
// TODO: Store resolved path to Reference?
|
||||
@@ -188,6 +156,7 @@ bool LoadAsset(AssetResolutionResolver &resolver,
|
||||
|
||||
DCOUT("Loading references: " << resolved_path
|
||||
<< ", asset_path: " << asset_path);
|
||||
|
||||
if (resolved_path.empty()) {
|
||||
if (error_when_asset_not_found) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
@@ -207,11 +176,49 @@ bool LoadAsset(AssetResolutionResolver &resolver,
|
||||
}
|
||||
|
||||
Asset asset;
|
||||
if (!resolver.open_asset(resolved_path, asset_path, &asset, &_warn, &_err)) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Failed to open resolved asset `{}`(`{}`)", resolved_path, asset_path, _err));
|
||||
if (!resolver.open_asset(resolved_path, asset_path, &asset, warn, err)) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format("Failed to open asset `{}`.", resolved_path));
|
||||
}
|
||||
|
||||
DCOUT("Opened resolved assst: " << resolved_path
|
||||
<< ", asset_path: " << asset_path);
|
||||
|
||||
if (IsBuiltinFileFormat(asset_path)) {
|
||||
if (IsUSDFileFormat(asset_path)) {
|
||||
// ok
|
||||
} else {
|
||||
// TODO: mtlx, obj
|
||||
if (error_when_unsupported_fileformat) {
|
||||
PUSH_ERROR_AND_RETURN(fmt::format(
|
||||
"TODO: Unknown/unsupported asset file format: {}", asset_path));
|
||||
} else {
|
||||
PUSH_WARN(fmt::format(
|
||||
"TODO: Unknown/unsupported asset file format. Skipped: {}",
|
||||
asset_path));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if (fileformats.count(ext)) {
|
||||
DCOUT("Fileformat handler found for: " + ext);
|
||||
|
||||
} else {
|
||||
DCOUT("Unknown/unsupported fileformat: " + ext);
|
||||
if (error_when_unsupported_fileformat) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Unknown/unsupported asset file format: {}", asset_path));
|
||||
} else {
|
||||
PUSH_WARN(fmt::format(
|
||||
"Unknown/unsupported asset file format. Skipped: {}", asset_path));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Layer layer;
|
||||
std::string _warn;
|
||||
std::string _err;
|
||||
|
||||
if (IsUSDFileFormat(asset_path)) {
|
||||
if (!LoadLayerFromMemory(asset.data(), asset.size(), asset_path, &layer, &_warn, &_err)) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
@@ -220,12 +227,29 @@ bool LoadAsset(AssetResolutionResolver &resolver,
|
||||
} else if (IsMtlxFileFormat(asset_path)) {
|
||||
DCOUT("TODO:");
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("TODO: open mtlx asset `{}`", asset_path, _err));
|
||||
fmt::format("TODO: open mtlx asset `{}`", asset_path));
|
||||
|
||||
} else {
|
||||
// TODO: Invoke fileformat handler
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("TODO: open custom asset `{}`", asset_path, _err));
|
||||
if (fileformats.count(ext)) {
|
||||
PrimSpec ps;
|
||||
const FileFormatHandler &handler= fileformats.at(ext);
|
||||
|
||||
if (!handler.reader(asset, ps, &_warn, &_err, handler.userdata)) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("Failed to read asset `{}` error: {}", asset_path, _err));
|
||||
}
|
||||
|
||||
if (ps.name().empty()) {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("PrimSpec element_name is empty. asset `{}`", asset_path));
|
||||
}
|
||||
|
||||
layer.primspecs()[ps.name()] = ps;
|
||||
DCOUT("Read asset from custom fileformat handler: " << ext);
|
||||
} else {
|
||||
PUSH_ERROR_AND_RETURN(
|
||||
fmt::format("FileFormat handler not found for asset `{}`", asset_path));
|
||||
}
|
||||
}
|
||||
|
||||
DCOUT("layer = " << print_layer(layer, 0));
|
||||
|
||||
Reference in New Issue
Block a user