From 2969478764bc8be0c6cf5fc17c98aa129e124cf2 Mon Sep 17 00:00:00 2001 From: stujones11 Date: Thu, 4 Oct 2018 17:53:07 +0100 Subject: [PATCH] Add static mesh export feature --- README.md | 1 + src/dialog.cpp | 35 ++++++++++++++++++--------- src/dialog.h | 5 +++- src/gui.cpp | 15 +++++++++++- src/gui.h | 5 ++++ src/viewer.cpp | 65 ++++++++++++++++++++++++++++++++++++++++++++++---- src/viewer.h | 2 ++ 7 files changed, 110 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 8fc1b0a..54ffdfe 100644 --- a/README.md +++ b/README.md @@ -13,6 +13,7 @@ Features * Mesh debug view. (wire-frame, skeleton and normals) * Animation playback amd frame controls. * Simple lighting. +* Static mesh export. Supported Mesh Formats ---------------------- diff --git a/src/dialog.cpp b/src/dialog.cpp index 2c07b87..b5c4f6b 100644 --- a/src/dialog.cpp +++ b/src/dialog.cpp @@ -13,23 +13,36 @@ #else #define D_ABOUT_LINK_URL "https://github.com/stujones11/SAM-Viewer" #define D_ABOUT_LINK_TEXT "github.com/stujones11/SAM-Viewer" -#define D_VERSION "0.0" +#define D_VERSION "dirty" #endif namespace dialog { - const char *fileOpenDialog(IGUIEnvironment *env, const char *caption, + static inline void setWorkingDir(io::IFileSystem *fs, const char *fn) + { + if (!fn || stringc(fn).empty()) + return; + io::path cwd = fs->getFileDir(fn); + fs->changeWorkingDirectoryTo(cwd); + } + + const char *fileOpenDialog(io::IFileSystem *fs, const char *caption, const char **filters, const int filter_count) { - io::IFileSystem *fs = env->getFileSystem(); io::path path = fs->getWorkingDirectory() + "/"; const char *fn = tinyfd_openFileDialog(caption, path.c_str(), filter_count, filters, 0); - if (fn) - { - io::path cwd = fs->getFileDir(fn); - fs->changeWorkingDirectoryTo(cwd); - } + setWorkingDir(fs, fn); + return fn; + } + + const char *fileSaveDialog(io::IFileSystem *fs, const char *caption, + const char **filters, const int filter_count) + { + io::path path = fs->getWorkingDirectory() + "/"; + const char *fn = tinyfd_saveFileDialog(caption, path.c_str(), + filter_count, filters); + setWorkingDir(fs, fn); return fn; } } @@ -400,9 +413,9 @@ bool TexturesDialog::OnEvent(const SEvent &event) } if (edit) { - const char *fn = dialog::fileOpenDialog(Environment, - "Open Image File", dialog::texture_filters, - dialog::texture_filter_count); + const char *fn = dialog::fileOpenDialog( + Environment->getFileSystem(), "Open Image File", + dialog::texture_filters, dialog::texture_filter_count); if (fn) { edit->setText(stringw(fn).c_str()); diff --git a/src/dialog.h b/src/dialog.h index 1ea2d0f..f41492a 100644 --- a/src/dialog.h +++ b/src/dialog.h @@ -69,7 +69,10 @@ namespace dialog "*.psd", "*.pcx", "*.ppm", "*.wal" }; - const char *fileOpenDialog(IGUIEnvironment *env, const char *caption, + const char *fileOpenDialog(io::IFileSystem *fs, const char *caption, + const char **filters, const int filter_count); + + const char *fileSaveDialog(io::IFileSystem *fs, const char *caption, const char **filters, const int filter_count); } diff --git a/src/gui.cpp b/src/gui.cpp index a0645df..a1f3bee 100644 --- a/src/gui.cpp +++ b/src/gui.cpp @@ -169,11 +169,24 @@ void GUI::initMenu() submenu = menu->getSubMenu(0); submenu->addItem(L"Load Model Mesh", E_GUI_ID_LOAD_MODEL_MESH); submenu->addItem(L"Load Wield Mesh", E_GUI_ID_LOAD_WIELD_MESH); - submenu->addSeparator(); submenu->addItem(L"Save Configuration", E_GUI_ID_SAVE_CONFIG); submenu->addSeparator(); + submenu->addItem(L"Export Static Mesh", -1, true, true); + submenu->addSeparator(); submenu->addItem(L"Quit", E_GUI_ID_QUIT); + submenu = menu->getSubMenu(0)->getSubMenu(4); + submenu->addItem(L"Irrlcht (.irrmesh)", + E_GUI_ID_EXPORT_MESH_IRR); + submenu->addItem(L"Collada (.dae, .xml)", + E_GUI_ID_EXPORT_MESH_COL); + submenu->addItem(L"STL (.stl)", + E_GUI_ID_EXPORT_MESH_STL); + submenu->addItem(L"Wavefront (.obj)", + E_GUI_ID_EXPORT_MESH_OBJ); + submenu->addItem(L"Polygon file format (.ply)", + E_GUI_ID_EXPORT_MESH_PLY); + submenu = menu->getSubMenu(1); submenu->addItem(L"Textures", E_DIALOG_ID_TEXTURES); submenu->addItem(L"Lights", E_DIALOG_ID_LIGHTS); diff --git a/src/gui.h b/src/gui.h index 628c601..6eecf65 100644 --- a/src/gui.h +++ b/src/gui.h @@ -13,6 +13,11 @@ enum E_GUI_ID_TOOLBAR, E_GUI_ID_LOAD_MODEL_MESH, E_GUI_ID_LOAD_WIELD_MESH, + E_GUI_ID_EXPORT_MESH_IRR, + E_GUI_ID_EXPORT_MESH_COL, + E_GUI_ID_EXPORT_MESH_STL, + E_GUI_ID_EXPORT_MESH_OBJ, + E_GUI_ID_EXPORT_MESH_PLY, E_GUI_ID_SAVE_CONFIG, E_GUI_ID_QUIT, E_GUI_ID_TOOLBOX_MODEL, diff --git a/src/viewer.cpp b/src/viewer.cpp index 08fff5b..20ea2d6 100644 --- a/src/viewer.cpp +++ b/src/viewer.cpp @@ -132,6 +132,26 @@ void Viewer::setCaptionFileName(const io::path &filename) device->setWindowCaption(caption.c_str()); } +void Viewer::exportStaticMesh(const char *caption, const char **filters, + const int filter_count, EMESH_WRITER_TYPE id) +{ + io::IFileSystem *fs = device->getFileSystem(); + const char *fn = dialog::fileSaveDialog(fs, caption, filters, + filter_count); + if (!fn || stringc(fn).empty()) + return; + + IAnimatedMeshSceneNode *model = + (IAnimatedMeshSceneNode*)scene->getNode(E_SCENE_ID_MODEL); + IAnimatedMesh *mesh = model->getMesh(); + io::IWriteFile *file = fs->createAndWriteFile(fn); + ISceneManager *smgr = device->getSceneManager(); + IMeshWriter *writer = smgr->createMeshWriter(id); + writer->writeMesh(file, mesh); + writer->drop(); + file->drop(); +} + static inline std::string boolToString(bool b) { return (b) ? "true" : "false"; @@ -154,16 +174,16 @@ bool Viewer::OnEvent(const SEvent &event) IGUIContextMenu *menu = (IGUIContextMenu*)event.GUIEvent.Caller; s32 item = menu->getSelectedItem(); s32 id = menu->getItemCommandId(item); - IGUIEnvironment *env = device->getGUIEnvironment(); + io::IFileSystem *fs = device->getFileSystem(); switch (id) { case E_GUI_ID_LOAD_MODEL_MESH: { - const char *fn = dialog::fileOpenDialog(env, + const char *fn = dialog::fileOpenDialog(fs, "Open main model file", dialog::model_filters, dialog::model_filter_count); - if (fn && scene->loadModelMesh(fn)) + if (fn && !stringc(fn).empty() && scene->loadModelMesh(fn)) { ISceneNode *model = scene->getNode(E_SCENE_ID_MODEL); if (model) @@ -178,16 +198,51 @@ bool Viewer::OnEvent(const SEvent &event) } case E_GUI_ID_LOAD_WIELD_MESH: { - const char *fn = dialog::fileOpenDialog(env, + const char *fn = dialog::fileOpenDialog(fs, "Open wield model file", dialog::model_filters, dialog::model_filter_count); - if (fn && scene->loadWieldMesh(fn)) + if (fn && !stringc(fn).empty() && scene->loadWieldMesh(fn)) { gui->reloadToolBox(E_GUI_ID_TOOLBOX_WIELD); conf->set("wield_mesh", fn); } break; } + case E_GUI_ID_EXPORT_MESH_IRR: + { + const char *filters[] = {"*.irrmesh"}; + exportStaticMesh("Export Irrlicht Mesh", + filters, 1, EMWT_IRR_MESH); + break; + } + case E_GUI_ID_EXPORT_MESH_COL: + { + const char *filters[] = {"*.dae", "*.xml"}; + exportStaticMesh("Export Collada Mesh", + filters, 2, EMWT_COLLADA); + break; + } + case E_GUI_ID_EXPORT_MESH_STL: + { + const char *filters[] = {"*.stl"}; + exportStaticMesh("Export STL Mesh", + filters, 1, EMWT_STL); + break; + } + case E_GUI_ID_EXPORT_MESH_OBJ: + { + const char *filters[] = {"*.obj"}; + exportStaticMesh("Export Wavefront Mesh", + filters, 1, EMWT_OBJ); + break; + } + case E_GUI_ID_EXPORT_MESH_PLY: + { + const char *filters[] = {"*.ply"}; + exportStaticMesh("Export Polygon File", + filters, 1, EMWT_PLY); + break; + } case E_GUI_ID_ENABLE_WIELD: { ISceneNode *wield = scene->getNode(E_SCENE_ID_WIELD); diff --git a/src/viewer.h b/src/viewer.h index 9b5e83e..1bfdd4c 100644 --- a/src/viewer.h +++ b/src/viewer.h @@ -57,6 +57,8 @@ private: void setProjection(); void setBackgroundColor(const u32 &color); void setCaptionFileName(const io::path &filename); + void exportStaticMesh(const char *caption, const char **filters, + const int filter_count, EMESH_WRITER_TYPE id); Config *conf; IrrlichtDevice *device;