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.
This commit is contained in:
Philip Rideout
2019-03-13 18:04:33 -07:00
parent fbcdcc24af
commit e3e7073f74
4 changed files with 86 additions and 40 deletions

View File

@@ -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;

View File

@@ -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:

View File

@@ -57,6 +57,7 @@ public:
filament::Scene*, filament::Renderer*)>;
using ImGuiCallback = std::function<void(filament::Engine*, filament::View*)>;
using AnimCallback = std::function<void(filament::Engine*, filament::View*, double now)>;
using DropCallback = std::function<void(std::string)>;
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<filagui::ImGuiHelper> mImGuiHelper;
AnimCallback mAnimation;
DropCallback mDropHandler;
int mSidebarWidth = 0;
};

View File

@@ -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<long>(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<uint8_t> buffer(static_cast<unsigned long>(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<long>(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<uint8_t> buffer(static_cast<unsigned long>(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;