add export feature and more mimetypes

master
poikilos 2019-05-16 12:33:53 -04:00
parent c9860273e0
commit 36a1399cb5
11 changed files with 268 additions and 82 deletions

View File

@ -1,5 +1,14 @@
# Changelog
## [git] - 2019-05-16
(poikilos)
### Added
* export COLLADA (non-Blender), IRR, IRRMESH, OBJ, STL
* show dialog box if operation can't be performed
- improve error reporting in called methods
* add irr mimetype (Irrlicht Scene, including animations)
* add irrlicht mimetype (static/non-animated Irrlicht mesh)
## [git] - 2019-04-19
(poikilos)
### Added

View File

@ -310,8 +310,9 @@ vector3df Engine::camTarget()
return m_CamTarget;
}
void Engine::loadMesh(const wstring& fileName)
bool Engine::loadMesh(const wstring& fileName)
{
bool ret = false;
this->m_PreviousPath = fileName; // even if bad, set this
// to allow F5 to reload
@ -329,6 +330,7 @@ void Engine::loadMesh(const wstring& fileName)
m_View->setZUp(false);
}
if (m_LoadedMesh != nullptr) {
ret = true;
this->m_UserInterface->playbackFPSEditBox->setText(
Utility::toWstring(m_LoadedMesh->getAnimationSpeed()).c_str()
);
@ -380,32 +382,73 @@ void Engine::loadMesh(const wstring& fileName)
// EMT_TRANSPARENT_ALPHA_CHANNEL: constant transparency
}
}
return ret;
}
void Engine::reloadMesh()
bool Engine::reloadMesh()
{
bool ret = false;
if (this->m_PreviousPath.length() > 0) {
loadMesh(this->m_PreviousPath);
ret = loadMesh(this->m_PreviousPath);
}
return ret;
}
void Engine::saveMesh(const io::path path)
std::wstring Engine::saveMesh(const io::path path, const std::string& nameOrBlank, const std::string& extension)
{
wstring ret = L"";
// see also https://bitbucket.org/mzeilfelder/irr-playground-micha/src/default/obj_readwrite.cpp (saves scene::EMWT_OBJ)
scene::ISceneManager* smgr = m_Device->getSceneManager();
scene::IMeshWriter* meshWriter = smgr->createMeshWriter(scene::EMWT_COLLADA);
scene::IMeshWriter* meshWriter = nullptr;
//this->m_FileName = "";
io::path fileName = "export.dae";
//io::path filePath = path + fileName;
io::path filePath = fileName;
io::IWriteFile* meshFile = m_Device->getFileSystem()->createAndWriteFile(filePath);
if (!meshWriter->writeMesh(meshFile, m_LoadedMesh->getMesh())) {
debug() << "saving failed" << endl;
io::path fileName = io::path();
std::string beginning = "export-";
if (nameOrBlank.length() > 0) {
beginning = nameOrBlank + "-";
}
else
debug() << "saving ok" << endl;
meshFile->drop();
meshWriter->drop();
std::string partial = beginning + Utility::dateTimeNowPathString();
if (extension == "dae") {
fileName = (partial + ".dae").c_str();
meshWriter = smgr->createMeshWriter(scene::EMWT_COLLADA);
}
else if (extension == "obj") {
fileName = (partial + ".obj").c_str();
meshWriter = smgr->createMeshWriter(scene::EMWT_OBJ);
}
else if (extension == "irrmesh") {
fileName = (partial + ".irrmesh").c_str();
meshWriter = smgr->createMeshWriter(scene::EMWT_IRR_MESH);
}
else if (extension == "stl") {
fileName = (partial + ".stl").c_str();
meshWriter = smgr->createMeshWriter(scene::EMWT_STL);
}
if (meshWriter != nullptr) {
//io::path filePath = path + fileName;
io::path filePath = path + "/" + fileName;
io::IWriteFile* meshFile = m_Device->getFileSystem()->createAndWriteFile(filePath);
if (!meshWriter->writeMesh(meshFile, m_LoadedMesh->getMesh())) {
debug() << "saving failed" << endl;
}
else {
debug() << "saving ok" << endl;
ret = Utility::toWstring(filePath.c_str());
}
meshFile->drop();
meshWriter->drop();
}
else if (extension == "irr") {
fileName = (partial + ".irr").c_str();
io::path filePath = path + "/" + fileName;
if (!smgr->saveScene(filePath)) {
debug() << "saving failed" << endl;
}
else {
debug() << "saving ok" << endl;
ret = Utility::toWstring(filePath.c_str());
}
}
return ret;
}
void Engine::reloadTexture()

View File

@ -76,9 +76,9 @@ public:
irr::core::vector3df camTarget();
void run();
void loadMesh(const std::wstring& fileName);
void reloadMesh();
void saveMesh(const irr::io::path path);
bool loadMesh(const std::wstring& fileName);
bool reloadMesh();
std::wstring saveMesh(const irr::io::path path, const std::string& nameOrBlank, const std::string& extension);
void reloadTexture();
bool loadTexture(const std::wstring& fileName);
void setMeshDisplayMode(bool wireframe = false, bool lighting = true, bool textureInterpolation = true);

View File

@ -20,6 +20,9 @@ Website: [poikilos.org](https://poikilos.org)
* hotkeys to cycle through textures and reload model OR texture
(see [Usage](#Usage) below).
* see also CHANGELOG.md
* export feature: COLLADA (non-Blender), IRR (Irrlicht Scene including
animations), IRRMESH (Static Irrlicht Mesh), OBJ (Wavefront), STL
(stereolithography)
## Compile
(the original version of this section is from

View File

@ -39,7 +39,11 @@ void UserInterface::setupUserInterface()
fileMenu->addItem(L"Change Texture", UIC_FILE_OPEN_TEXTURE);
fileMenu->addItem(L"Previous Texture Shift F3", UIC_FILE_PREVIOUS_TEXTURE);
fileMenu->addItem(L"Next Texture F3", UIC_FILE_NEXT_TEXTURE);
fileMenu->addItem(L"Export", UIC_FILE_EXPORT);
fileMenu->addItem(L"Export DAE (non-Blender COLLADA)", UIC_FILE_EXPORT_DAE);
fileMenu->addItem(L"Export IRR (Irrlicht Scene)", UIC_FILE_EXPORT_IRR);
fileMenu->addItem(L"Export IRRMESH (Static Irrlicht Mesh)", UIC_FILE_EXPORT_IRRMESH);
fileMenu->addItem(L"Export OBJ (Wavefront)", UIC_FILE_EXPORT_OBJ);
fileMenu->addItem(L"Export STL (stereolithography)", UIC_FILE_EXPORT_STL);
fileMenu->addItem(L"Quit", UIC_FILE_QUIT);
// View Menu
@ -250,23 +254,54 @@ void UserInterface::handleMenuItemPressed(IGUIContextMenu* menu)
displayLoadFileDialog();
break;
case UIC_FILE_EXPORT:
if (this->m_Engine->m_LoadedMesh != nullptr) {
// this->m_Engine->m_LoadedMesh->getName();
displaySaveFileDialog();
}
case UIC_FILE_EXPORT_DAE:
exportMeshToHome("dae");
break;
case UIC_FILE_EXPORT_IRR:
exportMeshToHome("irr");
break;
case UIC_FILE_EXPORT_IRRMESH:
exportMeshToHome("irrmesh");
break;
case UIC_FILE_EXPORT_OBJ:
exportMeshToHome("obj");
break;
case UIC_FILE_EXPORT_STL:
exportMeshToHome("stl");
break;
case UIC_FILE_OPEN_TEXTURE:
displayLoadTextureDialog();
if (m_Engine->m_LoadedMesh != nullptr) {
displayLoadTextureDialog();
}
else {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Change Texture", L"You must load a model before a texture.");
}
break;
case UIC_FILE_PREVIOUS_TEXTURE:
loadNextTexture(-1);
if (m_Engine->m_LoadedMesh != nullptr) {
loadNextTexture(-1);
}
else {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Change Texture", L"You must load a model before a texture.");
}
break;
case UIC_FILE_NEXT_TEXTURE:
loadNextTexture(1);
if (m_Engine->m_LoadedMesh != nullptr) {
loadNextTexture(1);
}
else {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Change Texture", L"You must load a model before a texture.");
}
break;
case UIC_FILE_QUIT:
@ -490,6 +525,43 @@ bool UserInterface::loadNextTexture(int direction)
return ret;
}
void UserInterface::exportMeshToHome(std::string extension)
{
if (this->m_Engine->m_LoadedMesh != nullptr) {
// this->m_Engine->m_LoadedMesh->getName();
// displaySaveFileDialog();
irr::io::path where = irr::io::path();
if (const char* env_p = std::getenv("HOME")) {
// std::cout << "Your PATH is: " << env_p << '\n';
where = irr::io::path(env_p);
std::cout << "Your PATH is: " << where.c_str() << '\n';
}
else if (const char* env_p = std::getenv("USERPROFILE")) {
// std::cout << "Your PATH is: " << env_p << '\n';
where = irr::io::path(env_p);
std::cout << "Your PATH is: " << where.c_str() << '\n';
}
std::string name = "";
if (m_Engine->m_PreviousPath.length() > 0) {
name = Utility::toString(Utility::withoutExtension(Utility::basename(m_Engine->m_PreviousPath)));
}
wstring result = m_Engine->saveMesh(where, name, extension);
std::wstring caption = L"Export Failed";
std::wstring msg = L"The format or home variable is unwriteable";
if (result.length() > 0) {
caption = L"Export Finished";
msg = L"Saved " + result;
}
std::cout << "Exported as: " << Utility::toString(result) << '\n';
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
caption.c_str(), msg.c_str());
}
else {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Export", L"There is nothing to export.");
}
}
// IEventReceiver
bool UserInterface::OnEvent(const SEvent& event)
{
@ -518,13 +590,33 @@ bool UserInterface::OnEvent(const SEvent& event)
case UIE_LOADFILEDIALOG:
if (ge->EventType == EGET_FILE_SELECTED) {
IGUIFileOpenDialog* fileOpenDialog = static_cast<IGUIFileOpenDialog*>(ge->Caller);
m_Engine->loadMesh(fileOpenDialog->getFileName());
wstring path = fileOpenDialog->getFileName();
bool result = false;
wstring extension = Utility::extensionOf(path);
if (Utility::toLower(Utility::toString(extension)) == "irr") {
scene::ISceneManager* smgr = m_Engine->m_Device->getSceneManager();
result = smgr->loadScene(fileOpenDialog->getFileName());
}
else {
result = m_Engine->loadMesh(fileOpenDialog->getFileName());
}
if (!result) {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Load Mesh", L"The model is inaccessible or not in a compatible format.");
}
}
break;
case UIE_SAVEFILEDIALOG:
if (ge->EventType == EGET_FILE_SELECTED) {
IGUIFileOpenDialog* fileOpenDialog = static_cast<IGUIFileOpenDialog*>(ge->Caller);
m_Engine->saveMesh(fileOpenDialog->getDirectoryName());
if (m_Engine->m_LoadedMesh != nullptr) {
IGUIFileOpenDialog* fileOpenDialog = static_cast<IGUIFileOpenDialog*>(ge->Caller);
///fileOpenDialog->getFileName()
m_Engine->saveMesh(fileOpenDialog->getDirectoryName(), "", "dae");
}
else {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Export", L"There is nothing to save.");
}
}
break;
@ -599,8 +691,18 @@ bool UserInterface::OnEvent(const SEvent& event)
|| m_Engine->KeyIsDown[irr::KEY_RSHIFT]) {
m_Engine->reloadTexture();
}
else
m_Engine->reloadMesh();
else {
if (m_Engine->m_PreviousPath.length() > 0) {
bool result = m_Engine->reloadMesh();
if (!result) {
this->m_Engine->m_Device->getGUIEnvironment()->addMessageBox(
L"Reload Mesh", L"The model is inaccessible or not in a compatible format.");
}
}
else {
debug() << " - No mesh is loaded." << endl;
}
}
} else if (event.KeyInput.Key == irr::KEY_F3) {
if (m_Engine->KeyIsDown[irr::KEY_LSHIFT]
|| m_Engine->KeyIsDown[irr::KEY_RSHIFT]) {

View File

@ -4,6 +4,8 @@
#include "extlib/CGUITTFont.h"
#include <irrlicht/irrlicht.h>
#include <string>
// Forward declaration of class Engine
class Engine;
@ -34,7 +36,11 @@ enum UserInterfaceCommands {
UIC_FILE_OPEN_TEXTURE = 1002,
UIC_FILE_NEXT_TEXTURE = 1003,
UIC_FILE_PREVIOUS_TEXTURE = 1004,
UIC_FILE_EXPORT = 1005,
UIC_FILE_EXPORT_DAE = 1005,
UIC_FILE_EXPORT_IRR = 1006,
UIC_FILE_EXPORT_IRRMESH = 1007,
UIC_FILE_EXPORT_OBJ = 1008,
UIC_FILE_EXPORT_STL = 1009,
UIC_VIEW_WIREFRAME = 2001,
UIC_VIEW_LIGHTING = 2002,
UIC_VIEW_AXIS_WIDGET = 2003,
@ -93,6 +99,7 @@ public:
irr::gui::IGUIEnvironment* getGUIEnvironment() const;
void drawStatusLine() const;
bool loadNextTexture(int direction);
void exportMeshToHome(std::string extension);
// IEventReceiver
virtual bool OnEvent(const irr::SEvent& event);

View File

@ -231,6 +231,26 @@ wstring Utility::toWstring(const std::string& str)
return ret;
}
std::string Utility::dateTimePathString(const time_t& rawtime)
{
// see http://www.cplusplus.com/reference/ctime/strftime/
std::string ret = "";
struct tm * timeinfo;
char buffer[80];
timeinfo = localtime (&rawtime);
strftime (buffer,80,"%F_%H%M%S",timeinfo);
// %F is same as %Y-%m-%d (zero-padded)
ret.assign(buffer);
return ret;
}
std::string Utility::dateTimeNowPathString()
{
time_t rawtime;
time (&rawtime);
return dateTimePathString(rawtime);
}
irr::f32 Utility::toF32(wstring val)
{
std::wstringstream ss(val);

View File

@ -1,10 +1,11 @@
#ifndef UTILS_H
#define UTILS_H
#include <string>
#include <irrlicht/irrlicht.h>
#include <ctime>
#include <string>
class Utility {
public:
static void dumpVectorToConsole(const irr::core::vector3df& vector);
@ -23,6 +24,8 @@ public:
static std::wstring toWstring(irr::f32 val);
static std::wstring toWstring(int val);
static std::wstring toWstring(const std::string& str);
static std::string dateTimePathString(const time_t& rawtime);
static std::string dateTimeNowPathString();
static irr::f32 toF32(std::wstring val);
static irr::f32 distance(const irr::core::vector3df& start, const irr::core::vector3df& end);
// compiler doesn't like template function when class is not a template--instantiate immediately

View File

@ -16,8 +16,6 @@ icons_root=$PREFIX/share/pixmaps
applications_path=$PREFIX/share/applications
mimes_path="share/mime/packages"
mime_name=model-b3d.xml
mime_path="$mimes_path/$mime_name"
USER_MIMETYPES_DB_PATH=$HOME/.local/share/mime
#USER_MIMETYPES_PATH="$USER_MIMETYPES_DB_PATH/packages"
SYSTEM_MIMETYPES_DB_PATH=/usr/share/mime
@ -114,36 +112,36 @@ if [ ! -d "$MIMETYPES_DB_PATH/packages" ]; then
mkdir "$MIMETYPES_DB_PATH/packages"
fi
update_mime_enable=false
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "* (You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "* Successfully copied '$try_dest'"
update_mime_enable=true
#if [ ! -f "$mime_path" ]; then
#echo "ERROR: Stopped installing mime types since missing $mime_path"
#exit 1
#fi
install_mime() {
mime_name=$1
mime_path="$mimes_path/$mime_name"
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
fi
mime_name=model-x.xml
mime_path="$mimes_path/$mime_name"
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "* (You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$try_dest" ]; then
echo "* Successfully copied '$try_dest'"
update_mime_enable=true
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "(You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$MIMETYPES_DB_PATH/packages/$mime_name" ]; then
echo "Successfully copied '$MIMETYPES_DB_PATH/packages/$mime_name'"
# rm -f "$MIMETYPES_DB_PATH/packages/$mime_name"
update_mime_enable=true
fi
fi
fi
}
install_mime model-b3d.xml
install_mime model-x.xml
install_mime model-ms3d.xml
install_mime model-irr.xml
install_mime model-irrmesh.xml
# Since OBJ Mime type is broken on linux (detected as TGIF obj/sym
# hyperlinked vector graphics format unrelated to Wavefront OBJ
@ -169,23 +167,6 @@ try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
fi
#fi
mime_name=model-ms3d.xml
mime_path="$mimes_path/$mime_name"
if [ ! -f "$mime_path" ]; then
echo "ERROR: Stopped installing mime types since missing $mime_path"
exit 1
fi
try_dest="$MIMETYPES_DB_PATH/packages/$mime_name"
if diff -q $mime_path $try_dest; then
echo "(You already have an identical $try_dest)"
else
cp -f "$mime_path" "$MIMETYPES_DB_PATH/packages/"
if [ -f "$MIMETYPES_DB_PATH/packages/$mime_name" ]; then
echo "Successfully copied '$MIMETYPES_DB_PATH/packages/$mime_name'"
# rm -f "$MIMETYPES_DB_PATH/packages/$mime_name"
update_mime_enable=true
fi
fi
if [ "@$update_mime_enable" = "@true" ]; then
echo "Updating mime type database '$MIMETYPES_DB_PATH'..."

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="model/irr">
<comment>Irrlicht Mesh</comment>
<icon name="model-irr"/>
<glob-deleteall/>
<glob pattern="*.irr"/>
</mime-type>
</mime-info>

View File

@ -0,0 +1,9 @@
<?xml version="1.0" encoding="UTF-8"?>
<mime-info xmlns="http://www.freedesktop.org/standards/shared-mime-info">
<mime-type type="model/irrmesh">
<comment>Irrlicht Mesh</comment>
<icon name="model-irrmesh"/>
<glob-deleteall/>
<glob pattern="*.irrmesh"/>
</mime-type>
</mime-info>