Support triple-quoted string.

Support parsing&printing string-only data in stage/prim/attr meta.
This commit is contained in:
Syoyo Fujita
2022-08-24 22:31:05 +09:00
parent 4fc3d775a2
commit 7a5322af77
19 changed files with 990 additions and 490 deletions

View File

@@ -910,7 +910,7 @@ bool AsciiParser::ReadBasicType(bool *value) {
}
char sc;
if (!_sr->read1(&sc)) {
if (!Char1(&sc)) {
return false;
}
_curr_cursor.col++;
@@ -953,7 +953,7 @@ bool AsciiParser::ReadBasicType(int *value) {
// bool negative = false;
{
char sc;
if (!_sr->read1(&sc)) {
if (!Char1(&sc)) {
return false;
}
_curr_cursor.col++;
@@ -976,9 +976,9 @@ bool AsciiParser::ReadBasicType(int *value) {
ss << sc;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1035,7 +1035,7 @@ bool AsciiParser::ReadBasicType(uint32_t *value) {
bool negative = false;
{
char sc;
if (!_sr->read1(&sc)) {
if (!Char1(&sc)) {
return false;
}
_curr_cursor.col++;
@@ -1063,9 +1063,9 @@ bool AsciiParser::ReadBasicType(uint32_t *value) {
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1138,7 +1138,7 @@ bool AsciiParser::ReadBasicType(uint64_t *value) {
bool negative = false;
{
char sc;
if (!_sr->read1(&sc)) {
if (!Char1(&sc)) {
return false;
}
_curr_cursor.col++;
@@ -1166,9 +1166,9 @@ bool AsciiParser::ReadBasicType(uint64_t *value) {
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1385,14 +1385,14 @@ bool AsciiParser::SepBy1BasicType(const char sep,
result->push_back(value);
}
while (!_sr->eof()) {
while (!Eof()) {
// sep
if (!SkipWhitespaceAndNewline()) {
return false;
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1444,14 +1444,14 @@ bool AsciiParser::SepBy1BasicType(const char sep, std::vector<T> *result) {
result->push_back(value);
}
while (!_sr->eof()) {
while (!Eof()) {
// sep
if (!SkipWhitespaceAndNewline()) {
return false;
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1506,13 +1506,13 @@ bool AsciiParser::SepBy1TupleType(
result->push_back(value);
}
while (!_sr->eof()) {
while (!Eof()) {
if (!SkipWhitespaceAndNewline()) {
return false;
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1568,13 +1568,13 @@ bool AsciiParser::SepBy1TupleType(const char sep,
result->push_back(value);
}
while (!_sr->eof()) {
while (!Eof()) {
if (!SkipWhitespaceAndNewline()) {
return false;
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -1672,14 +1672,14 @@ bool AsciiParser::SepBy1BasicType(const char sep,
result->push_back(ref);
}
while (!_sr->eof()) {
while (!Eof()) {
// sep
if (!SkipWhitespaceAndNewline()) {
return false;
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -2491,7 +2491,7 @@ bool AsciiParser::ParseDict(std::map<std::string, MetaVariable> *out_dict) {
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!Char1(&c)) {
return false;
@@ -2595,7 +2595,7 @@ bool AsciiParser::ReadStringLiteral(std::string *literal) {
std::stringstream ss;
char c0;
if (!_sr->read1(&c0)) {
if (!Char1(&c0)) {
return false;
}
@@ -2607,13 +2607,18 @@ bool AsciiParser::ReadStringLiteral(std::string *literal) {
bool end_with_quotation{false};
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
if ((c == '\n') || (c == '\r')) {
PUSH_ERROR_AND_RETURN(
"New line in string literal.");
}
if (c == '"') {
end_with_quotation = true;
break;
@@ -2634,14 +2639,178 @@ bool AsciiParser::ReadStringLiteral(std::string *literal) {
return true;
}
bool AsciiParser::MaybeString(StringData *str) {
std::stringstream ss;
if (!str) {
return false;
}
auto loc = CurrLoc();
auto start_cursor = _curr_cursor;
char c0;
if (!Char1(&c0)) {
SeekTo(loc);
return false;
}
if (c0 != '"') {
SeekTo(loc);
return false;
}
bool end_with_quotation{false};
while (!Eof()) {
char c;
if (!Char1(&c)) {
// this should not happen.
SeekTo(loc);
return false;
}
if ((c == '\n') || (c == '\r')) {
SeekTo(loc);
return false;
}
if (c == '"') {
end_with_quotation = true;
break;
}
ss << c;
}
if (!end_with_quotation) {
SeekTo(loc);
return false;
}
DCOUT("Single quoted string found. col " << start_cursor.col << ", row " << start_cursor.row);
str->value = ss.str();
str->line_col = start_cursor.col;
str->line_row = start_cursor.row;
str->is_triple_quoted = false;
_curr_cursor.col += int(str->value.size() + 2); // +2 for quotation chars
return true;
}
bool AsciiParser::MaybeTripleQuotedString(StringData *str) {
std::stringstream ss;
auto loc = CurrLoc();
auto start_cursor = _curr_cursor;
std::vector<char> triple_quote;
if (!CharN(3, &triple_quote)) {
SeekTo(loc);
return false;
}
if (triple_quote.size() != 3) {
SeekTo(loc);
return false;
}
if (triple_quote[0] == '"' &&
triple_quote[1] == '"' &&
triple_quote[2] == '"') {
// ok
} else {
SeekTo(loc);
return false;
}
// Read until next triple-quote `"""`
std::stringstream str_buf;
auto locinfo = _curr_cursor;
int quote_count = 0;
while (!Eof()) {
char c;
if (!Char1(&c)) {
SeekTo(loc);
return false;
}
str_buf << c;
quote_count = (c == '"') ? (quote_count + 1) : 0;
// Update loc info
locinfo.col++;
if (c == '\n') {
locinfo.col = 0;
locinfo.row++;
} else if (c == '\r') {
// CRLF?
if (_sr->tell() < (_sr->size() - 1)) {
char d;
if (!Char1(&d)) {
// this should not happen.
SeekTo(loc);
return false;
}
if (d == '\n') {
// CRLF
str_buf << d;
} else {
// unwind 1 char
if (!_sr->seek_from_current(-1)) {
// this should not happen.
SeekTo(loc);
return false;
}
}
}
locinfo.col = 0;
locinfo.row++;
}
if (quote_count == 3) {
// got '"""'
break;
}
}
if (quote_count != 3) {
SeekTo(loc);
return false;
}
DCOUT("Triple quoted string found. col " << start_cursor.col << ", row " << start_cursor.row);
// remove last '"""'
str->value = removeSuffix(str_buf.str(), "\"\"\"");
str->line_col = start_cursor.col;
str->line_row = start_cursor.row;
str->is_triple_quoted = true;
_curr_cursor = locinfo;
return true;
}
bool AsciiParser::ReadPrimAttrIdentifier(std::string *token) {
// Example: xformOp:transform
std::stringstream ss;
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -2705,7 +2874,7 @@ bool AsciiParser::ReadIdentifier(std::string *token) {
// The first character.
{
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
DCOUT("read1 failed.");
return false;
@@ -2723,9 +2892,9 @@ bool AsciiParser::ReadIdentifier(std::string *token) {
ss << c;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -2760,9 +2929,9 @@ bool AsciiParser::ReadPathIdentifier(std::string *path_identifier) {
// read until '>'
bool ok = false;
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -2789,9 +2958,9 @@ bool AsciiParser::ReadPathIdentifier(std::string *path_identifier) {
}
bool AsciiParser::SkipUntilNewline() {
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -2802,7 +2971,7 @@ bool AsciiParser::SkipUntilNewline() {
// CRLF?
if (_sr->tell() < (_sr->size() - 1)) {
char d;
if (!_sr->read1(&d)) {
if (!Char1(&d)) {
// this should not happen.
return false;
}
@@ -2835,6 +3004,19 @@ bool AsciiParser::SkipUntilNewline() {
//
bool AsciiParser::ParseStageMetaOpt() {
// Maybe string
{
StringData str;
if (MaybeTripleQuotedString(&str)) {
_stage_metas.strings.push_back(str);
return true;
} else if (MaybeString(&str)) {
_stage_metas.strings.push_back(str);
return true;
}
}
std::string varname;
if (!ReadIdentifier(&varname)) {
return false;
@@ -2897,8 +3079,8 @@ bool AsciiParser::ParseStageMetaOpt() {
PUSH_ERROR_AND_RETURN("`upAxis` isn't a string value.");
}
} else if (varname == "doc") {
if (auto pv = var.value.get_value<std::string>()) {
DCOUT("doc = " << pv.value());
if (auto pv = var.value.get_value<StringData>()) {
DCOUT("doc = " << to_string(pv.value()));
_stage_metas.doc = pv.value();
} else {
PUSH_ERROR_AND_RETURN("`doc` isn't a string value.");
@@ -3068,7 +3250,7 @@ bool AsciiParser::ParseStageMetas() {
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!LookChar1(&c)) {
return false;
@@ -3112,7 +3294,7 @@ bool AsciiParser::ParseStageMetas() {
// `#` style comment
bool AsciiParser::ParseSharpComment() {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// eol
return false;
}
@@ -3126,7 +3308,7 @@ bool AsciiParser::ParseSharpComment() {
// Fetch 1 char. Do not change input stream position.
bool AsciiParser::LookChar1(char *c) {
if (!_sr->read1(c)) {
if (!Char1(c)) {
return false;
}
@@ -3208,9 +3390,9 @@ bool AsciiParser::PopParserState(ParseState *state) {
}
bool AsciiParser::SkipWhitespace() {
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -3233,9 +3415,9 @@ bool AsciiParser::SkipWhitespace() {
}
bool AsciiParser::SkipWhitespaceAndNewline() {
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -3253,7 +3435,7 @@ bool AsciiParser::SkipWhitespaceAndNewline() {
// CRLF?
if (_sr->tell() < (_sr->size() - 1)) {
char d;
if (!_sr->read1(&d)) {
if (!Char1(&d)) {
// this should not happen.
return false;
}
@@ -3285,9 +3467,9 @@ bool AsciiParser::SkipWhitespaceAndNewline() {
bool AsciiParser::SkipCommentAndWhitespaceAndNewline() {
// Skip multiple line of comments.
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -3309,7 +3491,7 @@ bool AsciiParser::SkipCommentAndWhitespaceAndNewline() {
// CRLF?
if (_sr->tell() < (_sr->size() - 1)) {
char d;
if (!_sr->read1(&d)) {
if (!Char1(&d)) {
// this should not happen.
return false;
}
@@ -3346,7 +3528,7 @@ bool AsciiParser::Expect(char expect_c) {
}
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -3612,7 +3794,7 @@ bool AsciiParser::ParseMagicHeader() {
return false;
}
if (_sr->eof()) {
if (Eof()) {
return false;
}
@@ -3717,7 +3899,7 @@ bool AsciiParser::ParseReference(Reference *out, bool *triple_deliminated) {
// Read until '@'
bool found_delimiter = false;
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!Char1(&c)) {
@@ -3745,7 +3927,7 @@ bool AsciiParser::ParseReference(Reference *out, bool *triple_deliminated) {
std::string tok;
// Read until '@@@' appears
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!Char1(&c)) {
@@ -3863,22 +4045,25 @@ bool AsciiParser::ParseMetaValue(const VariableDef &def,
var.value = value;
} else if (vartype == value::kString) {
std::string value;
if (!ReadStringLiteral(&value)) {
std::string msg = "String literal expected for `" + varname + "`.\n";
PushError(msg);
return false;
}
DCOUT("string = " << value);
StringData sdata;
if (MaybeTripleQuotedString(&sdata)) {
} else {
std::string value;
auto lineinfo = _curr_cursor;
if (!ReadStringLiteral(&value)) {
PUSH_ERROR_AND_RETURN("String literal expected for `" + varname + "`.");
}
auto ret = def.post_parse_handler(value);
if (!ret) {
DCOUT("error = " << ret.error());
PUSH_ERROR_AND_RETURN("Invalid string for `" + varname + "`. " + ret.error());
sdata.value = value;
sdata.is_triple_quoted = false;
sdata.line_row = lineinfo.row;
sdata.line_col = lineinfo.col;
}
DCOUT("string = " << sdata.value);
var.value = value;
var.value = sdata;
} else if (vartype == "string[]") {
// TODO: Support multi-line string?
std::vector<std::string> values;
if (!ParseBasicTypeArray(&values)) {
return false;
@@ -3981,7 +4166,7 @@ bool AsciiParser::ParseMetaValue(const VariableDef &def,
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
if (!SkipWhitespaceAndNewline()) {
return false;
}
@@ -4040,7 +4225,7 @@ bool AsciiParser::LexFloat(std::string *result) {
bool leading_decimal_dots{false};
{
char sc;
if (!_sr->read1(&sc)) {
if (!Char1(&sc)) {
return false;
}
_curr_cursor.col++;
@@ -4052,7 +4237,7 @@ bool AsciiParser::LexFloat(std::string *result) {
has_sign = true;
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
return false;
}
@@ -4084,8 +4269,8 @@ bool AsciiParser::LexFloat(std::string *result) {
if (!leading_decimal_dots) {
// std::cout << "1 read int part: ss = " << ss.str() << "\n";
while (!_sr->eof()) {
if (!_sr->read1(&curr)) {
while (!Eof()) {
if (!Char1(&curr)) {
return false;
}
@@ -4100,12 +4285,12 @@ bool AsciiParser::LexFloat(std::string *result) {
}
}
if (_sr->eof()) {
if (Eof()) {
(*result) = ss.str();
return true;
}
if (!_sr->read1(&curr)) {
if (!Char1(&curr)) {
return false;
}
@@ -4116,8 +4301,8 @@ bool AsciiParser::LexFloat(std::string *result) {
if (curr == '.') {
ss << curr;
while (!_sr->eof()) {
if (!_sr->read1(&curr)) {
while (!Eof()) {
if (!Char1(&curr)) {
return false;
}
@@ -4137,7 +4322,7 @@ bool AsciiParser::LexFloat(std::string *result) {
return true;
}
if (_sr->eof()) {
if (Eof()) {
(*result) = ss.str();
return true;
}
@@ -4147,7 +4332,7 @@ bool AsciiParser::LexFloat(std::string *result) {
if ((curr == 'e') || (curr == 'E')) {
ss << curr;
if (!_sr->read1(&curr)) {
if (!Char1(&curr)) {
return false;
}
@@ -4164,8 +4349,8 @@ bool AsciiParser::LexFloat(std::string *result) {
PUSH_ERROR_AND_RETURN("Empty `E' is not allowed.");
}
while (!_sr->eof()) {
if (!_sr->read1(&curr)) {
while (!Eof()) {
if (!Char1(&curr)) {
return false;
}
@@ -4369,6 +4554,32 @@ AsciiParser::ParsePrimMeta() {
}
tinyusdz::ListEditQual qual{ListEditQual::ResetToExplicit};
// May be string only
// For some reason, string-only data is stored in `MetaVariable` and
// reconstructed in ReconstructPrimMeta in usda-reader.cc
//
{
StringData sdata;
if (MaybeTripleQuotedString(&sdata)) {
MetaVariable var;
var.name = ""; // empty
var.value = sdata;
return std::make_tuple(qual, var);
} else if (MaybeString(&sdata)) {
MetaVariable var;
var.name = ""; // empty
var.value = sdata;
return std::make_tuple(qual, var);
}
}
if (!MaybeListEditQual(&qual)) {
return nonstd::nullopt;
}
@@ -4492,7 +4703,7 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) {
// The first character.
{
char c;
if (!_sr->read1(&c)) {
if (!Char1(&c)) {
// this should not happen.
return false;
}
@@ -4511,7 +4722,7 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) {
return false;
}
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!Char1(&c)) {
return false;
@@ -4525,6 +4736,28 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) {
return false;
}
// May be string only
{
StringData sdata;
if (MaybeTripleQuotedString(&sdata)) {
out_meta->stringData.push_back(sdata);
DCOUT("Add string to attr meta:" << to_string(sdata));
if (!SkipWhitespaceAndNewline()) {
return false;
}
continue;
} else if (MaybeString(&sdata)) {
out_meta->stringData.push_back(sdata);
DCOUT("Add string to attr meta:" << to_string(sdata));
if (!SkipWhitespaceAndNewline()) {
return false;
}
continue;
}
}
std::string token;
if (!ReadIdentifier(&token)) {
return false;
@@ -4534,12 +4767,10 @@ bool AsciiParser::ParseAttrMeta(AttrMeta *out_meta) {
if ((token != "interpolation") && (token != "customData") &&
(token != "elementSize")) {
PushError(
"Currently only `interpolation`, `elementSize` or `customData` "
PUSH_ERROR_AND_RETURN("Currently only string-only data, `interpolation`, `elementSize` or `customData` "
"is supported but "
"got: " +
token);
return false;
}
if (!SkipWhitespaceAndNewline()) {
@@ -5335,7 +5566,7 @@ bool AsciiParser::ParseClassBlock(const int64_t primIdx, const int64_t parentPri
// | def_block
// | prim_attr+
std::map<std::string, Property> props;
while (!_sr->eof()) {
while (!Eof()) {
char c;
if (!Char1(&c)) {
return false;
@@ -5612,7 +5843,7 @@ bool AsciiParser::ParseDefBlock(const int64_t primIdx, const int64_t parentPrimI
// expect = '}'
// | def_block
// | prim_attr+
while (!_sr->eof()) {
while (!Eof()) {
if (!SkipCommentAndWhitespaceAndNewline()) {
return false;
@@ -5846,12 +6077,12 @@ bool AsciiParser::Parse(LoadState state) {
PushPath("/");
// parse blocks
while (!_sr->eof()) {
while (!Eof()) {
if (!SkipCommentAndWhitespaceAndNewline()) {
return false;
}
if (_sr->eof()) {
if (Eof()) {
// Whitespaces in the end of line.
break;
}

View File

@@ -89,26 +89,29 @@ bool IsUSDA(const std::string &filename, size_t max_filesize = 0);
class AsciiParser {
public:
// TODO: refactor
struct PrimMetas {
// Frequently used prim metas
nonstd::optional<Kind> kind;
value::dict customData; // `customData`
std::vector<StringData> strings; // String only unregistered metadata.
};
struct StageMetas {
///
/// Predefined Stage metas
///
std::vector<std::string> subLayers;
std::string defaultPrim;
std::string doc;
std::vector<std::string> subLayers; // 'subLayers'
std::string defaultPrim; // 'defaultPrim'
StringData doc; // 'doc'
nonstd::optional<Axis> upAxis; // not specified = nullopt
nonstd::optional<double> metersPerUnit;
nonstd::optional<double> timeCodesPerSecond;
std::map<std::string, MetaVariable> customLayerData; // `customLayerData`.
std::vector<StringData> strings; // String only unregistered metadata.
};
struct ParseState {
@@ -370,6 +373,16 @@ class AsciiParser {
bool MaybeListEditQual(tinyusdz::ListEditQual *qual);
///
/// Try parsing single-quoted(`"`) string
///
bool MaybeString(StringData*str);
///
/// Try parsing triple-quited(`"""`) multi-line string.
///
bool MaybeTripleQuotedString(StringData *str);
#if 0
///
///

View File

@@ -151,8 +151,11 @@ std::string print_prim_metas(const PrimMeta &meta, const uint32_t indent) {
}
for (const auto &item : meta.meta) {
(void)item;
// TODO:
ss << print_meta(item.second, indent+1);
}
for (const auto &item : meta.stringData) {
ss << pprint::Indent(indent) << to_string(item) << "\n";
}
return ss.str();
@@ -176,7 +179,11 @@ std::string print_attr_metas(const AttrMeta &meta, const uint32_t indent) {
// other user defined metadataum.
for (const auto &item : meta.meta) {
ss << pprint::Indent(indent) << item.first << " = TODO\n";
ss << print_meta(item.second, indent+1);
}
for (const auto &item : meta.stringData) {
ss << pprint::Indent(indent) << to_string(item) << "\n";
}
return ss.str();
@@ -304,6 +311,14 @@ std::string print_props(const std::map<std::string, Property> &props, uint32_t i
} // namespace
std::string to_string(const StringData &s) {
if (s.is_triple_quoted) {
return quote(s.value, "\"\"\"");
} else {
return quote(s.value);
}
}
std::string print_meta(const MetaVariable &meta, const uint32_t indent) {
std::stringstream ss;
@@ -800,7 +815,7 @@ std::string to_string(const GeomSphere &sphere, const uint32_t indent, bool clos
ss << pprint::Indent(indent) << "{\n";
// members
ss << pprint::Indent(indent+1) << "double radius" << prefix(sphere.radius) << " = " << print_animatable(sphere.radius) << "\n";
ss << print_typed_attr(sphere.radius, "radius", indent+1);
ss << print_gprim_predefined(sphere, indent);
@@ -995,7 +1010,7 @@ std::string to_string(const GeomCube &geom, const uint32_t indent, bool closing_
ss << pprint::Indent(indent) << "{\n";
// members
ss << pprint::Indent(indent+1) << "double size" << prefix(geom.size) << " = " << print_animatable(geom.size) << "\n";
ss << print_typed_attr(geom.size, "size", indent+1);
ss << print_gprim_predefined(geom, indent);
@@ -1016,8 +1031,8 @@ std::string to_string(const GeomCone &geom, const uint32_t indent, bool closing_
ss << pprint::Indent(indent) << "{\n";
// members
ss << pprint::Indent(indent+1) << "double radius" << prefix(geom.radius) << " = " << print_animatable(geom.radius) << "\n";
ss << pprint::Indent(indent+1) << "double height" << prefix(geom.height) << " = " << print_animatable(geom.height) << "\n";
ss << print_typed_attr(geom.radius, "radius", indent+1);
ss << print_typed_attr(geom.height, "height", indent+1);
ss << print_gprim_predefined(geom, indent);
@@ -1038,8 +1053,8 @@ std::string to_string(const GeomCylinder &geom, const uint32_t indent, bool clos
ss << pprint::Indent(indent) << "{\n";
// members
ss << pprint::Indent(indent+1) << "double radius" << prefix(geom.radius) << " = " << print_animatable(geom.radius) << "\n";
ss << pprint::Indent(indent+1) << "double height" << prefix(geom.height) << " = " << print_animatable(geom.height) << "\n";
ss << print_typed_attr(geom.radius, "radius", indent+1);
ss << print_typed_attr(geom.height, "height", indent+1);
std::string axis;
if (geom.axis == Axis::X) {
@@ -1071,8 +1086,8 @@ std::string to_string(const GeomCapsule &geom, const uint32_t indent, bool closi
ss << pprint::Indent(indent) << "{\n";
// members
ss << pprint::Indent(indent+1) << "double radius" << prefix(geom.radius) << " = " << print_animatable(geom.radius) << "\n";
ss << pprint::Indent(indent+1) << "double height" << prefix(geom.height) << " = " << print_animatable(geom.height) << "\n";
ss << print_typed_attr(geom.radius, "radius", indent+1);
ss << print_typed_attr(geom.height, "height", indent+1);
std::string axis;
if (geom.axis == Axis::X) {

View File

@@ -48,6 +48,8 @@ std::string to_string(GeomMesh::SubdivisionScheme subd_scheme);
std::string to_string(const Path &path, bool show_full_path = true);
std::string to_string(const std::vector<Path> &v, bool show_full_path = true);
std::string to_string(const StringData &s);
template<typename T>
std::string to_string(const std::vector<T> &v, const uint32_t level = 0) {
std::stringstream ss;

View File

@@ -37,6 +37,16 @@
namespace tinyusdz {
// single or triple-quoted('"""') string
struct StringData {
std::string value;
bool is_triple_quoted{false};
// optional(for USDA)
int line_row{0};
int line_col{0};
};
template <typename T>
class AttribWithFallback;
@@ -857,7 +867,11 @@ struct PrimMeta {
std::map<std::string, MetaVariable> meta; // other meta values
bool authorized() const { return (kind || customData || meta.size()); }
// String only metadataum.
// TODO: Represent as `MetaVariable`?
std::vector<StringData> stringData;
bool authorized() const { return (kind || customData || meta.size() || stringData.size()); }
};
// Metadata for Attribute
@@ -870,8 +884,12 @@ struct AttrMeta {
std::map<std::string, MetaVariable> meta; // other meta values
// String only metadataum.
// TODO: Represent as `MetaVariable`?
std::vector<StringData> stringData;
bool authorized() const {
return (interpolation || elementSize || customData || meta.size());
return (interpolation || elementSize || customData || meta.size() || stringData.size());
}
};
@@ -1475,6 +1493,8 @@ DEFINE_TYPE_TRAIT(value::TimeSamples, "TimeSamples", TYPE_ID_TIMESAMPLES, 1);
DEFINE_TYPE_TRAIT(Model, "Model", TYPE_ID_MODEL, 1);
DEFINE_TYPE_TRAIT(Scope, "Scope", TYPE_ID_SCOPE, 1);
DEFINE_TYPE_TRAIT(StringData, "String", TYPE_ID_SCOPE, 1);
#undef DEFINE_TYPE_TRAIT
#undef DEFINE_ROLE_TYPE_TRAIT

View File

@@ -770,11 +770,11 @@ std::string Stage::ExportToString() const {
ss << "#usda 1.0\n";
ss << "(\n";
if (stage_metas.doc.empty()) {
if (stage_metas.doc.value.empty()) {
ss << " doc = \"TinyUSDZ v" << tinyusdz::version_major << "."
<< tinyusdz::version_minor << "." << tinyusdz::version_micro << "\"\n";
} else {
ss << " doc = \"" << stage_metas.doc << "\"\n";
ss << " doc = " << to_string(stage_metas.doc) << "\n";
}
if (stage_metas.metersPerUnit.authorized()) {
ss << " metersPerUnit = " << stage_metas.metersPerUnit.get() << "\n";
@@ -800,6 +800,11 @@ std::string Stage::ExportToString() const {
ss << " }\n";
}
// TODO: Sort by line_no?(preserve appearance in read USDA)
for (const auto &item : stage_metas.stringData) {
ss << " " << to_string(item) << "\n";
}
// TODO: write other header data.
ss << ")\n";
ss << "\n";

View File

@@ -430,9 +430,13 @@ struct StageMetas {
std::string defaultPrim; // prim node name
AttribWithFallback<double> metersPerUnit{1.0}; // default [m]
AttribWithFallback<double> timeCodesPerSecond {24.0}; // default 24 fps
std::string doc; // `documentation`
StringData doc; // `documentation`
std::map<std::string, MetaVariable> customLayerData; // customLayerData
// String only metadataum.
// TODO: Represent as `MetaVariable`?
std::vector<StringData> stringData;
};
class PrimRange;

View File

@@ -306,8 +306,9 @@ struct GeomCone : public GPrim {
//
// Properties
//
AnimatableDouble height{2.0};
AnimatableDouble radius{1.0};
TypedAttribute<double> height{2.0};
TypedAttribute<double> radius{1.0};
Axis axis{Axis::Z};
@@ -318,8 +319,8 @@ struct GeomCapsule : public GPrim {
//
// Properties
//
AnimatableDouble height{2.0};
AnimatableDouble radius{0.5};
TypedAttribute<double> height{2.0};
TypedAttribute<double> radius{0.5};
Axis axis{Axis::Z};
@@ -330,8 +331,8 @@ struct GeomCylinder : public GPrim {
//
// Properties
//
AnimatableDouble height{2.0};
AnimatableDouble radius{1.0};
TypedAttribute<double> height{2.0};
TypedAttribute<double> radius{1.0};
Axis axis{Axis::Z};
};
@@ -341,7 +342,7 @@ struct GeomCube : public GPrim {
//
// Properties
//
AnimatableDouble size{2.0};
TypedAttribute<double> size{2.0};
};
@@ -350,8 +351,7 @@ struct GeomSphere : public GPrim {
//
// Predefined attribs.
//
AnimatableDouble radius{1.0};
TypedAttribute<double> radius{1.0};
};
//

File diff suppressed because it is too large Load Diff

View File

@@ -190,6 +190,7 @@ enum TypeId {
TYPE_ID_TOKEN,
TYPE_ID_STRING,
TYPE_ID_STRING_DATA, // String for primvar and metadata. Includes multi-line string
TYPE_ID_BOOL,

View File

@@ -0,0 +1,9 @@
#usda 1.0
(
)
def Xform "bora" (
doc = "bora"
) {
}

View File

@@ -0,0 +1,4 @@
#usda 1.0
(
doc = "bora"
)

View File

@@ -0,0 +1,15 @@
#usda 1.0
(
)
def Xform "hello"
(
)
{
def Sphere "world"
{
string a = "bora
dora"
double radius = 1.2
}
}

View File

@@ -0,0 +1,17 @@
#usda 1.0
(
)
def Xform "hello"
(
)
{
def Sphere "world"
{
"""
bora
dora
"""
double radius = 1.2
}
}

View File

@@ -0,0 +1,22 @@
#usda 1.0
(
"""
bora
dora
"""
"""
muda
ari
"""
)
def Xform "hello"
(
)
{
def Sphere "world"
{
double radius = 1.2
}
}

View File

@@ -0,0 +1,17 @@
#usda 1.0
(
)
def Xform "hello"
(
"""
bora
dora
"""
)
{
def Sphere "world"
{
double radius = 1.2
}
}

View File

@@ -0,0 +1,19 @@
#usda 1.0
(
)
def Xform "hello"
(
)
{
def Sphere "world"
{
double radius = 1.2 (
"""
muda
ari
"""
)
}
}

View File

@@ -0,0 +1,17 @@
#usda 1.0
(
)
def Xform "hello"
(
)
{
def Sphere "world"
{
string bora = """
bora
dora
"""
double radius = 1.2
}
}

View File

@@ -0,0 +1,17 @@
#usda 1.0
(
)
def Xform "hello"
(
)
{
def Sphere "world"
{
string bora = """
bora
dora
"""
double radius = 1.2
}
}