celestia/src/tools/cmod/cmodview/materialwidget.cpp

369 lines
11 KiB
C++

// materialwidget.cpp
//
// Copyright (C) 2010, Chris Laurel <claurel@gmail.com>
//
// This program is free software; you can redistribute it and/or
// modify it under the terms of the GNU General Public License
// as published by the Free Software Foundation; either version 2
// of the License, or (at your option) any later version.
#include <QColorDialog>
#include <QDir>
#include <QGridLayout>
#include <QPushButton>
#include <QSet>
#include <QStringList>
#include "pathmanager.h"
#include "materialwidget.h"
namespace
{
QColor toQtColor(const cmod::Color& color)
{
return QColor(static_cast<int>(color.red() * 255.99f),
static_cast<int>(color.green() * 255.99f),
static_cast<int>(color.blue() * 255.99f));
}
cmod::Color fromQtColor(const QColor& color)
{
return cmod::Color(color.redF(), color.greenF(), color.blueF());
}
// TODO: implement a copy constructor and assignment operator for materials
void copyMaterial(cmod::Material& dest, const cmod::Material& src)
{
dest.diffuse = src.diffuse;
dest.specular = src.specular;
dest.emissive = src.emissive;
dest.opacity = src.opacity;
dest.specularPower = src.specularPower;
dest.blend = src.blend;
dest.maps = src.maps;
}
static void setWidgetColor(QLabel* widget, const cmod::Color& color)
{
widget->setPalette(QPalette(toQtColor(color)));
widget->setAutoFillBackground(true);
widget->setText(QString("%1, %2, %3").arg(color.red(), 0, 'g', 3).arg(color.green(), 0, 'g', 3).arg(color.blue(), 0, 'g', 3));
}
inline QString toQString(const wchar_t *s)
{
return QString::fromWCharArray(s);
}
inline QString toQString(const char *s)
{
return QString::fromLocal8Bit(s);
}
void selectComboBoxItem(QComboBox* combo, const QString &text)
{
int itemIndex = combo->findText(text);
if (itemIndex < 0)
{
combo->addItem(text, text);
itemIndex = combo->count() - 1;
}
combo->setCurrentIndex(itemIndex);
}
void selectComboBoxItem(QComboBox* combo, const fs::path &path)
{
selectComboBoxItem(combo, toQString(path.c_str()));
}
// Return a list of all texture filenames in the specified folder
QSet<QString> listTextures(QDir& dir)
{
QStringList filters;
filters << "*.png" << "*.jpg" << "*.dds" << "*.dxt5nm";
QStringList textureFileNames = dir.entryList(filters, QDir::Files);
#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
return QSet<QString>(textureFileNames.begin(), textureFileNames.end());
#else
return QSet<QString>::fromList(textureFileNames);
#endif
}
} // end unnamed namespace
MaterialWidget::MaterialWidget(QWidget* parent) :
QWidget(parent)
{
QGridLayout *layout = new QGridLayout;
layout->setColumnStretch(1, 1);
int frameStyle = QFrame::Sunken | QFrame::Panel;
m_diffuseColor = new QLabel(this);
m_specularColor = new QLabel(this);
m_emissiveColor = new QLabel(this);
m_opacity = new QLineEdit(this);
m_specularPower = new QLineEdit(this);
m_baseTexture = new QComboBox(this);
m_specularMap = new QComboBox(this);
m_emissiveMap = new QComboBox(this);
m_normalMap = new QComboBox(this);
m_diffuseColor->setFrameStyle(frameStyle);
m_specularColor->setFrameStyle(frameStyle);
m_emissiveColor->setFrameStyle(frameStyle);
QPushButton* changeDiffuse = new QPushButton(tr("Change..."), this);
QPushButton* changeSpecular = new QPushButton(tr("Change..."), this);
QPushButton* changeEmissive = new QPushButton(tr("Change..."), this);
/*
QPushButton* changeBaseTexture = new QPushButton(tr("Change..."), this);
QPushButton* changeSpecularMap = new QPushButton(tr("Change..."), this);
QPushButton* changeEmissiveMap = new QPushButton(tr("Change..."), this);
QPushButton* changeNormalMap = new QPushButton(tr("Change..."), this);
*/
layout->addWidget(new QLabel(tr("Diffuse")), 0, 0);
layout->addWidget(m_diffuseColor, 0, 1);
layout->addWidget(changeDiffuse, 0, 2);
layout->addWidget(new QLabel(tr("Specular")), 1, 0);
layout->addWidget(m_specularColor, 1, 1);
layout->addWidget(changeSpecular, 1, 2);
layout->addWidget(new QLabel(tr("Emissive")), 2, 0);
layout->addWidget(m_emissiveColor, 2, 1);
layout->addWidget(changeEmissive, 2, 2);
layout->addWidget(new QLabel(tr("Opacity")), 3, 0);
layout->addWidget(m_opacity, 3, 1);
layout->addWidget(new QLabel(tr("Shininess")), 4, 0);
layout->addWidget(m_specularPower, 4, 1);
layout->addWidget(new QLabel(tr("Base Texture")), 5, 0);
layout->addWidget(m_baseTexture, 5, 1);
//layout->addWidget(changeBaseTexture, 5, 2);
layout->addWidget(new QLabel(tr("Specular Map")), 6, 0);
layout->addWidget(m_specularMap, 6, 1);
//layout->addWidget(changeSpecularMap, 6, 2);
layout->addWidget(new QLabel(tr("Emissive Map")), 7, 0);
layout->addWidget(m_emissiveMap, 7, 1);
//layout->addWidget(changeEmissiveMap, 7, 2);
layout->addWidget(new QLabel(tr("Normal Map")), 8, 0);
layout->addWidget(m_normalMap, 8, 1);
//layout->addWidget(changeNormalMap, 8, 2);
layout->setRowStretch(9, 10);
connect(changeDiffuse, SIGNAL(clicked()), this, SLOT(editDiffuse()));
connect(changeSpecular, SIGNAL(clicked()), this, SLOT(editSpecular()));
connect(changeEmissive, SIGNAL(clicked()), this, SLOT(editEmissive()));
connect(m_opacity, SIGNAL(editingFinished()), this, SLOT(changeMaterialParameters()));
connect(m_specularPower, SIGNAL(editingFinished()), this, SLOT(changeMaterialParameters()));
connect(m_baseTexture, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
connect(m_specularMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
connect(m_normalMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
connect(m_emissiveMap, SIGNAL(activated(int)), this, SLOT(changeMaterialParameters()));
setMaterial(cmod::Material());
this->setLayout(layout);
}
void
MaterialWidget::setMaterial(const cmod::Material& material)
{
copyMaterial(m_material, material);
setWidgetColor(m_diffuseColor, m_material.diffuse);
setWidgetColor(m_specularColor, m_material.specular);
setWidgetColor(m_emissiveColor, m_material.emissive);
m_opacity->setText(QString::number(m_material.opacity));
m_specularPower->setText(QString::number(m_material.specularPower));
if (m_material.getMap(cmod::TextureSemantic::DiffuseMap) != InvalidResource)
selectComboBoxItem(m_baseTexture, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::DiffuseMap)));
else
m_baseTexture->setCurrentIndex(0);
if (m_material.getMap(cmod::TextureSemantic::SpecularMap) != InvalidResource)
selectComboBoxItem(m_specularMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::SpecularMap)));
else
m_specularMap->setCurrentIndex(0);
if (m_material.getMap(cmod::TextureSemantic::EmissiveMap) != InvalidResource)
selectComboBoxItem(m_emissiveMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::EmissiveMap)));
else
m_emissiveMap->setCurrentIndex(0);
if (m_material.getMap(cmod::TextureSemantic::NormalMap) != InvalidResource)
selectComboBoxItem(m_normalMap, GetPathManager()->getSource(m_material.getMap(cmod::TextureSemantic::NormalMap)));
else
m_normalMap->setCurrentIndex(0);
emit materialChanged(m_material);
}
void
MaterialWidget::editDiffuse()
{
QColorDialog dialog(toQtColor(m_material.diffuse), this);
connect(&dialog, SIGNAL(currentColorChanged(QColor)), this, SLOT(setDiffuse(QColor)));
dialog.exec();
}
void
MaterialWidget::editSpecular()
{
QColorDialog dialog(toQtColor(m_material.specular), this);
connect(&dialog, SIGNAL(currentColorChanged(QColor)), this, SLOT(setSpecular(QColor)));
dialog.exec();
}
void
MaterialWidget::editEmissive()
{
QColorDialog dialog(toQtColor(m_material.emissive), this);
connect(&dialog, SIGNAL(currentColorChanged(QColor)), this, SLOT(setEmissive(QColor)));
dialog.exec();
}
void
MaterialWidget::editBaseTexture()
{
}
void
MaterialWidget::editSpecularMap()
{
}
void
MaterialWidget::editEmissiveMap()
{
}
void
MaterialWidget::editNormalMap()
{
}
void
MaterialWidget::setDiffuse(const QColor& color)
{
m_material.diffuse = fromQtColor(color);
setWidgetColor(m_diffuseColor, m_material.diffuse);
emit materialEdited(m_material);
}
void
MaterialWidget::setSpecular(const QColor& color)
{
m_material.specular = fromQtColor(color);
setWidgetColor(m_specularColor, m_material.specular);
emit materialEdited(m_material);
}
void
MaterialWidget::setEmissive(const QColor& color)
{
m_material.emissive = fromQtColor(color);
setWidgetColor(m_emissiveColor, m_material.emissive);
emit materialEdited(m_material);
}
void
MaterialWidget::changeMaterialParameters()
{
m_material.opacity = m_opacity->text().toFloat();
m_material.specularPower = m_specularPower->text().toFloat();
m_material.setMap(cmod::TextureSemantic::DiffuseMap, InvalidResource);
if (!m_baseTexture->itemData(m_baseTexture->currentIndex()).isNull())
{
m_material.setMap(cmod::TextureSemantic::DiffuseMap, GetPathManager()->getHandle(m_baseTexture->currentText().toStdString()));
}
m_material.setMap(cmod::TextureSemantic::SpecularMap, InvalidResource);
if (!m_specularMap->itemData(m_specularMap->currentIndex()).isNull())
{
m_material.setMap(cmod::TextureSemantic::SpecularMap, GetPathManager()->getHandle(m_specularMap->currentText().toStdString()));
}
m_material.setMap(cmod::TextureSemantic::NormalMap, InvalidResource);
if (!m_normalMap->itemData(m_normalMap->currentIndex()).isNull())
{
m_material.setMap(cmod::TextureSemantic::NormalMap, GetPathManager()->getHandle(m_normalMap->currentText().toStdString()));
}
m_material.setMap(cmod::TextureSemantic::EmissiveMap, InvalidResource);
if (!m_emissiveMap->itemData(m_emissiveMap->currentIndex()).isNull())
{
m_material.setMap(cmod::TextureSemantic::EmissiveMap, GetPathManager()->getHandle(m_emissiveMap->currentText().toStdString()));
}
emit materialEdited(m_material);
}
void
MaterialWidget::setTextureSearchPath(const QString& path)
{
m_baseTexture->clear();
m_specularMap->clear();
m_normalMap->clear();
m_emissiveMap->clear();
m_baseTexture->addItem("NONE");
m_specularMap->addItem("NONE");
m_normalMap->addItem("NONE");
m_emissiveMap->addItem("NONE");
if (!path.isEmpty())
{
QDir searchDir1(path);
QDir searchDir2(path + "/../textures/medres/");
QSet<QString> textureFileNames = listTextures(searchDir1);
textureFileNames.unite(listTextures(searchDir2));
QStringList sortedNames = textureFileNames.values();
sortedNames.sort();
foreach (QString fileName, sortedNames)
{
m_baseTexture->addItem(fileName, fileName);
m_specularMap->addItem(fileName, fileName);
m_normalMap->addItem(fileName, fileName);
m_emissiveMap->addItem(fileName, fileName);
}
}
}