// materialwidget.cpp // // Copyright (C) 2010, Chris Laurel // // 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 #include #include #include #include #include #include "pathmanager.h" #include "materialwidget.h" namespace { QColor toQtColor(const cmod::Color& color) { return QColor(static_cast(color.red() * 255.99f), static_cast(color.green() * 255.99f), static_cast(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 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(textureFileNames.begin(), textureFileNames.end()); #else return QSet::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 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); } } }