From e3e7073f74ff5b2ea02c507a5d638018b6a3f3fb Mon Sep 17 00:00:00 2001 From: Philip Rideout Date: Wed, 13 Mar 2019 18:04:33 -0700 Subject: [PATCH] gltf_viewer: add support for drag-and-drop. You can now drop gltf or glb files into the app. Note that we will soon be migrating from SDL to GLFW, which also has support for drag-and-drop. --- libs/gltfio/include/gltfio/SimpleViewer.h | 28 ++++++-- samples/app/FilamentApp.cpp | 8 +++ samples/app/FilamentApp.h | 4 ++ samples/gltf_viewer.cpp | 86 ++++++++++++++--------- 4 files changed, 86 insertions(+), 40 deletions(-) diff --git a/libs/gltfio/include/gltfio/SimpleViewer.h b/libs/gltfio/include/gltfio/SimpleViewer.h index 49012db04e..24b4abd6df 100644 --- a/libs/gltfio/include/gltfio/SimpleViewer.h +++ b/libs/gltfio/include/gltfio/SimpleViewer.h @@ -68,6 +68,13 @@ public: */ void setAsset(FilamentAsset* asset, utils::NameComponentManager* names); + /** + * Removes the current asset from the viewer. + * + * This removes all the asset entities from the Scene, but does not destroy them. + */ + void removeAsset(); + /** * Sets or changes the current scene's IBL to allow the UI manipulate it. * NOTE: this could be removed if we add a getter method to Scene. @@ -179,13 +186,7 @@ SimpleViewer::~SimpleViewer() { void SimpleViewer::setAsset(FilamentAsset* asset, utils::NameComponentManager* names) { using namespace filament::math; - if (mAsset) { - const auto begin = mAsset->getEntities(); - const auto end = begin + mAsset->getEntityCount(); - for (auto entity = begin; entity != end; ++entity) { - mScene->remove(*entity); - } - } + removeAsset(); mAsset = asset; mAnimator = asset->getAnimator(); mNames = names; @@ -196,6 +197,19 @@ void SimpleViewer::setAsset(FilamentAsset* asset, utils::NameComponentManager* n mScene->addEntities(mAsset->getEntities(), mAsset->getEntityCount()); } +void SimpleViewer::removeAsset() { + if (mAsset) { + const auto begin = mAsset->getEntities(); + const auto end = begin + mAsset->getEntityCount(); + for (auto entity = begin; entity != end; ++entity) { + mScene->remove(*entity); + } + } + mAsset = nullptr; + mAnimator = nullptr; + mNames = nullptr; +} + void SimpleViewer::setIndirectLight(filament::IndirectLight* ibl) { using namespace filament::math; mIndirectLight = ibl; diff --git a/samples/app/FilamentApp.cpp b/samples/app/FilamentApp.cpp index 4cf0ece745..c81c456271 100644 --- a/samples/app/FilamentApp.cpp +++ b/samples/app/FilamentApp.cpp @@ -194,6 +194,8 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, int sidebarWidth = mSidebarWidth; + SDL_EventState(SDL_DROPFILE, SDL_ENABLE); + while (!mClosed) { if (mSidebarWidth != sidebarWidth) { @@ -284,6 +286,12 @@ void FilamentApp::run(const Config& config, SetupCallback setupCallback, if (!io || !io->WantCaptureMouse) window->mouseMoved(event.motion.x, event.motion.y); break; + case SDL_DROPFILE: + if (mDropHandler) { + mDropHandler(event.drop.file); + } + SDL_free(event.drop.file); + break; case SDL_WINDOWEVENT: switch (event.window.event) { case SDL_WINDOWEVENT_RESIZED: diff --git a/samples/app/FilamentApp.h b/samples/app/FilamentApp.h index 102c18c8de..035b8770c1 100644 --- a/samples/app/FilamentApp.h +++ b/samples/app/FilamentApp.h @@ -57,6 +57,7 @@ public: filament::Scene*, filament::Renderer*)>; using ImGuiCallback = std::function; using AnimCallback = std::function; + using DropCallback = std::function; static FilamentApp& get(); @@ -64,6 +65,8 @@ public: void animate(AnimCallback animation) { mAnimation = animation; } + void setDropHandler(DropCallback handler) { mDropHandler = handler; } + void run(const Config& config, SetupCallback setup, CleanupCallback cleanup, ImGuiCallback imgui = ImGuiCallback(), PreRenderCallback preRender = PreRenderCallback(), PostRenderCallback postRender = PostRenderCallback(), @@ -203,6 +206,7 @@ private: filament::MaterialInstance* mDepthMI = nullptr; std::unique_ptr mImGuiHelper; AnimCallback mAnimation; + DropCallback mDropHandler; int mSidebarWidth = 0; }; diff --git a/samples/gltf_viewer.cpp b/samples/gltf_viewer.cpp index 5d3501f0f0..5258dfefd3 100644 --- a/samples/gltf_viewer.cpp +++ b/samples/gltf_viewer.cpp @@ -43,10 +43,11 @@ using namespace gltfio; using namespace utils; struct App { + Engine* engine; SimpleViewer* viewer; Config config; AssetLoader* loader; - FilamentAsset* asset; + FilamentAsset* asset = nullptr; NameComponentManager* names; MaterialSource materialSource = GENERATE_SHADERS; }; @@ -138,46 +139,41 @@ int main(int argc, char** argv) { } } - auto setup = [&app, filename](Engine* engine, View* view, Scene* scene) { - app.names = new NameComponentManager(EntityManager::get()); - app.viewer = new SimpleViewer(engine, scene, view); - app.loader = AssetLoader::create({engine, app.names, app.materialSource}); - if (filename.isEmpty()) { - app.asset = app.loader->createAssetFromBinary(GLTF_DAMAGEDHELMET_DATA, - GLTF_DAMAGEDHELMET_SIZE); - } else { - // Peek at the file size to allow pre-allocation. - long contentSize = static_cast(getFileSize(filename.c_str())); - if (contentSize <= 0) { - std::cerr << "Unable to open " << filename << std::endl; - exit(1); - } - - // Consume the glTF file. - std::ifstream in(filename.c_str(), std::ifstream::in); - std::vector buffer(static_cast(contentSize)); - if (!in.read((char*) buffer.data(), contentSize)) { - std::cerr << "Unable to read " << filename << std::endl; - exit(1); - } - - // Parse the glTF file and create Filament entities. - if (filename.getExtension() == "glb") { - app.asset = app.loader->createAssetFromBinary(buffer.data(), buffer.size()); - } else { - app.asset = app.loader->createAssetFromJson(buffer.data(), buffer.size()); - } - buffer.clear(); - buffer.shrink_to_fit(); + auto loadAsset = [&app](utils::Path filename) { + // Peek at the file size to allow pre-allocation. + long contentSize = static_cast(getFileSize(filename.c_str())); + if (contentSize <= 0) { + std::cerr << "Unable to open " << filename << std::endl; + exit(1); } + + // Consume the glTF file. + std::ifstream in(filename.c_str(), std::ifstream::in); + std::vector buffer(static_cast(contentSize)); + if (!in.read((char*) buffer.data(), contentSize)) { + std::cerr << "Unable to read " << filename << std::endl; + exit(1); + } + + // Parse the glTF file and create Filament entities. + if (filename.getExtension() == "glb") { + app.asset = app.loader->createAssetFromBinary(buffer.data(), buffer.size()); + } else { + app.asset = app.loader->createAssetFromJson(buffer.data(), buffer.size()); + } + buffer.clear(); + buffer.shrink_to_fit(); + if (!app.asset) { std::cerr << "Unable to parse " << filename << std::endl; exit(1); } + }; + auto loadResources = [&app] (utils::Path filename) { // Load external textures and buffers. utils::Path assetFolder = filename.getParent(); - gltfio::ResourceLoader({engine, assetFolder, true, false}).loadResources(app.asset); + gltfio::ResourceLoader({app.engine, assetFolder, true, false}).loadResources(app.asset); // Load animation data then free the source hierarchy. app.asset->getAnimator(); @@ -185,7 +181,23 @@ int main(int argc, char** argv) { // Add the renderables to the scene. app.viewer->setAsset(app.asset, app.names); + app.viewer->setIndirectLight(FilamentApp::get().getIBL()->getIndirectLight()); + }; + + auto setup = [&](Engine* engine, View* view, Scene* scene) { + app.engine = engine; + app.names = new NameComponentManager(EntityManager::get()); + app.viewer = new SimpleViewer(engine, scene, view); + app.loader = AssetLoader::create({engine, app.names, app.materialSource}); + if (filename.isEmpty()) { + app.asset = app.loader->createAssetFromBinary(GLTF_DAMAGEDHELMET_DATA, + GLTF_DAMAGEDHELMET_SIZE); + } else { + loadAsset(filename); + } + + loadResources(filename); // Leave FXAA enabled but we also enable MSAA for a nice result. The wireframe looks // much better with MSAA enabled. @@ -212,6 +224,14 @@ int main(int argc, char** argv) { FilamentApp& filamentApp = FilamentApp::get(); filamentApp.animate(animate); + + filamentApp.setDropHandler([&] (std::string path) { + app.viewer->removeAsset(); + app.loader->destroyAsset(app.asset); + loadAsset(path); + loadResources(path); + }); + filamentApp.run(app.config, setup, cleanup, gui); return 0;