670dd6c5bc
Updated OpenMaterialExporter() to account for the fact that multiple material slots can have the same default material asset. Updated the material inspector to sort material slots by name to match the order in the Material Component. Updated ExportItem to protect its data members, which makes it more clear that assetId and materialSlotName are readonly inputs. Signed-off-by: santorac <55155825+santorac@users.noreply.github.com>
236 lines
13 KiB
C++
236 lines
13 KiB
C++
/*
|
|
* Copyright (c) Contributors to the Open 3D Engine Project.
|
|
* For complete copyright and license terms please see the LICENSE at the root of this distribution.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0 OR MIT
|
|
*
|
|
*/
|
|
|
|
#include <Material/EditorMaterialComponentExporter.h>
|
|
#include <Material/EditorMaterialComponentUtil.h>
|
|
|
|
#include <AzFramework/API/ApplicationAPI.h>
|
|
#include <AzQtComponents/Components/Widgets/BrowseEdit.h>
|
|
#include <AzToolsFramework/API/EditorAssetSystemAPI.h>
|
|
#include <AzToolsFramework/API/EditorWindowRequestBus.h>
|
|
#include <AzToolsFramework/API/ToolsApplicationAPI.h>
|
|
|
|
#include <Atom/RPI.Edit/Common/AssetUtils.h>
|
|
|
|
AZ_PUSH_DISABLE_WARNING(4251 4800, "-Wunknown-warning-option") // disable warnings spawned by QT
|
|
#include <QApplication>
|
|
#include <QCheckBox>
|
|
#include <QComboBox>
|
|
#include <QDialogButtonBox>
|
|
#include <QFileDialog>
|
|
#include <QHBoxLayout>
|
|
#include <QHeaderView>
|
|
#include <QLabel>
|
|
#include <QPushButton>
|
|
#include <QTableWidget>
|
|
#include <QVBoxLayout>
|
|
AZ_POP_DISABLE_WARNING
|
|
|
|
namespace AZ
|
|
{
|
|
namespace Render
|
|
{
|
|
namespace EditorMaterialComponentExporter
|
|
{
|
|
AZStd::string GetExportPathByAssetId(const AZ::Data::AssetId& assetId, const AZStd::string& materialSlotName)
|
|
{
|
|
AZStd::string exportPath;
|
|
if (assetId.IsValid())
|
|
{
|
|
exportPath = AZ::RPI::AssetUtils::GetSourcePathByAssetId(assetId);
|
|
AZ::StringFunc::Path::StripExtension(exportPath);
|
|
exportPath += "_";
|
|
exportPath += materialSlotName;
|
|
exportPath += ".";
|
|
exportPath += AZ::RPI::MaterialSourceData::Extension;
|
|
AZ::StringFunc::Path::Normalize(exportPath);
|
|
}
|
|
return exportPath;
|
|
}
|
|
|
|
bool OpenExportDialog(ExportItemsContainer& exportItems)
|
|
{
|
|
QWidget* activeWindow = nullptr;
|
|
AzToolsFramework::EditorWindowRequestBus::BroadcastResult(activeWindow, &AzToolsFramework::EditorWindowRequests::GetAppMainWindow);
|
|
|
|
// Constructing a dialog with a table to display all configurable material export items
|
|
QDialog dialog(activeWindow);
|
|
dialog.setWindowTitle("Generate/Manage Source Materials");
|
|
|
|
const QStringList headerLabels = { "Material Slot", "Material Filename", "Overwrite" };
|
|
const int MaterialSlotColumn = 0;
|
|
const int MaterialFileColumn = 1;
|
|
const int OverwriteFileColumn = 2;
|
|
|
|
// Create a table widget that will be filled with all of the data and options for each exported material
|
|
QTableWidget* tableWidget = new QTableWidget(&dialog);
|
|
tableWidget->setColumnCount(headerLabels.size());
|
|
tableWidget->setRowCount((int)exportItems.size());
|
|
tableWidget->setHorizontalHeaderLabels(headerLabels);
|
|
tableWidget->setSortingEnabled(false);
|
|
tableWidget->setAlternatingRowColors(true);
|
|
tableWidget->setCornerButtonEnabled(false);
|
|
tableWidget->setContextMenuPolicy(Qt::DefaultContextMenu);
|
|
tableWidget->setSelectionBehavior(QAbstractItemView::SelectRows);
|
|
tableWidget->setSelectionMode(QAbstractItemView::SingleSelection);
|
|
tableWidget->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding);
|
|
|
|
// Force the table to stretch its header to fill the entire width of the dialog
|
|
tableWidget->horizontalHeader()->setSectionResizeMode(MaterialSlotColumn, QHeaderView::ResizeToContents);
|
|
tableWidget->horizontalHeader()->setSectionResizeMode(MaterialFileColumn, QHeaderView::Stretch);
|
|
tableWidget->horizontalHeader()->setSectionResizeMode(OverwriteFileColumn, QHeaderView::ResizeToContents);
|
|
tableWidget->horizontalHeader()->setStretchLastSection(false);
|
|
|
|
// Hide row numbers
|
|
tableWidget->verticalHeader()->setVisible(false);
|
|
|
|
int row = 0;
|
|
for (ExportItem& exportItem : exportItems)
|
|
{
|
|
QFileInfo fileInfo(GetExportPathByAssetId(exportItem.GetOriginalAssetId(), exportItem.GetMaterialSlotName()).c_str());
|
|
|
|
// Configuring initial settings based on whether or not the target file already exists
|
|
exportItem.SetExportPath(fileInfo.absoluteFilePath().toUtf8().constData());
|
|
exportItem.SetExists(fileInfo.exists());
|
|
exportItem.SetOverwrite(false);
|
|
|
|
// Populate the table with data for every column
|
|
tableWidget->setItem(row, MaterialSlotColumn, new QTableWidgetItem());
|
|
tableWidget->setItem(row, MaterialFileColumn, new QTableWidgetItem());
|
|
tableWidget->setItem(row, OverwriteFileColumn, new QTableWidgetItem());
|
|
|
|
// Create a check box for toggling the enabled state of this item
|
|
QCheckBox* materialSlotCheckBox = new QCheckBox(tableWidget);
|
|
materialSlotCheckBox->setChecked(exportItem.GetEnabled());
|
|
materialSlotCheckBox->setText(exportItem.GetMaterialSlotName().c_str());
|
|
tableWidget->setCellWidget(row, MaterialSlotColumn, materialSlotCheckBox);
|
|
|
|
// Create a file picker widget for selecting the save path for the exported material
|
|
AzQtComponents::BrowseEdit* materialFileWidget = new AzQtComponents::BrowseEdit(tableWidget);
|
|
materialFileWidget->setLineEditReadOnly(true);
|
|
materialFileWidget->setClearButtonEnabled(false);
|
|
materialFileWidget->setEnabled(exportItem.GetEnabled());
|
|
materialFileWidget->setText(fileInfo.fileName());
|
|
tableWidget->setCellWidget(row, MaterialFileColumn, materialFileWidget);
|
|
|
|
// Create a check box for toggling the overwrite state of this item
|
|
QWidget* overwriteCheckBoxContainer = new QWidget(tableWidget);
|
|
QCheckBox* overwriteCheckBox = new QCheckBox(overwriteCheckBoxContainer);
|
|
overwriteCheckBox->setChecked(exportItem.GetOverwrite());
|
|
overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists());
|
|
|
|
overwriteCheckBoxContainer->setLayout(new QHBoxLayout(overwriteCheckBoxContainer));
|
|
overwriteCheckBoxContainer->layout()->addWidget(overwriteCheckBox);
|
|
overwriteCheckBoxContainer->layout()->setAlignment(Qt::AlignCenter);
|
|
overwriteCheckBoxContainer->layout()->setContentsMargins(0, 0, 0, 0);
|
|
|
|
tableWidget->setCellWidget(row, OverwriteFileColumn, overwriteCheckBoxContainer);
|
|
|
|
// Whenever the selection is updated, automatically apply the change to the export item
|
|
QObject::connect(materialSlotCheckBox, &QCheckBox::stateChanged, materialSlotCheckBox, [&exportItem, materialFileWidget, materialSlotCheckBox, overwriteCheckBox]([[maybe_unused]] int state) {
|
|
exportItem.SetEnabled(materialSlotCheckBox->isChecked());
|
|
materialFileWidget->setEnabled(exportItem.GetEnabled());
|
|
overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists());
|
|
});
|
|
|
|
// Whenever the overwrite check box is updated, automatically apply the change to the export item
|
|
QObject::connect(overwriteCheckBox, &QCheckBox::stateChanged, overwriteCheckBox, [&exportItem, overwriteCheckBox]([[maybe_unused]] int state) {
|
|
exportItem.SetOverwrite(overwriteCheckBox->isChecked());
|
|
});
|
|
|
|
// Whenever the browse button is clicked, open a save file dialog in the same location as the current export file setting
|
|
QObject::connect(materialFileWidget, &AzQtComponents::BrowseEdit::attachedButtonTriggered, materialFileWidget, [&dialog, &exportItem, materialFileWidget, overwriteCheckBox]() {
|
|
QFileInfo fileInfo = QFileDialog::getSaveFileName(&dialog,
|
|
QString("Select Material Filename"),
|
|
exportItem.GetExportPath().c_str(),
|
|
QString("Material (*.material)"),
|
|
nullptr,
|
|
QFileDialog::DontConfirmOverwrite);
|
|
|
|
// Only update the export data if a valid path and filename was selected
|
|
if (!fileInfo.absoluteFilePath().isEmpty())
|
|
{
|
|
exportItem.SetExportPath(fileInfo.absoluteFilePath().toUtf8().constData());
|
|
exportItem.SetExists(fileInfo.exists());
|
|
exportItem.SetOverwrite(fileInfo.exists());
|
|
|
|
// Update the controls to display the new state
|
|
materialFileWidget->setText(fileInfo.fileName());
|
|
overwriteCheckBox->setChecked(exportItem.GetOverwrite());
|
|
overwriteCheckBox->setEnabled(exportItem.GetEnabled() && exportItem.GetExists());
|
|
}
|
|
});
|
|
|
|
++row;
|
|
}
|
|
|
|
tableWidget->sortItems(MaterialSlotColumn);
|
|
|
|
// Create the bottom row of the dialog with action buttons for exporting or canceling the operation
|
|
QDialogButtonBox* buttonBox = new QDialogButtonBox(&dialog);
|
|
buttonBox->setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
|
QObject::connect(buttonBox, &QDialogButtonBox::accepted, &dialog, &QDialog::accept);
|
|
QObject::connect(buttonBox, &QDialogButtonBox::rejected, &dialog, &QDialog::reject);
|
|
|
|
// Create a heading label for the top of the dialog
|
|
QLabel* labelWidget = new QLabel("\nSelect the material slots that you want to generate new source materials for. Edit the material file name and location using the file picker.\n", &dialog);
|
|
labelWidget->setWordWrap(true);
|
|
|
|
QVBoxLayout* dialogLayout = new QVBoxLayout(&dialog);
|
|
dialogLayout->addWidget(labelWidget);
|
|
dialogLayout->addWidget(tableWidget);
|
|
dialogLayout->addWidget(buttonBox);
|
|
dialog.setLayout(dialogLayout);
|
|
dialog.setModal(true);
|
|
|
|
// Forcing the initial dialog size to accomodate typical content.
|
|
// Temporarily settng fixed size because dialog.show/exec invokes WindowDecorationWrapper::showEvent.
|
|
// This forces the dialog to be centered and sized based on the layout of content.
|
|
// Resizing the dialog after show will not be centered and moving the dialog programatically doesn't m0ve the custmk frame.
|
|
dialog.setFixedSize(500, 200);
|
|
dialog.show();
|
|
|
|
// Removing fixed size to allow drag resizing
|
|
dialog.setMinimumSize(0, 0);
|
|
dialog.setMaximumSize(QWIDGETSIZE_MAX, QWIDGETSIZE_MAX);
|
|
|
|
// Return true if the user press the export button
|
|
return dialog.exec() == QDialog::Accepted;
|
|
}
|
|
|
|
bool ExportMaterialSourceData(const ExportItem& exportItem)
|
|
{
|
|
if (!exportItem.GetEnabled() || exportItem.GetExportPath().empty())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
if (exportItem.GetExists() && !exportItem.GetOverwrite())
|
|
{
|
|
return true;
|
|
}
|
|
|
|
EditorMaterialComponentUtil::MaterialEditData editData;
|
|
if (!EditorMaterialComponentUtil::LoadMaterialEditDataFromAssetId(exportItem.GetOriginalAssetId(), editData))
|
|
{
|
|
AZ_Warning("AZ::Render::EditorMaterialComponentExporter", false, "Failed to load material data.");
|
|
return false;
|
|
}
|
|
|
|
if (!EditorMaterialComponentUtil::SaveSourceMaterialFromEditData(exportItem.GetExportPath(), editData))
|
|
{
|
|
AZ_Warning("AZ::Render::EditorMaterialComponentExporter", false, "Failed to save material data.");
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
} // namespace EditorMaterialComponentExporter
|
|
} // namespace Render
|
|
} // namespace AZ
|