Add "combineMode" configuration for component to replace the "inverse" attribute

Currently, only support "Normal" and "Inversion" modes, "Normal" means normal mesh union, "Inversion" means mesh diff, it behaves like subtract itself from the previous mesh.
master
huxingyi 2018-11-14 21:21:45 +08:00
parent 724e745f2e
commit ab97615bea
13 changed files with 123 additions and 34 deletions

View File

@ -291,6 +291,9 @@ HEADERS += src/skeletondocument.h
SOURCES += src/posedocument.cpp
HEADERS += src/posedocument.h
SOURCES += src/combinemode.cpp
HEADERS += src/combinemode.h
SOURCES += src/main.cpp
HEADERS += src/version.h

6
src/combinemode.cpp Normal file
View File

@ -0,0 +1,6 @@
#include <QObject>
#include "combinemode.h"
IMPL_CombineModeToString
IMPL_CombineModeFromString
IMPL_CombineModeToDispName

49
src/combinemode.h Normal file
View File

@ -0,0 +1,49 @@
#ifndef DUST3D_COMBINE_MODE_H
#define DUST3D_COMBINE_MODE_H
#include <QString>
enum class CombineMode
{
Normal = 0,
Inversion,
Count
};
CombineMode CombineModeFromString(const char *modeString);
#define IMPL_CombineModeFromString \
CombineMode CombineModeFromString(const char *modeString) \
{ \
QString mode = modeString; \
if (mode == "Normal") \
return CombineMode::Normal; \
if (mode == "Inversion") \
return CombineMode::Inversion; \
return CombineMode::Normal; \
}
const char *CombineModeToString(CombineMode mode);
#define IMPL_CombineModeToString \
const char *CombineModeToString(CombineMode mode) \
{ \
switch (mode) { \
case CombineMode::Normal: \
return "Normal"; \
case CombineMode::Inversion: \
return "Inversion"; \
default: \
return "Normal"; \
} \
}
QString CombineModeToDispName(CombineMode mode);
#define IMPL_CombineModeToDispName \
QString CombineModeToDispName(CombineMode mode) \
{ \
switch (mode) { \
case CombineMode::Normal: \
return QObject::tr("Normal"); \
case CombineMode::Inversion: \
return QObject::tr("Inversion"); \
default: \
return QObject::tr("Normal"); \
} \
}
#endif

View File

@ -903,7 +903,7 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
if (!componentIt.second.name.isEmpty())
component["name"] = componentIt.second.name;
component["expanded"] = componentIt.second.expanded ? "true" : "false";
component["inverse"] = componentIt.second.inverse ? "true" : "false";
component["combineMode"] = CombineModeToString(componentIt.second.combineMode);
component["dirty"] = componentIt.second.dirty ? "true" : "false";
if (componentIt.second.smoothAllAdjusted())
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
@ -1178,7 +1178,11 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
oldNewIdMap[QUuid(componentKv.first)] = component.id;
component.name = valueOfKeyInMapOrEmpty(componentKv.second, "name");
component.expanded = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "expanded"));
component.inverse = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "inverse"));
component.combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(componentKv.second, "combineMode").toUtf8().constData());
if (component.combineMode == CombineMode::Normal) {
if (isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "inverse")))
component.combineMode = CombineMode::Inversion;
}
const auto &smoothAllIt = componentKv.second.find("smoothAll");
if (smoothAllIt != componentKv.second.end())
component.setSmoothAll(smoothAllIt->second.toFloat());
@ -1192,7 +1196,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
//qDebug() << "Add part:" << partId << " from component:" << component.id;
partMap[partId].componentId = component.id;
if (inversePartIds.find(partId) != inversePartIds.end())
component.inverse = true;
component.combineMode = CombineMode::Inversion;
}
componentMap[component.id] = component;
newAddedComponentIds.insert(component.id);
@ -1609,18 +1613,18 @@ void Document::setPartVisibleState(QUuid partId, bool visible)
emit optionsChanged();
}
void Document::setComponentInverseState(QUuid componentId, bool inverse)
void Document::setComponentCombineMode(QUuid componentId, CombineMode combineMode)
{
auto component = componentMap.find(componentId);
if (component == componentMap.end()) {
qDebug() << "Component not found:" << componentId;
return;
}
if (component->second.inverse == inverse)
if (component->second.combineMode == combineMode)
return;
component->second.inverse = inverse;
component->second.combineMode = combineMode;
component->second.dirty = true;
emit componentInverseStateChanged(componentId);
emit componentCombineModeChanged(componentId);
emit skeletonChanged();
}

View File

@ -24,6 +24,7 @@
#include "interpolationtype.h"
#include "jointnodetree.h"
#include "skeletondocument.h"
#include "combinemode.h"
class MaterialPreviewsGenerator;
class MotionsGenerator;
@ -55,7 +56,7 @@ public:
QUuid linkToPartId;
QUuid parentId;
bool expanded = true;
bool inverse = false;
CombineMode combineMode = CombineMode::Normal;
bool dirty = true;
float smoothAll = 0.0;
float smoothSeam = 0.0;
@ -401,7 +402,7 @@ signals:
void partColorStateChanged(QUuid partId);
void partWrapStateChanged(QUuid partId);
void partMaterialIdChanged(QUuid partId);
void componentInverseStateChanged(QUuid partId);
void componentCombineModeChanged(QUuid componentId);
void cleanup();
void originChanged();
void xlockStateChanged();
@ -549,7 +550,7 @@ public slots:
void setPartColorState(QUuid partId, bool hasColor, QColor color);
void setPartWrapState(QUuid partId, bool wrapped);
void setPartMaterialId(QUuid partId, QUuid materialId);
void setComponentInverseState(QUuid componentId, bool inverse);
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
void moveComponentUp(QUuid componentId);
void moveComponentDown(QUuid componentId);
void moveComponentToTop(QUuid componentId);

View File

@ -783,7 +783,7 @@ DocumentWindow::DocumentWindow() :
connect(partTreeWidget, &PartTreeWidget::unlockAllComponents, m_document, &Document::unlockAllComponents);
connect(partTreeWidget, &PartTreeWidget::setPartLockState, m_document, &Document::setPartLockState);
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
connect(partTreeWidget, &PartTreeWidget::setComponentInverseState, m_document, &Document::setComponentInverseState);
connect(partTreeWidget, &PartTreeWidget::setComponentCombineMode, m_document, &Document::setComponentCombineMode);
connect(partTreeWidget, &PartTreeWidget::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
@ -796,7 +796,7 @@ DocumentWindow::DocumentWindow() :
connect(m_document, &Document::componentRemoved, partTreeWidget, &PartTreeWidget::componentRemoved);
connect(m_document, &Document::componentAdded, partTreeWidget, &PartTreeWidget::componentAdded);
connect(m_document, &Document::componentExpandStateChanged, partTreeWidget, &PartTreeWidget::componentExpandStateChanged);
connect(m_document, &Document::componentInverseStateChanged, partTreeWidget, &PartTreeWidget::componentInverseStateChanged);
connect(m_document, &Document::componentCombineModeChanged, partTreeWidget, &PartTreeWidget::componentCombineModeChanged);
connect(m_document, &Document::partPreviewChanged, partTreeWidget, &PartTreeWidget::partPreviewChanged);
connect(m_document, &Document::partLockStateChanged, partTreeWidget, &PartTreeWidget::partLockStateChanged);
connect(m_document, &Document::partVisibleStateChanged, partTreeWidget, &PartTreeWidget::partVisibleStateChanged);

View File

@ -516,7 +516,8 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
component = &findComponent->second;
}
if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse")))
CombineMode combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(*component, "combineMode").toUtf8().constData());
if (combineMode == CombineMode::Inversion)
*inverse = true;
if (m_dirtyComponentIds.find(componentId) == m_dirtyComponentIds.end()) {

View File

@ -6,6 +6,7 @@
#include <QRadialGradient>
#include <QBrush>
#include <QGuiApplication>
#include <QComboBox>
#include "parttreewidget.h"
#include "partwidget.h"
#include "skeletongraphicswidget.h"
@ -119,8 +120,8 @@ void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected
auto item = m_partItemMap.find(component->linkToPartId);
if (item != m_componentItemMap.end()) {
PartWidget *widget = (PartWidget *)itemWidget(item->second, 0);
// Inverse state updating call should be called before check state updating call
widget->updateInverseState(component->inverse);
// Unnormal state updating call should be called before check state updating call
widget->updateUnnormalState(component->combineMode != CombineMode::Normal);
widget->updateCheckedState(selected);
}
return;
@ -128,7 +129,7 @@ void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected
auto item = m_componentItemMap.find(componentId);
if (item != m_componentItemMap.end()) {
item->second->setFont(0, selected ? m_selectedFont : m_normalFont);
if (component->inverse)
if (component->combineMode != CombineMode::Normal)
item->second->setForeground(0, selected ? QBrush(Theme::blue) : QBrush(Theme::blue));
else
item->second->setForeground(0, selected ? QBrush(Theme::red) : QBrush(Theme::white));
@ -259,7 +260,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
} else {
QLabel *previewLabel = new QLabel;
previewLabel->setFixedHeight(Theme::partPreviewImageSize);
previewLabel->setStyleSheet("QLabel {color: " + (component && component->inverse ? Theme::blue.name() : Theme::red.name()) + "}");
previewLabel->setStyleSheet("QLabel {color: " + (component && (component->combineMode != CombineMode::Normal) ? Theme::blue.name() : Theme::red.name()) + "}");
if (nullptr != component) {
previewLabel->setText(component->name);
} else if (!componentIds.empty()) {
@ -268,7 +269,31 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
layout->addWidget(previewLabel);
}
QWidget *widget = new QWidget;
if (nullptr != component) {
QComboBox *combineModeSelectBox = new QComboBox;
for (size_t i = 0; i < (size_t)CombineMode::Count; ++i) {
CombineMode mode = (CombineMode)i;
combineModeSelectBox->addItem(CombineModeToDispName(mode));
}
combineModeSelectBox->setCurrentIndex((int)component->combineMode);
connect(combineModeSelectBox, static_cast<void (QComboBox::*)(int)>(&QComboBox::currentIndexChanged), this, [=](int index) {
emit setComponentCombineMode(component->id, (CombineMode)index);
});
QHBoxLayout *combineModeLayout = new QHBoxLayout;
combineModeLayout->setAlignment(Qt::AlignCenter);
combineModeLayout->setContentsMargins(0, 0, 0, 0);
combineModeLayout->setSpacing(0);
combineModeLayout->addWidget(combineModeSelectBox);
QVBoxLayout *newLayout = new QVBoxLayout;
newLayout->addLayout(layout);
newLayout->addLayout(combineModeLayout);
widget->setLayout(newLayout);
} else {
widget->setLayout(layout);
}
forDisplayPartImage.setDefaultWidget(widget);
if (!componentIds.empty()) {
contextMenu.addAction(&forDisplayPartImage);
@ -283,8 +308,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
lockAction.setIcon(Theme::awesome()->icon(fa::lock));
QAction unlockAction(tr("Unlock"), this);
unlockAction.setIcon(Theme::awesome()->icon(fa::unlock));
QAction invertAction(tr("Invert"), this);
QAction cancelInverseAction(tr("Cancel Inverse"), this);
QAction selectAction(tr("Select"), this);
if (nullptr != component && nullptr != part) {
@ -353,6 +376,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
contextMenu.addAction(&unlockAction);
}
/*
if (component && !component->inverse) {
connect(&invertAction, &QAction::triggered, [=]() {
emit setComponentInverseState(component->id, true);
@ -366,6 +390,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
});
contextMenu.addAction(&cancelInverseAction);
}
*/
contextMenu.addSeparator();
@ -655,7 +680,7 @@ void PartTreeWidget::componentExpandStateChanged(QUuid componentId)
componentItem->second->setExpanded(component->expanded);
}
void PartTreeWidget::componentInverseStateChanged(QUuid componentId)
void PartTreeWidget::componentCombineModeChanged(QUuid componentId)
{
updateComponentAppearance(componentId);
}

View File

@ -33,7 +33,7 @@ signals:
void unlockAllComponents();
void setPartLockState(QUuid partId, bool locked);
void setPartVisibleState(QUuid partId, bool visible);
void setComponentInverseState(QUuid componentId, bool inverse);
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
void hideDescendantComponents(QUuid componentId);
void showDescendantComponents(QUuid componentId);
void lockDescendantComponents(QUuid componentId);
@ -49,7 +49,7 @@ public slots:
void componentRemoved(QUuid componentId);
void componentAdded(QUuid componentId);
void componentExpandStateChanged(QUuid componentId);
void componentInverseStateChanged(QUuid componentId);
void componentCombineModeChanged(QUuid componentId);
void partRemoved(QUuid partId);
void partPreviewChanged(QUuid partid);
void partLockStateChanged(QUuid partId);

View File

@ -15,7 +15,7 @@
PartWidget::PartWidget(const Document *document, QUuid partId) :
m_document(document),
m_partId(partId),
m_inverted(false)
m_unnormal(false)
{
QSizePolicy retainSizePolicy = sizePolicy();
retainSizePolicy.setRetainSizeWhenHidden(true);
@ -263,17 +263,17 @@ void PartWidget::updateAllButtons()
void PartWidget::updateCheckedState(bool checked)
{
if (checked)
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + (m_inverted ? Theme::blue.name() : Theme::red.name()) + ";}");
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + (m_unnormal ? Theme::blue.name() : Theme::red.name()) + ";}");
else
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}");
}
void PartWidget::updateInverseState(bool inverse)
void PartWidget::updateUnnormalState(bool unnormal)
{
if (m_inverted == inverse)
if (m_unnormal == unnormal)
return;
m_inverted = inverse;
m_unnormal = unnormal;
updateAllButtons();
}
@ -439,7 +439,7 @@ void PartWidget::initButton(QPushButton *button)
void PartWidget::updateButton(QPushButton *button, QChar icon, bool highlighted)
{
Theme::updateAwesomeMiniButton(button, icon, highlighted, m_inverted);
Theme::updateAwesomeMiniButton(button, icon, highlighted, m_unnormal);
}
void PartWidget::updatePreview()

View File

@ -45,7 +45,7 @@ public:
void updateColorButton();
void updateWrapButton();
void updateCheckedState(bool checked);
void updateInverseState(bool inverse);
void updateUnnormalState(bool unnormal);
static QSize preferredSize();
ModelWidget *previewWidget();
protected:
@ -56,7 +56,7 @@ public slots:
private: // need initialize
const Document *m_document;
QUuid m_partId;
bool m_inverted;
bool m_unnormal;
private:
ModelWidget *m_previewWidget;
QPushButton *m_visibleButton;

View File

@ -103,14 +103,14 @@ void Theme::initAwesomeMiniButton(QPushButton *button)
button->setFocusPolicy(Qt::NoFocus);
}
void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool inverted)
void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal)
{
button->setText(icon);
QColor color;
bool needDesaturation = true;
if (highlighted) {
if (inverted) {
if (unnormal) {
color = Theme::blue;
needDesaturation = false;
} else {

View File

@ -47,7 +47,7 @@ public:
static void initAwesomeLabel(QLabel *label);
static void initAwesomeSmallButton(QPushButton *button);
static void initAwesomeMiniButton(QPushButton *button);
static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool inverted=false);
static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal=false);
static void initAwesomeToolButton(QPushButton *button);
static void initAwesomeToolButtonWithoutFont(QPushButton *button);
};