diff --git a/src/floatnumberwidget.cpp b/src/floatnumberwidget.cpp index af6f2919..2ff3365f 100644 --- a/src/floatnumberwidget.cpp +++ b/src/floatnumberwidget.cpp @@ -6,15 +6,14 @@ FloatNumberWidget::FloatNumberWidget(QWidget *parent) : { m_slider = new QSlider(Qt::Horizontal, this); m_slider->setRange(0, 100); + m_slider->setFixedWidth(120); m_label = new QLabel(this); - m_label->setAlignment(Qt::AlignCenter); - m_label->setNum(0); - m_label->setFixedWidth(30); + m_label->setAlignment(Qt::AlignLeft); connect(m_slider, &QAbstractSlider::valueChanged, [=](int value) { float fvalue = value / 100.0; - m_label->setText(QString().sprintf("%.2f", fvalue)); + updateValueLabel(fvalue); emit valueChanged(fvalue); }); @@ -24,6 +23,21 @@ FloatNumberWidget::FloatNumberWidget(QWidget *parent) : popupLayout->addWidget(m_label); } +void FloatNumberWidget::updateValueLabel(float value) +{ + QString valueString = QString().sprintf("%.2f", value); + if (m_itemName.isEmpty()) + m_label->setText(valueString); + else + m_label->setText(m_itemName + ": " + valueString); +} + +void FloatNumberWidget::setItemName(const QString &name) +{ + m_itemName = name; + updateValueLabel(value()); +} + void FloatNumberWidget::setRange(float min, float max) { m_slider->setRange(min * 100, max * 100); diff --git a/src/floatnumberwidget.h b/src/floatnumberwidget.h index 4df1d5a2..48df208d 100644 --- a/src/floatnumberwidget.h +++ b/src/floatnumberwidget.h @@ -12,6 +12,7 @@ public: explicit FloatNumberWidget(QWidget *parent = nullptr); void setRange(float min, float max); float value() const; + void setItemName(const QString &name); public slots: void increaseValue(); @@ -20,10 +21,14 @@ public slots: signals: void valueChanged(float value); + +private: + void updateValueLabel(float value); private: QLabel *m_label = nullptr; QSlider *m_slider = nullptr; + QString m_itemName; }; #endif diff --git a/src/main.cpp b/src/main.cpp index 6812a14c..ffe1216a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -28,7 +28,7 @@ int main(int argc, char ** argv) darkPalette.setColor(QPalette::ButtonText, Theme::white); darkPalette.setColor(QPalette::BrightText, Theme::red); darkPalette.setColor(QPalette::Link, QColor(42, 130, 218)); - darkPalette.setColor(QPalette::Highlight, Theme::white); + darkPalette.setColor(QPalette::Highlight, Theme::red); darkPalette.setColor(QPalette::HighlightedText, Theme::black); qApp->setPalette(darkPalette); qApp->setStyleSheet("QToolTip { color: #ffffff; background-color: #fc6621; border: 1px solid white; }"); diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 6d2e5476..d5dd7a4d 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -215,12 +215,12 @@ void *MeshGenerator::combinePartMesh(QString partId) if (MeshGenerator::m_enableDebug) meshlite_bmesh_enable_debug(m_meshliteContext, bmeshId, 1); - QString mirroredPartId; - QUuid mirroredPartIdNotAsString; - if (xMirrored) { - mirroredPartIdNotAsString = QUuid().createUuid(); - mirroredPartId = mirroredPartIdNotAsString.toString(); - } + //QString mirroredPartId; + //QUuid mirroredPartIdNotAsString; + //if (xMirrored) { + // mirroredPartIdNotAsString = QUuid().createUuid(); + // mirroredPartId = mirroredPartIdNotAsString.toString(); + //} std::map nodeToBmeshIdMap; std::map bmeshToNodeIdMap; @@ -252,12 +252,11 @@ void *MeshGenerator::combinePartMesh(QString partId) bmeshNode.nodeId = QUuid(nodeId); bmeshNode.color = partColor; cacheBmeshNodes.push_back(bmeshNode); - - if (xMirrored) { - bmeshNode.partId = mirroredPartId; - bmeshNode.origin.setX(-x); - cacheBmeshNodes.push_back(bmeshNode); - } + //if (xMirrored) { + // bmeshNode.partId = mirroredPartId; + // bmeshNode.origin.setX(-x); + // cacheBmeshNodes.push_back(bmeshNode); + //} } for (const auto &edgeId: m_partEdgeIds[partId]) { @@ -300,7 +299,7 @@ void *MeshGenerator::combinePartMesh(QString partId) if (nullptr != resultMesh) { if (xMirrored) { int xMirroredMeshId = meshlite_mirror_in_x(m_meshliteContext, meshId, 0); - loadVertexSources(m_meshliteContext, xMirroredMeshId, mirroredPartIdNotAsString, bmeshToNodeIdMap, cacheBmeshVertices); + loadVertexSources(m_meshliteContext, xMirroredMeshId, partIdNotAsString, bmeshToNodeIdMap, cacheBmeshVertices); void *mirroredMesh = nullptr; if (wrapped) mirroredMesh = convertToCombinableConvexHullMesh(m_meshliteContext, xMirroredMeshId); @@ -411,41 +410,122 @@ void *MeshGenerator::combineComponentMesh(QString componentId, bool *inverse) } } - QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType"); - if ("partId" == linkDataType) { - QString partId = valueOfKeyInMapOrEmpty(*component, "linkData"); - return combinePartMesh(partId); + bool smoothSeam = false; + float smoothSeamFactor = 0.0; + QString smoothSeamString = valueOfKeyInMapOrEmpty(*component, "smoothSeam"); + if (!smoothSeamString.isEmpty()) { + smoothSeam = true; + smoothSeamFactor = smoothSeamString.toFloat(); + } + + bool smoothAll = false; + float smoothAllFactor = 0.0; + QString smoothAllString = valueOfKeyInMapOrEmpty(*component, "smoothAll"); + if (!smoothAllString.isEmpty()) { + smoothAll = true; + smoothAllFactor = smoothAllString.toFloat(); } void *resultMesh = nullptr; - for (const auto &childId: valueOfKeyInMapOrEmpty(*component, "children").split(",")) { - if (childId.isEmpty()) - continue; - bool childInverse = false; - void *childCombinedMesh = combineComponentMesh(childId, &childInverse); - if (nullptr == childCombinedMesh) - continue; - if (nullptr == resultMesh) { - if (childInverse) { - deleteCombinableMesh(childCombinedMesh); - } else { - resultMesh = childCombinedMesh; + PositionMap positionsBeforeCombination; + auto &verticesSources = m_cacheContext->componentVerticesSources[componentId]; + verticesSources.map().clear(); + QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType"); + if ("partId" == linkDataType) { + QString partId = valueOfKeyInMapOrEmpty(*component, "linkData"); + resultMesh = combinePartMesh(partId); + for (const auto &bmeshVertex: m_cacheContext->partBmeshVertices[partId]) { + verticesSources.addPosition(bmeshVertex.position.x(), bmeshVertex.position.y(), bmeshVertex.position.z(), + bmeshVertex); + } + } else { + for (const auto &childId: valueOfKeyInMapOrEmpty(*component, "children").split(",")) { + if (childId.isEmpty()) + continue; + bool childInverse = false; + void *childCombinedMesh = combineComponentMesh(childId, &childInverse); + if (smoothSeam) { + for (const auto &positionIt: m_cacheContext->componentPositions[childId]) { + positionsBeforeCombination.addPosition(positionIt.x(), positionIt.y(), positionIt.z(), true); + } } - } else { - void *newResultMesh = childInverse ? diffCombinableMeshs(resultMesh, childCombinedMesh) : unionCombinableMeshs(resultMesh, childCombinedMesh); - deleteCombinableMesh(childCombinedMesh); - if (nullptr != newResultMesh) { - deleteCombinableMesh(resultMesh); - resultMesh = newResultMesh; + for (const auto &verticesSourceIt: m_cacheContext->componentVerticesSources[childId].map()) { + verticesSources.map()[verticesSourceIt.first] = verticesSourceIt.second; + } + if (nullptr == childCombinedMesh) + continue; + if (nullptr == resultMesh) { + if (childInverse) { + deleteCombinableMesh(childCombinedMesh); + } else { + resultMesh = childCombinedMesh; + } + } else { + void *newResultMesh = childInverse ? diffCombinableMeshs(resultMesh, childCombinedMesh) : unionCombinableMeshs(resultMesh, childCombinedMesh); + deleteCombinableMesh(childCombinedMesh); + if (nullptr != newResultMesh) { + deleteCombinableMesh(resultMesh); + resultMesh = newResultMesh; + } } } } - if (!componentIdNotAsString.isNull()) { - m_cacheContext->updateComponentCombinableMesh(componentId, resultMesh); + if (nullptr != resultMesh) { + if (smoothSeam || smoothAll) { + int meshIdForSmooth = convertFromCombinableMesh(m_meshliteContext, resultMesh); + std::vector positionsBeforeSmooth; + loadMeshVerticesPositions(m_meshliteContext, meshIdForSmooth, positionsBeforeSmooth); + + if (!positionsBeforeSmooth.empty()) { + + if (smoothSeam) { + int *seamVerticesIndicies = new int[positionsBeforeSmooth.size()]; + int seamVerticesNum = 0; + for (size_t vertexIndex = 0; vertexIndex < positionsBeforeSmooth.size(); vertexIndex++) { + const auto &oldPosition = positionsBeforeSmooth[vertexIndex]; + if (!positionsBeforeCombination.findPosition(oldPosition.x(), oldPosition.y(), oldPosition.z())) { + seamVerticesIndicies[seamVerticesNum++] = vertexIndex + 1; + } + } + if (seamVerticesNum > 0) { + qDebug() << "smoothSeamFactor:" << smoothSeamFactor << "seamVerticesIndicies.size():" << seamVerticesNum; + meshlite_smooth_vertices(m_meshliteContext, meshIdForSmooth, smoothSeamFactor, seamVerticesIndicies, seamVerticesNum); + } + delete[] seamVerticesIndicies; + } + + if (smoothAll) { + meshlite_smooth(m_meshliteContext, meshIdForSmooth, smoothAllFactor); + } + + std::vector positionsAfterSmooth; + loadMeshVerticesPositions(m_meshliteContext, meshIdForSmooth, positionsAfterSmooth); + assert(positionsBeforeSmooth.size() == positionsAfterSmooth.size()); + + for (size_t vertexIndex = 0; vertexIndex < positionsBeforeSmooth.size(); vertexIndex++) { + const auto &oldPosition = positionsBeforeSmooth[vertexIndex]; + const auto &smoothedPosition = positionsAfterSmooth[vertexIndex]; + BmeshVertex source; + if (verticesSources.findPosition(oldPosition.x(), oldPosition.y(), oldPosition.z(), &source)) { + verticesSources.removePosition(oldPosition.x(), oldPosition.y(), oldPosition.z()); + source.position = smoothedPosition; + verticesSources.addPosition(smoothedPosition.x(), smoothedPosition.y(), smoothedPosition.z(), source); + } + } + + deleteCombinableMesh(resultMesh); + resultMesh = convertToCombinableMesh(m_meshliteContext, meshIdForSmooth); + } + } } + m_cacheContext->updateComponentCombinableMesh(componentId, resultMesh); + auto &cachedComponentPositions = m_cacheContext->componentPositions[componentId]; + cachedComponentPositions.clear(); + loadCombinableMeshVerticesPositions(resultMesh, cachedComponentPositions); + return resultMesh; } @@ -488,11 +568,27 @@ void MeshGenerator::process() } it++; } + for (auto it = m_cacheContext->componentPositions.begin(); it != m_cacheContext->componentPositions.end(); ) { + if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) { + it = m_cacheContext->componentPositions.erase(it); + continue; + } + it++; + } + for (auto it = m_cacheContext->componentVerticesSources.begin(); it != m_cacheContext->componentVerticesSources.end(); ) { + if (m_snapshot->components.find(it->first) == m_snapshot->components.end()) { + it = m_cacheContext->componentVerticesSources.erase(it); + continue; + } + it++; + } } collectParts(); checkDirtyFlags(); + m_dirtyComponentIds.insert(QUuid().toString()); + m_mainProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originX").toFloat(); m_mainProfileMiddleY = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originY").toFloat(); m_sideProfileMiddleX = valueOfKeyInMapOrEmpty(m_snapshot->canvas, "originZ").toFloat(); @@ -506,9 +602,8 @@ void MeshGenerator::process() deleteCombinableMesh(combinedMesh); } - for (const auto &bmeshVertices: m_cacheContext->partBmeshVertices) { - m_meshResultContext->bmeshVertices.insert(m_meshResultContext->bmeshVertices.end(), - bmeshVertices.second.begin(), bmeshVertices.second.end()); + for (const auto &verticesSourcesIt: m_cacheContext->componentVerticesSources[QUuid().toString()].map()) { + m_meshResultContext->bmeshVertices.push_back(verticesSourcesIt.second); } for (const auto &bmeshNodes: m_cacheContext->partBmeshNodes) { diff --git a/src/meshgenerator.h b/src/meshgenerator.h index abe52b81..5f2fced3 100644 --- a/src/meshgenerator.h +++ b/src/meshgenerator.h @@ -11,6 +11,7 @@ #include "meshloader.h" #include "modelofflinerender.h" #include "meshresultcontext.h" +#include "positionmap.h" class GeneratedCacheContext { @@ -19,6 +20,8 @@ public: std::map> partBmeshVertices; std::map> partBmeshNodes; std::map componentCombinableMeshs; + std::map> componentPositions; + std::map> componentVerticesSources; void updateComponentCombinableMesh(QString componentId, void *mesh); }; @@ -29,7 +32,6 @@ public: MeshGenerator(SkeletonSnapshot *snapshot, QThread *thread); ~MeshGenerator(); void setSharedContextWidget(QOpenGLWidget *widget); - //void addPreviewRequirement(); void addPartPreviewRequirement(const QString &partId); void setGeneratedCacheContext(GeneratedCacheContext *cacheContext); MeshLoader *takeResultMesh(); @@ -59,6 +61,7 @@ private: std::map> m_partEdgeIds; std::set m_dirtyComponentIds; std::set m_dirtyPartIds; + PositionMap> m_bmeshPartVerticesIndiciesMap; private: static bool m_enableDebug; private: diff --git a/src/meshutil.cpp b/src/meshutil.cpp index 0237b60b..b04d85d0 100644 --- a/src/meshutil.cpp +++ b/src/meshutil.cpp @@ -31,16 +31,13 @@ typedef CGAL::Surface_mesh ExactMesh; typedef CGAL::Surface_mesh SimpleMesh; namespace PMP = CGAL::Polygon_mesh_processing; -template -typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite(void *meshlite, int meshId) +void loadMeshVerticesPositions(void *meshliteContext, int meshId, std::vector &positions) { - typename CGAL::Surface_mesh *mesh = new typename CGAL::Surface_mesh; - int vertexCount = meshlite_get_vertex_count(meshlite, meshId); + int vertexCount = meshlite_get_vertex_count(meshliteContext, meshId); float *vertexPositions = new float[vertexCount * 3]; - int vertexArrayLen = meshlite_get_vertex_position_array(meshlite, meshId, vertexPositions, vertexCount * 3); + int vertexArrayLen = meshlite_get_vertex_position_array(meshliteContext, meshId, vertexPositions, vertexCount * 3); int offset = 0; assert(vertexArrayLen == vertexCount * 3); - std::vector::Vertex_index> vertices; for (int i = 0; i < vertexCount; i++) { float x = vertexPositions[offset + 0]; float y = vertexPositions[offset + 1]; @@ -51,7 +48,34 @@ typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite( y = 0; if (std::isnan(z) || std::isinf(z)) z = 0; - vertices.push_back(mesh->add_vertex(typename Kernel::Point_3(x, y, z))); + positions.push_back(QVector3D(x, y, z)); + offset += 3; + } + delete[] vertexPositions; +} + +template +typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite(void *meshlite, int meshId) +{ + typename CGAL::Surface_mesh *mesh = new typename CGAL::Surface_mesh; + int vertexCount = meshlite_get_vertex_count(meshlite, meshId); + float *vertexPositions = new float[vertexCount * 3]; + int vertexArrayLen = meshlite_get_vertex_position_array(meshlite, meshId, vertexPositions, vertexCount * 3); + int offset = 0; + assert(vertexArrayLen == vertexCount * 3); + std::vector oldPositions; + std::map::Vertex_index> oldToNewMap; + for (int i = 0; i < vertexCount; i++) { + float x = vertexPositions[offset + 0]; + float y = vertexPositions[offset + 1]; + float z = vertexPositions[offset + 2]; + 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; + oldPositions.push_back(QVector3D(x, y, z)); offset += 3; } int faceCount = meshlite_get_face_count(meshlite, meshId); @@ -62,26 +86,51 @@ typename CGAL::Surface_mesh *makeCgalMeshFromMeshlite( while (i < filledLength) { int num = faceVertexNumAndIndices[i++]; assert(num > 0 && num <= MAX_VERTICES_PER_FACE); + if (num < 3) + continue; std::vector::Vertex_index> faceVertexIndices; for (int j = 0; j < num; j++) { int index = faceVertexNumAndIndices[i++]; assert(index >= 0 && index < vertexCount); - faceVertexIndices.push_back(vertices[index]); - } - if (faceVertexIndices.size() >= 3) { - mesh->add_face(faceVertexIndices); - addedFaceCount++; + if (oldToNewMap.find(index) == oldToNewMap.end()) { + const auto &pos = oldPositions[index]; + oldToNewMap[index] = mesh->add_vertex(typename Kernel::Point_3(pos.x(), pos.y(), pos.z())); + } + faceVertexIndices.push_back(oldToNewMap[index]); } + mesh->add_face(faceVertexIndices); + addedFaceCount++; } delete[] faceVertexNumAndIndices; delete[] vertexPositions; - if (0 == addedFaceCount) { + if (addedFaceCount < 3) { delete mesh; mesh = nullptr; } return mesh; } +void loadCombinableMeshVerticesPositions(void *mesh, std::vector &positions) +{ + 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)); + } +} + // https://doc.cgal.org/latest/Surface_mesh/index.html#circulators_example // https://www.cgal.org/FAQ.html template @@ -256,7 +305,6 @@ ExactMesh *diffCgalMeshs(ExactMesh *first, ExactMesh *second) int unionMeshs(void *meshliteContext, const std::vector &meshIds, const std::set &inverseIds, int *errorCount) { #if USE_CGAL == 1 - CGAL::set_error_behaviour(CGAL::CONTINUE); std::vector externalMeshs; for (size_t i = 0; i < meshIds.size(); i++) { int triangledMeshId = meshlite_triangulate(meshliteContext, meshIds[i]); @@ -331,7 +379,6 @@ int subdivMesh(void *meshliteContext, int meshId, int *errorCount) int triangulatedMeshId = meshlite_triangulate(meshliteContext, meshId); if (0 == meshlite_is_triangulated_manifold(meshliteContext, triangulatedMeshId)) { #if USE_CGAL == 1 - CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); int subdiviedMeshId = 0; SimpleMesh *simpleMesh = nullptr; try { @@ -359,7 +406,7 @@ int fixMeshHoles(void *meshliteContext, int meshId) void initMeshUtils() { - CGAL::set_error_behaviour(CGAL::CONTINUE); + CGAL::set_error_behaviour(CGAL::THROW_EXCEPTION); } void *convertToCombinableMesh(void *meshliteContext, int meshId) diff --git a/src/meshutil.h b/src/meshutil.h index afdafde6..a767efe3 100644 --- a/src/meshutil.h +++ b/src/meshutil.h @@ -2,6 +2,7 @@ #define MESH_UTIL_H #include #include +#include int mergeMeshs(void *meshliteContext, const std::vector &meshIds); int unionMeshs(void *meshliteContext, const std::vector &meshIds, const std::set &inverseIds, int *errorCount=0); @@ -16,5 +17,7 @@ int convertFromCombinableMesh(void *meshliteContext, void *mesh); void deleteCombinableMesh(void *mesh); void *cloneCombinableMesh(void *mesh); void *convertToCombinableConvexHullMesh(void *meshliteContext, int meshId); +void loadMeshVerticesPositions(void *meshliteContext, int meshId, std::vector &positions); +void loadCombinableMeshVerticesPositions(void *mesh, std::vector &positions); #endif diff --git a/src/positionmap.h b/src/positionmap.h index c74d8691..beb30a3a 100644 --- a/src/positionmap.h +++ b/src/positionmap.h @@ -50,7 +50,7 @@ public: m_map[makeKey(x, y, z)] = data; } - bool findPosition(float x, float y, float z, T *data) + bool findPosition(float x, float y, float z, T *data = nullptr) { const auto &result = m_map.find(makeKey(x, y, z)); if (result == m_map.end()) @@ -59,6 +59,16 @@ public: *data = result->second; return true; } + + void removePosition(float x, float y, float z) + { + m_map.erase(makeKey(x, y, z)); + } + + std::map &map() + { + return m_map; + } private: std::map m_map; diff --git a/src/skeletondocument.cpp b/src/skeletondocument.cpp index 9b2612c3..241121ec 100644 --- a/src/skeletondocument.cpp +++ b/src/skeletondocument.cpp @@ -725,6 +725,10 @@ void SkeletonDocument::toSnapshot(SkeletonSnapshot *snapshot, const std::setsecond.toFloat()); + const auto &smoothSeamIt = componentKv.second.find("smoothSeam"); + if (smoothSeamIt != componentKv.second.end()) + component.setSmoothSeam(smoothSeamIt->second.toFloat()); qDebug() << "Add component:" << component.id << " old:" << componentKv.first << "name:" << component.name; if ("partId" == linkDataType) { QUuid partId = oldNewIdMap[QUuid(linkData)]; @@ -1284,6 +1294,32 @@ void SkeletonDocument::setComponentInverseState(QUuid componentId, bool inverse) emit skeletonChanged(); } +void SkeletonDocument::setComponentSmoothAll(QUuid componentId, float toSmoothAll) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "Component not found:" << componentId; + return; + } + component->second.setSmoothAll(toSmoothAll); + component->second.dirty = true; + emit componentSmoothAllChanged(componentId); + emit skeletonChanged(); +} + +void SkeletonDocument::setComponentSmoothSeam(QUuid componentId, float toSmoothSeam) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + qDebug() << "Component not found:" << componentId; + return; + } + component->second.setSmoothSeam(toSmoothSeam); + component->second.dirty = true; + emit componentSmoothSeamChanged(componentId); + emit skeletonChanged(); +} + void SkeletonDocument::setPartSubdivState(QUuid partId, bool subdived) { auto part = partMap.find(partId); diff --git a/src/skeletondocument.h b/src/skeletondocument.h index b2d21358..4892f9f3 100644 --- a/src/skeletondocument.h +++ b/src/skeletondocument.h @@ -199,6 +199,8 @@ public: bool expanded = true; bool inverse = false; bool dirty = true; + float smoothAll = 0.0; + float smoothSeam = 0.0; std::vector childrenIds; QString linkData() const { @@ -290,6 +292,34 @@ public: for (int i = index; i <= (int)childrenIds.size() - 2; i++) std::swap(childrenIds[i], childrenIds[i + 1]); } + void setSmoothAll(float toSmoothAll) + { + if (toSmoothAll < 0) + toSmoothAll = 0; + else if (toSmoothAll > 1) + toSmoothAll = 1; + smoothAll = toSmoothAll; + } + void setSmoothSeam(float toSmoothSeam) + { + if (toSmoothSeam < 0) + toSmoothSeam = 0; + else if (toSmoothSeam > 1) + toSmoothSeam = 1; + smoothSeam = toSmoothSeam; + } + bool smoothAllAdjusted() const + { + return fabs(smoothAll - 0.0) >= 0.01; + } + bool smoothSeamAdjusted() const + { + return fabs(smoothSeam - 0.0) >= 0.01; + } + bool smoothAdjusted() const + { + return smoothAllAdjusted() || smoothSeamAdjusted(); + } private: std::set m_childrenIdSet; }; @@ -307,6 +337,8 @@ signals: void componentRemoved(QUuid componentId); void componentAdded(QUuid componentId); void componentExpandStateChanged(QUuid componentId); + void componentSmoothAllChanged(QUuid componentId); + void componentSmoothSeamChanged(QUuid componentId); void nodeRemoved(QUuid nodeId); void edgeRemoved(QUuid edgeId); void nodeRadiusChanged(QUuid nodeId); @@ -442,6 +474,8 @@ public slots: void setCurrentCanvasComponentId(QUuid componentId); void createNewComponentAndMoveThisIn(QUuid componentId); void setComponentExpandState(QUuid componentId, bool expanded); + void setComponentSmoothAll(QUuid componentId, float toSmoothAll); + void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); void hideOtherComponents(QUuid componentId); void lockOtherComponents(QUuid componentId); void hideAllComponents(); diff --git a/src/skeletondocumentwindow.cpp b/src/skeletondocumentwindow.cpp index 0bc945b3..86e0aa07 100644 --- a/src/skeletondocumentwindow.cpp +++ b/src/skeletondocumentwindow.cpp @@ -596,6 +596,8 @@ SkeletonDocumentWindow::SkeletonDocumentWindow() : connect(partTreeWidget, &SkeletonPartTreeWidget::createNewComponentAndMoveThisIn, m_document, &SkeletonDocument::createNewComponentAndMoveThisIn); connect(partTreeWidget, &SkeletonPartTreeWidget::renameComponent, m_document, &SkeletonDocument::renameComponent); connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentExpandState, m_document, &SkeletonDocument::setComponentExpandState); + connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentSmoothAll, m_document, &SkeletonDocument::setComponentSmoothAll); + connect(partTreeWidget, &SkeletonPartTreeWidget::setComponentSmoothSeam, m_document, &SkeletonDocument::setComponentSmoothSeam); connect(partTreeWidget, &SkeletonPartTreeWidget::moveComponent, m_document, &SkeletonDocument::moveComponent); connect(partTreeWidget, &SkeletonPartTreeWidget::removeComponent, m_document, &SkeletonDocument::removeComponent); connect(partTreeWidget, &SkeletonPartTreeWidget::hideOtherComponents, m_document, &SkeletonDocument::hideOtherComponents); diff --git a/src/skeletonparttreewidget.cpp b/src/skeletonparttreewidget.cpp index 87440501..3ad0df81 100644 --- a/src/skeletonparttreewidget.cpp +++ b/src/skeletonparttreewidget.cpp @@ -1,8 +1,12 @@ #include #include +#include +#include +#include #include "skeletonparttreewidget.h" #include "skeletonpartwidget.h" #include "skeletongraphicswidget.h" +#include "floatnumberwidget.h" SkeletonPartTreeWidget::SkeletonPartTreeWidget(const SkeletonDocument *document, QWidget *parent) : QTreeWidget(parent), @@ -22,6 +26,7 @@ SkeletonPartTreeWidget::SkeletonPartTreeWidget(const SkeletonDocument *document, m_componentItemMap[QUuid()] = invisibleRootItem(); setContextMenuPolicy(Qt::CustomContextMenu); + //setIconSize(QSize(Theme::miniIconFontSize, Theme::miniIconFontSize)); setStyleSheet("QTreeView {qproperty-indentation: 10; margin-left: 5px; margin-top: 5px;}" "QTreeView::branch:has-siblings:!adjoins-item {border-image: url(:/resources/tree-vline.png);}" @@ -30,42 +35,63 @@ SkeletonPartTreeWidget::SkeletonPartTreeWidget(const SkeletonDocument *document, "QTreeView::branch:has-children:!has-siblings:closed, QTreeView::branch:closed:has-children:has-siblings {border-image: none; image: url(:/resources/tree-branch-closed.png);}" "QTreeView::branch:open:has-children:!has-siblings, QTreeView::branch:open:has-children:has-siblings {border-image: none; image: url(:/resources/tree-branch-open.png);}"); - QFont font; - font.setWeight(QFont::Light); - font.setPixelSize(9); - font.setBold(false); - setFont(font); + m_normalFont.setWeight(QFont::Light); + m_normalFont.setPixelSize(9); + m_normalFont.setBold(false); + + m_selectedFont.setWeight(QFont::Light); + m_selectedFont.setPixelSize(9); + m_selectedFont.setBold(true); + + setFont(m_normalFont); connect(this, &QTreeWidget::customContextMenuRequested, this, &SkeletonPartTreeWidget::showContextMenu); connect(this, &QTreeWidget::itemChanged, this, &SkeletonPartTreeWidget::groupChanged); connect(this, &QTreeWidget::itemExpanded, this, &SkeletonPartTreeWidget::groupExpanded); connect(this, &QTreeWidget::itemCollapsed, this, &SkeletonPartTreeWidget::groupCollapsed); - connect(this, &QTreeWidget::currentItemChanged, this, &SkeletonPartTreeWidget::currentGroupChanged); } -void SkeletonPartTreeWidget::currentGroupChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous) +void SkeletonPartTreeWidget::selectComponent(QUuid componentId) { - if (nullptr != current) { - auto componentId = QUuid(current->data(0, Qt::UserRole).toString()); - const SkeletonComponent *component = m_document->findComponent(componentId); - if (nullptr != component) { - emit currentComponentChanged(componentId); - return; + if (m_currentSelectedComponent != componentId) { + if (!m_currentSelectedComponent.isNull()) { + auto item = m_componentItemMap.find(m_currentSelectedComponent); + if (item != m_componentItemMap.end()) { + item->second->setFont(0, m_normalFont); + } } + m_currentSelectedComponent = componentId; + if (!m_currentSelectedComponent.isNull()) { + auto item = m_componentItemMap.find(m_currentSelectedComponent); + if (item != m_componentItemMap.end()) { + item->second->setFont(0, m_selectedFont); + } + } + emit currentComponentChanged(m_currentSelectedComponent); } - emit currentComponentChanged(QUuid()); } void SkeletonPartTreeWidget::mousePressEvent(QMouseEvent *event) { - QModelIndex item = indexAt(event->pos()); - if (item.isValid()) { - QTreeView::mousePressEvent(event); - } else { - clearSelection(); - QTreeView::mousePressEvent(event); - emit currentComponentChanged(QUuid()); + QModelIndex itemIndex = indexAt(event->pos()); + QTreeView::mousePressEvent(event); + if (itemIndex.isValid()) { + QTreeWidgetItem *item = itemFromIndex(itemIndex); + auto componentId = QUuid(item->data(0, Qt::UserRole).toString()); + if (m_componentItemMap.find(componentId) != m_componentItemMap.end()) { + selectComponent(componentId); + return; + } + item = item->parent(); + if (nullptr != item) { + componentId = QUuid(item->data(0, Qt::UserRole).toString()); + if (m_componentItemMap.find(componentId) != m_componentItemMap.end()) { + selectComponent(componentId); + return; + } + } } + selectComponent(QUuid()); } void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) @@ -92,9 +118,13 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addSection(component->name); QAction showAction(tr("Show"), this); + showAction.setIcon(Theme::awesome()->icon(fa::eye)); QAction hideAction(tr("Hide"), this); + hideAction.setIcon(Theme::awesome()->icon(fa::eyeslash)); QAction lockAction(tr("Lock"), this); + 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); @@ -176,13 +206,22 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addSeparator(); + QMenu *smoothMenu = contextMenu.addMenu(tr("Smooth")); + QWidgetAction smoothAction(this); + smoothAction.setDefaultWidget(createSmoothMenuWidget(componentId)); + smoothMenu->addAction(&smoothAction); + + contextMenu.addSeparator(); + QAction hideOthersAction(tr("Hide Others"), this); + hideOthersAction.setIcon(Theme::awesome()->icon(fa::eyeslash)); connect(&hideOthersAction, &QAction::triggered, [=]() { emit hideOtherComponents(componentId); }); contextMenu.addAction(&hideOthersAction); QAction lockOthersAction(tr("Lock Others"), this); + lockOthersAction.setIcon(Theme::awesome()->icon(fa::lock)); connect(&lockOthersAction, &QAction::triggered, [=]() { emit lockOtherComponents(componentId); }); @@ -205,12 +244,14 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addSeparator(); QAction hideAllAction(tr("Hide All"), this); + hideAllAction.setIcon(Theme::awesome()->icon(fa::eyeslash)); connect(&hideAllAction, &QAction::triggered, [=]() { emit hideAllComponents(); }); contextMenu.addAction(&hideAllAction); QAction showAllAction(tr("Show All"), this); + showAllAction.setIcon(Theme::awesome()->icon(fa::eye)); connect(&showAllAction, &QAction::triggered, [=]() { emit showAllComponents(); }); @@ -219,12 +260,14 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addSeparator(); QAction lockAllAction(tr("Lock All"), this); + lockAllAction.setIcon(Theme::awesome()->icon(fa::lock)); connect(&lockAllAction, &QAction::triggered, [=]() { emit lockAllComponents(); }); contextMenu.addAction(&lockAllAction); QAction unlockAllAction(tr("Unlock All"), this); + unlockAllAction.setIcon(Theme::awesome()->icon(fa::unlock)); connect(&unlockAllAction, &QAction::triggered, [=]() { emit unlockAllComponents(); }); @@ -234,25 +277,29 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) QMenu *moveToMenu = contextMenu.addMenu(tr("Move To")); + QAction moveToTopAction(tr("Top"), this); + moveToTopAction.setIcon(Theme::awesome()->icon(fa::angledoubleup)); + connect(&moveToTopAction, &QAction::triggered, [=]() { + emit moveComponentToTop(componentId); + }); + moveToMenu->addAction(&moveToTopAction); + QAction moveUpAction(tr("Up"), this); + moveUpAction.setIcon(Theme::awesome()->icon(fa::angleup)); connect(&moveUpAction, &QAction::triggered, [=]() { emit moveComponentUp(componentId); }); moveToMenu->addAction(&moveUpAction); QAction moveDownAction(tr("Down"), this); + moveDownAction.setIcon(Theme::awesome()->icon(fa::angledown)); connect(&moveDownAction, &QAction::triggered, [=]() { emit moveComponentDown(componentId); }); moveToMenu->addAction(&moveDownAction); - QAction moveToTopAction(tr("Top"), this); - connect(&moveToTopAction, &QAction::triggered, [=]() { - emit moveComponentToTop(componentId); - }); - moveToMenu->addAction(&moveToTopAction); - QAction moveToBottomAction(tr("Bottom"), this); + moveToBottomAction.setIcon(Theme::awesome()->icon(fa::angledoubledown)); connect(&moveToBottomAction, &QAction::triggered, [=]() { emit moveComponentToBottom(componentId); }); @@ -261,6 +308,7 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) moveToMenu->addSeparator(); QAction moveToNewGroupAction(tr("New Group"), this); + moveToNewGroupAction.setIcon(Theme::awesome()->icon(fa::file)); moveToMenu->addAction(&moveToNewGroupAction); connect(&moveToNewGroupAction, &QAction::triggered, [=]() { emit createNewComponentAndMoveThisIn(componentId); @@ -297,6 +345,7 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) contextMenu.addSeparator(); QAction deleteAction(tr("Delete"), this); + deleteAction.setIcon(Theme::awesome()->icon(fa::trash)); connect(&deleteAction, &QAction::triggered, [=]() { emit removeComponent(componentId); }); @@ -309,6 +358,78 @@ void SkeletonPartTreeWidget::showContextMenu(const QPoint &pos) } } +QWidget *SkeletonPartTreeWidget::createSmoothMenuWidget(QUuid componentId) +{ + QWidget *popup = new QWidget; + + const SkeletonComponent *component = m_document->findComponent(componentId); + if (!component) { + qDebug() << "Find component failed:" << componentId; + return popup; + } + + bool showSeamControl = component->linkToPartId.isNull(); + + FloatNumberWidget *smoothAllWidget = new FloatNumberWidget; + smoothAllWidget->setItemName(tr("All")); + smoothAllWidget->setRange(0, 1); + smoothAllWidget->setValue(component->smoothAll); + + connect(smoothAllWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setComponentSmoothAll(componentId, value); + emit groupOperationAdded(); + }); + + QPushButton *smoothAllEraser = new QPushButton(QChar(fa::eraser)); + Theme::initAwesomeToolButton(smoothAllEraser); + + connect(smoothAllEraser, &QPushButton::clicked, [=]() { + smoothAllWidget->setValue(0.0); + }); + + FloatNumberWidget *smoothSeamWidget = nullptr; + QPushButton *smoothSeamEraser = nullptr; + + if (showSeamControl) { + smoothSeamWidget = new FloatNumberWidget; + smoothSeamWidget->setItemName(tr("Seam")); + smoothSeamWidget->setRange(0, 1); + smoothSeamWidget->setValue(component->smoothSeam); + + connect(smoothSeamWidget, &FloatNumberWidget::valueChanged, [=](float value) { + emit setComponentSmoothSeam(componentId, value); + emit groupOperationAdded(); + }); + + smoothSeamEraser = new QPushButton(QChar(fa::eraser)); + Theme::initAwesomeToolButton(smoothSeamEraser); + + connect(smoothSeamEraser, &QPushButton::clicked, [=]() { + smoothSeamWidget->setValue(0.0); + }); + } + + QHBoxLayout *smoothSeamLayout = nullptr; + + QVBoxLayout *layout = new QVBoxLayout; + QHBoxLayout *smoothAllLayout = new QHBoxLayout; + if (showSeamControl) + smoothSeamLayout = new QHBoxLayout; + smoothAllLayout->addWidget(smoothAllEraser); + smoothAllLayout->addWidget(smoothAllWidget); + if (showSeamControl) { + smoothSeamLayout->addWidget(smoothSeamEraser); + smoothSeamLayout->addWidget(smoothSeamWidget); + } + layout->addLayout(smoothAllLayout); + if (showSeamControl) + layout->addLayout(smoothSeamLayout); + + popup->setLayout(layout); + + return popup; +} + QTreeWidgetItem *SkeletonPartTreeWidget::findComponentItem(QUuid componentId) { auto findResult = m_componentItemMap.find(componentId); @@ -379,7 +500,7 @@ void SkeletonPartTreeWidget::addComponentChildrenToItem(QUuid componentId, QTree item->setData(0, Qt::UserRole, QVariant(component->id.toString())); item->setChildIndicatorPolicy(QTreeWidgetItem::ShowIndicator); item->setExpanded(component->expanded); - item->setFlags(item->flags() | Qt::ItemIsEditable | Qt::ItemIsEnabled | Qt::ItemIsSelectable); + item->setFlags((item->flags() | Qt::ItemIsEditable | Qt::ItemIsEnabled) & ~(Qt::ItemIsSelectable)); m_componentItemMap[childId] = item; addComponentChildrenToItem(childId, item); } diff --git a/src/skeletonparttreewidget.h b/src/skeletonparttreewidget.h index 94505e9f..08043f76 100644 --- a/src/skeletonparttreewidget.h +++ b/src/skeletonparttreewidget.h @@ -20,6 +20,8 @@ signals: void createNewComponentAndMoveThisIn(QUuid componentId); void renameComponent(QUuid componentId, QString name); void setComponentExpandState(QUuid componentId, bool expanded); + void setComponentSmoothAll(QUuid componentId, float toSmoothAll); + void setComponentSmoothSeam(QUuid componentId, float toSmoothSeam); void moveComponent(QUuid componentId, QUuid toParentId); void removeComponent(QUuid componentId); void hideOtherComponents(QUuid componentId); @@ -38,6 +40,7 @@ signals: void lockDescendantComponents(QUuid componentId); void unlockDescendantComponents(QUuid componentId); void addPartToSelection(QUuid partId); + void groupOperationAdded(); public: SkeletonPartTreeWidget(const SkeletonDocument *document, QWidget *parent); QTreeWidgetItem *findComponentItem(QUuid componentId); @@ -64,7 +67,6 @@ public slots: void groupChanged(QTreeWidgetItem *item, int column); void groupExpanded(QTreeWidgetItem *item); void groupCollapsed(QTreeWidgetItem *item); - void currentGroupChanged(QTreeWidgetItem *current, QTreeWidgetItem *previous); void removeAllContent(); void showContextMenu(const QPoint &pos); protected: @@ -74,11 +76,16 @@ protected: private: void addComponentChildrenToItem(QUuid componentId, QTreeWidgetItem *parentItem); void deleteItemChildren(QTreeWidgetItem *item); + void selectComponent(QUuid componentId); + QWidget *createSmoothMenuWidget(QUuid componentId); private: const SkeletonDocument *m_document = nullptr; std::map m_partItemMap; std::map m_componentItemMap; SkeletonGraphicsFunctions *m_graphicsFunctions = nullptr; + QFont m_normalFont; + QFont m_selectedFont; + QUuid m_currentSelectedComponent; }; #endif diff --git a/src/skeletonpartwidget.cpp b/src/skeletonpartwidget.cpp index 3adcbfdb..5df4799f 100644 --- a/src/skeletonpartwidget.cpp +++ b/src/skeletonpartwidget.cpp @@ -263,15 +263,12 @@ void SkeletonPartWidget::mouseDoubleClickEvent(QMouseEvent *event) void SkeletonPartWidget::initToolButtonWithoutFont(QPushButton *button) { - button->setFixedSize(Theme::toolIconSize / 2, Theme::toolIconSize / 2); - button->setStyleSheet("QPushButton {color: #f7d9c8}"); - button->setFocusPolicy(Qt::NoFocus); + Theme::initAwesomeToolButtonWithoutFont(button); } void SkeletonPartWidget::initToolButton(QPushButton *button) { - button->setFont(Theme::awesome()->font(Theme::toolIconFontSize / 2)); - initToolButtonWithoutFont(button); + Theme::initAwesomeToolButton(button); } void SkeletonPartWidget::showColorSettingPopup(const QPoint &pos) @@ -289,10 +286,6 @@ void SkeletonPartWidget::showColorSettingPopup(const QPoint &pos) QPushButton *colorEraser = new QPushButton(QChar(fa::eraser)); initToolButton(colorEraser); - //QLabel *colorPreviewLabel = new QLabel; - //colorPreviewLabel->setFixedSize(Theme::miniIconSize, Theme::miniIconSize); - //colorPreviewLabel->setAutoFillBackground(true); - QPushButton *pickButton = new QPushButton(); initToolButtonWithoutFont(pickButton); QPalette palette = pickButton->palette(); @@ -343,14 +336,17 @@ void SkeletonPartWidget::showDeformSettingPopup(const QPoint &pos) QWidget *popup = new QWidget; FloatNumberWidget *thicknessWidget = new FloatNumberWidget; + thicknessWidget->setItemName(tr("Thickness")); thicknessWidget->setRange(0, 2); thicknessWidget->setValue(part->deformThickness); connect(thicknessWidget, &FloatNumberWidget::valueChanged, [=](float value) { emit setPartDeformThickness(m_partId, value); + emit groupOperationAdded(); }); FloatNumberWidget *widthWidget = new FloatNumberWidget; + widthWidget->setItemName(tr("Width")); widthWidget->setRange(0, 2); widthWidget->setValue(part->deformWidth); @@ -364,6 +360,7 @@ void SkeletonPartWidget::showDeformSettingPopup(const QPoint &pos) connect(thicknessEraser, &QPushButton::clicked, [=]() { thicknessWidget->setValue(1.0); + emit groupOperationAdded(); }); QPushButton *widthEraser = new QPushButton(QChar(fa::eraser)); @@ -371,6 +368,7 @@ void SkeletonPartWidget::showDeformSettingPopup(const QPoint &pos) connect(widthEraser, &QPushButton::clicked, [=]() { widthWidget->setValue(1.0); + emit groupOperationAdded(); }); QVBoxLayout *layout = new QVBoxLayout; @@ -385,35 +383,22 @@ void SkeletonPartWidget::showDeformSettingPopup(const QPoint &pos) popup->setLayout(layout); - QWidgetAction *action = new QWidgetAction(this); - action->setDefaultWidget(popup); + QWidgetAction action(this); + action.setDefaultWidget(popup); - popupMenu.addAction(action); + popupMenu.addAction(&action); popupMenu.exec(mapToGlobal(pos)); } void SkeletonPartWidget::initButton(QPushButton *button) { - button->setFont(Theme::awesome()->font(Theme::miniIconFontSize)); - button->setFixedSize(Theme::miniIconSize, Theme::miniIconSize); - button->setFocusPolicy(Qt::NoFocus); + Theme::initAwesomeMiniButton(button); } void SkeletonPartWidget::updateButton(QPushButton *button, QChar icon, bool highlighted) { - button->setText(icon); - QColor color; - if (highlighted) - color = QColor("#fc6621"); - else - color = QColor("#525252"); - - 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() + ";}"); + Theme::updateAwesomeMiniButton(button, icon, highlighted); } void SkeletonPartWidget::updatePreview() diff --git a/src/theme.cpp b/src/theme.cpp index 85d46755..9054f2d0 100644 --- a/src/theme.cpp +++ b/src/theme.cpp @@ -92,4 +92,39 @@ void Theme::initAwesomeLabel(QLabel *label) label->setStyleSheet("QLabel {color: #f7d9c8}"); } +void Theme::initAwesomeMiniButton(QPushButton *button) +{ + button->setFont(Theme::awesome()->font(Theme::miniIconFontSize)); + button->setFixedSize(Theme::miniIconSize, Theme::miniIconSize); + button->setFocusPolicy(Qt::NoFocus); +} + +void Theme::updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted) +{ + button->setText(icon); + QColor color; + if (highlighted) + color = QColor("#fc6621"); + else + color = QColor("#525252"); + + 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() + ";}"); +} + +void Theme::initAwesomeToolButtonWithoutFont(QPushButton *button) +{ + button->setFixedSize(Theme::toolIconSize / 2, Theme::toolIconSize / 2); + button->setStyleSheet("QPushButton {color: #f7d9c8}"); + button->setFocusPolicy(Qt::NoFocus); +} + +void Theme::initAwesomeToolButton(QPushButton *button) +{ + button->setFont(Theme::awesome()->font(Theme::toolIconFontSize / 2)); + Theme::initAwesomeToolButtonWithoutFont(button); +} diff --git a/src/theme.h b/src/theme.h index e077e4cf..f54218f1 100644 --- a/src/theme.h +++ b/src/theme.h @@ -40,6 +40,10 @@ public: static void initAwesomeButton(QPushButton *button); static void initAwesomeLabel(QLabel *label); static void initAwesomeSmallButton(QPushButton *button); + static void initAwesomeMiniButton(QPushButton *button); + static void updateAwesomeMiniButton(QPushButton *button, QChar icon, bool highlighted); + static void initAwesomeToolButton(QPushButton *button); + static void initAwesomeToolButtonWithoutFont(QPushButton *button); }; #endif diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.dll index fcbed62b..8713069b 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 7f113f7d..0cd8d14b 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 47ab475a..2b35b8cd 100644 --- a/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h +++ b/thirdparty/meshlite/meshlite_unstable_vc14_x64/meshlite.h @@ -59,6 +59,8 @@ int meshlite_skeletonmesh_create(void *context); int meshlite_skeletonmesh_set_end_radius(void *context, float radius); int meshlite_skeletonmesh_add_bone(void *context, int sklt_id, float from_x, float from_y, float from_z, float to_x, float to_y, float to_z); int meshlite_skeletonmesh_generate_mesh(void *context, int sklt_id); +int meshlite_smooth_vertices(void *context, int mesh_id, float factor, int *buffer, int max_buffer_len); +int meshlite_smooth(void *context, int mesh_id, float factor); #ifdef __cplusplus } diff --git a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.dll index 80dbab3f..b596e8b7 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 a1f34716..572ebc23 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 47ab475a..2b35b8cd 100644 --- a/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h +++ b/thirdparty/meshlite/meshlite_unstable_vc14_x86/meshlite.h @@ -59,6 +59,8 @@ int meshlite_skeletonmesh_create(void *context); int meshlite_skeletonmesh_set_end_radius(void *context, float radius); int meshlite_skeletonmesh_add_bone(void *context, int sklt_id, float from_x, float from_y, float from_z, float to_x, float to_y, float to_z); int meshlite_skeletonmesh_generate_mesh(void *context, int sklt_id); +int meshlite_smooth_vertices(void *context, int mesh_id, float factor, int *buffer, int max_buffer_len); +int meshlite_smooth(void *context, int mesh_id, float factor); #ifdef __cplusplus }