diff --git a/.gitignore b/.gitignore index 689537de..7dc62739 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ moc_* .DS_Store +*.o diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 138799dc..fc1c45b8 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -125,9 +125,12 @@ void MeshGenerator::process() int bmeshId = meshlite_bmesh_create(meshliteContext); if (subdived) meshlite_bmesh_set_cut_subdiv_count(meshliteContext, bmeshId, 1); - QString thicknessString = valueOfKeyInMapOrEmpty(part->second, "thickness"); + QString thicknessString = valueOfKeyInMapOrEmpty(part->second, "deformThickness"); if (!thicknessString.isEmpty()) - meshlite_bmesh_set_thickness(meshliteContext, bmeshId, thicknessString.toFloat()); + meshlite_bmesh_set_deform_thickness(meshliteContext, bmeshId, thicknessString.toFloat()); + QString widthString = valueOfKeyInMapOrEmpty(part->second, "deformWidth"); + if (!widthString.isEmpty()) + meshlite_bmesh_set_deform_width(meshliteContext, bmeshId, widthString.toFloat()); if (MeshGenerator::enableDebug) meshlite_bmesh_enable_debug(meshliteContext, bmeshId, 1); partBmeshMap[partIdIt] = bmeshId; diff --git a/src/skeletondocument.cpp b/src/skeletondocument.cpp index 8011479c..a0d0c2d7 100644 --- a/src/skeletondocument.cpp +++ b/src/skeletondocument.cpp @@ -585,8 +585,10 @@ void SkeletonDocument::toSnapshot(SkeletonSnapshot *snapshot, const std::setparts[part["id"]] = part; @@ -657,9 +659,12 @@ void SkeletonDocument::addFromSnapshot(const SkeletonSnapshot &snapshot) part.disabled = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "disabled")); part.xMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "xMirrored")); part.zMirrored = isTrueValueString(valueOfKeyInMapOrEmpty(partKv.second, "zMirrored")); - const auto &thicknessIt = partKv.second.find("thickness"); - if (thicknessIt != partKv.second.end()) - part.setThickness(thicknessIt->second.toFloat()); + const auto &deformThicknessIt = partKv.second.find("deformThickness"); + if (deformThicknessIt != partKv.second.end()) + part.setDeformThickness(deformThicknessIt->second.toFloat()); + const auto &deformWidthIt = partKv.second.find("deformWidth"); + if (deformWidthIt != partKv.second.end()) + part.setDeformWidth(deformWidthIt->second.toFloat()); partMap[part.id] = part; } for (const auto &nodeKv : snapshot.nodes) { @@ -929,15 +934,27 @@ void SkeletonDocument::setPartZmirrorState(QUuid partId, bool mirrored) emit skeletonChanged(); } -void SkeletonDocument::setPartThickness(QUuid partId, float thickness) +void SkeletonDocument::setPartDeformThickness(QUuid partId, float thickness) { auto part = partMap.find(partId); if (part == partMap.end()) { qDebug() << "Part not found:" << partId; return; } - part->second.setThickness(thickness); - emit partThicknessChanged(partId); + part->second.setDeformThickness(thickness); + emit partDeformThicknessChanged(partId); + emit skeletonChanged(); +} + +void SkeletonDocument::setPartDeformWidth(QUuid partId, float width) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + qDebug() << "Part not found:" << partId; + return; + } + part->second.setDeformWidth(width); + emit partDeformWidthChanged(partId); emit skeletonChanged(); } diff --git a/src/skeletondocument.h b/src/skeletondocument.h index 1f3d15b8..6ee1ea0c 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -71,7 +71,8 @@ public: bool disabled; bool xMirrored; bool zMirrored; - float thickness; + float deformThickness; + float deformWidth; QImage preview; std::vector nodeIds; SkeletonPart(const QUuid &withId=QUuid()) : @@ -81,21 +82,38 @@ public: disabled(false), xMirrored(false), zMirrored(false), - thickness(1.0) + deformThickness(1.0), + deformWidth(1.0) { id = withId.isNull() ? QUuid::createUuid() : withId; } - void setThickness(float toThickness) + void setDeformThickness(float toThickness) { if (toThickness < 0) toThickness = 0; else if (toThickness > 2) toThickness = 2; - thickness = toThickness; + deformThickness = toThickness; } - bool thicknessAdjusted() const + void setDeformWidth(float toWidth) { - return fabs(thickness - 1.0) >= 0.01; + if (toWidth < 0) + toWidth = 0; + else if (toWidth > 2) + toWidth = 2; + deformWidth = toWidth; + } + bool deformThicknessAdjusted() const + { + return fabs(deformThickness - 1.0) >= 0.01; + } + bool deformWidthAdjusted() const + { + return fabs(deformWidth - 1.0) >= 0.01; + } + bool deformAdjusted() const + { + return deformThicknessAdjusted() || deformWidthAdjusted(); } bool isEditVisible() const { @@ -109,7 +127,8 @@ public: disabled = other.disabled; xMirrored = other.xMirrored; zMirrored = other.zMirrored; - thickness = other.thickness; + deformThickness = other.deformThickness; + deformWidth = other.deformWidth; } }; @@ -161,7 +180,8 @@ signals: void partDisableStateChanged(QUuid partId); void partXmirrorStateChanged(QUuid partId); void partZmirrorStateChanged(QUuid partId); - void partThicknessChanged(QUuid partId); + void partDeformThicknessChanged(QUuid partId); + void partDeformWidthChanged(QUuid partId); void cleanup(); void originChanged(); void xlockStateChanged(); @@ -220,7 +240,8 @@ public slots: void setPartDisableState(QUuid partId, bool disabled); void setPartXmirrorState(QUuid partId, bool mirrored); void setPartZmirrorState(QUuid partId, bool mirrored); - void setPartThickness(QUuid partId, float thickness); + void setPartDeformThickness(QUuid partId, float thickness); + void setPartDeformWidth(QUuid partId, float width); void saveSnapshot(); void undo(); void redo(); diff --git a/src/skeletondocumentwindow.cpp b/src/skeletondocumentwindow.cpp index 64f1d8c6..5dd185bc 100644 --- a/src/skeletondocumentwindow.cpp +++ b/src/skeletondocumentwindow.cpp @@ -422,7 +422,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : connect(m_document, &SkeletonDocument::partSubdivStateChanged, partListWidget, &SkeletonPartListWidget::partSubdivStateChanged); connect(m_document, &SkeletonDocument::partDisableStateChanged, partListWidget, &SkeletonPartListWidget::partDisableStateChanged); connect(m_document, &SkeletonDocument::partXmirrorStateChanged, partListWidget, &SkeletonPartListWidget::partXmirrorStateChanged); - connect(m_document, &SkeletonDocument::partThicknessChanged, partListWidget, &SkeletonPartListWidget::partThicknessChanged); + connect(m_document, &SkeletonDocument::partDeformThicknessChanged, partListWidget, &SkeletonPartListWidget::partDeformChanged); + connect(m_document, &SkeletonDocument::partDeformWidthChanged, partListWidget, &SkeletonPartListWidget::partDeformChanged); connect(m_document, &SkeletonDocument::cleanup, partListWidget, &SkeletonPartListWidget::partListChanged); connect(m_document, &SkeletonDocument::skeletonChanged, m_document, &SkeletonDocument::generateMesh); diff --git a/src/skeletonpartlistwidget.cpp b/src/skeletonpartlistwidget.cpp index 16e7c0d9..a924b2aa 100644 --- a/src/skeletonpartlistwidget.cpp +++ b/src/skeletonpartlistwidget.cpp @@ -31,9 +31,9 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p initButton(m_xMirrorButton); updateXmirrorButton(); - m_thicknessButton = new QPushButton(); - initButton(m_thicknessButton); - updateThicknessButton(); + m_deformButton = new QPushButton(); + initButton(m_deformButton); + updateDeformButton(); m_previewLabel = new QLabel; @@ -49,8 +49,8 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p miniBottomToolLayout->setSpacing(0); miniBottomToolLayout->setContentsMargins(0, 0, 0, 0); miniBottomToolLayout->addWidget(m_subdivButton); + miniBottomToolLayout->addWidget(m_deformButton); miniBottomToolLayout->addWidget(m_xMirrorButton); - miniBottomToolLayout->addWidget(m_thicknessButton); miniBottomToolLayout->addStretch(); QWidget *hrWidget = new QWidget; @@ -74,7 +74,8 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p connect(this, &SkeletonPartWidget::setPartSubdivState, m_document, &SkeletonDocument::setPartSubdivState); connect(this, &SkeletonPartWidget::setPartDisableState, m_document, &SkeletonDocument::setPartDisableState); connect(this, &SkeletonPartWidget::setPartXmirrorState, m_document, &SkeletonDocument::setPartXmirrorState); - connect(this, &SkeletonPartWidget::setPartThickness, m_document, &SkeletonDocument::setPartThickness); + connect(this, &SkeletonPartWidget::setPartDeformThickness, m_document, &SkeletonDocument::setPartDeformThickness); + connect(this, &SkeletonPartWidget::setPartDeformWidth, m_document, &SkeletonDocument::setPartDeformWidth); connect(m_lockButton, &QPushButton::clicked, [=]() { const SkeletonPart *part = m_document->findPart(m_partId); @@ -121,17 +122,25 @@ SkeletonPartWidget::SkeletonPartWidget(const SkeletonDocument *document, QUuid p emit setPartXmirrorState(m_partId, !part->xMirrored); }); - connect(m_thicknessButton, &QPushButton::clicked, [=]() { + connect(m_deformButton, &QPushButton::clicked, [=]() { const SkeletonPart *part = m_document->findPart(m_partId); if (!part) { qDebug() << "Part not found:" << m_partId; return; } - showThicknessSettingPopup(mapFromGlobal(QCursor::pos())); + showDeformSettingPopup(mapFromGlobal(QCursor::pos())); }); } -void SkeletonPartWidget::showThicknessSettingPopup(const QPoint &pos) +void SkeletonPartWidget::initToolButton(QPushButton *button) +{ + button->setFont(Theme::awesome()->font(Theme::toolIconFontSize / 2)); + button->setFixedSize(Theme::toolIconSize / 2, Theme::toolIconSize / 2); + button->setStyleSheet("QPushButton {color: #f7d9c8}"); + button->setFocusPolicy(Qt::NoFocus); +} + +void SkeletonPartWidget::showDeformSettingPopup(const QPoint &pos) { QMenu popupMenu; @@ -141,14 +150,50 @@ void SkeletonPartWidget::showThicknessSettingPopup(const QPoint &pos) return; } - FloatNumberWidget *popup = new FloatNumberWidget; - popup->setRange(0, 2); - popup->setValue(part->thickness); + QWidget *popup = new QWidget; - connect(popup, &FloatNumberWidget::valueChanged, [=](float value) { - emit setPartThickness(m_partId, value); + FloatNumberWidget *thicknessWidget = new FloatNumberWidget; + thicknessWidget->setRange(0, 2); + thicknessWidget->setValue(part->deformThickness); + + connect(thicknessWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setPartDeformThickness(m_partId, value); }); + FloatNumberWidget *widthWidget = new FloatNumberWidget; + widthWidget->setRange(0, 2); + widthWidget->setValue(part->deformWidth); + + connect(widthWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setPartDeformWidth(m_partId, value); + }); + + QPushButton *thicknessEraser = new QPushButton(QChar(fa::eraser)); + initToolButton(thicknessEraser); + + connect(thicknessEraser, &QPushButton::clicked, [=]() { + thicknessWidget->setValue(1.0); + }); + + QPushButton *widthEraser = new QPushButton(QChar(fa::eraser)); + initToolButton(widthEraser); + + connect(widthEraser, &QPushButton::clicked, [=]() { + widthWidget->setValue(1.0); + }); + + QVBoxLayout *layout = new QVBoxLayout; + QHBoxLayout *thicknessLayout = new QHBoxLayout; + QHBoxLayout *widthLayout = new QHBoxLayout; + thicknessLayout->addWidget(thicknessEraser); + thicknessLayout->addWidget(thicknessWidget); + widthLayout->addWidget(widthEraser); + widthLayout->addWidget(widthWidget); + layout->addLayout(thicknessLayout); + layout->addLayout(widthLayout); + + popup->setLayout(layout); + QWidgetAction *action = new QWidgetAction(this); action->setDefaultWidget(popup); @@ -248,17 +293,17 @@ void SkeletonPartWidget::updateXmirrorButton() updateButton(m_xMirrorButton, QChar(fa::balancescale), false); } -void SkeletonPartWidget::updateThicknessButton() +void SkeletonPartWidget::updateDeformButton() { const SkeletonPart *part = m_document->findPart(m_partId); if (!part) { qDebug() << "Part not found:" << m_partId; return; } - if (part->thicknessAdjusted()) - updateButton(m_thicknessButton, QChar(fa::handlizardo), true); + if (part->deformAdjusted()) + updateButton(m_deformButton, QChar(fa::handlizardo), true); else - updateButton(m_thicknessButton, QChar(fa::handlizardo), false); + updateButton(m_deformButton, QChar(fa::handlizardo), false); } void SkeletonPartWidget::reload() @@ -269,7 +314,7 @@ void SkeletonPartWidget::reload() updateSubdivButton(); updateDisableButton(); updateXmirrorButton(); - updateThicknessButton(); + updateDeformButton(); } SkeletonPartListWidget::SkeletonPartListWidget(const SkeletonDocument *document) : @@ -376,7 +421,7 @@ void SkeletonPartListWidget::partXmirrorStateChanged(QUuid partId) widget->updateXmirrorButton(); } -void SkeletonPartListWidget::partThicknessChanged(QUuid partId) +void SkeletonPartListWidget::partDeformChanged(QUuid partId) { auto item = m_itemMap.find(partId); if (item == m_itemMap.end()) { @@ -384,5 +429,5 @@ void SkeletonPartListWidget::partThicknessChanged(QUuid partId) return; } SkeletonPartWidget *widget = (SkeletonPartWidget *)itemWidget(item->second); - widget->updateThicknessButton(); + widget->updateDeformButton(); } diff --git a/src/skeletonpartlistwidget.h b/src/skeletonpartlistwidget.h index 0dc5dc74..f3dd0c11 100644 --- a/src/skeletonpartlistwidget.h +++ b/src/skeletonpartlistwidget.h @@ -16,7 +16,8 @@ signals: void setPartDisableState(QUuid partId, bool disabled); void setPartXmirrorState(QUuid partId, bool mirrored); void setPartZmirrorState(QUuid partId, bool mirrored); - void setPartThickness(QUuid partId, float thickness); + void setPartDeformThickness(QUuid partId, float thickness); + void setPartDeformWidth(QUuid partId, float width); public: SkeletonPartWidget(const SkeletonDocument *document, QUuid partId); void reload(); @@ -27,9 +28,9 @@ public: void updateDisableButton(); void updateXmirrorButton(); void updateZmirrorButton(); - void updateThicknessButton(); + void updateDeformButton(); public slots: - void showThicknessSettingPopup(const QPoint &pos); + void showDeformSettingPopup(const QPoint &pos); private: const SkeletonDocument *m_document; QUuid m_partId; @@ -40,9 +41,10 @@ private: QPushButton *m_disableButton; QPushButton *m_xMirrorButton; QPushButton *m_zMirrorButton; - QPushButton *m_thicknessButton; + QPushButton *m_deformButton; QLabel *m_nameLabel; private: + void initToolButton(QPushButton *button); void initButton(QPushButton *button); void updateButton(QPushButton *button, QChar icon, bool highlighted); }; @@ -61,7 +63,7 @@ public slots: void partSubdivStateChanged(QUuid partId); void partDisableStateChanged(QUuid partId); void partXmirrorStateChanged(QUuid partId); - void partThicknessChanged(QUuid partId); + void partDeformChanged(QUuid partId); private: const SkeletonDocument *m_document; std::map m_itemMap; diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll index 8be2b867..4c226e49 100644 Binary files a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll and b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll differ diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib index 77d7b201..3d4b1850 100644 Binary files a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib and b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll.lib differ diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h index 8267039f..b6ed35f8 100644 --- a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h +++ b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h @@ -33,7 +33,8 @@ int meshlite_get_halfedge_normal_array(void *context, int mesh_id, float *buffer int meshlite_build(void *context, float *vertex_position_buffer, int vertex_count, int *face_index_buffer, int face_index_buffer_len); int meshlite_bmesh_create(void *context); int meshlite_bmesh_set_cut_subdiv_count(void *context, int bmesh_id, int subdiv_count); -int meshlite_bmesh_set_thickness(void *context, int bmesh_id, float thickness); +int meshlite_bmesh_set_deform_thickness(void *context, int bmesh_id, float thickness); +int meshlite_bmesh_set_deform_width(void *context, int bmesh_id, float width); int meshlite_bmesh_enable_debug(void *context, int bmesh_id, int enable); int meshlite_bmesh_add_node(void *context, int bmesh_id, float x, float y, float z, float radius); int meshlite_bmesh_add_edge(void *context, int bmesh_id, int first_node_id, int second_node_id); diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll index 0681b7e1..7f2e8f80 100644 Binary files a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll and b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll differ diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib index 8d28a127..4e134c58 100644 Binary files a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib and b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll.lib differ diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h index 8267039f..b6ed35f8 100644 --- a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h +++ b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h @@ -33,7 +33,8 @@ int meshlite_get_halfedge_normal_array(void *context, int mesh_id, float *buffer int meshlite_build(void *context, float *vertex_position_buffer, int vertex_count, int *face_index_buffer, int face_index_buffer_len); int meshlite_bmesh_create(void *context); int meshlite_bmesh_set_cut_subdiv_count(void *context, int bmesh_id, int subdiv_count); -int meshlite_bmesh_set_thickness(void *context, int bmesh_id, float thickness); +int meshlite_bmesh_set_deform_thickness(void *context, int bmesh_id, float thickness); +int meshlite_bmesh_set_deform_width(void *context, int bmesh_id, float width); int meshlite_bmesh_enable_debug(void *context, int bmesh_id, int enable); int meshlite_bmesh_add_node(void *context, int bmesh_id, float x, float y, float z, float radius); int meshlite_bmesh_add_edge(void *context, int bmesh_id, int first_node_id, int second_node_id);