diff --git a/libs/gltfio/include/gltfio/ResourceLoader.h b/libs/gltfio/include/gltfio/ResourceLoader.h index ab0a6f10fa..2a13e546f2 100644 --- a/libs/gltfio/include/gltfio/ResourceLoader.h +++ b/libs/gltfio/include/gltfio/ResourceLoader.h @@ -69,9 +69,12 @@ class UTILS_PUBLIC ResourceLoader { public: using BufferDescriptor = filament::backend::BufferDescriptor; - ResourceLoader(const ResourceConfiguration& config); + explicit ResourceLoader(const ResourceConfiguration& config); ~ResourceLoader(); + + void setConfiguration(const ResourceConfiguration& config); + /** * Feeds the binary content of an external resource into the loader's URI cache. * diff --git a/libs/gltfio/src/ResourceLoader.cpp b/libs/gltfio/src/ResourceLoader.cpp index 0d54c780b7..25d0a60d32 100644 --- a/libs/gltfio/src/ResourceLoader.cpp +++ b/libs/gltfio/src/ResourceLoader.cpp @@ -74,15 +74,15 @@ enum class CacheResult { }; struct ResourceLoader::Impl { - Impl(const ResourceConfiguration& config) : + explicit Impl(const ResourceConfiguration& config) : mEngine(config.engine), mNormalizeSkinningWeights(config.normalizeSkinningWeights), mGltfPath(config.gltfPath ? config.gltfPath : ""), mUriDataCache(std::make_shared()) {} Engine* const mEngine; - const bool mNormalizeSkinningWeights; - const std::string mGltfPath; + bool mNormalizeSkinningWeights; + std::string mGltfPath; // User-provided resource data with URI string keys, populated with addResourceData(). // This is used on platforms without traditional file systems, such as Android, iOS, and WebGL. @@ -320,6 +320,11 @@ ResourceLoader::~ResourceLoader() { delete pImpl; } +void ResourceLoader::setConfiguration(const ResourceConfiguration& config) { + pImpl->mNormalizeSkinningWeights = config.normalizeSkinningWeights; + pImpl->mGltfPath = config.gltfPath; +} + void ResourceLoader::addResourceData(const char* uri, BufferDescriptor&& buffer) { pImpl->addResourceData(uri, std::move(buffer)); } diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index cd46e0d76c..36ecdd8236 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -53,6 +53,8 @@ #include #include +#include + #include #include #include @@ -485,6 +487,57 @@ static void onClick(App& app, View* view, ImVec2 pos) { }); } +static utils::Path getPathForAsset(std::string_view string) { + utils::Path filename{ string }; + if (!filename.exists()) { + std::cerr << "file " << filename << " not found!" << std::endl; + return {}; + } + if (filename.isDirectory()) { + auto files = filename.listContents(); + for (const auto& file: files) { + if (file.getExtension() == "gltf" || file.getExtension() == "glb") { + filename = file; + break; + } + } + if (filename.isDirectory()) { + std::cerr << "no glTF file found in " << filename << std::endl; + return {}; + } + } + return filename; +} + + +static bool checkAsset(const utils::Path& filename) { + // Peek at the file size to allow pre-allocation. + long const contentSize = static_cast(getFileSize(filename.c_str())); + if (contentSize <= 0) { + std::cerr << "Unable to open " << filename << std::endl; + return false; + } + + // Consume the glTF file. + std::ifstream in(filename.c_str(), std::ifstream::binary | std::ifstream::in); + std::vector buffer(static_cast(contentSize)); + if (!in.read((char*) buffer.data(), contentSize)) { + std::cerr << "Unable to read " << filename << std::endl; + return false; + } + + // Parse the glTF file and create Filament entities. + cgltf_options options{}; + cgltf_data* sourceAsset; + cgltf_result result = cgltf_parse(&options, buffer.data(), contentSize, &sourceAsset); + if (result != cgltf_result_success) { + slog.e << "Unable to parse glTF file." << io::endl; + return false; + } + return true; +}; + + int main(int argc, char** argv) { App app; @@ -496,24 +549,10 @@ int main(int argc, char** argv) { utils::Path filename; int const num_args = argc - optionIndex; if (num_args >= 1) { - filename = argv[optionIndex]; - if (!filename.exists()) { - std::cerr << "file " << filename << " not found!" << std::endl; + filename = getPathForAsset(argv[optionIndex]); + if (filename.isEmpty()) { return 1; } - if (filename.isDirectory()) { - auto files = filename.listContents(); - for (const auto& file : files) { - if (file.getExtension() == "gltf" || file.getExtension() == "glb") { - filename = file; - break; - } - } - if (filename.isDirectory()) { - std::cerr << "no glTF file found in " << filename << std::endl; - return 1; - } - } } auto loadAsset = [&app](const utils::Path& filename) { @@ -534,14 +573,14 @@ int main(int argc, char** argv) { // Parse the glTF file and create Filament entities. app.asset = app.assetLoader->createAsset(buffer.data(), buffer.size()); - app.instance = app.asset->getInstance(); - buffer.clear(); - buffer.shrink_to_fit(); - if (!app.asset) { std::cerr << "Unable to parse " << filename << std::endl; exit(1); } + + app.instance = app.asset->getInstance(); + buffer.clear(); + buffer.shrink_to_fit(); }; auto loadResources = [&app] (const utils::Path& filename) { @@ -559,6 +598,8 @@ int main(int argc, char** argv) { app.resourceLoader->addTextureProvider("image/png", app.stbDecoder); app.resourceLoader->addTextureProvider("image/jpeg", app.stbDecoder); app.resourceLoader->addTextureProvider("image/ktx2", app.ktxDecoder); + } else { + app.resourceLoader->setConfiguration(configuration); } if (!app.resourceLoader->asyncBeginLoad(app.asset)) { @@ -1021,14 +1062,19 @@ int main(int argc, char** argv) { filamentApp.animate(animate); filamentApp.resize(resize); - filamentApp.setDropHandler([&] (std::string_view path) { - app.resourceLoader->asyncCancelLoad(); - app.resourceLoader->evictResourceData(); - app.viewer->removeAsset(); - app.assetLoader->destroyAsset(app.asset); - loadAsset(path); - loadResources(path); - app.viewer->setAsset(app.asset, app.instance); + filamentApp.setDropHandler([&](std::string_view path) { + utils::Path const filename = getPathForAsset(path); + if (!filename.isEmpty()) { + if (checkAsset(filename)) { + app.resourceLoader->asyncCancelLoad(); + app.resourceLoader->evictResourceData(); + app.viewer->removeAsset(); + app.assetLoader->destroyAsset(app.asset); + loadAsset(filename); + loadResources(filename); + app.viewer->setAsset(app.asset, app.instance); + } + } }); filamentApp.run(app.config, setup, cleanup, gui, preRender, postRender);