Use configured resolution for login/outgame/ingame
[ryzomcore.git] / nel / tools / 3d / panoply_preview / panoply_preview.cpp
blobcc53e4531260f52cf09c9edf9df4b0abf23c0583
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2014-2016 Jan BOON (Kaetemi) <jan.boon@kaetemi.be>
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
17 #include <nel/misc/types_nl.h>
18 #include "panoply_preview.h"
20 // STL includes
22 // Qt includes
23 #include <QVBoxLayout>
24 #include <QDockWidget>
25 #include <QMenu>
26 #include <QGroupBox>
27 #include <QLineEdit>
28 #include <QSlider>
29 #include <QScrollArea>
30 #include <QPushButton>
31 #include <QLabel>
32 #include <QPainter>
34 // NeL includes
35 #include <nel/misc/debug.h>
36 #include <nel/misc/command.h>
37 #include <nel/misc/path.h>
38 #include <nel/misc/thread.h>
39 #include <nel/misc/mutex.h>
40 #include <nel/misc/bitmap.h>
41 #include <nel/misc/file.h>
43 // Project includes
44 #include "main_window.h"
45 #include "../panoply_maker/color_modifier.h"
47 using namespace std;
48 using namespace NLMISC;
50 namespace NLTOOLS {
52 class CColorThread : public NLMISC::IRunnable
54 public:
55 // Called when a thread is run.
56 virtual void run()
58 while (Running)
60 SettingsMutex.enter();
61 if (!Running)
63 SettingsMutex.leave();
64 return;
66 if (!Process)
68 SettingsMutex.leave();
69 nlSleep(10); // TODO: Should wait on an event signal...
70 continue;
72 // nldebug("Update color modifier");
73 m_ColorModifier.Hue = Hue;
74 m_ColorModifier.Lightness = Lightness;
75 m_ColorModifier.Saturation = Saturation;
76 m_ColorModifier.Luminosity = Luminosity;
77 m_ColorModifier.Contrast = Contrast;
78 Process = false;
79 SettingsMutex.leave();
81 BitmapMutex.enter();
82 if (!Running)
84 BitmapMutex.leave();
85 return;
87 if (!BitmapsOk)
89 nldebug("Bitmaps not ready");
90 BitmapMutex.leave();
91 nlSleep(500);
92 continue;
94 float retDeltaHue;
95 DestBitmap = ColorBitmap;
96 m_ColorModifier.convertBitmap(DestBitmap, ColorBitmap, MaskBitmap, retDeltaHue);
97 BitmapMutex.leave();
99 PanoplyPreview->displayBitmap(DestBitmap);
101 nlSleep(10); // TODO: Should wait on an event signal...
105 CColorThread() : PanoplyPreview(NULL), BitmapsOk(false), Hue(0), Lightness(0), Saturation(0), Luminosity(0), Contrast(0), Process(false), Running(true) { }
106 virtual ~CColorThread() { }
107 virtual void getName (std::string &result) const { result = "CColorThread"; }
109 private:
110 CColorModifier m_ColorModifier;
112 public:
113 CPanoplyPreview *PanoplyPreview;
115 NLMISC::CMutex BitmapMutex;
116 NLMISC::CBitmap ColorBitmap;
117 NLMISC::CBitmap MaskBitmap;
118 bool BitmapsOk;
119 NLMISC::CBitmap DestBitmap;
121 NLMISC::CMutex SettingsMutex;
122 float Hue;
123 float Lightness;
124 float Saturation;
125 float Luminosity;
126 float Contrast;
127 bool Process;
129 bool Running;
132 // *****************************************************************
134 CPanoplyPreview::CPanoplyPreview(CMainWindow *parent) : QWidget(parent)
136 connect(this, SIGNAL(tSigBitmap()), this, SLOT(tSlotBitmap()));
138 createDockWindows(parent);
140 m_Image = new QImage(512, 512, QImage::Format_RGB32);
141 m_Pixmap = new QPixmap(512, 512);
143 setMinimumWidth(512);
144 setMinimumHeight(512);
146 m_ColorThread = new CColorThread();
147 m_ColorThread->PanoplyPreview = this;
148 m_Thread = IThread::create(m_ColorThread);
149 m_Thread->start();
152 CPanoplyPreview::~CPanoplyPreview()
154 m_ColorThread->SettingsMutex.enter();
155 m_ColorThread->BitmapMutex.enter();
156 m_ColorThread->Running = false;
157 m_ColorThread->BitmapMutex.leave();
158 m_ColorThread->SettingsMutex.leave();
159 m_Thread->wait();
160 delete m_Thread;
161 delete m_ColorThread;
164 void CPanoplyPreview::paintEvent(QPaintEvent* e)
166 QPainter painter(this);
167 painter.drawPixmap(0, 0, *m_Pixmap);
170 void CPanoplyPreview::displayBitmap(const CBitmap &bitmap) // Called from thread!
172 // nldebug("received bitmap");
174 m_ColorThread->BitmapMutex.enter();
175 m_ImageMutex.enter();
177 const char *buffer = (const char *)&bitmap.getPixels()[0];
179 if (bitmap.getWidth() != m_Image->width() || bitmap.getHeight() != m_Image->height())
181 QImage *image = m_Image;
182 m_Image = new QImage(bitmap.getWidth(), bitmap.getHeight(), QImage::Format_RGB32);
183 delete image;
186 for (uint32 y = 0; y < bitmap.getHeight(); ++y)
188 uint8 *dst = (uint8 *)m_Image->scanLine(y);
189 const uint8 *src = (const uint8 *)&buffer[y * bitmap.getWidth() * sizeof(uint32)];
190 for (uint32 x = 0; x < bitmap.getWidth(); ++x)
192 uint32 xb = x * 4;
193 dst[xb + 0] = src[xb + 2];
194 dst[xb + 1] = src[xb + 1];
195 dst[xb + 2] = src[xb + 0];
196 dst[xb + 3] = src[xb + 3];
199 //memcpy(m_Image->scanLine(y), &buffer[y * bitmap.getWidth() * sizeof(uint32)], sizeof(uint32) * bitmap.getWidth());
202 m_ImageMutex.leave();
203 m_ColorThread->BitmapMutex.leave();
205 tSigBitmap();
208 void CPanoplyPreview::tSlotBitmap()
210 // nldebug("display bitmap");
212 m_ImageMutex.enter();
214 if (m_Image->width() != m_Pixmap->width()
215 || m_Image->height() != m_Pixmap->height())
217 QPixmap *pixmap = m_Pixmap;
218 m_Pixmap = new QPixmap(m_Image->width(), m_Image->height());
219 setMinimumWidth(m_Pixmap->width());
220 setMinimumHeight(m_Pixmap->height());
221 delete pixmap;
223 m_Pixmap->convertFromImage(*m_Image);
224 repaint();
226 m_ImageMutex.leave();
230 void CPanoplyPreview::colorEdited(const QString &text)
232 m_ColorFile = text;
235 void CPanoplyPreview::maskEdited(const QString &text)
237 m_MaskFile = text;
240 void CPanoplyPreview::goPushed(bool)
242 // nldebug("push bitmaps");
243 m_ColorThread->SettingsMutex.enter();
244 m_ColorThread->BitmapMutex.enter();
245 m_ColorThread->BitmapsOk = false;
250 NLMISC::CIFile is;
251 if (!is.open(m_ColorFile.toLocal8Bit().data()))
252 throw NLMISC::Exception("Cannot open file '%s'", m_ColorFile.toLocal8Bit().data());
253 uint32 depth = m_ColorThread->ColorBitmap.load(is);
254 if (depth == 0 || m_ColorThread->ColorBitmap.getPixels().empty())
255 throw NLMISC::Exception("Failed to load bitmap '%s'", m_ColorFile.toLocal8Bit().data());
256 if (m_ColorThread->ColorBitmap.PixelFormat != NLMISC::CBitmap::RGBA)
257 m_ColorThread->ColorBitmap.convertToType(NLMISC::CBitmap::RGBA);
260 NLMISC::CIFile is;
261 if (!is.open(m_MaskFile.toLocal8Bit().data()))
262 throw NLMISC::Exception("Cannot open file '%s'", m_MaskFile.toLocal8Bit().data());
263 uint32 depth = m_ColorThread->MaskBitmap.load(is);
264 if (depth == 0 || m_ColorThread->MaskBitmap.getPixels().empty())
265 throw NLMISC::Exception("Failed to load bitmap '%s'", m_MaskFile.toLocal8Bit().data());
266 if (m_ColorThread->MaskBitmap.PixelFormat != NLMISC::CBitmap::Luminance)
267 m_ColorThread->MaskBitmap.convertToType(NLMISC::CBitmap::Luminance);
270 m_ColorThread->BitmapsOk = true;
271 m_ColorThread->Process = true;
274 catch (const NLMISC::Exception &e)
276 nlwarning("Exception: '%s'", e.what());
279 m_ColorThread->BitmapMutex.leave();
280 m_ColorThread->SettingsMutex.leave();
281 // nldebug("done pushing butmaps");
284 void CPanoplyPreview::hueChanged(int value)
286 float v = (float)value;
287 m_ColorThread->SettingsMutex.enter();
288 m_ColorThread->Hue = v;
289 m_ColorThread->Process = true;
290 m_ColorThread->SettingsMutex.leave();
293 void CPanoplyPreview::lightnessChanged(int value)
295 float v = (float)value * 0.01f;
296 m_ColorThread->SettingsMutex.enter();
297 m_ColorThread->Lightness = v;
298 m_ColorThread->Process = true;
299 m_ColorThread->SettingsMutex.leave();
302 void CPanoplyPreview::saturationChanged(int value)
304 float v = (float)value * 0.01f;
305 m_ColorThread->SettingsMutex.enter();
306 m_ColorThread->Saturation = v;
307 m_ColorThread->Process = true;
308 m_ColorThread->SettingsMutex.leave();
311 void CPanoplyPreview::luminosityChanged(int value)
313 float v = (float)value;
314 m_ColorThread->SettingsMutex.enter();
315 m_ColorThread->Luminosity = v;
316 m_ColorThread->Process = true;
317 m_ColorThread->SettingsMutex.leave();
320 void CPanoplyPreview::contrastChanged(int value)
322 float v = (float)value;
323 m_ColorThread->SettingsMutex.enter();
324 m_ColorThread->Contrast = v;
325 m_ColorThread->Process = true;
326 m_ColorThread->SettingsMutex.leave();
329 // *****************************************************************
331 CSliderTextEdit::CSliderTextEdit(QWidget *parent, QLineEdit *lineEdit, float scale) : QSlider(Qt::Horizontal, parent), m_LineEdit(lineEdit), m_Updating(false), m_Scale(scale)
333 connect(this, SIGNAL(valueChanged(int)), this, SLOT(sliderValueChanged(int)));
334 connect(lineEdit, SIGNAL(textEdited(const QString &)), this, SLOT(lineEditTextEdited(const QString &)));
337 CSliderTextEdit::~CSliderTextEdit()
342 void CSliderTextEdit::lineEditTextEdited(const QString &text)
344 if (!m_Updating)
346 m_Updating = true;
347 setValue((int)(text.toFloat() * m_Scale));
348 m_Updating = false;
352 void CSliderTextEdit::sliderValueChanged(int value)
354 if (!m_Updating)
356 m_Updating = true;
357 m_LineEdit->setText(QString::number((double)value / (double)m_Scale));
358 m_Updating = false;
362 // *****************************************************************
364 void CPanoplyPreview::createDockWindows(CMainWindow *mainWindow)
366 nlassert(mainWindow);
368 // Color Modifier
370 QDockWidget *dockWidget = new QDockWidget(mainWindow);
371 nlassert(dockWidget);
372 dockWidget->setWindowTitle(tr("Color Modifier"));
373 dockWidget->setAllowedAreas(Qt::LeftDockWidgetArea | Qt::RightDockWidgetArea);
374 QScrollArea *scrollArea = new QScrollArea(dockWidget);
375 scrollArea->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
376 scrollArea->setWidgetResizable(true);
377 QWidget *widget = new QWidget(scrollArea);
378 QVBoxLayout *vboxLayout = new QVBoxLayout(widget);
380 // Input File Paths
382 QGroupBox *groupBox = new QGroupBox(widget);
383 groupBox->setTitle(tr("Input File Paths"));
384 QGridLayout *groupLayout = new QGridLayout(groupBox);
386 QLabel *colorLabel = new QLabel(groupBox);
387 colorLabel->setText(tr("Color: "));
388 groupLayout->addWidget(colorLabel, 0, 0);
390 QLineEdit *colorFile = new QLineEdit(groupBox);
391 colorFile->setText("W:\\database\\stuff\\fyros\\agents\\_textures\\actors\\fy_hof_armor00_arm01_c1.png");
392 groupLayout->addWidget(colorFile, 0, 1);
394 m_ColorFile = colorFile->text();
395 connect(colorFile, SIGNAL(textEdited(const QString &)), this, SLOT(colorEdited(const QString &)));
397 QLabel *maskLabel = new QLabel(groupBox);
398 maskLabel->setText(tr("Mask: "));
399 groupLayout->addWidget(maskLabel, 1, 0);
401 QLineEdit *maskFile = new QLineEdit(groupBox);
402 maskFile->setText("W:\\database\\stuff\\fyros\\agents\\_textures\\actors\\mask\\fy_hof_armor00_arm01_c1_skin.png");
403 groupLayout->addWidget(maskFile, 1, 1);
405 m_MaskFile = maskFile->text();
406 connect(maskFile, SIGNAL(textEdited(const QString &)), this, SLOT(maskEdited(const QString &)));
408 QPushButton *go = new QPushButton(groupBox);
409 go->setText(tr("Go"));
410 groupLayout->addWidget(go, 2, 0, 1, 2);
412 connect(go, SIGNAL(clicked(bool)), this, SLOT(goPushed(bool)));
414 groupBox->setLayout(groupLayout);
415 vboxLayout->addWidget(groupBox);
418 // Color Modifier
420 QGroupBox *groupBox = new QGroupBox(widget);
421 groupBox->setTitle(tr("Color Modifier"));
422 QGridLayout *groupLayout = new QGridLayout(groupBox);
424 QLabel *label;
425 QLineEdit *edit;
426 CSliderTextEdit *slider;
428 label = new QLabel(groupBox);
429 label->setText(tr("Hue [0, 360]: "));
430 groupLayout->addWidget(label, 0, 0);
432 edit = new QLineEdit(groupBox);
433 edit->setText("0");
434 groupLayout->addWidget(edit, 0, 1);
436 slider = new CSliderTextEdit(groupBox, edit, 1.0f);
437 slider->setMinimum(0);
438 slider->setMaximum(360);
439 slider->setValue(0);
440 groupLayout->addWidget(slider, 1, 0, 1, 2);
442 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(hueChanged(int)));
444 label = new QLabel(groupBox);
445 label->setText(tr("Lightness [-1, 1]: "));
446 groupLayout->addWidget(label, 2, 0);
448 edit = new QLineEdit(groupBox);
449 edit->setText("0");
450 groupLayout->addWidget(edit, 2, 1);
452 slider = new CSliderTextEdit(groupBox, edit, 100.0f);
453 slider->setMinimum(-100);
454 slider->setMaximum(100);
455 slider->setValue(0);
456 groupLayout->addWidget(slider, 3, 0, 1, 2);
458 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(lightnessChanged(int)));
460 label = new QLabel(groupBox);
461 label->setText(tr("Saturation [-1, 1]: "));
462 groupLayout->addWidget(label, 4, 0);
464 edit = new QLineEdit(groupBox);
465 edit->setText("0");
466 groupLayout->addWidget(edit, 4, 1);
468 slider = new CSliderTextEdit(groupBox, edit, 100.0f);
469 slider->setMinimum(-100);
470 slider->setMaximum(100);
471 slider->setValue(0);
472 groupLayout->addWidget(slider, 5, 0, 1, 2);
474 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(saturationChanged(int)));
476 label = new QLabel(groupBox);
477 label->setText(tr("Luminosity [-100, 100]: "));
478 groupLayout->addWidget(label, 6, 0);
480 edit = new QLineEdit(groupBox);
481 edit->setText("0");
482 groupLayout->addWidget(edit, 6, 1);
484 slider = new CSliderTextEdit(groupBox, edit, 1.0f);
485 slider->setMinimum(-100);
486 slider->setMaximum(100);
487 slider->setValue(0);
488 groupLayout->addWidget(slider, 7, 0, 1, 2);
490 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(luminosityChanged(int)));
492 label = new QLabel(groupBox);
493 label->setText(tr("Contrast [-100, 100]: "));
494 groupLayout->addWidget(label, 8, 0);
496 edit = new QLineEdit(groupBox);
497 edit->setText("0");
498 groupLayout->addWidget(edit, 8, 1);
500 slider = new CSliderTextEdit(groupBox, edit, 1.0f);
501 slider->setMinimum(-100);
502 slider->setMaximum(100);
503 slider->setValue(0);
504 groupLayout->addWidget(slider, 9, 0, 1, 2);
506 connect(slider, SIGNAL(valueChanged(int)), this, SLOT(contrastChanged(int)));
508 groupBox->setLayout(groupLayout);
509 vboxLayout->addWidget(groupBox);
512 vboxLayout->addStretch();
513 widget->setLayout(vboxLayout);
514 scrollArea->setWidget(widget);
515 dockWidget->setWidget(scrollArea);
516 mainWindow->addDockWidget(Qt::LeftDockWidgetArea, dockWidget);
517 mainWindow->widgetsMenu()->addAction(dockWidget->toggleViewAction());
521 } /* namespace NLTOOLS */
523 /* end of file */