diff --git a/examples/sdlviewer/main.cc b/examples/sdlviewer/main.cc index a56c7bff..438e7b22 100644 --- a/examples/sdlviewer/main.cc +++ b/examples/sdlviewer/main.cc @@ -304,6 +304,20 @@ bool LoadModel(const std::string& filename, tinyusdz::Scene* scene) { std::cerr << "Failed to load USDZ file: " << filename << "\n"; return false; } + } else if (ext.compare("usda") == 0) { + std::cout << "usda\n"; + bool ret = tinyusdz::LoadUSDAFromFile(filename, scene, &warn, &err); + if (!warn.empty()) { + std::cerr << "WARN : " << warn << "\n"; + } + if (!err.empty()) { + std::cerr << "ERR : " << err << "\n"; + } + + if (!ret) { + std::cerr << "Failed to load USDA file: " << filename << "\n"; + return false; + } } else { // assume usdc bool ret = tinyusdz::LoadUSDCFromFile(filename, scene, &warn, &err); if (!warn.empty()) { diff --git a/models/texturedcube.usdc b/models/texturedcube.usdc new file mode 100644 index 00000000..899b005e Binary files /dev/null and b/models/texturedcube.usdc differ diff --git a/models/textures/01.jpg b/models/textures/01.jpg new file mode 100644 index 00000000..b24c7c70 Binary files /dev/null and b/models/textures/01.jpg differ diff --git a/src/prim-types.hh b/src/prim-types.hh index 1858154e..099afdf7 100644 --- a/src/prim-types.hh +++ b/src/prim-types.hh @@ -1925,7 +1925,7 @@ struct Shader { std::string info_id; // Shader type. // Currently we only support PreviewSurface, UVTexture and PrimvarReader_float2 - nonstd::variant value; + nonstd::variant value; }; diff --git a/src/tinyusdz.cc b/src/tinyusdz.cc index 99d43adb..9fe3addd 100644 --- a/src/tinyusdz.cc +++ b/src/tinyusdz.cc @@ -52,6 +52,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "tinyusdz.hh" #include "io-util.hh" #include "pprinter.hh" +#include "usda-parser.hh" #if defined(TINYUSDZ_SUPPORT_AUDIO) @@ -1328,13 +1329,26 @@ class Parser { &path_index_to_spec_index_map, Material *material); - /// - /// NOTE: Currently we only support UsdPreviewSurface - /// bool ReconstructShader(const Node &node, const FieldValuePairVector &fields, const std::unordered_map &path_index_to_spec_index_map, - PreviewSurface *shader); + Shader *shader); + + bool ReconstructPreviewSurface(const Node &node, const FieldValuePairVector &fields, + const std::unordered_map + &path_index_to_spec_index_map, + PreviewSurface *surface); + + bool ReconstructUVTexture(const Node &node, const FieldValuePairVector &fields, + const std::unordered_map + &path_index_to_spec_index_map, + UVTexture *uvtex); + + bool ReconstructPrimvarReader_float2(const Node &node, + const FieldValuePairVector &fields, + const std::unordered_map + &path_index_to_spec_index_map, + PrimvarReader_float2 *preader); bool ReconstructSceneRecursively(int parent_id, int level, const std::unordered_map @@ -4674,7 +4688,7 @@ bool Parser::ReconstructMaterial( bool Parser::ReconstructShader( const Node &node, const FieldValuePairVector &fields, const std::unordered_map &path_index_to_spec_index_map, - PreviewSurface *shader) { + Shader *shader) { #ifdef TINYUSDZ_LOCAL_DEBUG_PRINT std::cout << "Parse shader\n"; #endif @@ -4695,6 +4709,108 @@ bool Parser::ReconstructShader( } + // + // Find shader type. + // + std::string shader_type; + + for (size_t i = 0; i < node.GetChildren().size(); i++) { + int child_index = int(node.GetChildren()[i]); + if ((child_index < 0) || (child_index >= int(_nodes.size()))) { + _err += "Invalid child node id: " + std::to_string(child_index) + + ". Must be in range [0, " + std::to_string(_nodes.size()) + ")\n"; + return false; + } + + // const Node &child_node = _nodes[size_t(child_index)]; + + if (!path_index_to_spec_index_map.count(uint32_t(child_index))) { + // No specifier assigned to this child node. + _err += "No specifier found for node id: " + std::to_string(child_index) + + "\n"; + return false; + } + + uint32_t spec_index = + path_index_to_spec_index_map.at(uint32_t(child_index)); + if (spec_index >= _specs.size()) { + _err += "Invalid specifier id: " + std::to_string(spec_index) + + ". Must be in range [0, " + std::to_string(_specs.size()) + ")\n"; + return false; + } + + const Spec &spec = _specs[spec_index]; + + Path path = GetPath(spec.path_index); +#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT + std::cout << "Path prim part: " << path.GetPrimPart() + << ", prop part: " << path.GetPropPart() + << ", spec_index = " << spec_index << "\n"; +#endif + + if (!_live_fieldsets.count(spec.fieldset_index)) { + _err += "FieldSet id: " + std::to_string(spec.fieldset_index.value) + + " must exist in live fieldsets.\n"; + return false; + } + + const FieldValuePairVector &child_fields = + _live_fieldsets.at(spec.fieldset_index); + + { + std::string prop_name = path.GetPropPart(); + + PrimAttrib attr; + + bool ret = ParseAttribute(child_fields, &attr, prop_name); +#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT + std::cout << "prop: " << prop_name << ", ret = " << ret << "\n"; +#endif + + if (ret) { + // Currently we only support predefined PBR attributes. + + if (prop_name.compare("info:id") == 0) { + auto p = attr.var.get_value(); // `token` type, but treat it as string + if (p) { + shader_type = (*p); + } + } + } + } + } + + if (shader_type.empty()) { + _err += "`info:id` is missing in Shader.\n"; + return false; + } + + return true; +} + +bool Parser::ReconstructPreviewSurface( + const Node &node, const FieldValuePairVector &fields, + const std::unordered_map &path_index_to_spec_index_map, + PreviewSurface *shader) { +#ifdef TINYUSDZ_LOCAL_DEBUG_PRINT + std::cout << "Parse shader\n"; +#endif + + (void)shader; + + for (const auto &fv : fields) { + if (fv.first == "properties") { + if (fv.second.GetTypeName() != "TokenArray") { + _err += "`properties` attribute must be TokenArray type\n"; + return false; + } + assert(fv.second.IsArray()); + + for (size_t i = 0; i < fv.second.GetStringArray().size(); i++) { + } + } + } + // // NOTE: Currently we assume one deeper node has Shader's attribute // @@ -4754,13 +4870,16 @@ bool Parser::ReconstructShader( if (ret) { // Currently we only support predefined PBR attributes. - if (prop_name.compare("info:id") == 0) { - auto p = attr.var.get_value(); // `token` type, but treat it as string + if (prop_name.compare("info:id") == 0) { + auto p = attr.var.get_value(); // `token` type, but + // treat it as string if (p) { - shader->info_id = (*p); + if (p->compare("UsdPreviewSurface") != 0) { + _err += "`info:id` must be `UsdPreviewSurface`.\n"; + return false; + } } - } - else if (prop_name.compare("outputs:surface") == 0) { + } else if (prop_name.compare("outputs:surface") == 0) { // Surface shader output available } else if (prop_name.compare("outputs:displacement") == 0) { // Displacement shader output available @@ -4804,45 +4923,44 @@ bool Parser::ReconstructShader( // type: float auto p = attr.var.get_value(); if (p) { - shader->metallic.value = (*p); + shader->metallic.value = (*p); } } else if (prop_name.compare("inputs:metallic.connect") == 0) { // Currently we assume texture is assigned to this attribute. auto p = attr.var.get_value(); if (p) { - shader->metallic.path = *p; + shader->metallic.path = *p; } - } else if (prop_name.compare("inputs:diffuseColor") == 0) - { + } else if (prop_name.compare("inputs:diffuseColor") == 0) { auto p = attr.var.get_value(); if (p) { shader->diffuseColor.color = (*p); #ifdef TINYUSDZ_LOCAL_DEBUG_PRINT - std::cout << "diffuseColor: " << shader->diffuseColor.color[0] - << ", " << shader->diffuseColor.color[1] << ", " - << shader->diffuseColor.color[2] << "\n"; + std::cout << "diffuseColor: " << shader->diffuseColor.color[0] + << ", " << shader->diffuseColor.color[1] << ", " + << shader->diffuseColor.color[2] << "\n"; #endif - } + } } else if (prop_name.compare("inputs:diffuseColor.connect") == 0) { // Currently we assume texture is assigned to this attribute. auto p = attr.var.get_value(); if (p) { - shader->diffuseColor.path = *p; + shader->diffuseColor.path = *p; } } else if (prop_name.compare("inputs:emissiveColor") == 0) { - //if (auto p = primvar::as_basic(&attr.var)) { - // shader->emissiveColor.color = (*p); + // if (auto p = primvar::as_basic(&attr.var)) { + // shader->emissiveColor.color = (*p); #ifdef TINYUSDZ_LOCAL_DEBUG_PRINT - // std::cout << "emissiveColor: " << shader->emissiveColor.color[0] - // << ", " << shader->emissiveColor.color[1] << ", " - // << shader->emissiveColor.color[2] << "\n"; + // std::cout << "emissiveColor: " << shader->emissiveColor.color[0] + // << ", " << shader->emissiveColor.color[1] << ", " + // << shader->emissiveColor.color[2] << "\n"; #endif - //} + //} } else if (prop_name.compare("inputs:emissiveColor.connect") == 0) { // Currently we assume texture is assigned to this attribute. - //if (auto p = primvar::as_basic(&attr.var)) { + // if (auto p = primvar::as_basic(&attr.var)) { // shader->emissiveColor.path = *p; //} } @@ -5052,13 +5170,17 @@ bool Parser::ReconstructSceneRecursively( } scene->materials.push_back(material); } else if (node_type == "Shader") { - PreviewSurface shader; + Shader shader; if (!ReconstructShader(node, fields, path_index_to_spec_index_map, &shader)) { _err += "Failed to reconstruct PreviewSurface(Shader).\n"; return false; } - scene->shaders.push_back(shader); + + auto p = nonstd::get_if(&shader.value); + if (p) { + scene->shaders.push_back(*p); + } } else if (node_type == "Scope") { std::cout << "Scope\n"; } else { @@ -5935,7 +6057,7 @@ bool LoadUSDZFromFile(const std::wstring &_filename, Scene *scene, } #endif -bool LoadUSDAFromMemory(const uint8_t *addr, const size_t length, Scene *scene, +bool LoadUSDAFromMemory(const uint8_t *addr, const size_t length, const std::string &base_dir, Scene *scene, std::string *warn, std::string *err, const USDLoadOptions &options) { if (addr == nullptr) { @@ -5952,14 +6074,29 @@ bool LoadUSDAFromMemory(const uint8_t *addr, const size_t length, Scene *scene, return false; } - (void)length; - (void)warn; + tinyusdz::StreamReader sr(addr, length, /* swap endian */ false); + tinyusdz::usda::USDAParser parser(&sr); + + parser.SetBaseDir(base_dir); + (void)options; - if (err) { - (*err) += "USDA parsing is TODO\n"; - } + { + bool ret = parser.Parse(); + if (!ret) { + if (err) { + (*err) += "Failed to parse USDA\n"; + (*err) += parser.GetError(); + } + + return false; + } + } + // TODO: Reconstruct Scene + if (err) { + (*err) += "USDA parsing success, but reconstructing Scene is TODO.\n"; + } return false; } @@ -5968,6 +6105,7 @@ bool LoadUSDAFromFile(const std::string &_filename, Scene *scene, const USDLoadOptions &options) { std::string filepath = io::ExpandFilePath(_filename, /* userdata */nullptr); + std::string base_dir = io::GetBaseDir(_filename); std::vector data; size_t max_bytes = size_t(1024 * 1024 * options.max_memory_limit_in_mb); @@ -5975,56 +6113,8 @@ bool LoadUSDAFromFile(const std::string &_filename, Scene *scene, return false; } -#if 0 - { - std::ifstream ifs(filename.c_str(), std::ifstream::binary); - if (!ifs) { - if (err) { - (*err) = "File not found or cannot open file : " + filename; - } - return false; - } - // TODO(syoyo): Use mmap - ifs.seekg(0, ifs.end); - size_t sz = static_cast(ifs.tellg()); - if (int64_t(sz) < 0) { - // Looks reading directory, not a file. - if (err) { - (*err) += "Looks like filename is a directory : \"" + filename + "\"\n"; - } - return false; - } - - if (sz < 8) { - // ??? - if (err) { - (*err) += - "File size too short. Looks like this file is not a USDA : \"" + - filename + "\"\n"; - } - return false; - } - - if (sz > size_t(1024 * 1024 * options.max_memory_limit_in_mb)) { - if (err) { - (*err) += "USDA file is too large(size = " + std::to_string(sz) + - ", which exceeds memory limit " + - std::to_string(options.max_memory_limit_in_mb) + " [mb]).\n"; - } - - return false; - } - - data.resize(sz); - - ifs.seekg(0, ifs.beg); - ifs.read(reinterpret_cast(&data.at(0)), - static_cast(sz)); - } -#endif - - return LoadUSDAFromMemory(data.data(), data.size(), scene, warn, err, + return LoadUSDAFromMemory(data.data(), data.size(), base_dir, scene, warn, err, options); } diff --git a/src/tinyusdz.hh b/src/tinyusdz.hh index d205d195..3b791bbc 100644 --- a/src/tinyusdz.hh +++ b/src/tinyusdz.hh @@ -665,6 +665,7 @@ bool LoadUSDAFromFile(const std::string &filename, Scene *scene, /// /// @param[in] addr Memory address of USDA data /// @param[in] length Byte length of USDA data +/// @param[in[ base_dir Base directory(can be empty) /// @param[out] scene USD scene. /// @param[out] warn Warning message. /// @param[out] err Error message(filled when the function returns false) @@ -672,7 +673,7 @@ bool LoadUSDAFromFile(const std::string &filename, Scene *scene, /// /// @return true upon success /// -bool LoadUSDAFromMemory(const uint8_t *addr, const size_t length, Scene *scene, +bool LoadUSDAFromMemory(const uint8_t *addr, const size_t length, const std::string &base_dir, Scene *scene, std::string *warn, std::string *err, const USDLoadOptions &options = USDLoadOptions()); diff --git a/src/usda-parser.cc b/src/usda-parser.cc index 52677ee8..5afa3a0e 100644 --- a/src/usda-parser.cc +++ b/src/usda-parser.cc @@ -1093,6 +1093,9 @@ static bool ParseTupleThreaded( #endif class USDAParser::Impl { + private: + Scene scene_; + public: struct ParseState { int64_t loc{-1}; // byte location in StreamReder @@ -6015,7 +6018,7 @@ class USDAParser::Impl { xform.name = node_name; std::cout << to_string(xform, nestlevel) << "\n"; - + } else if (prim_type == "Mesh") { GeomMesh mesh; std::cout << "Reconstruct GeomMesh\n"; @@ -6026,6 +6029,8 @@ class USDAParser::Impl { mesh.name = node_name; std::cout << to_string(mesh, nestlevel) << "\n"; + + scene_.geom_meshes.push_back(mesh); } else if (prim_type == "Sphere") { GeomSphere sphere; diff --git a/src/usda-parser.hh b/src/usda-parser.hh index 3da047be..1708bf3a 100644 --- a/src/usda-parser.hh +++ b/src/usda-parser.hh @@ -66,9 +66,15 @@ class USDAParser { /// std::string GetError(); + /// + /// Get as scene + /// + const Scene& GetScene() const; + private: class Impl; Impl *_impl; + }; } // namespace usda