diff --git a/code/nel/tools/3d/CMakeLists.txt b/code/nel/tools/3d/CMakeLists.txt
index bb35cbb5f..034fc5f55 100644
--- a/code/nel/tools/3d/CMakeLists.txt
+++ b/code/nel/tools/3d/CMakeLists.txt
@@ -67,6 +67,11 @@ 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/panoply_preview/CMakeLists.txt b/code/nel/tools/3d/panoply_preview/CMakeLists.txt
new file mode 100644
index 000000000..6d1cbd354
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/CMakeLists.txt
@@ -0,0 +1,36 @@
+
+FILE(GLOB SRCS *.cpp)
+FILE(GLOB HDRS *.h)
+IF (WIN32)
+ FILE(GLOB RSRC *.rc)
+ENDIF (WIN32)
+FILE(GLOB RESOURCES *.qrc)
+
+FILE(GLOB PANOPLY_MAKER ../panoply_maker/color_modifier.cpp ../panoply_maker/color_modifier.h)
+
+SOURCE_GROUP("" FILES ${SRCS} ${HDRS} ${RSRC} ${RESOURCES})
+SOURCE_GROUP("panoply_maker" FILES ${PANOPLY_MAKER})
+
+SET(CMAKE_AUTOMOC ON)
+
+QT5_ADD_RESOURCES(RESOURCE_ADDED ${RESOURCES})
+
+CMAKE_POLICY(SET CMP0020 NEW)
+ADD_EXECUTABLE(nl_panoply_preview WIN32 ${SRC}
+ ${SRCS}
+ ${HDRS}
+ ${RSRC}
+ ${RESOURCE_ADDED}
+ ${PANOPLY_MAKER}
+ )
+
+TARGET_LINK_LIBRARIES(nl_panoply_preview
+ nelmisc
+ nel3d
+ shared_widgets
+ Qt5::Widgets)
+
+NL_DEFAULT_PROPS(nl_panoply_preview "NeL, Tools, 3D: panoply_preview")
+NL_ADD_RUNTIME_FLAGS(nl_panoply_preview)
+
+INSTALL(TARGETS nl_panoply_preview RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT samples3d)
diff --git a/code/nel/tools/3d/panoply_preview/greenpill.ico b/code/nel/tools/3d/panoply_preview/greenpill.ico
new file mode 100644
index 000000000..d2b9e8a20
Binary files /dev/null and b/code/nel/tools/3d/panoply_preview/greenpill.ico differ
diff --git a/code/nel/tools/3d/panoply_preview/icon.rc b/code/nel/tools/3d/panoply_preview/icon.rc
new file mode 100644
index 000000000..64e741cac
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/icon.rc
@@ -0,0 +1 @@
+IDI_ICON1 ICON DISCARDABLE "greenpill.ico"
\ No newline at end of file
diff --git a/code/nel/tools/3d/panoply_preview/main_window.cpp b/code/nel/tools/3d/panoply_preview/main_window.cpp
new file mode 100644
index 000000000..4f7b7ddc2
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/main_window.cpp
@@ -0,0 +1,138 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 "main_window.h"
+
+// STL includes
+
+// Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// NeL includes
+// #include
+#include
+#include
+
+// Project includes
+#include "../shared_widgets/command_log.h"
+#include "panoply_preview.h"
+
+using namespace std;
+using namespace NLMISC;
+
+namespace NLTOOLS {
+
+namespace {
+
+QString nli18n(const char *label)
+{
+ return QString::fromUtf16(CI18N::get(label).c_str());
+}
+
+} /* anonymous namespace */
+
+CMainWindow::CMainWindow(const QMap &customSizeHints, QWidget *parent, Qt::WindowFlags flags)
+ : QMainWindow(parent, flags),
+ m_PanoplyPreview(NULL),
+ m_CommandLog(NULL), m_CommandLogDock(NULL),
+ m_WidgetsMenu(NULL), m_HelpMenu(NULL),
+ m_AboutAct(NULL)
+{
+ setObjectName("CMainWindow");
+ setWindowTitle(tr("NeL Panoply Preview"));
+
+ createActions();
+ createMenus();
+ createToolBars();
+ createStatusBar();
+
+ m_PanoplyPreview = new CPanoplyPreview(this);
+ setCentralWidget(m_PanoplyPreview);
+
+ createDockWindows();
+}
+
+CMainWindow::~CMainWindow()
+{
+
+}
+
+void CMainWindow::createActions()
+{
+ m_AboutAct = new QAction(this);
+ connect(m_AboutAct, SIGNAL(triggered()), this, SLOT(about()));
+
+ m_AboutAct->setText(tr("About"));
+ m_AboutAct->setStatusTip(tr("About"));
+}
+
+void CMainWindow::createMenus()
+{
+ m_WidgetsMenu = menuBar()->addMenu(QString::null);
+
+ m_HelpMenu = menuBar()->addMenu(QString::null);
+ m_HelpMenu->addAction(m_AboutAct);
+
+ m_WidgetsMenu->setTitle(tr("Widgets"));
+ m_HelpMenu->setTitle(tr("Help"));
+}
+
+void CMainWindow::createToolBars()
+{
+
+}
+
+void CMainWindow::createStatusBar()
+{
+ statusBar()->showMessage(tr("Ready"));
+}
+
+void CMainWindow::createDockWindows()
+{
+ // CommandLog (Console)
+ {
+ m_CommandLogDock = new QDockWidget(this);
+ m_CommandLogDock->setWindowTitle(tr("Console"));
+ m_CommandLogDock->setAllowedAreas(Qt::TopDockWidgetArea | Qt::BottomDockWidgetArea);
+ m_CommandLog = new NLQT::CCommandLogDisplayer(m_CommandLogDock);
+ m_CommandLogDock->setWidget(m_CommandLog);
+ addDockWidget(Qt::BottomDockWidgetArea, m_CommandLogDock);
+ m_WidgetsMenu->addAction(m_CommandLogDock->toggleViewAction());
+ }
+}
+
+void CMainWindow::about()
+{
+ QMessageBox::about(this, tr("Panoply Preview"), tr("Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)"));
+}
+
+} /* namespace NLTOOLS */
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/main_window.h b/code/nel/tools/3d/panoply_preview/main_window.h
new file mode 100644
index 000000000..3e3d2f025
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/main_window.h
@@ -0,0 +1,95 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 NLTOOLS_MAIN_WINDOW_H
+#define NLTOOLS_MAIN_WINDOW_H
+#include
+
+// STL includes
+
+// Qt includes
+#include
+
+// NeL includes
+#include
+#include
+#include
+#include
+#include
+
+// Project includes
+// ...
+
+class QTreeView;
+class QDirModel;
+class QUndoStack;
+class QScrollArea;
+
+namespace NLQT {
+ class CCommandLogDisplayer;
+}
+
+namespace NLTOOLS {
+ class CPanoplyPreview;
+
+/**
+ * CMainWindow
+ * \brief CMainWindow
+ * \date 2014-09-19 09:38GMT
+ * \author Jan BOON (jan.boon@kaetemi.be)
+ */
+class CMainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ CMainWindow(const QMap &customSizeHints, QWidget *parent = 0, Qt::WindowFlags flags = 0);
+ virtual ~CMainWindow();
+
+ inline QMenu *widgetsMenu() { return m_WidgetsMenu; }
+
+private slots:
+ void about();
+
+private:
+ void createActions();
+ void createMenus();
+ void createToolBars();
+ void createStatusBar();
+ void createDockWindows();
+
+private:
+ CMainWindow(const CMainWindow &);
+ CMainWindow &operator=(const CMainWindow &);
+
+private:
+ CPanoplyPreview *m_PanoplyPreview;
+
+ NLQT::CCommandLogDisplayer *m_CommandLog;
+ QDockWidget *m_CommandLogDock;
+
+ QMenu *m_WidgetsMenu;
+ QMenu *m_HelpMenu;
+
+ QAction *m_AboutAct;
+
+}; /* class CMainWindow */
+
+} /* namespace NLTOOLS */
+
+#endif /* #ifndef NLTOOLS_MAIN_WINDOW_H */
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/panoply_preview.cpp b/code/nel/tools/3d/panoply_preview/panoply_preview.cpp
new file mode 100644
index 000000000..964711eea
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/panoply_preview.cpp
@@ -0,0 +1,523 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 "panoply_preview.h"
+
+// STL includes
+
+// Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// NeL includes
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Project includes
+#include "main_window.h"
+#include "../panoply_maker/color_modifier.h"
+
+using namespace std;
+using namespace NLMISC;
+
+namespace NLTOOLS {
+
+class CColorThread : public NLMISC::IRunnable
+{
+public:
+ // Called when a thread is run.
+ virtual void run()
+ {
+ while (Running)
+ {
+ SettingsMutex.enter();
+ if (!Running)
+ {
+ SettingsMutex.leave();
+ return;
+ }
+ if (!Process)
+ {
+ SettingsMutex.leave();
+ nlSleep(10); // TODO: Should wait on an event signal...
+ continue;
+ }
+ // nldebug("Update color modifier");
+ m_ColorModifier.Hue = Hue;
+ m_ColorModifier.Lightness = Lightness;
+ m_ColorModifier.Saturation = Saturation;
+ m_ColorModifier.Luminosity = Luminosity;
+ m_ColorModifier.Contrast = Contrast;
+ Process = false;
+ SettingsMutex.leave();
+
+ BitmapMutex.enter();
+ if (!Running)
+ {
+ BitmapMutex.leave();
+ return;
+ }
+ if (!BitmapsOk)
+ {
+ nldebug("Bitmaps not ready");
+ BitmapMutex.leave();
+ nlSleep(500);
+ continue;
+ }
+ float retDeltaHue;
+ DestBitmap = ColorBitmap;
+ m_ColorModifier.convertBitmap(DestBitmap, ColorBitmap, MaskBitmap, retDeltaHue);
+ BitmapMutex.leave();
+
+ PanoplyPreview->displayBitmap(DestBitmap);
+
+ nlSleep(10); // TODO: Should wait on an event signal...
+ }
+ }
+
+ CColorThread() : PanoplyPreview(NULL), BitmapsOk(false), Hue(0), Lightness(0), Saturation(0), Luminosity(0), Contrast(0), Process(false), Running(true) { }
+ virtual ~CColorThread() { }
+ virtual void getName (std::string &result) const { result = "CColorThread"; }
+
+private:
+ CColorModifier m_ColorModifier;
+
+public:
+ CPanoplyPreview *PanoplyPreview;
+
+ NLMISC::CMutex BitmapMutex;
+ NLMISC::CBitmap ColorBitmap;
+ NLMISC::CBitmap MaskBitmap;
+ bool BitmapsOk;
+ NLMISC::CBitmap DestBitmap;
+
+ NLMISC::CMutex SettingsMutex;
+ float Hue;
+ float Lightness;
+ float Saturation;
+ float Luminosity;
+ float Contrast;
+ bool Process;
+
+ bool Running;
+};
+
+// *****************************************************************
+
+CPanoplyPreview::CPanoplyPreview(CMainWindow *parent) : QWidget(parent)
+{
+ connect(this, SIGNAL(tSigBitmap()), this, SLOT(tSlotBitmap()));
+
+ createDockWindows(parent);
+
+ m_Image = new QImage(512, 512, QImage::Format_RGB32);
+ m_Pixmap = new QPixmap(512, 512);
+
+ setMinimumWidth(512);
+ setMinimumHeight(512);
+
+ m_ColorThread = new CColorThread();
+ m_ColorThread->PanoplyPreview = this;
+ m_Thread = IThread::create(m_ColorThread);
+ m_Thread->start();
+}
+
+CPanoplyPreview::~CPanoplyPreview()
+{
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->BitmapMutex.enter();
+ m_ColorThread->Running = false;
+ m_ColorThread->BitmapMutex.leave();
+ m_ColorThread->SettingsMutex.leave();
+ m_Thread->wait();
+ delete m_Thread;
+ delete m_ColorThread;
+}
+
+void CPanoplyPreview::paintEvent(QPaintEvent* e)
+{
+ QPainter painter(this);
+ painter.drawPixmap(0, 0, *m_Pixmap);
+}
+
+void CPanoplyPreview::displayBitmap(const CBitmap &bitmap) // Called from thread!
+{
+ // nldebug("received bitmap");
+
+ m_ColorThread->BitmapMutex.enter();
+ m_ImageMutex.enter();
+
+ const char *buffer = (const char *)&bitmap.getPixels()[0];
+
+ if (bitmap.getWidth() != m_Image->width() || bitmap.getHeight() != m_Image->height())
+ {
+ QImage *image = m_Image;
+ m_Image = new QImage(bitmap.getWidth(), bitmap.getHeight(), QImage::Format_RGB32);
+ delete image;
+ }
+
+ for (uint32 y = 0; y < bitmap.getHeight(); ++y)
+ {
+ uint8 *dst = (uint8 *)m_Image->scanLine(y);
+ const uint8 *src = (const uint8 *)&buffer[y * bitmap.getWidth() * sizeof(uint32)];
+ for (uint32 x = 0; x < bitmap.getWidth(); ++x)
+ {
+ uint32 xb = x * 4;
+ dst[xb + 0] = src[xb + 2];
+ dst[xb + 1] = src[xb + 1];
+ dst[xb + 2] = src[xb + 0];
+ dst[xb + 3] = src[xb + 3];
+ }
+
+ //memcpy(m_Image->scanLine(y), &buffer[y * bitmap.getWidth() * sizeof(uint32)], sizeof(uint32) * bitmap.getWidth());
+ }
+
+ m_ImageMutex.leave();
+ m_ColorThread->BitmapMutex.leave();
+
+ tSigBitmap();
+}
+
+void CPanoplyPreview::tSlotBitmap()
+{
+ // nldebug("display bitmap");
+
+ m_ImageMutex.enter();
+
+ if (m_Image->width() != m_Pixmap->width()
+ || m_Image->height() != m_Pixmap->height())
+ {
+ QPixmap *pixmap = m_Pixmap;
+ m_Pixmap = new QPixmap(m_Image->width(), m_Image->height());
+ setMinimumWidth(m_Pixmap->width());
+ setMinimumHeight(m_Pixmap->height());
+ delete pixmap;
+ }
+ m_Pixmap->convertFromImage(*m_Image);
+ repaint();
+
+ m_ImageMutex.leave();
+
+}
+
+void CPanoplyPreview::colorEdited(const QString &text)
+{
+ m_ColorFile = text;
+}
+
+void CPanoplyPreview::maskEdited(const QString &text)
+{
+ m_MaskFile = text;
+}
+
+void CPanoplyPreview::goPushed(bool)
+{
+ // nldebug("push bitmaps");
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->BitmapMutex.enter();
+ m_ColorThread->BitmapsOk = false;
+
+ try
+ {
+ {
+ NLMISC::CIFile is;
+ if (!is.open(m_ColorFile.toLocal8Bit().data()))
+ throw NLMISC::Exception("Cannot open file '%s'", m_ColorFile.toLocal8Bit().data());
+ uint32 depth = m_ColorThread->ColorBitmap.load(is);
+ if (depth == 0 || m_ColorThread->ColorBitmap.getPixels().empty())
+ throw NLMISC::Exception("Failed to load bitmap '%s'", m_ColorFile.toLocal8Bit().data());
+ if (m_ColorThread->ColorBitmap.PixelFormat != NLMISC::CBitmap::RGBA)
+ m_ColorThread->ColorBitmap.convertToType(NLMISC::CBitmap::RGBA);
+ }
+ {
+ NLMISC::CIFile is;
+ if (!is.open(m_MaskFile.toLocal8Bit().data()))
+ throw NLMISC::Exception("Cannot open file '%s'", m_MaskFile.toLocal8Bit().data());
+ uint32 depth = m_ColorThread->MaskBitmap.load(is);
+ if (depth == 0 || m_ColorThread->MaskBitmap.getPixels().empty())
+ throw NLMISC::Exception("Failed to load bitmap '%s'", m_MaskFile.toLocal8Bit().data());
+ if (m_ColorThread->MaskBitmap.PixelFormat != NLMISC::CBitmap::RGBA)
+ m_ColorThread->MaskBitmap.convertToType(NLMISC::CBitmap::RGBA);
+ }
+ {
+ m_ColorThread->BitmapsOk = true;
+ m_ColorThread->Process = true;
+ }
+ }
+ catch (const NLMISC::Exception &e)
+ {
+ nlwarning("Exception: '%s'", e.what());
+ }
+
+ m_ColorThread->BitmapMutex.leave();
+ m_ColorThread->SettingsMutex.leave();
+ // nldebug("done pushing butmaps");
+}
+
+void CPanoplyPreview::hueChanged(int value)
+{
+ float v = (float)value;
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->Hue = v;
+ m_ColorThread->Process = true;
+ m_ColorThread->SettingsMutex.leave();
+}
+
+void CPanoplyPreview::lightnessChanged(int value)
+{
+ float v = (float)value * 0.01f;
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->Lightness = v;
+ m_ColorThread->Process = true;
+ m_ColorThread->SettingsMutex.leave();
+}
+
+void CPanoplyPreview::saturationChanged(int value)
+{
+ float v = (float)value * 0.01f;
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->Saturation = v;
+ m_ColorThread->Process = true;
+ m_ColorThread->SettingsMutex.leave();
+}
+
+void CPanoplyPreview::luminosityChanged(int value)
+{
+ float v = (float)value;
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->Luminosity = v;
+ m_ColorThread->Process = true;
+ m_ColorThread->SettingsMutex.leave();
+}
+
+void CPanoplyPreview::contrastChanged(int value)
+{
+ float v = (float)value;
+ m_ColorThread->SettingsMutex.enter();
+ m_ColorThread->Contrast = v;
+ m_ColorThread->Process = true;
+ m_ColorThread->SettingsMutex.leave();
+}
+
+// *****************************************************************
+
+CSliderTextEdit::CSliderTextEdit(QWidget *parent, QLineEdit *lineEdit, float scale) : QSlider(Qt::Horizontal, parent), m_LineEdit(lineEdit), m_Updating(false), m_Scale(scale)
+{
+ connect(this, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int)));
+ connect(lineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(lineEditTextEdited(const QString &)));
+}
+
+CSliderTextEdit::~CSliderTextEdit()
+{
+
+}
+
+void CSliderTextEdit::lineEditTextEdited(const QString &text)
+{
+ if (!m_Updating)
+ {
+ m_Updating = true;
+ setValue((int)(text.toFloat() * m_Scale));
+ m_Updating = false;
+ }
+}
+
+void CSliderTextEdit::sliderValueChanged(int value)
+{
+ if (!m_Updating)
+ {
+ m_Updating = true;
+ m_LineEdit->setText(QString::number((double)value / (double)m_Scale));
+ m_Updating = false;
+ }
+}
+
+// *****************************************************************
+
+void CPanoplyPreview::createDockWindows(CMainWindow *mainWindow)
+{
+ nlassert(mainWindow);
+
+ // Color Modifier
+ {
+ QDockWidget *dockWidget = new QDockWidget(mainWindow);
+ nlassert(dockWidget);
+ dockWidget->setWindowTitle(tr("Color Modifier"));
+ dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
+ QScrollArea *scrollArea = new QScrollArea(dockWidget);
+ scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
+ scrollArea->setWidgetResizable(true);
+ QWidget *widget = new QWidget(scrollArea);
+ QVBoxLayout *vboxLayout = new QVBoxLayout(widget);
+
+ // Input File Paths
+ {
+ QGroupBox *groupBox = new QGroupBox(widget);
+ groupBox->setTitle(tr("Input File Paths"));
+ QGridLayout *groupLayout = new QGridLayout(groupBox);
+
+ QLabel *colorLabel = new QLabel(groupBox);
+ colorLabel->setText(tr("Color: "));
+ groupLayout->addWidget(colorLabel, 0, 0);
+
+ QLineEdit *colorFile = new QLineEdit(groupBox);
+ colorFile->setText("W:\\database\\stuff\\fyros\\agents\\_textures\\actors\\fy_hof_armor00_arm01_c1.png");
+ groupLayout->addWidget(colorFile, 0, 1);
+
+ m_ColorFile = colorFile->text();
+ connect(colorFile, SIGNAL(textEdited(const QString &)), this, SLOT(colorEdited(const QString &)));
+
+ QLabel *maskLabel = new QLabel(groupBox);
+ maskLabel->setText(tr("Mask: "));
+ groupLayout->addWidget(maskLabel, 1, 0);
+
+ QLineEdit *maskFile = new QLineEdit(groupBox);
+ maskFile->setText("W:\\database\\stuff\\fyros\\agents\\_textures\\actors\\mask\\fy_hof_armor00_arm01_c1_skin.png");
+ groupLayout->addWidget(maskFile, 1, 1);
+
+ m_MaskFile = maskFile->text();
+ connect(maskFile, SIGNAL(textEdited(const QString &)), this, SLOT(maskEdited(const QString &)));
+
+ QPushButton *go = new QPushButton(groupBox);
+ go->setText(tr("Go"));
+ groupLayout->addWidget(go, 2, 0, 1, 2);
+
+ connect(go, SIGNAL(clicked(bool)), this, SLOT(goPushed(bool)));
+
+ groupBox->setLayout(groupLayout);
+ vboxLayout->addWidget(groupBox);
+ }
+
+ // Color Modifier
+ {
+ QGroupBox *groupBox = new QGroupBox(widget);
+ groupBox->setTitle(tr("Color Modifier"));
+ QGridLayout *groupLayout = new QGridLayout(groupBox);
+
+ QLabel *label;
+ QLineEdit *edit;
+ CSliderTextEdit *slider;
+
+ label = new QLabel(groupBox);
+ label->setText(tr("Hue [0, 360]: "));
+ groupLayout->addWidget(label, 0, 0);
+
+ edit = new QLineEdit(groupBox);
+ edit->setText("0");
+ groupLayout->addWidget(edit, 0, 1);
+
+ slider = new CSliderTextEdit(groupBox, edit, 1.0f);
+ slider->setMinimum(0);
+ slider->setMaximum(360);
+ slider->setValue(0);
+ groupLayout->addWidget(slider, 1, 0, 1, 2);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(hueChanged(int)));
+
+ label = new QLabel(groupBox);
+ label->setText(tr("Lightness [-1, 1]: "));
+ groupLayout->addWidget(label, 2, 0);
+
+ edit = new QLineEdit(groupBox);
+ edit->setText("0");
+ groupLayout->addWidget(edit, 2, 1);
+
+ slider = new CSliderTextEdit(groupBox, edit, 100.0f);
+ slider->setMinimum(-100);
+ slider->setMaximum(100);
+ slider->setValue(0);
+ groupLayout->addWidget(slider, 3, 0, 1, 2);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(lightnessChanged(int)));
+
+ label = new QLabel(groupBox);
+ label->setText(tr("Saturation [-1, 1]: "));
+ groupLayout->addWidget(label, 4, 0);
+
+ edit = new QLineEdit(groupBox);
+ edit->setText("0");
+ groupLayout->addWidget(edit, 4, 1);
+
+ slider = new CSliderTextEdit(groupBox, edit, 100.0f);
+ slider->setMinimum(-100);
+ slider->setMaximum(100);
+ slider->setValue(0);
+ groupLayout->addWidget(slider, 5, 0, 1, 2);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(saturationChanged(int)));
+
+ label = new QLabel(groupBox);
+ label->setText(tr("Luminosity [-100, 100]: "));
+ groupLayout->addWidget(label, 6, 0);
+
+ edit = new QLineEdit(groupBox);
+ edit->setText("0");
+ groupLayout->addWidget(edit, 6, 1);
+
+ slider = new CSliderTextEdit(groupBox, edit, 1.0f);
+ slider->setMinimum(-100);
+ slider->setMaximum(100);
+ slider->setValue(0);
+ groupLayout->addWidget(slider, 7, 0, 1, 2);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(luminosityChanged(int)));
+
+ label = new QLabel(groupBox);
+ label->setText(tr("Contrast [-100, 100]: "));
+ groupLayout->addWidget(label, 8, 0);
+
+ edit = new QLineEdit(groupBox);
+ edit->setText("0");
+ groupLayout->addWidget(edit, 8, 1);
+
+ slider = new CSliderTextEdit(groupBox, edit, 1.0f);
+ slider->setMinimum(-100);
+ slider->setMaximum(100);
+ slider->setValue(0);
+ groupLayout->addWidget(slider, 9, 0, 1, 2);
+
+ connect(slider, SIGNAL(valueChanged(int)), this, SLOT(contrastChanged(int)));
+
+ groupBox->setLayout(groupLayout);
+ vboxLayout->addWidget(groupBox);
+ }
+
+ vboxLayout->addStretch();
+ widget->setLayout(vboxLayout);
+ scrollArea->setWidget(widget);
+ dockWidget->setWidget(scrollArea);
+ mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
+ mainWindow->widgetsMenu()->addAction(dockWidget->toggleViewAction());
+ }
+}
+
+} /* namespace NLTOOLS */
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/panoply_preview.h b/code/nel/tools/3d/panoply_preview/panoply_preview.h
new file mode 100644
index 000000000..9fbe2bad3
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/panoply_preview.h
@@ -0,0 +1,125 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 NLTOOLS_PANOPLY_PREVIEW_H
+#define NLTOOLS_PANOPLY_PREVIEW_H
+#include
+
+// STL includes
+
+// Qt includes
+#include
+#include
+#include
+#include
+#include
+#include
+
+// NeL includes
+#include
+#include
+
+// Project includes
+
+namespace NLMISC {
+ class CBitmap;
+ class IThread;
+}
+
+namespace NLTOOLS {
+ class CMainWindow;
+ class CColorThread;
+
+/**
+ * CPanoplyPreview
+ * \brief CPanoplyPreview
+ * \date 2014-09-19 09:38GMT
+ * \author Jan BOON (jan.boon@kaetemi.be)
+ */
+class CPanoplyPreview : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CPanoplyPreview(CMainWindow *parent);
+ virtual ~CPanoplyPreview();
+
+ void displayBitmap(const NLMISC::CBitmap &bitmap); // Called from thread!
+
+protected:
+ virtual void paintEvent(QPaintEvent *e);
+
+signals:
+ void tSigBitmap();
+
+private slots:
+ void tSlotBitmap();
+
+ void colorEdited(const QString &text);
+ void maskEdited(const QString &text);
+ void goPushed(bool);
+
+ void hueChanged(int value);
+ void lightnessChanged(int value);
+ void saturationChanged(int value);
+ void luminosityChanged(int value);
+ void contrastChanged(int value);
+
+private:
+ void createDockWindows(CMainWindow *mainWindow);
+
+private:
+ NLMISC::IThread *m_Thread;
+ CColorThread *m_ColorThread;
+
+ QString m_ColorFile;
+ QString m_MaskFile;
+
+ QImage *m_Image;
+ QPixmap *m_Pixmap;
+
+ NLMISC::CMutex m_ImageMutex;
+
+private:
+ CPanoplyPreview(const CPanoplyPreview &);
+ CPanoplyPreview &operator=(const CPanoplyPreview &);
+
+}; /* class CPanoplyPreview */
+
+class CSliderTextEdit : public QSlider
+{
+ Q_OBJECT
+
+public:
+ CSliderTextEdit(QWidget *parent, QLineEdit *lineEdit, float scale);
+ virtual ~CSliderTextEdit();
+
+private slots:
+ void lineEditTextEdited(const QString &text);
+ void sliderValueChanged(int value);
+
+private:
+ QLineEdit *m_LineEdit;
+ bool m_Updating;
+ float m_Scale;
+
+};
+
+} /* namespace NLTOOLS */
+
+#endif /* #ifndef NLTOOLS_PANOPLY_PREVIEW_H */
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/tool_config.h b/code/nel/tools/3d/panoply_preview/tool_config.h
new file mode 100644
index 000000000..94e53d2dc
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/tool_config.h
@@ -0,0 +1,105 @@
+// 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 NLTOOLS_CONFIG_H
+#define NLTOOLS_CONFIG_H
+#include
+
+
+
+// use the default log.log file (not erased on use)
+// #define NLTOOLS_USE_LOG_LOG false
+
+
+
+// the config file name
+// #define NLTOOLS_CONFIG_FILE "panoply_preview.cfg"
+// #define NLTOOLS_CONFIG_FILE_DEFAULT "panoply_preview_default.cfg"
+
+
+
+// use panoply_preview log file
+// #define NLTOOLS_USE_LOG 1
+
+// panoply_preview log file name
+#define NLTOOLS_LOG_FILE "panoply_preview.log"
+
+// clear panoply_preview log before use
+#define NLTOOLS_ERASE_LOG true
+
+// version number
+#define NLTOOLS_VERSION "0.10.0"
+
+
+
+// use the low fragmentation heap (windows feature)
+// #define NLTOOLS_LOW_FRAGMENTATION_HEAP 1
+
+
+
+// temporary dev tags
+//#define NL_DEV_STEREO 0
+//#define NL_DEV_MEMLEAK 1
+//#define NL_DEV_NET 0
+//#define NL_DEV_NETNEW 1
+//#define NL_DEV_CG 0
+//#define NL_DEV_BULLET 0
+
+
+
+// some default defines
+#if FINAL_VERSION
+# if !defined(NLTOOLS_USE_LOG_LOG)
+# define NLTOOLS_USE_LOG_LOG false
+# endif
+# if !defined(NLTOOLS_USE_LOG)
+# define NLTOOLS_USE_LOG 0
+# endif
+#endif
+
+#if !defined (NLTOOLS_USE_LOG_LOG)
+# define NLTOOLS_USE_LOG_LOG true
+#endif
+#if !defined (NLTOOLS_USE_LOG)
+# define NLTOOLS_USE_LOG 1
+#endif
+
+#if !defined (NLTOOLS_LOW_FRAGMENTATION_HEAP)
+# ifdef NL_OS_WINDOWS
+# define NLTOOLS_LOW_FRAGMENTATION_HEAP 1
+# else
+# define NLTOOLS_LOW_FRAGMENTATION_HEAP 0
+# endif
+#endif
+
+// for compatibility with old configuration
+#ifndef NLTOOLS_CONFIG_FILE
+# ifndef NLTOOLS_CONFIG
+# define NLTOOLS_CONFIG_FILE "panoply_preview.cfg"
+# else
+# define NLTOOLS_CONFIG_FILE NLTOOLS_CONFIG "panoply_preview.cfg"
+# endif
+#endif
+
+#ifndef NLTOOLS_CONFIG_FILE_DEFAULT
+# define NLTOOLS_CONFIG_FILE_DEFAULT "panoply_preview_default.cfg"
+#endif
+
+
+
+#endif /* #ifndef NLTOOLS_CONFIG_H */
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/tool_main.cpp b/code/nel/tools/3d/panoply_preview/tool_main.cpp
new file mode 100644
index 000000000..d1e08205f
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/tool_main.cpp
@@ -0,0 +1,176 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 "tool_main.h"
+
+// STL includes
+#include
+#ifdef NL_OS_WINDOWS
+# include
+# include
+# include
+#endif
+
+// Qt includes
+#include
+#include
+#include
+#include
+
+// NeL includes
+#include
+#include
+#include
+#include
+#include
+#include
+
+// Project includes
+#include "../shared_widgets/common.h"
+#include "tool_config.h"
+#include "main_window.h"
+
+using namespace std;
+using namespace NLMISC;
+
+namespace NLTOOLS {
+
+namespace {
+
+CFileDisplayer *s_FileDisplayer = NULL;
+
+} /* anonymous namespace */
+
+} /* namespace NLTOOLS */
+
+void usage()
+{
+ /* from Qt sample */
+
+ qWarning() << "Usage: mainwindow [-SizeHint x] ...";
+ exit(1);
+}
+
+QMap parseCustomSizeHints(int argc, char **argv)
+{
+ /* from Qt sample */
+
+ QMap result;
+
+ for (int i = 1; i < argc; ++i) {
+ QString arg = QString::fromLocal8Bit(argv[i]);
+
+ if (arg.startsWith(QLatin1String("-SizeHint"))) {
+ QString name = arg.mid(9);
+ if (name.isEmpty())
+ usage();
+ if (++i == argc)
+ usage();
+ QString sizeStr = QString::fromLocal8Bit(argv[i]);
+ int idx = sizeStr.indexOf(QLatin1Char('x'));
+ if (idx == -1)
+ usage();
+ bool ok;
+ int w = sizeStr.left(idx).toInt(&ok);
+ if (!ok)
+ usage();
+ int h = sizeStr.mid(idx + 1).toInt(&ok);
+ if (!ok)
+ usage();
+ result[name] = QSize(w, h);
+ }
+ }
+
+ return result;
+}
+
+#ifdef NL_OS_WINDOWS
+# ifdef _UNICODE
+# define tstring wstring
+# else
+# define tstring string
+# endif
+#endif
+
+sint main(int argc, char **argv)
+{
+ // go nel!
+ {
+ // use log.log if NEL_LOG_IN_FILE and NLTOOLS_USE_LOG_LOG defined as 1
+ createDebug(NULL, NLTOOLS_USE_LOG_LOG, false);
+
+#if NLTOOLS_USE_LOG
+ // create toverhex_client.log
+ // filedisplayer only deletes the 001 etc
+ if (NLTOOLS_ERASE_LOG && CFile::isExists(NLTOOLS_LOG_FILE))
+ CFile::deleteFile(NLTOOLS_LOG_FILE);
+ // initialize the log file
+ NLTOOLS::s_FileDisplayer = new CFileDisplayer();
+ NLTOOLS::s_FileDisplayer->setParam(NLTOOLS_LOG_FILE, NLTOOLS_ERASE_LOG);
+ DebugLog->addDisplayer(NLTOOLS::s_FileDisplayer);
+ InfoLog->addDisplayer(NLTOOLS::s_FileDisplayer);
+ WarningLog->addDisplayer(NLTOOLS::s_FileDisplayer);
+ AssertLog->addDisplayer(NLTOOLS::s_FileDisplayer);
+ ErrorLog->addDisplayer(NLTOOLS::s_FileDisplayer);
+#endif
+
+ nlinfo("Welcome to NeL!");
+ }
+
+ // low fragmentation heap (windows)
+#if NLTOOLS_LOW_FRAGMENTATION_HEAP
+ ULONG heapFragValue = 2; // enable low fragmentation heap
+ if (HeapSetInformation(GetProcessHeap(),
+ HeapCompatibilityInformation,
+ &heapFragValue, sizeof(heapFragValue)))
+ {
+ nlinfo("HeapSetInformation OK!\n");
+ }
+ else
+ {
+ nlwarning("HeapSetInformation FAIL! (%d)\n", GetLastError());
+ }
+#endif
+
+#ifdef NL_OS_WINDOWS
+ HRESULT hr;
+ hr = hr = CoInitializeEx(NULL, COINIT_MULTITHREADED);
+ bool coInitOk = (hr == S_OK) || (hr == S_FALSE);
+#endif
+
+ CSheetId::initWithoutSheet();
+
+ NLQT::preApplication();
+ QApplication app(argc, const_cast(argv));
+ NLQT::postApplication();
+
+ QMap customSizeHints = parseCustomSizeHints(argc, argv);
+
+ NLTOOLS::CMainWindow mainWin(customSizeHints);
+ mainWin.resize(800, 600);
+ mainWin.show(); // calls isVisible(true)
+
+ int result = app.exec();
+
+#ifdef NL_OS_WINDOWS
+ if (coInitOk) CoUninitialize();
+#endif
+
+ return result;
+}
+
+/* end of file */
diff --git a/code/nel/tools/3d/panoply_preview/tool_main.h b/code/nel/tools/3d/panoply_preview/tool_main.h
new file mode 100644
index 000000000..75eae7204
--- /dev/null
+++ b/code/nel/tools/3d/panoply_preview/tool_main.h
@@ -0,0 +1,33 @@
+// NeL - MMORPG Framework
+// Copyright (C) 2014 Jan BOON (jan.boon@kaetemi.be)
+//
+// 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 NLTOOLS_MAIN_H
+#define NLTOOLS_MAIN_H
+#include
+
+// STL includes
+
+// NeL includes
+
+// Project includes
+
+namespace NLTOOLS {
+
+} /* namespace NLTOOLS */
+
+#endif /* #ifndef NLTOOLS_MAIN_H */
+
+/* end of file */
diff --git a/code/nel/tools/3d/shared_widgets/CMakeLists.txt b/code/nel/tools/3d/shared_widgets/CMakeLists.txt
new file mode 100644
index 000000000..153995dd2
--- /dev/null
+++ b/code/nel/tools/3d/shared_widgets/CMakeLists.txt
@@ -0,0 +1,23 @@
+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})
+
+CMAKE_POLICY(SET CMP0020 NEW)
+NL_TARGET_LIB(shared_widgets ${SRCS} ${HDRS} ${RSRC} ${RESOURCE_ADDED})
+
+TARGET_LINK_LIBRARIES(shared_widgets nelmisc nel3d Qt5::Widgets)
+NL_DEFAULT_PROPS(shared_widgets "NeL, Tools, 3D: Shared Widgets")
+NL_ADD_RUNTIME_FLAGS(shared_widgets)
+
+IF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)
+ INSTALL(TARGETS shared_widgets LIBRARY DESTINATION ${NL_LIB_PREFIX} ARCHIVE DESTINATION ${NL_LIB_PREFIX} COMPONENT tools3d)
+ENDIF((WITH_INSTALL_LIBRARIES AND WITH_STATIC) OR NOT WITH_STATIC)
diff --git a/code/nel/tools/3d/shared_widgets/command_log.cpp b/code/nel/tools/3d/shared_widgets/command_log.cpp
new file mode 100644
index 000000000..d7b9ee735
--- /dev/null
+++ b/code/nel/tools/3d/shared_widgets/command_log.cpp
@@ -0,0 +1,159 @@
+/*
+
+Copyright (C) 2010-2015 by authors
+Author: Jan Boon
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#include
+#include "command_log.h"
+
+// STL includes
+
+// Qt includes
+#include
+
+// NeL includes
+#include
+#include
+#include
+#include
+
+// Project includes
+
+using namespace std;
+using namespace NLMISC;
+
+namespace NLQT {
+
+CCommandLog::CCommandLog(QWidget *parent) : QWidget(parent)
+{
+ m_DisplayerOutput = new QTextEdit();
+ m_DisplayerOutput->setReadOnly(true);
+ m_DisplayerOutput->setFocusPolicy(Qt::NoFocus);
+ m_CommandInput = new QLineEdit();
+
+ QVBoxLayout *layout = new QVBoxLayout();
+ layout->addWidget(m_DisplayerOutput);
+ layout->addWidget(m_CommandInput);
+ setLayout(layout);
+
+ connect(m_CommandInput, SIGNAL(returnPressed()), this, SLOT(returnPressed()));
+ connect(this, SIGNAL(tSigDisplay(const QColor &, const QString &)), this, SLOT(tSlotDisplay(const QColor &, const QString &)));
+
+}
+
+CCommandLog::~CCommandLog()
+{
+
+}
+
+void CCommandLog::doDisplay(const CLog::TDisplayInfo& args, const char *message)
+{
+ QColor color;
+ switch (args.LogType)
+ {
+ case CLog::LOG_DEBUG:
+ color = Qt::gray;
+ break;
+ case CLog::LOG_STAT:
+ color = Qt::green;
+ break;
+ case CLog::LOG_NO:
+ case CLog::LOG_UNKNOWN:
+ case CLog::LOG_INFO:
+ color = Qt::white;
+ break;
+ case CLog::LOG_WARNING:
+ color = Qt::yellow;
+ break;
+ case CLog::LOG_ERROR:
+ case CLog::LOG_ASSERT:
+ color = Qt::red;
+ break;
+ default:
+ color = Qt::black;
+ break;
+ }
+
+ std::string str = NLMISC::CWindowDisplayer::stringifyMessage(args, message);
+
+ tSigDisplay(color, str.substr(0, str.size() - 1).c_str());
+}
+
+void CCommandLog::tSlotDisplay(const QColor &c, const QString &text)
+{
+ m_DisplayerOutput->setTextColor(c);
+ m_DisplayerOutput->append(text);
+}
+
+void CCommandLog::returnPressed()
+{
+ QString text = m_CommandInput->text();
+ if (text.isEmpty())
+ return;
+
+ std::string cmd = text.toLocal8Bit().data();
+ execCommand(cmd);
+ if (m_Func) m_Func(cmd);
+
+ m_CommandInput->clear();
+}
+
+CCommandLogDisplayer::CCommandLogDisplayer(QWidget *parent) : CCommandLog(parent)
+{
+ connect(this, SIGNAL(execCommand(const std::string &)), this, SLOT(execCommandLog(const std::string &)));
+ DebugLog->addDisplayer(this);
+ InfoLog->addDisplayer(this);
+ WarningLog->addDisplayer(this);
+ AssertLog->addDisplayer(this);
+ ErrorLog->addDisplayer(this);
+ m_Log.addDisplayer(this);
+}
+
+CCommandLogDisplayer::~CCommandLogDisplayer()
+{
+ DebugLog->removeDisplayer(this);
+ InfoLog->removeDisplayer(this);
+ WarningLog->removeDisplayer(this);
+ AssertLog->removeDisplayer(this);
+ ErrorLog->removeDisplayer(this);
+ m_Log.removeDisplayer(this);
+}
+
+void CCommandLogDisplayer::doDisplay(const NLMISC::CLog::TDisplayInfo& args, const char *message)
+{
+ CCommandLog::doDisplay(args, message);
+}
+
+void CCommandLogDisplayer::execCommandLog(const std::string &cmd)
+{
+ m_Log.displayRawNL("> %s", cmd.c_str());
+ ICommand::execute(cmd, m_Log);
+}
+
+} /* namespace NLQT */
+
+/* end of file */
diff --git a/code/nel/tools/3d/shared_widgets/command_log.h b/code/nel/tools/3d/shared_widgets/command_log.h
new file mode 100644
index 000000000..d92f84b72
--- /dev/null
+++ b/code/nel/tools/3d/shared_widgets/command_log.h
@@ -0,0 +1,111 @@
+/*
+
+Copyright (C) 2010-2015 by authors
+Author: Jan Boon
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NLQT_COMMAND_LOG_H
+#define NLQT_COMMAND_LOG_H
+#include
+
+// STL includes
+
+// Qt includes
+#include
+#include
+#include
+
+// NeL includes
+#include
+#include
+#include
+
+// Project includes
+
+namespace NLQT {
+
+typedef NLMISC::CCallback TCommandExecute;
+
+class CCommandLog : public QWidget
+{
+ Q_OBJECT
+
+public:
+ CCommandLog(QWidget *parent);
+ virtual ~CCommandLog();
+
+ void setExecCommand(const TCommandExecute &func) { m_Func = func; }
+ void doDisplay(const NLMISC::CLog::TDisplayInfo& args, const char *message);
+
+ void clear() { m_DisplayerOutput->clear(); }
+
+signals:
+ void tSigDisplay(const QColor &c, const QString &text);
+ void execCommand(const std::string &cmd);
+
+private slots:
+ void returnPressed();
+ void tSlotDisplay(const QColor &c, const QString &text);
+
+private:
+ QTextEdit *m_DisplayerOutput;
+ QLineEdit *m_CommandInput;
+ TCommandExecute m_Func;
+
+private:
+ CCommandLog(const CCommandLog &);
+ CCommandLog &operator=(const CCommandLog &);
+
+}; /* class CCommandLog */
+
+class CCommandLogDisplayer : public CCommandLog, public NLMISC::IDisplayer
+{
+ Q_OBJECT
+
+public:
+ CCommandLogDisplayer(QWidget *parent);
+ virtual ~CCommandLogDisplayer();
+
+protected:
+ virtual void doDisplay(const NLMISC::CLog::TDisplayInfo& args, const char *message);
+
+private slots:
+ void execCommandLog(const std::string &cmd);
+
+private:
+ NLMISC::CLog m_Log;
+
+private:
+ CCommandLogDisplayer(const CCommandLogDisplayer &);
+ CCommandLogDisplayer &operator=(const CCommandLogDisplayer &);
+
+}; /* class CCommandLogDisplayer */
+
+} /* namespace NLQT */
+
+#endif /* #ifndef NLQT_COMMAND_LOG_H */
+
+/* end of file */
diff --git a/code/nel/tools/3d/shared_widgets/common.h b/code/nel/tools/3d/shared_widgets/common.h
new file mode 100644
index 000000000..23cb2b86d
--- /dev/null
+++ b/code/nel/tools/3d/shared_widgets/common.h
@@ -0,0 +1,87 @@
+/*
+
+Copyright (C) 2015 by authors
+Author: Jan Boon
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+* Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+* Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+*/
+
+#ifndef NLQT_COMMON_H
+#define NLQT_COMMON_H
+#include
+
+// STL includes
+
+// Qt includes
+#include
+#include
+#include
+#include
+
+// NeL includes
+
+// Project includes
+
+namespace NLQT {
+namespace {
+
+void preApplication()
+{
+ QCoreApplication::libraryPaths();
+ QString app_location = QCoreApplication::applicationFilePath();
+ app_location.truncate(app_location.lastIndexOf(QLatin1Char('/')));
+ app_location = QDir(app_location).canonicalPath();
+ QCoreApplication::removeLibraryPath(app_location);
+ QCoreApplication::addLibraryPath("./platforms");
+ QCoreApplication::addLibraryPath("./qtwebengine");
+ QCoreApplication::addLibraryPath("./imageformats");
+ QCoreApplication::addLibraryPath("./iconengines");
+ QCoreApplication::addLibraryPath("./designer");
+}
+
+void postApplication()
+{
+ QApplication::setStyle(QStyleFactory::create("Fusion"));
+ QPalette palette = qApp->palette();
+ palette.setColor(QPalette::Window, QColor(64, 64, 64));
+ palette.setColor(QPalette::WindowText, Qt::white);
+ palette.setColor(QPalette::Base, QColor(48, 48, 48));
+ palette.setColor(QPalette::AlternateBase, QColor(64, 64, 64));
+ palette.setColor(QPalette::ToolTipBase, Qt::white);
+ palette.setColor(QPalette::ToolTipText, Qt::white);
+ palette.setColor(QPalette::Text, Qt::white);
+ palette.setColor(QPalette::Button, QColor(64, 64, 64));
+ palette.setColor(QPalette::ButtonText, Qt::white);
+ palette.setColor(QPalette::BrightText, Qt::red);
+ palette.setColor(QPalette::Highlight, QColor(64, 128, 96));
+ palette.setColor(QPalette::HighlightedText, Qt::white);
+ qApp->setPalette(palette);
+}
+
+}
+} /* namespace NLQT */
+
+#endif /* #ifndef NLQT_SERVICE_WINDOW_H */
+
+/* end of file */