mirror of
https://github.com/redstrate/Novus.git
synced 2025-04-21 11:57:44 +00:00
Create reusable material part
This takes the existing properties widget in the new material editor and makes it reusable across multiple applications. It's now added to the Armoury which shows the gear's used materials. It's also added to the Data Explorer which now supports viewing material files. I fixed the render viewport crashing when hiding it again, and made it even more resilient.
This commit is contained in:
parent
5c31965691
commit
51ea3c3920
24 changed files with 342 additions and 285 deletions
|
@ -11,7 +11,6 @@ target_sources(novus-armoury
|
||||||
include/gearlistwidget.h
|
include/gearlistwidget.h
|
||||||
include/gearview.h
|
include/gearview.h
|
||||||
include/mainwindow.h
|
include/mainwindow.h
|
||||||
include/materialview.h
|
|
||||||
include/metadataview.h
|
include/metadataview.h
|
||||||
include/penumbraapi.h
|
include/penumbraapi.h
|
||||||
include/settingswindow.h
|
include/settingswindow.h
|
||||||
|
@ -25,7 +24,6 @@ target_sources(novus-armoury
|
||||||
src/gearview.cpp
|
src/gearview.cpp
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
src/materialview.cpp
|
|
||||||
src/metadataview.cpp
|
src/metadataview.cpp
|
||||||
src/penumbraapi.cpp
|
src/penumbraapi.cpp
|
||||||
src/settingswindow.cpp
|
src/settingswindow.cpp
|
||||||
|
@ -41,6 +39,7 @@ target_link_libraries(novus-armoury
|
||||||
Novus::MdlPart
|
Novus::MdlPart
|
||||||
Novus::CmpPart
|
Novus::CmpPart
|
||||||
Novus::SklbPart
|
Novus::SklbPart
|
||||||
|
Novus::MtrlPart
|
||||||
Physis::Physis
|
Physis::Physis
|
||||||
Physis::Logger
|
Physis::Logger
|
||||||
imgui
|
imgui
|
||||||
|
|
|
@ -9,8 +9,8 @@
|
||||||
|
|
||||||
#include "fullmodelviewer.h"
|
#include "fullmodelviewer.h"
|
||||||
#include "gearview.h"
|
#include "gearview.h"
|
||||||
#include "materialview.h"
|
|
||||||
#include "metadataview.h"
|
#include "metadataview.h"
|
||||||
|
#include "mtrlpart.h"
|
||||||
#include "novusmainwindow.h"
|
#include "novusmainwindow.h"
|
||||||
#include "singlegearview.h"
|
#include "singlegearview.h"
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@ protected:
|
||||||
private:
|
private:
|
||||||
SingleGearView *gearView = nullptr;
|
SingleGearView *gearView = nullptr;
|
||||||
FullModelViewer *fullModelViewer = nullptr;
|
FullModelViewer *fullModelViewer = nullptr;
|
||||||
MaterialView *materialView = nullptr;
|
QTabWidget *materialsView = nullptr;
|
||||||
MetadataView *metadataView = nullptr;
|
MetadataView *metadataView = nullptr;
|
||||||
|
|
||||||
GameData &data;
|
GameData &data;
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include "filecache.h"
|
|
||||||
#include "gearview.h"
|
|
||||||
|
|
||||||
#include <QWidget>
|
|
||||||
|
|
||||||
struct GameData;
|
|
||||||
|
|
||||||
class MaterialView : public QWidget
|
|
||||||
{
|
|
||||||
Q_OBJECT
|
|
||||||
|
|
||||||
public:
|
|
||||||
explicit MaterialView(GameData *data, QWidget *parent = nullptr);
|
|
||||||
|
|
||||||
private:
|
|
||||||
GameData *data = nullptr;
|
|
||||||
};
|
|
|
@ -18,6 +18,7 @@ public:
|
||||||
explicit SingleGearView(GameData *data, FileCache &cache, QWidget *parent = nullptr);
|
explicit SingleGearView(GameData *data, FileCache &cache, QWidget *parent = nullptr);
|
||||||
|
|
||||||
QString getLoadedGearPath() const;
|
QString getLoadedGearPath() const;
|
||||||
|
QList<physis_Material> getLoadedMaterials() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void gearChanged();
|
void gearChanged();
|
||||||
|
@ -31,6 +32,8 @@ Q_SIGNALS:
|
||||||
void addToFullModelViewer(GearInfo &info);
|
void addToFullModelViewer(GearInfo &info);
|
||||||
void importedModel();
|
void importedModel();
|
||||||
|
|
||||||
|
void doneLoadingModel();
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
void clear();
|
void clear();
|
||||||
void setGear(const GearInfo &info);
|
void setGear(const GearInfo &info);
|
||||||
|
|
|
@ -49,13 +49,13 @@ MainWindow::MainWindow(GameData *in_data)
|
||||||
});
|
});
|
||||||
connect(gearView, &SingleGearView::importedModel, m_api, &PenumbraApi::redrawAll);
|
connect(gearView, &SingleGearView::importedModel, m_api, &PenumbraApi::redrawAll);
|
||||||
|
|
||||||
materialView = new MaterialView(&data);
|
materialsView = new QTabWidget();
|
||||||
|
|
||||||
metadataView = new MetadataView(&data);
|
metadataView = new MetadataView(&data);
|
||||||
|
|
||||||
auto tabWidget = new QTabWidget();
|
auto tabWidget = new QTabWidget();
|
||||||
tabWidget->addTab(gearView, i18nc("@title:tab", "Models"));
|
tabWidget->addTab(gearView, i18nc("@title:tab", "Models"));
|
||||||
tabWidget->addTab(materialView, i18nc("@title:tab", "Materials"));
|
tabWidget->addTab(materialsView, i18nc("@title:tab", "Materials"));
|
||||||
tabWidget->addTab(metadataView, i18nc("@title:tab", "Metadata"));
|
tabWidget->addTab(metadataView, i18nc("@title:tab", "Metadata"));
|
||||||
tabWidget->setDocumentMode(true); // Don't draw the borders
|
tabWidget->setDocumentMode(true); // Don't draw the borders
|
||||||
tabWidget->tabBar()->setExpanding(true);
|
tabWidget->tabBar()->setExpanding(true);
|
||||||
|
@ -65,6 +65,19 @@ MainWindow::MainWindow(GameData *in_data)
|
||||||
connect(fullModelViewer, &FullModelViewer::loadingChanged, this, [this](const bool loading) {
|
connect(fullModelViewer, &FullModelViewer::loadingChanged, this, [this](const bool loading) {
|
||||||
gearView->setFMVAvailable(!loading);
|
gearView->setFMVAvailable(!loading);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
connect(gearView, &SingleGearView::doneLoadingModel, this, [this, in_data] {
|
||||||
|
materialsView->clear();
|
||||||
|
|
||||||
|
int i = 0;
|
||||||
|
for (auto material : gearView->getLoadedMaterials()) {
|
||||||
|
auto materialView = new MtrlPart(in_data);
|
||||||
|
materialView->load(material);
|
||||||
|
materialsView->addTab(materialView, i18n("Material %1", i)); // TODO: it would be nice to get the actual material name here
|
||||||
|
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::setupAdditionalMenus(QMenuBar *menuBar)
|
void MainWindow::setupAdditionalMenus(QMenuBar *menuBar)
|
||||||
|
|
|
@ -1,16 +0,0 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
|
||||||
|
|
||||||
#include "materialview.h"
|
|
||||||
|
|
||||||
#include <QVBoxLayout>
|
|
||||||
|
|
||||||
MaterialView::MaterialView(GameData *data, QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, data(data)
|
|
||||||
{
|
|
||||||
auto layout = new QVBoxLayout();
|
|
||||||
setLayout(layout);
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_materialview.cpp"
|
|
|
@ -38,6 +38,7 @@ SingleGearView::SingleGearView(GameData *data, FileCache &cache, QWidget *parent
|
||||||
|
|
||||||
connect(this, &SingleGearView::gotMDLPath, this, [this, mdlPathEdit] {
|
connect(this, &SingleGearView::gotMDLPath, this, [this, mdlPathEdit] {
|
||||||
mdlPathEdit->setText(gearView->getLoadedGearPath());
|
mdlPathEdit->setText(gearView->getLoadedGearPath());
|
||||||
|
Q_EMIT doneLoadingModel();
|
||||||
});
|
});
|
||||||
|
|
||||||
auto topControlLayout = new QHBoxLayout();
|
auto topControlLayout = new QHBoxLayout();
|
||||||
|
@ -442,4 +443,18 @@ void SingleGearView::importModel(const QString &filename)
|
||||||
Q_EMIT importedModel();
|
Q_EMIT importedModel();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QList<physis_Material> SingleGearView::getLoadedMaterials() const
|
||||||
|
{
|
||||||
|
QList<physis_Material> materialPaths;
|
||||||
|
|
||||||
|
for (int i = 0; i < gearView->part().numModels(); i++) {
|
||||||
|
auto model = gearView->part().getModel(i);
|
||||||
|
for (auto material : model.materials) {
|
||||||
|
materialPaths.push_back(material.mat);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return materialPaths;
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_singlegearview.cpp"
|
#include "moc_singlegearview.cpp"
|
|
@ -7,7 +7,7 @@
|
||||||
|
|
||||||
#include "novuscommon_export.h"
|
#include "novuscommon_export.h"
|
||||||
|
|
||||||
enum class FileType { Unknown, ExcelList, ExcelHeader, ExcelData, Model, Texture, ShaderPackage, CharaMakeParams, Skeleton, Dictionary };
|
enum class FileType { Unknown, ExcelList, ExcelHeader, ExcelData, Model, Texture, ShaderPackage, CharaMakeParams, Skeleton, Dictionary, Material };
|
||||||
|
|
||||||
class NOVUSCOMMON_EXPORT FileTypes
|
class NOVUSCOMMON_EXPORT FileTypes
|
||||||
{
|
{
|
||||||
|
|
|
@ -14,7 +14,8 @@ const static QMap<QString, FileType> extensionToType{{QStringLiteral("exl"), Fil
|
||||||
{QStringLiteral("shpk"), FileType::ShaderPackage},
|
{QStringLiteral("shpk"), FileType::ShaderPackage},
|
||||||
{QStringLiteral("cmp"), FileType::CharaMakeParams},
|
{QStringLiteral("cmp"), FileType::CharaMakeParams},
|
||||||
{QStringLiteral("sklb"), FileType::Skeleton},
|
{QStringLiteral("sklb"), FileType::Skeleton},
|
||||||
{QStringLiteral("dic"), FileType::Dictionary}};
|
{QStringLiteral("dic"), FileType::Dictionary},
|
||||||
|
{QStringLiteral("mtrl"), FileType::Material}};
|
||||||
|
|
||||||
const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknown")},
|
const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknown")},
|
||||||
{FileType::ExcelList, i18n("Excel List")},
|
{FileType::ExcelList, i18n("Excel List")},
|
||||||
|
@ -25,7 +26,8 @@ const static QMap<FileType, QString> typeToName{{FileType::Unknown, i18n("Unknow
|
||||||
{FileType::ShaderPackage, i18n("Shader Package")},
|
{FileType::ShaderPackage, i18n("Shader Package")},
|
||||||
{FileType::CharaMakeParams, i18n("Chara Make Params")},
|
{FileType::CharaMakeParams, i18n("Chara Make Params")},
|
||||||
{FileType::Skeleton, i18n("Skeleton")},
|
{FileType::Skeleton, i18n("Skeleton")},
|
||||||
{FileType::Dictionary, i18n("Dictionary")}};
|
{FileType::Dictionary, i18n("Dictionary")},
|
||||||
|
{FileType::Material, i18n("Material")}};
|
||||||
|
|
||||||
const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiteral("unknown")},
|
const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiteral("unknown")},
|
||||||
{FileType::ExcelList, QStringLiteral("x-office-spreadsheet")},
|
{FileType::ExcelList, QStringLiteral("x-office-spreadsheet")},
|
||||||
|
@ -36,7 +38,8 @@ const static QMap<FileType, QString> typeToIcon{{FileType::Unknown, QStringLiter
|
||||||
{FileType::ShaderPackage, QStringLiteral("paint-pattern-symbolic")},
|
{FileType::ShaderPackage, QStringLiteral("paint-pattern-symbolic")},
|
||||||
{FileType::CharaMakeParams, QStringLiteral("step_object_SoftBody-symbolic")},
|
{FileType::CharaMakeParams, QStringLiteral("step_object_SoftBody-symbolic")},
|
||||||
{FileType::Skeleton, QStringLiteral("user-symbolic")},
|
{FileType::Skeleton, QStringLiteral("user-symbolic")},
|
||||||
{FileType::Dictionary, QStringLiteral("accessories-dictionary-symbolic")}};
|
{FileType::Dictionary, QStringLiteral("accessories-dictionary-symbolic")},
|
||||||
|
{FileType::Material, QStringLiteral("map-globe-symbolic")}};
|
||||||
|
|
||||||
FileType FileTypes::getFileType(const QString &extension)
|
FileType FileTypes::getFileType(const QString &extension)
|
||||||
{
|
{
|
||||||
|
|
|
@ -5,12 +5,10 @@ add_executable(novus-mateditor)
|
||||||
target_sources(novus-mateditor
|
target_sources(novus-mateditor
|
||||||
PRIVATE
|
PRIVATE
|
||||||
include/mainwindow.h
|
include/mainwindow.h
|
||||||
include/materialpropertyedit.h
|
|
||||||
include/materialview.h
|
include/materialview.h
|
||||||
|
|
||||||
src/main.cpp
|
src/main.cpp
|
||||||
src/mainwindow.cpp
|
src/mainwindow.cpp
|
||||||
src/materialpropertyedit.cpp
|
|
||||||
src/materialview.cpp)
|
src/materialview.cpp)
|
||||||
target_include_directories(novus-mateditor
|
target_include_directories(novus-mateditor
|
||||||
PUBLIC
|
PUBLIC
|
||||||
|
@ -19,9 +17,10 @@ target_link_libraries(novus-mateditor
|
||||||
PRIVATE
|
PRIVATE
|
||||||
Novus::Common
|
Novus::Common
|
||||||
Novus::MdlPart
|
Novus::MdlPart
|
||||||
Novus::TexPart
|
Novus::MtrlPart
|
||||||
Physis::Physis
|
Physis::Physis
|
||||||
Physis::Logger
|
Physis::Logger
|
||||||
|
KF6::I18n
|
||||||
Qt6::Core
|
Qt6::Core
|
||||||
Qt6::Widgets)
|
Qt6::Widgets)
|
||||||
|
|
||||||
|
|
|
@ -3,14 +3,15 @@
|
||||||
|
|
||||||
#include "mainwindow.h"
|
#include "mainwindow.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
#include <QApplication>
|
#include <QApplication>
|
||||||
#include <QListWidget>
|
#include <QListWidget>
|
||||||
#include <QMenuBar>
|
#include <QMenuBar>
|
||||||
#include <QSplitter>
|
#include <QSplitter>
|
||||||
#include <physis.hpp>
|
#include <physis.hpp>
|
||||||
|
|
||||||
#include "materialpropertyedit.h"
|
|
||||||
#include "materialview.h"
|
#include "materialview.h"
|
||||||
|
#include "mtrlpart.h"
|
||||||
|
|
||||||
MainWindow::MainWindow(GameData *data)
|
MainWindow::MainWindow(GameData *data)
|
||||||
: NovusMainWindow()
|
: NovusMainWindow()
|
||||||
|
@ -27,9 +28,9 @@ MainWindow::MainWindow(GameData *data)
|
||||||
dummyWidget->setChildrenCollapsible(false);
|
dummyWidget->setChildrenCollapsible(false);
|
||||||
setCentralWidget(dummyWidget);
|
setCentralWidget(dummyWidget);
|
||||||
|
|
||||||
auto materialProperty = new MaterialPropertyEdit(data);
|
auto materialProperty = new MtrlPart(data);
|
||||||
materialProperty->setMaximumWidth(400);
|
materialProperty->setMaximumWidth(400);
|
||||||
materialProperty->setMaterial(m_material);
|
materialProperty->load(m_material);
|
||||||
dummyWidget->addWidget(materialProperty);
|
dummyWidget->addWidget(materialProperty);
|
||||||
|
|
||||||
auto matView = new MaterialView(data, cache);
|
auto matView = new MaterialView(data, cache);
|
||||||
|
|
|
@ -7,6 +7,7 @@ add_subdirectory(exd)
|
||||||
add_subdirectory(exl)
|
add_subdirectory(exl)
|
||||||
add_subdirectory(hex)
|
add_subdirectory(hex)
|
||||||
add_subdirectory(mdl)
|
add_subdirectory(mdl)
|
||||||
|
add_subdirectory(mtrl)
|
||||||
add_subdirectory(shpk)
|
add_subdirectory(shpk)
|
||||||
add_subdirectory(sklb)
|
add_subdirectory(sklb)
|
||||||
add_subdirectory(tex)
|
add_subdirectory(tex)
|
|
@ -39,6 +39,7 @@ MDLPart::MDLPart(GameData *data, FileCache &cache, QWidget *parent)
|
||||||
vkWindow->setVulkanInstance(inst);
|
vkWindow->setVulkanInstance(inst);
|
||||||
|
|
||||||
auto widget = QWidget::createWindowContainer(vkWindow);
|
auto widget = QWidget::createWindowContainer(vkWindow);
|
||||||
|
widget->installEventFilter(vkWindow);
|
||||||
|
|
||||||
viewportLayout->addWidget(widget);
|
viewportLayout->addWidget(widget);
|
||||||
|
|
||||||
|
@ -332,4 +333,9 @@ bool MDLPart::wireframe() const
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int MDLPart::numModels() const
|
||||||
|
{
|
||||||
|
return models.size();
|
||||||
|
}
|
||||||
|
|
||||||
#include "moc_mdlpart.cpp"
|
#include "moc_mdlpart.cpp"
|
|
@ -47,6 +47,8 @@ public:
|
||||||
void setWireframe(bool wireframe);
|
void setWireframe(bool wireframe);
|
||||||
bool wireframe() const;
|
bool wireframe() const;
|
||||||
|
|
||||||
|
int numModels() const;
|
||||||
|
|
||||||
Q_SIGNALS:
|
Q_SIGNALS:
|
||||||
void modelChanged();
|
void modelChanged();
|
||||||
void skeletonChanged();
|
void skeletonChanged();
|
||||||
|
|
|
@ -37,6 +37,21 @@ void VulkanWindow::exposeEvent(QExposeEvent *)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool VulkanWindow::eventFilter(QObject *watched, QEvent *event)
|
||||||
|
{
|
||||||
|
switch (event->type()) {
|
||||||
|
case QEvent::Hide:
|
||||||
|
// QWindow is reset when hiding a widget container without "SurfaceAboutToBeDestroyed" notification (Qt bug, tested on 6.5.1)
|
||||||
|
m_renderer->destroySwapchain();
|
||||||
|
m_initialized = false;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
// dispatchEvent(event, watched);
|
||||||
|
return QWindow::eventFilter(watched, event);
|
||||||
|
}
|
||||||
|
|
||||||
bool VulkanWindow::event(QEvent *e)
|
bool VulkanWindow::event(QEvent *e)
|
||||||
{
|
{
|
||||||
switch (e->type()) {
|
switch (e->type()) {
|
||||||
|
@ -52,11 +67,16 @@ bool VulkanWindow::event(QEvent *e)
|
||||||
resizeEvent->size().height() * screen()->devicePixelRatio());
|
resizeEvent->size().height() * screen()->devicePixelRatio());
|
||||||
}
|
}
|
||||||
} break;
|
} break;
|
||||||
case QEvent::PlatformSurface:
|
case QEvent::Hide: {
|
||||||
if (dynamic_cast<QPlatformSurfaceEvent *>(e)->surfaceEventType() == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed && m_initialized) {
|
m_renderer->destroySwapchain();
|
||||||
|
} break;
|
||||||
|
case QEvent::PlatformSurface: {
|
||||||
|
auto surfaceEvent = dynamic_cast<QPlatformSurfaceEvent *>(e);
|
||||||
|
auto surfaceEventType = surfaceEvent->surfaceEventType();
|
||||||
|
if (surfaceEventType == QPlatformSurfaceEvent::SurfaceAboutToBeDestroyed && m_initialized) {
|
||||||
m_renderer->destroySwapchain();
|
m_renderer->destroySwapchain();
|
||||||
}
|
}
|
||||||
break;
|
} break;
|
||||||
case QEvent::MouseButtonPress: {
|
case QEvent::MouseButtonPress: {
|
||||||
auto mouseEvent = dynamic_cast<QMouseEvent *>(e);
|
auto mouseEvent = dynamic_cast<QMouseEvent *>(e);
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@ public:
|
||||||
|
|
||||||
void exposeEvent(QExposeEvent *) override;
|
void exposeEvent(QExposeEvent *) override;
|
||||||
|
|
||||||
|
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||||
bool event(QEvent *e) override;
|
bool event(QEvent *e) override;
|
||||||
|
|
||||||
void render();
|
void render();
|
||||||
|
|
20
parts/mtrl/CMakeLists.txt
Normal file
20
parts/mtrl/CMakeLists.txt
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
# SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||||
|
# SPDX-License-Identifier: CC0-1.0
|
||||||
|
|
||||||
|
add_library(mtrlpart STATIC)
|
||||||
|
target_sources(mtrlpart
|
||||||
|
PRIVATE
|
||||||
|
knownvalues.h
|
||||||
|
mtrlpart.cpp
|
||||||
|
mtrlpart.h)
|
||||||
|
target_link_libraries(mtrlpart
|
||||||
|
PUBLIC
|
||||||
|
Physis::Physis
|
||||||
|
Novus::TexPart
|
||||||
|
KF6::I18n
|
||||||
|
Qt6::Core
|
||||||
|
Qt6::Widgets)
|
||||||
|
target_include_directories(mtrlpart PUBLIC ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
|
target_compile_definitions(mtrlpart PRIVATE TRANSLATION_DOMAIN="novus")
|
||||||
|
|
||||||
|
add_library(Novus::MtrlPart ALIAS mtrlpart)
|
|
@ -1,15 +1,6 @@
|
||||||
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||||
// SPDX-License-Identifier: GPL-3.0-or-later
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
#include "materialpropertyedit.h"
|
|
||||||
#include "texpart.h"
|
|
||||||
|
|
||||||
#include <KLocalizedString>
|
|
||||||
#include <QFormLayout>
|
|
||||||
#include <QGroupBox>
|
|
||||||
#include <QHBoxLayout>
|
|
||||||
#include <QPushButton>
|
|
||||||
|
|
||||||
const QHash<uint, const char *> keys = {
|
const QHash<uint, const char *> keys = {
|
||||||
// Taken from https://github.com/0ceal0t/Dalamud-VFXEditor
|
// Taken from https://github.com/0ceal0t/Dalamud-VFXEditor
|
||||||
{0x2C6C023C, "DecodeDepthBuffer"},
|
{0x2C6C023C, "DecodeDepthBuffer"},
|
||||||
|
@ -328,213 +319,3 @@ const QHash<uint, const char *> keys = {
|
||||||
{0xC8BD1DEF, "Specular Map Mode"},
|
{0xC8BD1DEF, "Specular Map Mode"},
|
||||||
{0x198D11CD, "Color"},
|
{0x198D11CD, "Color"},
|
||||||
{0xA02F4828, "Multi"}};
|
{0xA02F4828, "Multi"}};
|
||||||
|
|
||||||
MaterialPropertyEdit::MaterialPropertyEdit(GameData *data, QWidget *parent)
|
|
||||||
: QWidget(parent)
|
|
||||||
, m_data(data)
|
|
||||||
{
|
|
||||||
m_itemsLayout = new QVBoxLayout(this);
|
|
||||||
|
|
||||||
auto shaderPackageLayout = new QHBoxLayout();
|
|
||||||
m_itemsLayout->addLayout(shaderPackageLayout);
|
|
||||||
|
|
||||||
m_shaderPackageName = new QLineEdit();
|
|
||||||
m_shaderPackageName->setReadOnly(true);
|
|
||||||
shaderPackageLayout->addWidget(m_shaderPackageName);
|
|
||||||
|
|
||||||
auto selectShaderPackageButton = new QPushButton(i18n("Shaders…"));
|
|
||||||
shaderPackageLayout->addWidget(selectShaderPackageButton);
|
|
||||||
|
|
||||||
m_tabWidget = new QTabWidget();
|
|
||||||
m_itemsLayout->addWidget(m_tabWidget);
|
|
||||||
|
|
||||||
auto propertiesTab = new QWidget();
|
|
||||||
m_propertiesLayout = new QVBoxLayout();
|
|
||||||
propertiesTab->setLayout(m_propertiesLayout);
|
|
||||||
|
|
||||||
auto texturesTab = new QWidget();
|
|
||||||
m_texturesLayout = new QVBoxLayout();
|
|
||||||
texturesTab->setLayout(m_texturesLayout);
|
|
||||||
|
|
||||||
auto constantsTab = new QWidget();
|
|
||||||
m_constantsLayout = new QVBoxLayout();
|
|
||||||
constantsTab->setLayout(m_constantsLayout);
|
|
||||||
|
|
||||||
m_tabWidget->addTab(propertiesTab, i18n("Parameters"));
|
|
||||||
m_tabWidget->addTab(texturesTab, i18n("Textures"));
|
|
||||||
m_tabWidget->addTab(constantsTab, i18n("Constants"));
|
|
||||||
|
|
||||||
setLayout(m_itemsLayout);
|
|
||||||
|
|
||||||
rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialPropertyEdit::setMaterial(physis_Material material)
|
|
||||||
{
|
|
||||||
m_material = material;
|
|
||||||
m_shaderPackageName->setText(QString::fromLatin1(material.shpk_name));
|
|
||||||
if (material.shpk_name != nullptr) {
|
|
||||||
std::string shpkPath = "shader/sm5/shpk/" + std::string(material.shpk_name);
|
|
||||||
|
|
||||||
auto shpkData = physis_gamedata_extract_file(m_data, shpkPath.c_str());
|
|
||||||
if (shpkData.data != nullptr) {
|
|
||||||
m_shpk = physis_parse_shpk(shpkData);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
rebuild();
|
|
||||||
}
|
|
||||||
|
|
||||||
void MaterialPropertyEdit::rebuild()
|
|
||||||
{
|
|
||||||
QLayoutItem *child = nullptr;
|
|
||||||
while ((child = m_propertiesLayout->takeAt(0)) != nullptr) {
|
|
||||||
child->widget()->setParent(nullptr);
|
|
||||||
child->widget()->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m_shpk.num_material_keys; i++) {
|
|
||||||
const auto materialKey = m_shpk.material_keys[i];
|
|
||||||
|
|
||||||
auto groupBox = new QGroupBox();
|
|
||||||
m_propertiesLayout->addWidget(groupBox);
|
|
||||||
|
|
||||||
if (keys.contains(materialKey.id)) {
|
|
||||||
groupBox->setTitle(QString::fromLatin1(keys[materialKey.id]));
|
|
||||||
} else {
|
|
||||||
groupBox->setTitle(i18n("Unknown Property %1", QStringLiteral("%1").arg(materialKey.id, 1, 16)));
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32_t value = 0;
|
|
||||||
|
|
||||||
bool found = false;
|
|
||||||
for (int j = 0; j < m_material.num_shader_keys; j++) {
|
|
||||||
auto shaderKey = m_material.shader_keys[j];
|
|
||||||
|
|
||||||
if (shaderKey.category == materialKey.id) {
|
|
||||||
value = shaderKey.value;
|
|
||||||
found = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Fall back to default value
|
|
||||||
if (!found) {
|
|
||||||
value = materialKey.default_value;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto layout = new QFormLayout();
|
|
||||||
groupBox->setLayout(layout);
|
|
||||||
|
|
||||||
auto label = new QLabel();
|
|
||||||
if (keys.contains(value)) {
|
|
||||||
label->setText(QString::fromLatin1(keys[value]));
|
|
||||||
} else {
|
|
||||||
label->setText(i18n("Unknown value %1", QStringLiteral("%1").arg(value, 1, 16)));
|
|
||||||
}
|
|
||||||
|
|
||||||
layout->addRow(i18n("Value:"), label);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = nullptr;
|
|
||||||
while ((child = m_texturesLayout->takeAt(0)) != nullptr) {
|
|
||||||
child->widget()->setParent(nullptr);
|
|
||||||
child->widget()->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m_material.num_samplers; i++) {
|
|
||||||
const auto sampler = m_material.samplers[i];
|
|
||||||
|
|
||||||
QString name;
|
|
||||||
switch (sampler.texture_usage) {
|
|
||||||
case TextureUsage::Sampler:
|
|
||||||
case TextureUsage::Sampler0:
|
|
||||||
case TextureUsage::Sampler1:
|
|
||||||
name = i18n("Generic");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerCatchlight:
|
|
||||||
name = i18n("Catchlight");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerColorMap0:
|
|
||||||
name = i18n("Color Map 0");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerColorMap1:
|
|
||||||
name = i18n("Color Map 1");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerDiffuse:
|
|
||||||
name = i18n("Diffuse");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerEnvMap:
|
|
||||||
name = i18n("Environment Map");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerMask:
|
|
||||||
name = i18n("Mask");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerNormal:
|
|
||||||
name = i18n("Normal");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerNormalMap0:
|
|
||||||
name = i18n("Normal Map 0");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerNormalMap1:
|
|
||||||
name = i18n("Normal Map 1");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerReflection:
|
|
||||||
name = i18n("Reflection");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerSpecular:
|
|
||||||
name = i18n("Specular");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerSpecularMap0:
|
|
||||||
name = i18n("Specular Map 0");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerSpecularMap1:
|
|
||||||
name = i18n("Specular Map 1");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerWaveMap:
|
|
||||||
name = i18n("Wave Map");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerWaveletMap0:
|
|
||||||
name = i18n("Wavelet Map 0");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerWaveletMap1:
|
|
||||||
name = i18n("Wavelet Map 1");
|
|
||||||
break;
|
|
||||||
case TextureUsage::SamplerWhitecapMap:
|
|
||||||
name = i18n("Whitecap Map");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
name = i18n("Unknown");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto groupBox = new QGroupBox(name);
|
|
||||||
m_texturesLayout->addWidget(groupBox);
|
|
||||||
|
|
||||||
auto layout = new QFormLayout();
|
|
||||||
groupBox->setLayout(layout);
|
|
||||||
|
|
||||||
auto texWidget = new TexPart(m_data);
|
|
||||||
texWidget->load(physis_gamedata_extract_file(m_data, m_material.textures[i]));
|
|
||||||
layout->addRow(i18n("Value:"), texWidget);
|
|
||||||
}
|
|
||||||
|
|
||||||
child = nullptr;
|
|
||||||
while ((child = m_constantsLayout->takeAt(0)) != nullptr) {
|
|
||||||
child->widget()->setParent(nullptr);
|
|
||||||
child->widget()->deleteLater();
|
|
||||||
}
|
|
||||||
|
|
||||||
for (int i = 0; i < m_material.num_constants; i++) {
|
|
||||||
const auto constant = m_material.constants[i];
|
|
||||||
|
|
||||||
auto groupBox = new QGroupBox(QString::number(constant.id));
|
|
||||||
m_constantsLayout->addWidget(groupBox);
|
|
||||||
|
|
||||||
auto layout = new QFormLayout();
|
|
||||||
groupBox->setLayout(layout);
|
|
||||||
|
|
||||||
auto label = new QLabel(QString::number(constant.value));
|
|
||||||
layout->addRow(i18n("Value:"), label);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#include "moc_materialpropertyedit.cpp"
|
|
224
parts/mtrl/mtrlpart.cpp
Normal file
224
parts/mtrl/mtrlpart.cpp
Normal file
|
@ -0,0 +1,224 @@
|
||||||
|
// SPDX-FileCopyrightText: 2024 Joshua Goins <josh@redstrate.com>
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
|
#include "mtrlpart.h"
|
||||||
|
|
||||||
|
#include <KLocalizedString>
|
||||||
|
#include <QFormLayout>
|
||||||
|
#include <QGroupBox>
|
||||||
|
#include <QPushButton>
|
||||||
|
#include <QVBoxLayout>
|
||||||
|
#include <physis.hpp>
|
||||||
|
|
||||||
|
#include "knownvalues.h"
|
||||||
|
#include "texpart.h"
|
||||||
|
|
||||||
|
MtrlPart::MtrlPart(GameData *data, QWidget *parent)
|
||||||
|
: QWidget(parent)
|
||||||
|
, m_data(data)
|
||||||
|
{
|
||||||
|
m_itemsLayout = new QVBoxLayout(this);
|
||||||
|
|
||||||
|
auto shaderPackageLayout = new QHBoxLayout();
|
||||||
|
m_itemsLayout->addLayout(shaderPackageLayout);
|
||||||
|
|
||||||
|
m_shaderPackageName = new QLineEdit();
|
||||||
|
m_shaderPackageName->setReadOnly(true);
|
||||||
|
shaderPackageLayout->addWidget(m_shaderPackageName);
|
||||||
|
|
||||||
|
auto selectShaderPackageButton = new QPushButton(i18n("Shaders…"));
|
||||||
|
shaderPackageLayout->addWidget(selectShaderPackageButton);
|
||||||
|
|
||||||
|
m_tabWidget = new QTabWidget();
|
||||||
|
m_itemsLayout->addWidget(m_tabWidget);
|
||||||
|
|
||||||
|
auto propertiesTab = new QWidget();
|
||||||
|
m_propertiesLayout = new QVBoxLayout();
|
||||||
|
propertiesTab->setLayout(m_propertiesLayout);
|
||||||
|
|
||||||
|
auto texturesTab = new QWidget();
|
||||||
|
m_texturesLayout = new QVBoxLayout();
|
||||||
|
texturesTab->setLayout(m_texturesLayout);
|
||||||
|
|
||||||
|
auto constantsTab = new QWidget();
|
||||||
|
m_constantsLayout = new QVBoxLayout();
|
||||||
|
constantsTab->setLayout(m_constantsLayout);
|
||||||
|
|
||||||
|
m_tabWidget->addTab(propertiesTab, i18n("Parameters"));
|
||||||
|
m_tabWidget->addTab(texturesTab, i18n("Textures"));
|
||||||
|
m_tabWidget->addTab(constantsTab, i18n("Constants"));
|
||||||
|
|
||||||
|
setLayout(m_itemsLayout);
|
||||||
|
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MtrlPart::load(physis_Material file)
|
||||||
|
{
|
||||||
|
m_material = file;
|
||||||
|
m_shaderPackageName->setText(QString::fromLatin1(m_material.shpk_name));
|
||||||
|
if (m_material.shpk_name != nullptr) {
|
||||||
|
std::string shpkPath = "shader/sm5/shpk/" + std::string(m_material.shpk_name);
|
||||||
|
|
||||||
|
auto shpkData = physis_gamedata_extract_file(m_data, shpkPath.c_str());
|
||||||
|
if (shpkData.data != nullptr) {
|
||||||
|
m_shpk = physis_parse_shpk(shpkData);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
void MtrlPart::rebuild()
|
||||||
|
{
|
||||||
|
QLayoutItem *child = nullptr;
|
||||||
|
while ((child = m_propertiesLayout->takeAt(0)) != nullptr) {
|
||||||
|
child->widget()->setParent(nullptr);
|
||||||
|
child->widget()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_shpk.num_material_keys; i++) {
|
||||||
|
const auto materialKey = m_shpk.material_keys[i];
|
||||||
|
|
||||||
|
auto groupBox = new QGroupBox();
|
||||||
|
m_propertiesLayout->addWidget(groupBox);
|
||||||
|
|
||||||
|
if (keys.contains(materialKey.id)) {
|
||||||
|
groupBox->setTitle(QString::fromLatin1(keys[materialKey.id]));
|
||||||
|
} else {
|
||||||
|
groupBox->setTitle(i18n("Unknown Property %1", QStringLiteral("%1").arg(materialKey.id, 1, 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32_t value = 0;
|
||||||
|
|
||||||
|
bool found = false;
|
||||||
|
for (int j = 0; j < m_material.num_shader_keys; j++) {
|
||||||
|
auto shaderKey = m_material.shader_keys[j];
|
||||||
|
|
||||||
|
if (shaderKey.category == materialKey.id) {
|
||||||
|
value = shaderKey.value;
|
||||||
|
found = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fall back to default value
|
||||||
|
if (!found) {
|
||||||
|
value = materialKey.default_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto layout = new QFormLayout();
|
||||||
|
groupBox->setLayout(layout);
|
||||||
|
|
||||||
|
auto label = new QLabel();
|
||||||
|
if (keys.contains(value)) {
|
||||||
|
label->setText(QString::fromLatin1(keys[value]));
|
||||||
|
} else {
|
||||||
|
label->setText(i18n("Unknown value %1", QStringLiteral("%1").arg(value, 1, 16)));
|
||||||
|
}
|
||||||
|
|
||||||
|
layout->addRow(i18n("Value:"), label);
|
||||||
|
}
|
||||||
|
|
||||||
|
child = nullptr;
|
||||||
|
while ((child = m_texturesLayout->takeAt(0)) != nullptr) {
|
||||||
|
child->widget()->setParent(nullptr);
|
||||||
|
child->widget()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_material.num_samplers; i++) {
|
||||||
|
const auto sampler = m_material.samplers[i];
|
||||||
|
|
||||||
|
QString name;
|
||||||
|
switch (sampler.texture_usage) {
|
||||||
|
case TextureUsage::Sampler:
|
||||||
|
case TextureUsage::Sampler0:
|
||||||
|
case TextureUsage::Sampler1:
|
||||||
|
name = i18n("Generic");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerCatchlight:
|
||||||
|
name = i18n("Catchlight");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerColorMap0:
|
||||||
|
name = i18n("Color Map 0");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerColorMap1:
|
||||||
|
name = i18n("Color Map 1");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerDiffuse:
|
||||||
|
name = i18n("Diffuse");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerEnvMap:
|
||||||
|
name = i18n("Environment Map");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerMask:
|
||||||
|
name = i18n("Mask");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerNormal:
|
||||||
|
name = i18n("Normal");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerNormalMap0:
|
||||||
|
name = i18n("Normal Map 0");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerNormalMap1:
|
||||||
|
name = i18n("Normal Map 1");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerReflection:
|
||||||
|
name = i18n("Reflection");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerSpecular:
|
||||||
|
name = i18n("Specular");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerSpecularMap0:
|
||||||
|
name = i18n("Specular Map 0");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerSpecularMap1:
|
||||||
|
name = i18n("Specular Map 1");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerWaveMap:
|
||||||
|
name = i18n("Wave Map");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerWaveletMap0:
|
||||||
|
name = i18n("Wavelet Map 0");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerWaveletMap1:
|
||||||
|
name = i18n("Wavelet Map 1");
|
||||||
|
break;
|
||||||
|
case TextureUsage::SamplerWhitecapMap:
|
||||||
|
name = i18n("Whitecap Map");
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
name = i18n("Unknown");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto groupBox = new QGroupBox(name);
|
||||||
|
m_texturesLayout->addWidget(groupBox);
|
||||||
|
|
||||||
|
auto layout = new QFormLayout();
|
||||||
|
groupBox->setLayout(layout);
|
||||||
|
|
||||||
|
auto texWidget = new TexPart(m_data);
|
||||||
|
texWidget->load(physis_gamedata_extract_file(m_data, m_material.textures[i]));
|
||||||
|
layout->addRow(i18n("Value:"), texWidget);
|
||||||
|
}
|
||||||
|
|
||||||
|
child = nullptr;
|
||||||
|
while ((child = m_constantsLayout->takeAt(0)) != nullptr) {
|
||||||
|
child->widget()->setParent(nullptr);
|
||||||
|
child->widget()->deleteLater();
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < m_material.num_constants; i++) {
|
||||||
|
const auto constant = m_material.constants[i];
|
||||||
|
|
||||||
|
auto groupBox = new QGroupBox(QString::number(constant.id));
|
||||||
|
m_constantsLayout->addWidget(groupBox);
|
||||||
|
|
||||||
|
auto layout = new QFormLayout();
|
||||||
|
groupBox->setLayout(layout);
|
||||||
|
|
||||||
|
auto label = new QLabel(QString::number(constant.value));
|
||||||
|
layout->addRow(i18n("Value:"), label);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "moc_mtrlpart.cpp"
|
|
@ -11,14 +11,14 @@
|
||||||
#include <QTabWidget>
|
#include <QTabWidget>
|
||||||
#include <physis.hpp>
|
#include <physis.hpp>
|
||||||
|
|
||||||
class MaterialPropertyEdit : public QWidget
|
class MtrlPart : public QWidget
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit MaterialPropertyEdit(GameData *data, QWidget *parent = nullptr);
|
explicit MtrlPart(GameData *data, QWidget *parent = nullptr);
|
||||||
|
|
||||||
void setMaterial(physis_Material material);
|
void load(physis_Material file);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void rebuild();
|
void rebuild();
|
|
@ -350,11 +350,10 @@ void RenderManager::resize(VkSurfaceKHR surface, int width, int height)
|
||||||
|
|
||||||
void RenderManager::destroySwapchain()
|
void RenderManager::destroySwapchain()
|
||||||
{
|
{
|
||||||
// TODO: port to new swapchain aPI
|
if (m_device->swapChain->swapchain != VK_NULL_HANDLE) {
|
||||||
/*if (swapchain != VK_NULL_HANDLE) {
|
vkDestroySwapchainKHR(m_device->device, m_device->swapChain->swapchain, nullptr);
|
||||||
vkDestroySwapchainKHR(device, swapchain, nullptr);
|
m_device->swapChain->swapchain = VK_NULL_HANDLE;
|
||||||
swapchain = VK_NULL_HANDLE;
|
}
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void RenderManager::render(const std::vector<DrawObject> &models)
|
void RenderManager::render(const std::vector<DrawObject> &models)
|
||||||
|
|
|
@ -44,6 +44,7 @@ target_link_libraries(novus-sagasu
|
||||||
Novus::ExdPart
|
Novus::ExdPart
|
||||||
Novus::TexPart
|
Novus::TexPart
|
||||||
Novus::DicPart
|
Novus::DicPart
|
||||||
|
Novus::MtrlPart
|
||||||
Physis::Logger
|
Physis::Logger
|
||||||
Qt6::Concurrent
|
Qt6::Concurrent
|
||||||
Qt6::Network)
|
Qt6::Network)
|
||||||
|
|
|
@ -256,6 +256,7 @@ int main(int argc, char *argv[])
|
||||||
database.addFile(QStringLiteral("chara/xls/bonedeformer/human.pbd"));
|
database.addFile(QStringLiteral("chara/xls/bonedeformer/human.pbd"));
|
||||||
database.addFile(QStringLiteral("chara/xls/charamake/human.cmp"));
|
database.addFile(QStringLiteral("chara/xls/charamake/human.cmp"));
|
||||||
database.addFile(QStringLiteral("chara/human/c0101/skeleton/base/b0001/skl_c0101b0001.sklb"));
|
database.addFile(QStringLiteral("chara/human/c0101/skeleton/base/b0001/skl_c0101b0001.sklb"));
|
||||||
|
database.addFile(QStringLiteral("chara/equipment/e0028/material/v0001/mt_c0101e0028_top_a.mtrl"));
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
|
@ -24,6 +24,7 @@
|
||||||
#include "filetypes.h"
|
#include "filetypes.h"
|
||||||
#include "hexpart.h"
|
#include "hexpart.h"
|
||||||
#include "mdlpart.h"
|
#include "mdlpart.h"
|
||||||
|
#include "mtrlpart.h"
|
||||||
#include "shpkpart.h"
|
#include "shpkpart.h"
|
||||||
#include "sklbpart.h"
|
#include "sklbpart.h"
|
||||||
#include "texpart.h"
|
#include "texpart.h"
|
||||||
|
@ -132,6 +133,11 @@ void MainWindow::refreshParts(const QString &path)
|
||||||
dicWidget->load(file);
|
dicWidget->load(file);
|
||||||
partHolder->addTab(dicWidget, i18nc("@title:tab", "Dictionary"));
|
partHolder->addTab(dicWidget, i18nc("@title:tab", "Dictionary"));
|
||||||
} break;
|
} break;
|
||||||
|
case FileType::Material: {
|
||||||
|
auto mtrlWidget = new MtrlPart(data);
|
||||||
|
mtrlWidget->load(physis_material_parse(file));
|
||||||
|
partHolder->addTab(mtrlWidget, i18nc("@title:tab", "Material"));
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue