Merge branch 'master' of https://github.com/huxingyi/dust3d
commit
d48bea6248
|
@ -291,6 +291,12 @@ HEADERS += src/skeletondocument.h
|
||||||
SOURCES += src/posedocument.cpp
|
SOURCES += src/posedocument.cpp
|
||||||
HEADERS += src/posedocument.h
|
HEADERS += src/posedocument.h
|
||||||
|
|
||||||
|
SOURCES += src/combinemode.cpp
|
||||||
|
HEADERS += src/combinemode.h
|
||||||
|
|
||||||
|
SOURCES += src/meshinflate.cpp
|
||||||
|
HEADERS += src/meshinflate.h
|
||||||
|
|
||||||
SOURCES += src/main.cpp
|
SOURCES += src/main.cpp
|
||||||
|
|
||||||
HEADERS += src/version.h
|
HEADERS += src/version.h
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
#include <QObject>
|
||||||
|
#include "combinemode.h"
|
||||||
|
|
||||||
|
IMPL_CombineModeToString
|
||||||
|
IMPL_CombineModeFromString
|
||||||
|
IMPL_CombineModeToDispName
|
|
@ -0,0 +1,56 @@
|
||||||
|
#ifndef DUST3D_COMBINE_MODE_H
|
||||||
|
#define DUST3D_COMBINE_MODE_H
|
||||||
|
#include <QString>
|
||||||
|
|
||||||
|
enum class CombineMode
|
||||||
|
{
|
||||||
|
Normal = 0,
|
||||||
|
Inversion,
|
||||||
|
Inflation,
|
||||||
|
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; \
|
||||||
|
if (mode == "Inflation") \
|
||||||
|
return CombineMode::Inflation; \
|
||||||
|
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"; \
|
||||||
|
case CombineMode::Inflation: \
|
||||||
|
return "Inflation"; \
|
||||||
|
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"); \
|
||||||
|
case CombineMode::Inflation: \
|
||||||
|
return QObject::tr("Inflation"); \
|
||||||
|
default: \
|
||||||
|
return QObject::tr("Normal"); \
|
||||||
|
} \
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -906,7 +906,7 @@ void Document::toSnapshot(Snapshot *snapshot, const std::set<QUuid> &limitNodeId
|
||||||
if (!componentIt.second.name.isEmpty())
|
if (!componentIt.second.name.isEmpty())
|
||||||
component["name"] = componentIt.second.name;
|
component["name"] = componentIt.second.name;
|
||||||
component["expanded"] = componentIt.second.expanded ? "true" : "false";
|
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";
|
component["dirty"] = componentIt.second.dirty ? "true" : "false";
|
||||||
if (componentIt.second.smoothAllAdjusted())
|
if (componentIt.second.smoothAllAdjusted())
|
||||||
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
|
component["smoothAll"] = QString::number(componentIt.second.smoothAll);
|
||||||
|
@ -1181,7 +1181,11 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
oldNewIdMap[QUuid(componentKv.first)] = component.id;
|
oldNewIdMap[QUuid(componentKv.first)] = component.id;
|
||||||
component.name = valueOfKeyInMapOrEmpty(componentKv.second, "name");
|
component.name = valueOfKeyInMapOrEmpty(componentKv.second, "name");
|
||||||
component.expanded = isTrueValueString(valueOfKeyInMapOrEmpty(componentKv.second, "expanded"));
|
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");
|
const auto &smoothAllIt = componentKv.second.find("smoothAll");
|
||||||
if (smoothAllIt != componentKv.second.end())
|
if (smoothAllIt != componentKv.second.end())
|
||||||
component.setSmoothAll(smoothAllIt->second.toFloat());
|
component.setSmoothAll(smoothAllIt->second.toFloat());
|
||||||
|
@ -1195,7 +1199,7 @@ void Document::addFromSnapshot(const Snapshot &snapshot, bool fromPaste)
|
||||||
//qDebug() << "Add part:" << partId << " from component:" << component.id;
|
//qDebug() << "Add part:" << partId << " from component:" << component.id;
|
||||||
partMap[partId].componentId = component.id;
|
partMap[partId].componentId = component.id;
|
||||||
if (inversePartIds.find(partId) != inversePartIds.end())
|
if (inversePartIds.find(partId) != inversePartIds.end())
|
||||||
component.inverse = true;
|
component.combineMode = CombineMode::Inversion;
|
||||||
}
|
}
|
||||||
componentMap[component.id] = component;
|
componentMap[component.id] = component;
|
||||||
newAddedComponentIds.insert(component.id);
|
newAddedComponentIds.insert(component.id);
|
||||||
|
@ -1615,18 +1619,18 @@ void Document::setPartVisibleState(QUuid partId, bool visible)
|
||||||
emit optionsChanged();
|
emit optionsChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::setComponentInverseState(QUuid componentId, bool inverse)
|
void Document::setComponentCombineMode(QUuid componentId, CombineMode combineMode)
|
||||||
{
|
{
|
||||||
auto component = componentMap.find(componentId);
|
auto component = componentMap.find(componentId);
|
||||||
if (component == componentMap.end()) {
|
if (component == componentMap.end()) {
|
||||||
qDebug() << "Component not found:" << componentId;
|
qDebug() << "Component not found:" << componentId;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (component->second.inverse == inverse)
|
if (component->second.combineMode == combineMode)
|
||||||
return;
|
return;
|
||||||
component->second.inverse = inverse;
|
component->second.combineMode = combineMode;
|
||||||
component->second.dirty = true;
|
component->second.dirty = true;
|
||||||
emit componentInverseStateChanged(componentId);
|
emit componentCombineModeChanged(componentId);
|
||||||
emit skeletonChanged();
|
emit skeletonChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "interpolationtype.h"
|
#include "interpolationtype.h"
|
||||||
#include "jointnodetree.h"
|
#include "jointnodetree.h"
|
||||||
#include "skeletondocument.h"
|
#include "skeletondocument.h"
|
||||||
|
#include "combinemode.h"
|
||||||
|
|
||||||
class MaterialPreviewsGenerator;
|
class MaterialPreviewsGenerator;
|
||||||
class MotionsGenerator;
|
class MotionsGenerator;
|
||||||
|
@ -55,7 +56,7 @@ public:
|
||||||
QUuid linkToPartId;
|
QUuid linkToPartId;
|
||||||
QUuid parentId;
|
QUuid parentId;
|
||||||
bool expanded = true;
|
bool expanded = true;
|
||||||
bool inverse = false;
|
CombineMode combineMode = CombineMode::Normal;
|
||||||
bool dirty = true;
|
bool dirty = true;
|
||||||
float smoothAll = 0.0;
|
float smoothAll = 0.0;
|
||||||
float smoothSeam = 0.0;
|
float smoothSeam = 0.0;
|
||||||
|
@ -401,7 +402,7 @@ signals:
|
||||||
void partColorStateChanged(QUuid partId);
|
void partColorStateChanged(QUuid partId);
|
||||||
void partWrapStateChanged(QUuid partId);
|
void partWrapStateChanged(QUuid partId);
|
||||||
void partMaterialIdChanged(QUuid partId);
|
void partMaterialIdChanged(QUuid partId);
|
||||||
void componentInverseStateChanged(QUuid partId);
|
void componentCombineModeChanged(QUuid componentId);
|
||||||
void cleanup();
|
void cleanup();
|
||||||
void originChanged();
|
void originChanged();
|
||||||
void xlockStateChanged();
|
void xlockStateChanged();
|
||||||
|
@ -550,7 +551,7 @@ public slots:
|
||||||
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
void setPartColorState(QUuid partId, bool hasColor, QColor color);
|
||||||
void setPartWrapState(QUuid partId, bool wrapped);
|
void setPartWrapState(QUuid partId, bool wrapped);
|
||||||
void setPartMaterialId(QUuid partId, QUuid materialId);
|
void setPartMaterialId(QUuid partId, QUuid materialId);
|
||||||
void setComponentInverseState(QUuid componentId, bool inverse);
|
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
||||||
void moveComponentUp(QUuid componentId);
|
void moveComponentUp(QUuid componentId);
|
||||||
void moveComponentDown(QUuid componentId);
|
void moveComponentDown(QUuid componentId);
|
||||||
void moveComponentToTop(QUuid componentId);
|
void moveComponentToTop(QUuid componentId);
|
||||||
|
|
|
@ -783,7 +783,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(partTreeWidget, &PartTreeWidget::unlockAllComponents, m_document, &Document::unlockAllComponents);
|
connect(partTreeWidget, &PartTreeWidget::unlockAllComponents, m_document, &Document::unlockAllComponents);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartLockState, m_document, &Document::setPartLockState);
|
connect(partTreeWidget, &PartTreeWidget::setPartLockState, m_document, &Document::setPartLockState);
|
||||||
connect(partTreeWidget, &PartTreeWidget::setPartVisibleState, m_document, &Document::setPartVisibleState);
|
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::hideDescendantComponents, m_document, &Document::hideDescendantComponents);
|
||||||
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::showDescendantComponents, m_document, &Document::showDescendantComponents);
|
||||||
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
|
connect(partTreeWidget, &PartTreeWidget::lockDescendantComponents, m_document, &Document::lockDescendantComponents);
|
||||||
|
@ -796,6 +796,7 @@ DocumentWindow::DocumentWindow() :
|
||||||
connect(m_document, &Document::componentRemoved, partTreeWidget, &PartTreeWidget::componentRemoved);
|
connect(m_document, &Document::componentRemoved, partTreeWidget, &PartTreeWidget::componentRemoved);
|
||||||
connect(m_document, &Document::componentAdded, partTreeWidget, &PartTreeWidget::componentAdded);
|
connect(m_document, &Document::componentAdded, partTreeWidget, &PartTreeWidget::componentAdded);
|
||||||
connect(m_document, &Document::componentExpandStateChanged, partTreeWidget, &PartTreeWidget::componentExpandStateChanged);
|
connect(m_document, &Document::componentExpandStateChanged, partTreeWidget, &PartTreeWidget::componentExpandStateChanged);
|
||||||
|
connect(m_document, &Document::componentCombineModeChanged, partTreeWidget, &PartTreeWidget::componentCombineModeChanged);
|
||||||
connect(m_document, &Document::partPreviewChanged, partTreeWidget, &PartTreeWidget::partPreviewChanged);
|
connect(m_document, &Document::partPreviewChanged, partTreeWidget, &PartTreeWidget::partPreviewChanged);
|
||||||
connect(m_document, &Document::partLockStateChanged, partTreeWidget, &PartTreeWidget::partLockStateChanged);
|
connect(m_document, &Document::partLockStateChanged, partTreeWidget, &PartTreeWidget::partLockStateChanged);
|
||||||
connect(m_document, &Document::partVisibleStateChanged, partTreeWidget, &PartTreeWidget::partVisibleStateChanged);
|
connect(m_document, &Document::partVisibleStateChanged, partTreeWidget, &PartTreeWidget::partVisibleStateChanged);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
#include "graphicscontainerwidget.h"
|
#include "graphicscontainerwidget.h"
|
||||||
|
|
||||||
GraphicsContainerWidget::GraphicsContainerWidget() :
|
GraphicsContainerWidget::GraphicsContainerWidget()
|
||||||
m_graphicsWidget(nullptr)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -31,11 +30,16 @@ void GraphicsContainerWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
|
||||||
void GraphicsContainerWidget::wheelEvent(QWheelEvent *event)
|
void GraphicsContainerWidget::wheelEvent(QWheelEvent *event)
|
||||||
{
|
{
|
||||||
|
if (m_graphicsWidget) {
|
||||||
|
m_graphicsWidget->inputWheelEventFromOtherWidget(event);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (m_modelWidget)
|
if (m_modelWidget)
|
||||||
m_modelWidget->inputWheelEventFromOtherWidget(event);
|
m_modelWidget->inputWheelEventFromOtherWidget(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GraphicsContainerWidget::setGraphicsWidget(QWidget *graphicsWidget)
|
void GraphicsContainerWidget::setGraphicsWidget(SkeletonGraphicsWidget *graphicsWidget)
|
||||||
{
|
{
|
||||||
m_graphicsWidget = graphicsWidget;
|
m_graphicsWidget = graphicsWidget;
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QMouseEvent>
|
#include <QMouseEvent>
|
||||||
#include <QWheelEvent>
|
#include <QWheelEvent>
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
|
#include "skeletongraphicswidget.h"
|
||||||
|
|
||||||
class GraphicsContainerWidget : public QWidget
|
class GraphicsContainerWidget : public QWidget
|
||||||
{
|
{
|
||||||
|
@ -13,7 +14,7 @@ signals:
|
||||||
void containerSizeChanged(QSize size);
|
void containerSizeChanged(QSize size);
|
||||||
public:
|
public:
|
||||||
GraphicsContainerWidget();
|
GraphicsContainerWidget();
|
||||||
void setGraphicsWidget(QWidget *graphicsWidget);
|
void setGraphicsWidget(SkeletonGraphicsWidget *graphicsWidget);
|
||||||
void setModelWidget(ModelWidget *modelWidget);
|
void setModelWidget(ModelWidget *modelWidget);
|
||||||
protected:
|
protected:
|
||||||
void resizeEvent(QResizeEvent *event) override;
|
void resizeEvent(QResizeEvent *event) override;
|
||||||
|
@ -22,8 +23,8 @@ protected:
|
||||||
void mouseReleaseEvent(QMouseEvent *event) override;
|
void mouseReleaseEvent(QMouseEvent *event) override;
|
||||||
void wheelEvent(QWheelEvent *event) override;
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
private:
|
private:
|
||||||
QWidget *m_graphicsWidget = nullptr;
|
|
||||||
ModelWidget *m_modelWidget = nullptr;
|
ModelWidget *m_modelWidget = nullptr;
|
||||||
|
SkeletonGraphicsWidget *m_graphicsWidget = nullptr;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -14,6 +14,7 @@
|
||||||
#include "imageforever.h"
|
#include "imageforever.h"
|
||||||
#include "material.h"
|
#include "material.h"
|
||||||
#include "trianglesourcenoderesolve.h"
|
#include "trianglesourcenoderesolve.h"
|
||||||
|
#include "meshinflate.h"
|
||||||
|
|
||||||
bool MeshGenerator::m_enableDebug = false;
|
bool MeshGenerator::m_enableDebug = false;
|
||||||
PositionMap<int> *MeshGenerator::m_forMakePositionKey = new PositionMap<int>;
|
PositionMap<int> *MeshGenerator::m_forMakePositionKey = new PositionMap<int>;
|
||||||
|
@ -225,7 +226,7 @@ bool MeshGenerator::checkIsPartDirty(QString partId)
|
||||||
return isTrueValueString(valueOfKeyInMapOrEmpty(findPart->second, "dirty"));
|
return isTrueValueString(valueOfKeyInMapOrEmpty(findPart->second, "dirty"));
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MeshGenerator::combinePartMesh(QString partId)
|
void *MeshGenerator::combinePartMesh(QString partId, std::vector<std::pair<QVector3D, float>> *balls)
|
||||||
{
|
{
|
||||||
auto findPart = m_snapshot->parts.find(partId);
|
auto findPart = m_snapshot->parts.find(partId);
|
||||||
if (findPart == m_snapshot->parts.end()) {
|
if (findPart == m_snapshot->parts.end()) {
|
||||||
|
@ -306,6 +307,13 @@ void *MeshGenerator::combinePartMesh(QString partId)
|
||||||
nodeInfo.position = QVector3D(x, y, z);
|
nodeInfo.position = QVector3D(x, y, z);
|
||||||
nodeInfo.radius = radius;
|
nodeInfo.radius = radius;
|
||||||
nodeInfo.boneMark = boneMark;
|
nodeInfo.boneMark = boneMark;
|
||||||
|
|
||||||
|
if (nullptr != balls) {
|
||||||
|
balls->push_back({QVector3D(x, y, z), radius});
|
||||||
|
if (xMirrored) {
|
||||||
|
balls->push_back({QVector3D(-x, y, z), radius});
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
std::set<std::pair<QString, QString>> edges;
|
std::set<std::pair<QString, QString>> edges;
|
||||||
for (const auto &edgeId: m_partEdgeIds[partId]) {
|
for (const auto &edgeId: m_partEdgeIds[partId]) {
|
||||||
|
@ -499,12 +507,10 @@ bool MeshGenerator::checkIsComponentDirty(QString componentId)
|
||||||
return isDirty;
|
return isDirty;
|
||||||
}
|
}
|
||||||
|
|
||||||
void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
void *MeshGenerator::combineComponentMesh(QString componentId, CombineMode *combineMode, std::vector<std::pair<QVector3D, float>> *inflateBalls)
|
||||||
{
|
{
|
||||||
QUuid componentIdNotAsString;
|
QUuid componentIdNotAsString;
|
||||||
|
|
||||||
*inverse = false;
|
|
||||||
|
|
||||||
const std::map<QString, QString> *component = &m_snapshot->rootComponent;
|
const std::map<QString, QString> *component = &m_snapshot->rootComponent;
|
||||||
if (componentId != QUuid().toString()) {
|
if (componentId != QUuid().toString()) {
|
||||||
componentIdNotAsString = QUuid(componentId);
|
componentIdNotAsString = QUuid(componentId);
|
||||||
|
@ -516,15 +522,26 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
||||||
component = &findComponent->second;
|
component = &findComponent->second;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse")))
|
*combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(*component, "combineMode").toUtf8().constData());
|
||||||
*inverse = true;
|
|
||||||
|
|
||||||
if (m_dirtyComponentIds.find(componentId) == m_dirtyComponentIds.end()) {
|
if (*combineMode == CombineMode::Inflation) {
|
||||||
auto findCachedMesh = m_cacheContext->componentCombinableMeshs.find(componentId);
|
if (m_dirtyComponentIds.find(componentId) == m_dirtyComponentIds.end()) {
|
||||||
if (findCachedMesh != m_cacheContext->componentCombinableMeshs.end() &&
|
auto findCacheInflateBalls = m_cacheContext->componentInflateBalls.find(componentId);
|
||||||
nullptr != findCachedMesh->second) {
|
if (findCacheInflateBalls != m_cacheContext->componentInflateBalls.end()) {
|
||||||
//qDebug() << "Component mesh cache used:" << componentId;
|
*inflateBalls = findCacheInflateBalls->second;
|
||||||
return cloneCombinableMesh(findCachedMesh->second);
|
return nullptr;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*combineMode != CombineMode::Inflation) {
|
||||||
|
if (m_dirtyComponentIds.find(componentId) == m_dirtyComponentIds.end()) {
|
||||||
|
auto findCachedMesh = m_cacheContext->componentCombinableMeshs.find(componentId);
|
||||||
|
if (findCachedMesh != m_cacheContext->componentCombinableMeshs.end() &&
|
||||||
|
nullptr != findCachedMesh->second) {
|
||||||
|
//qDebug() << "Component mesh cache used:" << componentId;
|
||||||
|
return cloneCombinableMesh(findCachedMesh->second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -552,17 +569,47 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
||||||
QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType");
|
QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType");
|
||||||
if ("partId" == linkDataType) {
|
if ("partId" == linkDataType) {
|
||||||
QString partId = valueOfKeyInMapOrEmpty(*component, "linkData");
|
QString partId = valueOfKeyInMapOrEmpty(*component, "linkData");
|
||||||
resultMesh = combinePartMesh(partId);
|
std::vector<std::pair<QVector3D, float>> partBalls;
|
||||||
for (const auto &bmeshVertex: m_cacheContext->partBmeshVertices[partId]) {
|
resultMesh = combinePartMesh(partId, &partBalls);
|
||||||
verticesSources.addPosition(bmeshVertex.first.x(), bmeshVertex.first.y(), bmeshVertex.first.z(),
|
if (*combineMode == CombineMode::Inflation) {
|
||||||
bmeshVertex);
|
deleteCombinableMesh(resultMesh);
|
||||||
|
resultMesh = nullptr;
|
||||||
|
inflateBalls->insert(inflateBalls->end(), partBalls.begin(), partBalls.end());
|
||||||
|
} else {
|
||||||
|
for (const auto &bmeshVertex: m_cacheContext->partBmeshVertices[partId]) {
|
||||||
|
verticesSources.addPosition(bmeshVertex.first.x(), bmeshVertex.first.y(), bmeshVertex.first.z(),
|
||||||
|
bmeshVertex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (const auto &childId: valueOfKeyInMapOrEmpty(*component, "children").split(",")) {
|
for (const auto &childId: valueOfKeyInMapOrEmpty(*component, "children").split(",")) {
|
||||||
if (childId.isEmpty())
|
if (childId.isEmpty())
|
||||||
continue;
|
continue;
|
||||||
bool childInverse = false;
|
CombineMode childCombineMode = CombineMode::Normal;
|
||||||
void *childCombinedMesh = combineComponentMesh(childId, &childInverse);
|
std::vector<std::pair<QVector3D, float>> childInflateBalls;
|
||||||
|
void *childCombinedMesh = combineComponentMesh(childId, &childCombineMode, &childInflateBalls);
|
||||||
|
inflateBalls->insert(inflateBalls->end(), childInflateBalls.begin(), childInflateBalls.end());
|
||||||
|
if (childCombineMode == CombineMode::Inflation) {
|
||||||
|
deleteCombinableMesh(childCombinedMesh);
|
||||||
|
childCombinedMesh = nullptr;
|
||||||
|
if (nullptr == resultMesh)
|
||||||
|
continue;
|
||||||
|
std::vector<std::pair<QVector3D, QVector3D>> inflatedVertices;
|
||||||
|
void *inflatedMesh = meshInflate(resultMesh, childInflateBalls, inflatedVertices);
|
||||||
|
deleteCombinableMesh(resultMesh);
|
||||||
|
resultMesh = inflatedMesh;
|
||||||
|
for (const auto &item: inflatedVertices) {
|
||||||
|
const auto &oldPosition = item.first;
|
||||||
|
const auto &newPosition = item.second;
|
||||||
|
std::pair<QVector3D, std::pair<QUuid, QUuid>> source;
|
||||||
|
if (verticesSources.findPosition(oldPosition.x(), oldPosition.y(), oldPosition.z(), &source)) {
|
||||||
|
verticesSources.removePosition(oldPosition.x(), oldPosition.y(), oldPosition.z());
|
||||||
|
source.first = newPosition;
|
||||||
|
verticesSources.addPosition(newPosition.x(), newPosition.y(), newPosition.z(), source);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
for (const auto &positionIt: m_cacheContext->componentPositions[childId]) {
|
for (const auto &positionIt: m_cacheContext->componentPositions[childId]) {
|
||||||
positionsBeforeCombination.addPosition(positionIt.x(), positionIt.y(), positionIt.z(), true);
|
positionsBeforeCombination.addPosition(positionIt.x(), positionIt.y(), positionIt.z(), true);
|
||||||
}
|
}
|
||||||
|
@ -572,13 +619,13 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
||||||
if (nullptr == childCombinedMesh)
|
if (nullptr == childCombinedMesh)
|
||||||
continue;
|
continue;
|
||||||
if (nullptr == resultMesh) {
|
if (nullptr == resultMesh) {
|
||||||
if (childInverse) {
|
if (childCombineMode == CombineMode::Inversion) {
|
||||||
deleteCombinableMesh(childCombinedMesh);
|
deleteCombinableMesh(childCombinedMesh);
|
||||||
} else {
|
} else {
|
||||||
resultMesh = childCombinedMesh;
|
resultMesh = childCombinedMesh;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
void *newResultMesh = childInverse ? diffCombinableMeshs(resultMesh, childCombinedMesh) : unionCombinableMeshs(resultMesh, childCombinedMesh);
|
void *newResultMesh = childCombineMode == CombineMode::Inversion ? diffCombinableMeshs(resultMesh, childCombinedMesh) : unionCombinableMeshs(resultMesh, childCombinedMesh);
|
||||||
deleteCombinableMesh(childCombinedMesh);
|
deleteCombinableMesh(childCombinedMesh);
|
||||||
if (nullptr != newResultMesh) {
|
if (nullptr != newResultMesh) {
|
||||||
deleteCombinableMesh(resultMesh);
|
deleteCombinableMesh(resultMesh);
|
||||||
|
@ -643,6 +690,8 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_cacheContext->componentInflateBalls[componentId] = *inflateBalls;
|
||||||
|
|
||||||
m_cacheContext->updateComponentCombinableMesh(componentId, resultMesh);
|
m_cacheContext->updateComponentCombinableMesh(componentId, resultMesh);
|
||||||
auto &cachedComponentPositions = m_cacheContext->componentPositions[componentId];
|
auto &cachedComponentPositions = m_cacheContext->componentPositions[componentId];
|
||||||
cachedComponentPositions.clear();
|
cachedComponentPositions.clear();
|
||||||
|
@ -712,6 +761,13 @@ void MeshGenerator::generate()
|
||||||
}
|
}
|
||||||
it++;
|
it++;
|
||||||
}
|
}
|
||||||
|
for (auto it = m_cacheContext->componentInflateBalls.begin(); it != m_cacheContext->componentInflateBalls.end(); ) {
|
||||||
|
if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) {
|
||||||
|
it = m_cacheContext->componentInflateBalls.erase(it);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
it++;
|
||||||
|
}
|
||||||
for (auto it = m_cacheContext->componentVerticesSources.begin(); it != m_cacheContext->componentVerticesSources.end(); ) {
|
for (auto it = m_cacheContext->componentVerticesSources.begin(); it != m_cacheContext->componentVerticesSources.end(); ) {
|
||||||
if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) {
|
if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) {
|
||||||
it = m_cacheContext->componentVerticesSources.erase(it);
|
it = m_cacheContext->componentVerticesSources.erase(it);
|
||||||
|
@ -732,8 +788,9 @@ void MeshGenerator::generate()
|
||||||
|
|
||||||
int resultMeshId = 0;
|
int resultMeshId = 0;
|
||||||
|
|
||||||
bool inverse = false;
|
CombineMode combineMode;
|
||||||
void *combinedMesh = combineComponentMesh(QUuid().toString(), &inverse);
|
std::vector<std::pair<QVector3D, float>> inflateBalls;
|
||||||
|
void *combinedMesh = combineComponentMesh(QUuid().toString(), &combineMode, &inflateBalls);
|
||||||
if (nullptr != combinedMesh) {
|
if (nullptr != combinedMesh) {
|
||||||
resultMeshId = convertFromCombinableMesh(m_meshliteContext, combinedMesh);
|
resultMeshId = convertFromCombinableMesh(m_meshliteContext, combinedMesh);
|
||||||
deleteCombinableMesh(combinedMesh);
|
deleteCombinableMesh(combinedMesh);
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
#include "meshloader.h"
|
#include "meshloader.h"
|
||||||
#include "outcome.h"
|
#include "outcome.h"
|
||||||
#include "positionmap.h"
|
#include "positionmap.h"
|
||||||
|
#include "combinemode.h"
|
||||||
|
|
||||||
class GeneratedCacheContext
|
class GeneratedCacheContext
|
||||||
{
|
{
|
||||||
|
@ -23,6 +24,7 @@ public:
|
||||||
std::map<QString, std::vector<QVector3D>> componentPositions;
|
std::map<QString, std::vector<QVector3D>> componentPositions;
|
||||||
std::map<QString, PositionMap<std::pair<QVector3D, std::pair<QUuid, QUuid>>>> componentVerticesSources;
|
std::map<QString, PositionMap<std::pair<QVector3D, std::pair<QUuid, QUuid>>>> componentVerticesSources;
|
||||||
std::map<QString, QString> partMirrorIdMap;
|
std::map<QString, QString> partMirrorIdMap;
|
||||||
|
std::map<QString, std::vector<std::pair<QVector3D, float>>> componentInflateBalls;
|
||||||
void updateComponentCombinableMesh(QString componentId, void *mesh);
|
void updateComponentCombinableMesh(QString componentId, void *mesh);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -78,8 +80,8 @@ private:
|
||||||
void checkDirtyFlags();
|
void checkDirtyFlags();
|
||||||
bool checkIsComponentDirty(QString componentId);
|
bool checkIsComponentDirty(QString componentId);
|
||||||
bool checkIsPartDirty(QString partId);
|
bool checkIsPartDirty(QString partId);
|
||||||
void *combineComponentMesh(QString componentId, bool *inverse);
|
void *combineComponentMesh(QString componentId, CombineMode *combineMode, std::vector<std::pair<QVector3D, float>> *inflateBalls);
|
||||||
void *combinePartMesh(QString partId);
|
void *combinePartMesh(QString partId, std::vector<std::pair<QVector3D, float>> *balls=nullptr);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,50 @@
|
||||||
|
#include <QDebug>
|
||||||
|
#include <set>
|
||||||
|
#include "meshinflate.h"
|
||||||
|
#include "meshutil.h"
|
||||||
|
|
||||||
|
void *meshInflate(void *combinableMesh, const std::vector<std::pair<QVector3D, float>> &inflateBalls, std::vector<std::pair<QVector3D, QVector3D>> &inflatedVertices)
|
||||||
|
{
|
||||||
|
std::vector<QVector3D> oldPositions;
|
||||||
|
std::vector<QVector3D> newPositions;
|
||||||
|
std::vector<std::vector<int>> faces;
|
||||||
|
std::set<int> changedVertices;
|
||||||
|
|
||||||
|
loadCombinableMeshVerticesPositionsAndFacesIndices(combinableMesh, oldPositions, faces);
|
||||||
|
newPositions = oldPositions;
|
||||||
|
|
||||||
|
std::vector<float> inflateBallRadius2s(inflateBalls.size());
|
||||||
|
for (size_t i = 0; i < inflateBalls.size(); ++i) {
|
||||||
|
const auto &radius = inflateBalls[i].second;
|
||||||
|
inflateBallRadius2s[i] = radius * radius;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (size_t i = 0; i < oldPositions.size(); ++i) {
|
||||||
|
const auto &oldPos = oldPositions[i];
|
||||||
|
QVector3D sumOfNewPos;
|
||||||
|
size_t pushedByBallNum = 0;
|
||||||
|
for (size_t j = 0; j < inflateBalls.size(); ++j) {
|
||||||
|
const auto &ball = inflateBalls[j];
|
||||||
|
const auto &ballPos = ball.first;
|
||||||
|
const auto &ballRadius = std::max(ball.second, (float)0.00001);
|
||||||
|
const auto ballToPosVec = oldPos - ballPos;
|
||||||
|
if (ballToPosVec.lengthSquared() > inflateBallRadius2s[j])
|
||||||
|
continue;
|
||||||
|
const auto distance = 1.0 - ballToPosVec.length() / ballRadius;
|
||||||
|
const auto smoothedDist = 3.0 * std::pow(distance, 2) - 2.0 * std::pow(distance, 3);
|
||||||
|
const auto newPosPushByBall = oldPos + ballToPosVec * smoothedDist;
|
||||||
|
sumOfNewPos += newPosPushByBall;
|
||||||
|
++pushedByBallNum;
|
||||||
|
}
|
||||||
|
if (0 == pushedByBallNum)
|
||||||
|
continue;
|
||||||
|
newPositions[i] = sumOfNewPos / pushedByBallNum;
|
||||||
|
changedVertices.insert(i);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const auto &index: changedVertices) {
|
||||||
|
inflatedVertices.push_back({oldPositions[index], newPositions[index]});
|
||||||
|
}
|
||||||
|
|
||||||
|
return buildCombinableMeshFromVerticesPositionsAndFacesIndices(newPositions, faces);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#ifndef DUST3D_MESH_INFLATE_H
|
||||||
|
#define DUST3D_MESH_INFLATE_H
|
||||||
|
#include <vector>
|
||||||
|
#include <QVector3D>
|
||||||
|
|
||||||
|
void *meshInflate(void *combinableMesh, const std::vector<std::pair<QVector3D, float>> &inflateBalls, std::vector<std::pair<QVector3D, QVector3D>> &inflatedVertices);
|
||||||
|
|
||||||
|
#endif
|
|
@ -52,6 +52,25 @@ void loadMeshVerticesPositions(void *meshliteContext, int meshId, std::vector<QV
|
||||||
delete[] vertexPositions;
|
delete[] vertexPositions;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
template <class Kernel>
|
||||||
|
typename CGAL::Surface_mesh<typename Kernel::Point_3> *buildCgalMesh(const std::vector<QVector3D> &positions, const std::vector<std::vector<int>> &indices)
|
||||||
|
{
|
||||||
|
typename CGAL::Surface_mesh<typename Kernel::Point_3> *mesh = new typename CGAL::Surface_mesh<typename Kernel::Point_3>;
|
||||||
|
std::map<int, typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> oldToNewMap;
|
||||||
|
for (int i = 0; i < (int)positions.size(); ++i) {
|
||||||
|
const auto &pos = positions[i];
|
||||||
|
oldToNewMap[i] = mesh->add_vertex(typename Kernel::Point_3(pos.x(), pos.y(), pos.z()));
|
||||||
|
}
|
||||||
|
for (const auto &face: indices) {
|
||||||
|
std::vector<typename CGAL::Surface_mesh<typename Kernel::Point_3>::Vertex_index> faceVertexIndices;
|
||||||
|
for (const auto &index: face) {
|
||||||
|
faceVertexIndices.push_back(oldToNewMap[index]);
|
||||||
|
}
|
||||||
|
mesh->add_face(faceVertexIndices);
|
||||||
|
}
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
|
||||||
template <class Kernel>
|
template <class Kernel>
|
||||||
typename CGAL::Surface_mesh<typename Kernel::Point_3> *makeCgalMeshFromMeshlite(void *meshlite, int meshId)
|
typename CGAL::Surface_mesh<typename Kernel::Point_3> *makeCgalMeshFromMeshlite(void *meshlite, int meshId)
|
||||||
{
|
{
|
||||||
|
@ -458,3 +477,54 @@ void *convertToCombinableConvexHullMesh(void *meshliteContext, int meshId)
|
||||||
ExactMesh *mesh = makeCgalConvexHullMeshFromMeshlite<ExactKernel>(meshliteContext, meshId);
|
ExactMesh *mesh = makeCgalConvexHullMeshFromMeshlite<ExactKernel>(meshliteContext, meshId);
|
||||||
return (void *)mesh;
|
return (void *)mesh;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void loadCombinableMeshVerticesPositionsAndFacesIndices(void *mesh, std::vector<QVector3D> &positions, std::vector<std::vector<int>> &indices)
|
||||||
|
{
|
||||||
|
ExactMesh *exactMesh = (ExactMesh *)mesh;
|
||||||
|
if (nullptr == exactMesh)
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto vertexIt = exactMesh->vertices_begin(); vertexIt != exactMesh->vertices_end(); vertexIt++) {
|
||||||
|
auto point = exactMesh->point(*vertexIt);
|
||||||
|
float x = (float)CGAL::to_double(point.x());
|
||||||
|
float y = (float)CGAL::to_double(point.y());
|
||||||
|
float z = (float)CGAL::to_double(point.z());
|
||||||
|
if (std::isnan(x) || std::isinf(x))
|
||||||
|
x = 0;
|
||||||
|
if (std::isnan(y) || std::isinf(y))
|
||||||
|
y = 0;
|
||||||
|
if (std::isnan(z) || std::isinf(z))
|
||||||
|
z = 0;
|
||||||
|
positions.push_back(QVector3D(x, y, z));
|
||||||
|
}
|
||||||
|
|
||||||
|
typename CGAL::Surface_mesh<ExactKernel::Point_3>::Face_range faceRage = exactMesh->faces();
|
||||||
|
typename CGAL::Surface_mesh<ExactKernel::Point_3>::Face_range::iterator faceIt;
|
||||||
|
for (faceIt = faceRage.begin(); faceIt != faceRage.end(); faceIt++) {
|
||||||
|
CGAL::Vertex_around_face_iterator<typename CGAL::Surface_mesh<ExactKernel::Point_3>> vbegin, vend;
|
||||||
|
std::vector<int> faceIndices;
|
||||||
|
for (boost::tie(vbegin, vend) = CGAL::vertices_around_face(exactMesh->halfedge(*faceIt), *exactMesh);
|
||||||
|
vbegin != vend;
|
||||||
|
++vbegin){
|
||||||
|
faceIndices.push_back(*vbegin);
|
||||||
|
}
|
||||||
|
indices.push_back(faceIndices);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void *buildCombinableMeshFromVerticesPositionsAndFacesIndices(const std::vector<QVector3D> &positions, const std::vector<std::vector<int>> &indices)
|
||||||
|
{
|
||||||
|
ExactMesh *mesh = nullptr;
|
||||||
|
if (indices.empty())
|
||||||
|
return nullptr;
|
||||||
|
mesh = buildCgalMesh<ExactKernel>(positions, indices);
|
||||||
|
if (nullptr == mesh) {
|
||||||
|
return mesh;
|
||||||
|
}
|
||||||
|
if (CGAL::Polygon_mesh_processing::does_self_intersect(*mesh)) {
|
||||||
|
qDebug() << "CGAL::Polygon_mesh_processing::does_self_intersect";
|
||||||
|
delete mesh;
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
return (void *)mesh;
|
||||||
|
}
|
||||||
|
|
|
@ -21,5 +21,7 @@ void *cloneCombinableMesh(void *mesh);
|
||||||
void *convertToCombinableConvexHullMesh(void *meshliteContext, int meshId);
|
void *convertToCombinableConvexHullMesh(void *meshliteContext, int meshId);
|
||||||
void loadMeshVerticesPositions(void *meshliteContext, int meshId, std::vector<QVector3D> &positions);
|
void loadMeshVerticesPositions(void *meshliteContext, int meshId, std::vector<QVector3D> &positions);
|
||||||
void loadCombinableMeshVerticesPositions(void *mesh, std::vector<QVector3D> &positions);
|
void loadCombinableMeshVerticesPositions(void *mesh, std::vector<QVector3D> &positions);
|
||||||
|
void loadCombinableMeshVerticesPositionsAndFacesIndices(void *mesh, std::vector<QVector3D> &positions, std::vector<std::vector<int>> &indices);
|
||||||
|
void *buildCombinableMeshFromVerticesPositionsAndFacesIndices(const std::vector<QVector3D> &positions, const std::vector<std::vector<int>> &indices);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -6,6 +6,7 @@
|
||||||
#include <QRadialGradient>
|
#include <QRadialGradient>
|
||||||
#include <QBrush>
|
#include <QBrush>
|
||||||
#include <QGuiApplication>
|
#include <QGuiApplication>
|
||||||
|
#include <QComboBox>
|
||||||
#include "parttreewidget.h"
|
#include "parttreewidget.h"
|
||||||
#include "partwidget.h"
|
#include "partwidget.h"
|
||||||
#include "skeletongraphicswidget.h"
|
#include "skeletongraphicswidget.h"
|
||||||
|
@ -103,6 +104,11 @@ void PartTreeWidget::selectComponent(QUuid componentId, bool multiple)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartTreeWidget::updateComponentAppearance(QUuid componentId)
|
||||||
|
{
|
||||||
|
updateComponentSelectState(componentId, isComponentSelected(componentId));
|
||||||
|
}
|
||||||
|
|
||||||
void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected)
|
void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected)
|
||||||
{
|
{
|
||||||
const Component *component = m_document->findComponent(componentId);
|
const Component *component = m_document->findComponent(componentId);
|
||||||
|
@ -114,19 +120,19 @@ void PartTreeWidget::updateComponentSelectState(QUuid componentId, bool selected
|
||||||
auto item = m_partItemMap.find(component->linkToPartId);
|
auto item = m_partItemMap.find(component->linkToPartId);
|
||||||
if (item != m_componentItemMap.end()) {
|
if (item != m_componentItemMap.end()) {
|
||||||
PartWidget *widget = (PartWidget *)itemWidget(item->second, 0);
|
PartWidget *widget = (PartWidget *)itemWidget(item->second, 0);
|
||||||
|
// Unnormal state updating call should be called before check state updating call
|
||||||
|
widget->updateUnnormalState(component->combineMode != CombineMode::Normal);
|
||||||
widget->updateCheckedState(selected);
|
widget->updateCheckedState(selected);
|
||||||
}
|
}
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
auto item = m_componentItemMap.find(componentId);
|
auto item = m_componentItemMap.find(componentId);
|
||||||
if (item != m_componentItemMap.end()) {
|
if (item != m_componentItemMap.end()) {
|
||||||
if (selected) {
|
item->second->setFont(0, selected ? m_selectedFont : m_normalFont);
|
||||||
item->second->setFont(0, m_selectedFont);
|
if (component->combineMode != CombineMode::Normal)
|
||||||
item->second->setForeground(0, QBrush(Theme::red));
|
item->second->setForeground(0, selected ? QBrush(Theme::blue) : QBrush(Theme::blue));
|
||||||
} else {
|
else
|
||||||
item->second->setFont(0, m_normalFont);
|
item->second->setForeground(0, selected ? QBrush(Theme::red) : QBrush(Theme::white));
|
||||||
item->second->setForeground(0, QBrush(Theme::white));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,7 +260,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
} else {
|
} else {
|
||||||
QLabel *previewLabel = new QLabel;
|
QLabel *previewLabel = new QLabel;
|
||||||
previewLabel->setFixedHeight(Theme::partPreviewImageSize);
|
previewLabel->setFixedHeight(Theme::partPreviewImageSize);
|
||||||
previewLabel->setStyleSheet("QLabel {color: " + Theme::red.name() + "}");
|
previewLabel->setStyleSheet("QLabel {color: " + (component && (component->combineMode != CombineMode::Normal) ? Theme::blue.name() : Theme::red.name()) + "}");
|
||||||
if (nullptr != component) {
|
if (nullptr != component) {
|
||||||
previewLabel->setText(component->name);
|
previewLabel->setText(component->name);
|
||||||
} else if (!componentIds.empty()) {
|
} else if (!componentIds.empty()) {
|
||||||
|
@ -263,7 +269,31 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
layout->addWidget(previewLabel);
|
layout->addWidget(previewLabel);
|
||||||
}
|
}
|
||||||
QWidget *widget = new QWidget;
|
QWidget *widget = new QWidget;
|
||||||
widget->setLayout(layout);
|
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);
|
forDisplayPartImage.setDefaultWidget(widget);
|
||||||
if (!componentIds.empty()) {
|
if (!componentIds.empty()) {
|
||||||
contextMenu.addAction(&forDisplayPartImage);
|
contextMenu.addAction(&forDisplayPartImage);
|
||||||
|
@ -278,8 +308,6 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
lockAction.setIcon(Theme::awesome()->icon(fa::lock));
|
lockAction.setIcon(Theme::awesome()->icon(fa::lock));
|
||||||
QAction unlockAction(tr("Unlock"), this);
|
QAction unlockAction(tr("Unlock"), this);
|
||||||
unlockAction.setIcon(Theme::awesome()->icon(fa::unlock));
|
unlockAction.setIcon(Theme::awesome()->icon(fa::unlock));
|
||||||
QAction invertAction(tr("Invert"), this);
|
|
||||||
QAction cancelInverseAction(tr("Cancel Inverse"), this);
|
|
||||||
QAction selectAction(tr("Select"), this);
|
QAction selectAction(tr("Select"), this);
|
||||||
|
|
||||||
if (nullptr != component && nullptr != part) {
|
if (nullptr != component && nullptr != part) {
|
||||||
|
@ -348,6 +376,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
contextMenu.addAction(&unlockAction);
|
contextMenu.addAction(&unlockAction);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
if (component && !component->inverse) {
|
if (component && !component->inverse) {
|
||||||
connect(&invertAction, &QAction::triggered, [=]() {
|
connect(&invertAction, &QAction::triggered, [=]() {
|
||||||
emit setComponentInverseState(component->id, true);
|
emit setComponentInverseState(component->id, true);
|
||||||
|
@ -361,6 +390,7 @@ void PartTreeWidget::showContextMenu(const QPoint &pos)
|
||||||
});
|
});
|
||||||
contextMenu.addAction(&cancelInverseAction);
|
contextMenu.addAction(&cancelInverseAction);
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
contextMenu.addSeparator();
|
contextMenu.addSeparator();
|
||||||
|
|
||||||
|
@ -650,6 +680,11 @@ void PartTreeWidget::componentExpandStateChanged(QUuid componentId)
|
||||||
componentItem->second->setExpanded(component->expanded);
|
componentItem->second->setExpanded(component->expanded);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartTreeWidget::componentCombineModeChanged(QUuid componentId)
|
||||||
|
{
|
||||||
|
updateComponentAppearance(componentId);
|
||||||
|
}
|
||||||
|
|
||||||
void PartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem)
|
void PartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem)
|
||||||
{
|
{
|
||||||
const Component *parentComponent = m_document->findComponent(componentId);
|
const Component *parentComponent = m_document->findComponent(componentId);
|
||||||
|
|
|
@ -33,7 +33,7 @@ signals:
|
||||||
void unlockAllComponents();
|
void unlockAllComponents();
|
||||||
void setPartLockState(QUuid partId, bool locked);
|
void setPartLockState(QUuid partId, bool locked);
|
||||||
void setPartVisibleState(QUuid partId, bool visible);
|
void setPartVisibleState(QUuid partId, bool visible);
|
||||||
void setComponentInverseState(QUuid componentId, bool inverse);
|
void setComponentCombineMode(QUuid componentId, CombineMode combineMode);
|
||||||
void hideDescendantComponents(QUuid componentId);
|
void hideDescendantComponents(QUuid componentId);
|
||||||
void showDescendantComponents(QUuid componentId);
|
void showDescendantComponents(QUuid componentId);
|
||||||
void lockDescendantComponents(QUuid componentId);
|
void lockDescendantComponents(QUuid componentId);
|
||||||
|
@ -49,6 +49,7 @@ public slots:
|
||||||
void componentRemoved(QUuid componentId);
|
void componentRemoved(QUuid componentId);
|
||||||
void componentAdded(QUuid componentId);
|
void componentAdded(QUuid componentId);
|
||||||
void componentExpandStateChanged(QUuid componentId);
|
void componentExpandStateChanged(QUuid componentId);
|
||||||
|
void componentCombineModeChanged(QUuid componentId);
|
||||||
void partRemoved(QUuid partId);
|
void partRemoved(QUuid partId);
|
||||||
void partPreviewChanged(QUuid partid);
|
void partPreviewChanged(QUuid partid);
|
||||||
void partLockStateChanged(QUuid partId);
|
void partLockStateChanged(QUuid partId);
|
||||||
|
@ -77,6 +78,7 @@ private:
|
||||||
void selectComponent(QUuid componentId, bool multiple=false);
|
void selectComponent(QUuid componentId, bool multiple=false);
|
||||||
QWidget *createSmoothMenuWidget(QUuid componentId);
|
QWidget *createSmoothMenuWidget(QUuid componentId);
|
||||||
void updateComponentSelectState(QUuid componentId, bool selected);
|
void updateComponentSelectState(QUuid componentId, bool selected);
|
||||||
|
void updateComponentAppearance(QUuid componentId);
|
||||||
bool isComponentSelected(QUuid componentId);
|
bool isComponentSelected(QUuid componentId);
|
||||||
private:
|
private:
|
||||||
const Document *m_document = nullptr;
|
const Document *m_document = nullptr;
|
||||||
|
|
|
@ -14,7 +14,8 @@
|
||||||
|
|
||||||
PartWidget::PartWidget(const Document *document, QUuid partId) :
|
PartWidget::PartWidget(const Document *document, QUuid partId) :
|
||||||
m_document(document),
|
m_document(document),
|
||||||
m_partId(partId)
|
m_partId(partId),
|
||||||
|
m_unnormal(false)
|
||||||
{
|
{
|
||||||
QSizePolicy retainSizePolicy = sizePolicy();
|
QSizePolicy retainSizePolicy = sizePolicy();
|
||||||
retainSizePolicy.setRetainSizeWhenHidden(true);
|
retainSizePolicy.setRetainSizeWhenHidden(true);
|
||||||
|
@ -262,11 +263,20 @@ void PartWidget::updateAllButtons()
|
||||||
void PartWidget::updateCheckedState(bool checked)
|
void PartWidget::updateCheckedState(bool checked)
|
||||||
{
|
{
|
||||||
if (checked)
|
if (checked)
|
||||||
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + Theme::red.name() + ";}");
|
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid " + (m_unnormal ? Theme::blue.name() : Theme::red.name()) + ";}");
|
||||||
else
|
else
|
||||||
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}");
|
m_backgroundWidget->setStyleSheet("QWidget#background {border: 1px solid transparent;}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PartWidget::updateUnnormalState(bool unnormal)
|
||||||
|
{
|
||||||
|
if (m_unnormal == unnormal)
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_unnormal = unnormal;
|
||||||
|
updateAllButtons();
|
||||||
|
}
|
||||||
|
|
||||||
void PartWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
void PartWidget::mouseDoubleClickEvent(QMouseEvent *event)
|
||||||
{
|
{
|
||||||
QWidget::mouseDoubleClickEvent(event);
|
QWidget::mouseDoubleClickEvent(event);
|
||||||
|
@ -429,7 +439,7 @@ void PartWidget::initButton(QPushButton *button)
|
||||||
|
|
||||||
void PartWidget::updateButton(QPushButton *button, QChar icon, bool highlighted)
|
void PartWidget::updateButton(QPushButton *button, QChar icon, bool highlighted)
|
||||||
{
|
{
|
||||||
Theme::updateAwesomeMiniButton(button, icon, highlighted);
|
Theme::updateAwesomeMiniButton(button, icon, highlighted, m_unnormal);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PartWidget::updatePreview()
|
void PartWidget::updatePreview()
|
||||||
|
|
|
@ -45,6 +45,7 @@ public:
|
||||||
void updateColorButton();
|
void updateColorButton();
|
||||||
void updateWrapButton();
|
void updateWrapButton();
|
||||||
void updateCheckedState(bool checked);
|
void updateCheckedState(bool checked);
|
||||||
|
void updateUnnormalState(bool unnormal);
|
||||||
static QSize preferredSize();
|
static QSize preferredSize();
|
||||||
ModelWidget *previewWidget();
|
ModelWidget *previewWidget();
|
||||||
protected:
|
protected:
|
||||||
|
@ -55,6 +56,7 @@ public slots:
|
||||||
private: // need initialize
|
private: // need initialize
|
||||||
const Document *m_document;
|
const Document *m_document;
|
||||||
QUuid m_partId;
|
QUuid m_partId;
|
||||||
|
bool m_unnormal;
|
||||||
private:
|
private:
|
||||||
ModelWidget *m_previewWidget;
|
ModelWidget *m_previewWidget;
|
||||||
QPushButton *m_visibleButton;
|
QPushButton *m_visibleButton;
|
||||||
|
|
|
@ -588,17 +588,21 @@ void SkeletonGraphicsWidget::mouseMoveEvent(QMouseEvent *event)
|
||||||
mouseMove(event);
|
mouseMove(event);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool SkeletonGraphicsWidget::inputWheelEventFromOtherWidget(QWheelEvent *event)
|
||||||
|
{
|
||||||
|
if (!wheel(event)) {
|
||||||
|
if (m_modelWidget && m_modelWidget->inputWheelEventFromOtherWidget(event))
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::wheelEvent(QWheelEvent *event)
|
void SkeletonGraphicsWidget::wheelEvent(QWheelEvent *event)
|
||||||
{
|
{
|
||||||
if (!wheel(event)) {
|
if (!wheel(event)) {
|
||||||
if (m_modelWidget && m_modelWidget->inputWheelEventFromOtherWidget(event))
|
if (m_modelWidget && m_modelWidget->inputWheelEventFromOtherWidget(event))
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//if (SkeletonDocumentEditMode::ZoomIn == m_document->editMode ||
|
|
||||||
// SkeletonDocumentEditMode::ZoomOut == m_document->editMode ||
|
|
||||||
// SkeletonDocumentEditMode::Drag == m_document->editMode)
|
|
||||||
// QGraphicsView::wheelEvent(event);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void SkeletonGraphicsWidget::mouseReleaseEvent(QMouseEvent *event)
|
void SkeletonGraphicsWidget::mouseReleaseEvent(QMouseEvent *event)
|
||||||
|
|
|
@ -410,6 +410,7 @@ public:
|
||||||
bool hasTwoDisconnectedNodesSelection();
|
bool hasTwoDisconnectedNodesSelection();
|
||||||
void setModelWidget(ModelWidget *modelWidget);
|
void setModelWidget(ModelWidget *modelWidget);
|
||||||
void setNodePositionModifyOnly(bool nodePositionModifyOnly);
|
void setNodePositionModifyOnly(bool nodePositionModifyOnly);
|
||||||
|
bool inputWheelEventFromOtherWidget(QWheelEvent *event);
|
||||||
protected:
|
protected:
|
||||||
void mouseMoveEvent(QMouseEvent *event) override;
|
void mouseMoveEvent(QMouseEvent *event) override;
|
||||||
void wheelEvent(QWheelEvent *event) override;
|
void wheelEvent(QWheelEvent *event) override;
|
||||||
|
|
|
@ -103,18 +103,28 @@ void Theme::initAwesomeMiniButton(QPushButton *button)
|
||||||
button->setFocusPolicy(Qt::NoFocus);
|
button->setFocusPolicy(Qt::NoFocus);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted)
|
void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal)
|
||||||
{
|
{
|
||||||
button->setText(icon);
|
button->setText(icon);
|
||||||
QColor color;
|
QColor color;
|
||||||
if (highlighted)
|
bool needDesaturation = true;
|
||||||
color = QColor("#fc6621");
|
|
||||||
else
|
|
||||||
color = QColor("#525252");
|
|
||||||
|
|
||||||
color = color.toHsv();
|
if (highlighted) {
|
||||||
color.setHsv(color.hue(), color.saturation() / 5, color.value() * 2 / 3);
|
if (unnormal) {
|
||||||
color = color.toRgb();
|
color = Theme::blue;
|
||||||
|
needDesaturation = false;
|
||||||
|
} else {
|
||||||
|
color = Theme::red;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
color = QColor("#525252");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (needDesaturation) {
|
||||||
|
color = color.toHsv();
|
||||||
|
color.setHsv(color.hue(), color.saturation() / 5, color.value() * 2 / 3);
|
||||||
|
color = color.toRgb();
|
||||||
|
}
|
||||||
|
|
||||||
button->setStyleSheet("QPushButton {border: none; background: none; color: " + color.name() + ";}");
|
button->setStyleSheet("QPushButton {border: none; background: none; color: " + color.name() + ";}");
|
||||||
}
|
}
|
||||||
|
|
|
@ -47,7 +47,7 @@ public:
|
||||||
static void initAwesomeLabel(QLabel *label);
|
static void initAwesomeLabel(QLabel *label);
|
||||||
static void initAwesomeSmallButton(QPushButton *button);
|
static void initAwesomeSmallButton(QPushButton *button);
|
||||||
static void initAwesomeMiniButton(QPushButton *button);
|
static void initAwesomeMiniButton(QPushButton *button);
|
||||||
static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted);
|
static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted, bool unnormal=false);
|
||||||
static void initAwesomeToolButton(QPushButton *button);
|
static void initAwesomeToolButton(QPushButton *button);
|
||||||
static void initAwesomeToolButtonWithoutFont(QPushButton *button);
|
static void initAwesomeToolButtonWithoutFont(QPushButton *button);
|
||||||
};
|
};
|
||||||
|
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Loading…
Reference in New Issue