diff --git a/code/nel/tools/3d/CMakeLists.txt b/code/nel/tools/3d/CMakeLists.txt
index 034fc5f55..57d297fc8 100644
--- a/code/nel/tools/3d/CMakeLists.txt
+++ b/code/nel/tools/3d/CMakeLists.txt
@@ -1,10 +1,20 @@
IF(WITH_NEL_TOOLS)
IF(WITH_3D)
+ IF(WITH_QT5)
+ SUBDIRS(
+ shared_widgets
+ panoply_preview)
+ ENDIF()
IF(WITH_ASSIMP)
SUBDIRS(
mesh_utils
mesh_export)
+ IF(WITH_QT5)
+ # NOTE: Also requires C++11, because.
+ SUBDIRS(
+ mesh_editor)
+ ENDIF()
ENDIF()
SUBDIRS(
anim_builder
@@ -67,11 +77,6 @@ IF(WITH_NEL_TOOLS AND WITH_3D)
ADD_SUBDIRECTORY(object_viewer_widget)
ENDIF()
- IF(WITH_QT5)
- ADD_SUBDIRECTORY(shared_widgets)
- ADD_SUBDIRECTORY(panoply_preview)
- ENDIF()
-
IF(WITH_NEL_TOOLS)
FIND_PACKAGE(Squish)
ENDIF()
diff --git a/code/nel/tools/3d/mesh_editor/CMakeLists.txt b/code/nel/tools/3d/mesh_editor/CMakeLists.txt
new file mode 100644
index 000000000..465df646f
--- /dev/null
+++ b/code/nel/tools/3d/mesh_editor/CMakeLists.txt
@@ -0,0 +1,39 @@
+
+FILE(GLOB SRCS *.cpp)
+FILE(GLOB HDRS *.h)
+IF (WIN32)
+ FILE(GLOB RSRC *.rc)
+ENDIF (WIN32)
+FILE(GLOB RESOURCES *.qrc)
+
+SOURCE_GROUP("" FILES ${SRCS} ${HDRS} ${RSRC} ${RESOURCES})
+
+SET(CMAKE_AUTOMOC ON)
+
+QT5_ADD_RESOURCES(RESOURCE_ADDED ${RESOURCES})
+
+ADD_EXECUTABLE(nl_mesh_editor WIN32 ${SRC}
+ ${SRCS}
+ ${HDRS}
+ ${RSRC}
+ ${RESOURCE_ADDED}
+ ${PANOPLY_MAKER}
+ )
+
+IF(QT_STATIC)
+ SET(PANOPLY_PREVIEW_QT_LIBRARIES ${QT_LIBRARIES})
+ELSE()
+ SET(PANOPLY_PREVIEW_QT_LIBRARIES Qt5::Widgets)
+ENDIF()
+
+TARGET_LINK_LIBRARIES(nl_mesh_editor
+ nelmisc
+ nel3d
+ nelsound
+ shared_widgets
+ mesh_utils)
+
+NL_DEFAULT_PROPS(nl_mesh_editor "NeL, Tools, 3D: Mesh Editor")
+NL_ADD_RUNTIME_FLAGS(nl_mesh_editor)
+
+INSTALL(TARGETS nl_mesh_editor RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samples3d)
diff --git a/code/nel/tools/3d/mesh_editor/configuration.cpp b/code/nel/tools/3d/mesh_editor/configuration.cpp
new file mode 100644
index 000000000..524a41c7b
--- /dev/null
+++ b/code/nel/tools/3d/mesh_editor/configuration.cpp
@@ -0,0 +1,242 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2010 Winch Gate Property Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+#include
+#include "configuration.h"
+
+// STL includes
+
+// NeL includes
+#include
+#include
+#include
+#include
+#include
+
+using namespace std;
+using namespace NLMISC;
+
+CConfiguration::CConfiguration()
+{
+
+}
+
+CConfiguration::~CConfiguration()
+{
+
+}
+
+void CConfiguration::init()
+{
+ // verify data
+ nlassert(m_ConfigCallbacks.empty());
+
+ // load config
+ std::string appData = CPath::getApplicationDirectory("NeL");
+ m_ConfigFile.load(appData + "mesh_editor.cfg");
+
+ // log config
+ CConfiguration::setAndCallback("NegFiltersDebug", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
+ CConfiguration::setAndCallback("NegFiltersInfo", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
+ CConfiguration::setAndCallback("NegFiltersWarning", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
+ CConfiguration::setAndCallback("NegFiltersAssert", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
+ CConfiguration::setAndCallback("NegFiltersError", CConfigCallback(this, &CConfiguration::cfcbLogFilter));
+
+ // set the search paths (kinda important)
+ /*
+ CConfigFile::CVar *var;
+ var = m_ConfigFile.getVarPtr("SearchPaths");
+ uint varsize = var->size();
+ for (uint i = 0; i < varsize; ++i)
+ CPath::addSearchPath(var->asString(i), true, false);
+ var = m_ConfigFile.getVarPtr("RemapExtensions");
+ varsize = var->size();
+ for (uint i = 0; i < varsize; i += 2)
+ CPath::remapExtension(var->asString(i), var->asString(i + 1), true);
+ */
+}
+
+void CConfiguration::release()
+{
+ // bye bye log config
+ CConfigFile::CVar emptyVar;
+ emptyVar.Name = "NegFiltersDebug";
+ CConfiguration::dropCallback(emptyVar.Name);
+ cfcbLogFilter(emptyVar);
+ emptyVar.Name = "NegFiltersInfo";
+ CConfiguration::dropCallback(emptyVar.Name);
+ cfcbLogFilter(emptyVar);
+ emptyVar.Name = "NegFiltersWarning";
+ CConfiguration::dropCallback(emptyVar.Name);
+ cfcbLogFilter(emptyVar);
+ emptyVar.Name = "NegFiltersAssert";
+ CConfiguration::dropCallback(emptyVar.Name);
+ cfcbLogFilter(emptyVar);
+ emptyVar.Name = "NegFiltersError";
+ CConfiguration::dropCallback(emptyVar.Name);
+ cfcbLogFilter(emptyVar);
+
+ // save and release the config file
+ if (m_ConfigFile.exists("SaveConfig") && m_ConfigFile.getVarPtr("SaveConfig")->asBool())
+ {
+ m_ConfigFile.save();
+ }
+ m_ConfigFile.clear();
+
+ // release the search paths etc
+ CPath::releaseInstance();
+
+ // verify data
+ nlassert(!m_ConfigCallbacks.size());
+}
+
+void CConfiguration::updateUtilities()
+{
+ //H_AUTO2
+
+ CConfigFile::checkConfigFiles();
+}
+
+void CConfiguration::setAndCallback(const std::string &varName, CConfigCallback configCallback)
+{
+ m_ConfigCallbacks[varName] = configCallback;
+ m_ConfigFile.setCallback(varName, cbConfigCallback);
+ configCallback(*m_ConfigFile.getVarPtr(varName));
+}
+
+void CConfiguration::setCallback(const std::string &varName, CConfigCallback configCallback)
+{
+ m_ConfigCallbacks[varName] = configCallback;
+ m_ConfigFile.setCallback(varName, cbConfigCallback);
+}
+
+void CConfiguration::dropCallback(const std::string &varName)
+{
+ m_ConfigFile.setCallback(varName, NULL);
+ m_ConfigCallbacks.erase(varName);
+}
+
+float CConfiguration::getValue(const string &varName, float defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asFloat();
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsDouble((double)defaultValue);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+double CConfiguration::getValue(const string &varName, double defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asDouble();
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsDouble(defaultValue);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+int CConfiguration::getValue(const string &varName, int defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asInt();
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsInt(defaultValue);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+string CConfiguration::getValue(const string &varName, const string &defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asString();
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsString(defaultValue);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+ucstring CConfiguration::getValue(const string &varName, const ucstring &defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return ucstring::makeFromUtf8(m_ConfigFile.getVar(varName).asString());
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsString(defaultValue.toUtf8());
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+bool CConfiguration::getValue(const string &varName, bool defaultValue)
+{
+ if (m_ConfigFile.exists(varName)) return m_ConfigFile.getVar(varName).asBool();
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsInt(defaultValue ? 1 : 0);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ return defaultValue;
+}
+
+CRGBA CConfiguration::getValue(const string &varName, const CRGBA &defaultValue)
+{
+ if (m_ConfigFile.exists(varName))
+ {
+ return getValue(m_ConfigFile.getVar(varName), defaultValue);
+ }
+ else
+ {
+ // create a new value only if one doesn't exist
+ CConfigFile::CVar varToCopy;
+ varToCopy.forceAsInt(defaultValue.R);
+ varToCopy.setAsInt(defaultValue.G, 1);
+ varToCopy.setAsInt(defaultValue.B, 2);
+ varToCopy.setAsInt(defaultValue.A, 3);
+ m_ConfigFile.insertVar(varName, varToCopy);
+ }
+ return defaultValue;
+}
+
+CRGBA CConfiguration::getValue(const CConfigFile::CVar &var, const CRGBA &defaultValue)
+{
+ if (var.size() >= 3)
+ {
+ if (var.size() > 4) nlwarning("RGBA value in config value '%s' is too long, ignoring unused values");
+ return CRGBA((uint8)var.asInt(0), (uint8)var.asInt(1), (uint8)var.asInt(2), var.size() >= 4 ? (uint8)var.asInt(3) : 255);
+ }
+ nlwarning("Invalid RGBA value in config value '%s', reverting to default { %i, %i, %i, %i }", var.Name.c_str(), (sint)defaultValue.R, (sint)defaultValue.G, (sint)defaultValue.B, (sint)defaultValue.A);
+ return defaultValue;
+}
+
+void CConfiguration::cbConfigCallback(NLMISC::CConfigFile::CVar &var)
+{
+ CConfiguration::getInstance()->m_ConfigCallbacks[var.Name](var);
+}
+
+void CConfiguration::cfcbLogFilter(CConfigFile::CVar &var)
+{
+ // from nel/net/service.cpp
+ CLog *log = NULL;
+ if (var.Name == "NegFiltersDebug") log = DebugLog;
+ else if (var.Name == "NegFiltersInfo") log = InfoLog;
+ else if (var.Name == "NegFiltersWarning") log = WarningLog;
+ else if (var.Name == "NegFiltersAssert") log = AssertLog;
+ else if (var.Name == "NegFiltersError") log = ErrorLog;
+ else nlstop;
+
+ // remove all old filters from config file
+ CConfigFile::CVar &oldvar = m_ConfigFile.getVar(var.Name);
+ for (uint j = 0; j < oldvar.size(); j++)
+ log->removeFilter(oldvar.asString(j).c_str());
+
+ // add all new filters from config file
+ for (uint i = 0; i < var.size(); i++)
+ log->addNegativeFilter(var.asString(i).c_str());
+}
+
+/* end of file */
diff --git a/code/nel/tools/3d/mesh_editor/configuration.h b/code/nel/tools/3d/mesh_editor/configuration.h
new file mode 100644
index 000000000..86f8bc161
--- /dev/null
+++ b/code/nel/tools/3d/mesh_editor/configuration.h
@@ -0,0 +1,81 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2010 Winch Gate Property Limited
+//
+// This program is free software: you can redistribute it and/or modify
+// it under the terms of the GNU Affero General Public License as
+// published by the Free Software Foundation, either version 3 of the
+// License, or (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU Affero General Public License for more details.
+//
+// You should have received a copy of the GNU Affero General Public License
+// along with this program. If not, see .
+
+#ifndef NLQT_CONFIGURATION_H
+#define NLQT_CONFIGURATION_H
+#include
+
+// STL includes
+#include