diff --git a/src/combinemode.h b/src/combinemode.h index 9ec4a328..95ff2a52 100644 --- a/src/combinemode.h +++ b/src/combinemode.h @@ -6,7 +6,6 @@ enum class CombineMode { Normal = 0, Inversion, - Inflation, Count }; CombineMode CombineModeFromString(const char *modeString); @@ -18,8 +17,6 @@ CombineMode CombineModeFromString(const char *modeString) \ return CombineMode::Normal; \ if (mode == "Inversion") \ return CombineMode::Inversion; \ - if (mode == "Inflation") \ - return CombineMode::Inflation; \ return CombineMode::Normal; \ } const char *CombineModeToString(CombineMode mode); @@ -31,8 +28,6 @@ const char *CombineModeToString(CombineMode mode) \ return "Normal"; \ case CombineMode::Inversion: \ return "Inversion"; \ - case CombineMode::Inflation: \ - return "Inflation"; \ default: \ return "Normal"; \ } \ @@ -46,8 +41,6 @@ QString CombineModeToDispName(CombineMode mode) \ return QObject::tr("Normal"); \ case CombineMode::Inversion: \ return QObject::tr("Inversion"); \ - case CombineMode::Inflation: \ - return QObject::tr("Inflation"); \ default: \ return QObject::tr("Normal"); \ } \ diff --git a/src/meshgenerator.cpp b/src/meshgenerator.cpp index 8e36273e..96958bdb 100644 --- a/src/meshgenerator.cpp +++ b/src/meshgenerator.cpp @@ -409,6 +409,53 @@ nodemesh::Combiner::Mesh *MeshGenerator::combinePartMesh(const QString &partIdSt return mesh; } +const std::map *MeshGenerator::findComponent(const QString &componentIdString) +{ + const std::map *component = &m_snapshot->rootComponent; + if (componentIdString != QUuid().toString()) { + auto findComponent = m_snapshot->components.find(componentIdString); + if (findComponent == m_snapshot->components.end()) { + qDebug() << "Component not found:" << componentIdString; + return nullptr; + } + return &findComponent->second; + } + return component; +} + +CombineMode MeshGenerator::componentCombineMode(const std::map *component) +{ + if (nullptr == component) + return CombineMode::Normal; + CombineMode combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(*component, "combineMode").toUtf8().constData()); + if (combineMode == CombineMode::Normal) { + if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse"))) + combineMode = CombineMode::Inversion; + } + return combineMode; +} + +QString MeshGenerator::componentColorName(const std::map *component) +{ + if (nullptr == component) + return QString(); + QString linkDataType = valueOfKeyInMapOrEmpty(*component, "linkDataType"); + if ("partId" == linkDataType) { + QString partIdString = valueOfKeyInMapOrEmpty(*component, "linkData"); + auto findPart = m_snapshot->parts.find(partIdString); + if (findPart == m_snapshot->parts.end()) { + qDebug() << "Find part failed:" << partIdString; + return QString(); + } + auto &part = findPart->second; + QString colorName = valueOfKeyInMapOrEmpty(part, "color"); + if (colorName.isEmpty()) + return QString("-"); + return colorName; + } + return QString(); +} + nodemesh::Combiner::Mesh *MeshGenerator::combineComponentMesh(const QString &componentIdString, CombineMode *combineMode) { nodemesh::Combiner::Mesh *mesh = nullptr; @@ -425,11 +472,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combineComponentMesh(const QString &com component = &findComponent->second; } - *combineMode = CombineModeFromString(valueOfKeyInMapOrEmpty(*component, "combineMode").toUtf8().constData()); - if (*combineMode == CombineMode::Normal) { - if (isTrueValueString(valueOfKeyInMapOrEmpty(*component, "inverse"))) - *combineMode = CombineMode::Inversion; - } + *combineMode = componentCombineMode(component); auto &componentCache = m_cacheContext->components[componentIdString]; @@ -462,56 +505,74 @@ nodemesh::Combiner::Mesh *MeshGenerator::combineComponentMesh(const QString &com for (const auto &it: partCache.outcomeNodeVertices) componentCache.outcomeNodeVertices.push_back(it); } else { + std::vector>>> combineGroups; + // Firstly, group by combine mode + int currentGroupIndex = -1; + auto lastCombineMode = CombineMode::Count; for (const auto &childIdString: valueOfKeyInMapOrEmpty(*component, "children").split(",")) { if (childIdString.isEmpty()) continue; - CombineMode childCombineMode = CombineMode::Normal; - nodemesh::Combiner::Mesh *subMesh = combineComponentMesh(childIdString, &childCombineMode); - - const auto &childComponentCache = m_cacheContext->components[childIdString]; - for (const auto &vertex: childComponentCache.noneSeamVertices) - componentCache.noneSeamVertices.insert(vertex); - for (const auto &it: childComponentCache.sharedQuadEdges) - componentCache.sharedQuadEdges.insert(it); - for (const auto &it: childComponentCache.outcomeNodes) - componentCache.outcomeNodes.push_back(it); - for (const auto &it: childComponentCache.outcomeNodeVertices) - componentCache.outcomeNodeVertices.push_back(it); - - qDebug() << "Combine mode:" << CombineModeToString(childCombineMode); - if (nullptr == subMesh) { - m_isSucceed = false; - qDebug() << "Child mesh is null"; + const auto &child = findComponent(childIdString); + QString colorName = componentColorName(child); + auto combineMode = componentCombineMode(child); + if (lastCombineMode != combineMode || lastCombineMode == CombineMode::Inversion) { + qDebug() << "New group[" << currentGroupIndex << "] for combine mode[" << CombineModeToString(combineMode) << "]"; + combineGroups.push_back({combineMode, {}}); + ++currentGroupIndex; + lastCombineMode = combineMode; + } + if (-1 == currentGroupIndex) { + qDebug() << "Should not happen: -1 == currentGroupIndex"; continue; } - if (subMesh->isNull()) { - m_isSucceed = false; - qDebug() << "Child mesh is uncombinable"; - delete subMesh; - continue; - } - if (nullptr == mesh) { - if (childCombineMode == CombineMode::Inversion) { - delete subMesh; - } else { - mesh = subMesh; - } - } else { - nodemesh::Combiner::Mesh *newMesh = combineTwoMeshes(*mesh, - *subMesh, - childCombineMode == CombineMode::Inversion ? - nodemesh::Combiner::Method::Diff : nodemesh::Combiner::Method::Union); - delete subMesh; - if (newMesh && !newMesh->isNull()) { - delete mesh; - mesh = newMesh; - } else { - m_isSucceed = false; - qDebug() << "Mesh combine failed"; - delete newMesh; - } - } + combineGroups[currentGroupIndex].second.push_back({childIdString, colorName}); } + // Secondly, sub group by color + std::vector> groupMeshes; + for (const auto &group: combineGroups) { + std::set used; + std::vector> componentIdStrings; + int currentSubGroupIndex = -1; + auto lastColorName = QString(); + for (size_t i = 0; i < group.second.size(); ++i) { + if (used.find(i) != used.end()) + continue; + const auto &colorName = group.second[i].second; + if (lastColorName != colorName || lastColorName.isEmpty()) { + qDebug() << "New sub group[" << currentSubGroupIndex << "] for color[" << colorName << "]"; + componentIdStrings.push_back({}); + ++currentSubGroupIndex; + lastColorName = colorName; + } + if (-1 == currentSubGroupIndex) { + qDebug() << "Should not happen: -1 == currentSubGroupIndex"; + continue; + } + used.insert(i); + componentIdStrings[currentSubGroupIndex].push_back(group.second[i].first); + if (colorName.isEmpty()) + continue; + for (size_t j = i + 1; j < group.second.size(); ++j) { + if (used.find(j) != used.end()) + continue; + const auto &otherColorName = group.second[j].second; + if (otherColorName.isEmpty()) + continue; + if (otherColorName != colorName) + continue; + used.insert(j); + componentIdStrings[currentSubGroupIndex].push_back(group.second[j].first); + } + } + std::vector> multipleMeshes; + for (const auto &it: componentIdStrings) { + nodemesh::Combiner::Mesh *childMesh = combineComponentChildGroupMesh(it, componentCache); + multipleMeshes.push_back({childMesh, CombineMode::Normal}); + } + nodemesh::Combiner::Mesh *subGroupMesh = combineMultipleMeshes(multipleMeshes, false); + groupMeshes.push_back({subGroupMesh, group.first}); + } + mesh = combineMultipleMeshes(groupMeshes, false); } if (nullptr != mesh) @@ -525,8 +586,75 @@ nodemesh::Combiner::Mesh *MeshGenerator::combineComponentMesh(const QString &com return mesh; } +nodemesh::Combiner::Mesh *MeshGenerator::combineMultipleMeshes(const std::vector> &multipleMeshes, bool recombine) +{ + nodemesh::Combiner::Mesh *mesh = nullptr; + for (const auto &it: multipleMeshes) { + const auto &childCombineMode = it.second; + nodemesh::Combiner::Mesh *subMesh = it.first; + qDebug() << "Combine mode:" << CombineModeToString(childCombineMode); + if (nullptr == subMesh) { + m_isSucceed = false; + qDebug() << "Child mesh is null"; + continue; + } + if (subMesh->isNull()) { + m_isSucceed = false; + qDebug() << "Child mesh is uncombinable"; + delete subMesh; + continue; + } + if (nullptr == mesh) { + //if (childCombineMode == CombineMode::Inversion) { + // delete subMesh; + //} else { + mesh = subMesh; + //} + } else { + nodemesh::Combiner::Mesh *newMesh = combineTwoMeshes(*mesh, + *subMesh, + childCombineMode == CombineMode::Inversion ? + nodemesh::Combiner::Method::Diff : nodemesh::Combiner::Method::Union, + recombine); + delete subMesh; + if (newMesh && !newMesh->isNull()) { + delete mesh; + mesh = newMesh; + } else { + m_isSucceed = false; + qDebug() << "Mesh combine failed"; + delete newMesh; + } + } + } + return mesh; +} + +nodemesh::Combiner::Mesh *MeshGenerator::combineComponentChildGroupMesh(const std::vector &componentIdStrings, GeneratedComponent &componentCache) +{ + std::vector> multipleMeshes; + for (const auto &childIdString: componentIdStrings) { + CombineMode childCombineMode = CombineMode::Normal; + nodemesh::Combiner::Mesh *subMesh = combineComponentMesh(childIdString, &childCombineMode); + + const auto &childComponentCache = m_cacheContext->components[childIdString]; + for (const auto &vertex: childComponentCache.noneSeamVertices) + componentCache.noneSeamVertices.insert(vertex); + for (const auto &it: childComponentCache.sharedQuadEdges) + componentCache.sharedQuadEdges.insert(it); + for (const auto &it: childComponentCache.outcomeNodes) + componentCache.outcomeNodes.push_back(it); + for (const auto &it: childComponentCache.outcomeNodeVertices) + componentCache.outcomeNodeVertices.push_back(it); + + multipleMeshes.push_back({subMesh, childCombineMode}); + } + return combineMultipleMeshes(multipleMeshes); +} + nodemesh::Combiner::Mesh *MeshGenerator::combineTwoMeshes(const nodemesh::Combiner::Mesh &first, const nodemesh::Combiner::Mesh &second, - nodemesh::Combiner::Method method) + nodemesh::Combiner::Method method, + bool recombine) { if (first.isNull() || second.isNull()) return nullptr; @@ -537,7 +665,7 @@ nodemesh::Combiner::Mesh *MeshGenerator::combineTwoMeshes(const nodemesh::Combin &combinedVerticesSources); if (nullptr == newMesh) return nullptr; - if (!newMesh->isNull()) { + if (!newMesh->isNull() && recombine) { nodemesh::Recombiner recombiner; std::vector combinedVertices; std::vector> combinedFaces; @@ -686,7 +814,7 @@ void MeshGenerator::generate() combinedVertices[face[2]] )); } - + recoverQuads(combinedVertices, combinedFaces, componentCache.sharedQuadEdges, m_outcome->triangleAndQuads); m_outcome->nodes = componentCache.outcomeNodes; @@ -699,6 +827,19 @@ void MeshGenerator::generate() triangleSourceNodeResolve(*m_outcome, sourceNodes); m_outcome->setTriangleSourceNodes(sourceNodes); + std::map, QColor> sourceNodeToColorMap; + for (const auto &node: m_outcome->nodes) + sourceNodeToColorMap.insert({{node.partId, node.nodeId}, node.color}); + + m_outcome->triangleColors.resize(m_outcome->triangles.size(), Qt::white); + const std::vector> *triangleSourceNodes = m_outcome->triangleSourceNodes(); + if (nullptr != triangleSourceNodes) { + for (size_t triangleIndex = 0; triangleIndex < m_outcome->triangles.size(); triangleIndex++) { + const auto &source = (*triangleSourceNodes)[triangleIndex]; + m_outcome->triangleColors[triangleIndex] = sourceNodeToColorMap[source]; + } + } + std::vector> triangleVertexNormals; generateSmoothTriangleVertexNormals(combinedVertices, combinedFaces, diff --git a/src/meshgenerator.h b/src/meshgenerator.h index d5f13581..1d6d52f6 100644 --- a/src/meshgenerator.h +++ b/src/meshgenerator.h @@ -93,10 +93,17 @@ private: void collectSharedQuadEdges(const std::vector &vertices, const std::vector> &faces, std::set> *sharedQuadEdges); nodemesh::Combiner::Mesh *combineTwoMeshes(const nodemesh::Combiner::Mesh &first, const nodemesh::Combiner::Mesh &second, - nodemesh::Combiner::Method method); + nodemesh::Combiner::Method method, + bool recombine=true); void generateSmoothTriangleVertexNormals(const std::vector &vertices, const std::vector> &triangles, const std::vector &triangleNormals, std::vector> *triangleVertexNormals); + const std::map *findComponent(const QString &componentIdString); + CombineMode componentCombineMode(const std::map *component); + nodemesh::Combiner::Mesh *combineComponentChildGroupMesh(const std::vector &componentIdStrings, + GeneratedComponent &componentCache); + nodemesh::Combiner::Mesh *combineMultipleMeshes(const std::vector> &multipleMeshes, bool recombine=true); + QString componentColorName(const std::map *component); }; #endif diff --git a/src/meshloader.cpp b/src/meshloader.cpp index 50f801ec..0ca7dd2e 100644 --- a/src/meshloader.cpp +++ b/src/meshloader.cpp @@ -112,6 +112,7 @@ MeshLoader::MeshLoader(Outcome &outcome) : const QVector2D defaultUv = QVector2D(0, 0); const QVector3D defaultTangent = QVector3D(0, 0, 0); for (size_t i = 0; i < outcome.triangles.size(); ++i) { + const auto &triangleColor = &outcome.triangleColors[i]; for (auto j = 0; j < 3; j++) { int vertexIndex = outcome.triangles[i][j]; const QVector3D *srcVert = &outcome.vertices[vertexIndex]; @@ -125,9 +126,9 @@ MeshLoader::MeshLoader(Outcome &outcome) : if (triangleTangents) srcTangent = &(*triangleTangents)[i]; Vertex *dest = &m_triangleVertices[destIndex]; - dest->colorR = 0; - dest->colorG = 0; - dest->colorB = 0; + dest->colorR = triangleColor->redF(); + dest->colorG = triangleColor->greenF(); + dest->colorB = triangleColor->blueF(); dest->posX = srcVert->x(); dest->posY = srcVert->y(); dest->posZ = srcVert->z(); @@ -144,6 +145,37 @@ MeshLoader::MeshLoader(Outcome &outcome) : destIndex++; } } + + // Uncomment out to show wireframes + /* + size_t edgeCount = 0; + for (const auto &face: outcome.triangleAndQuads) { + edgeCount += face.size(); + } + m_edgeVertexCount = edgeCount * 2; + m_edgeVertices = new Vertex[m_edgeVertexCount]; + size_t edgeVertexIndex = 0; + for (size_t faceIndex = 0; faceIndex < outcome.triangleAndQuads.size(); ++faceIndex) { + const auto &face = outcome.triangleAndQuads[faceIndex]; + for (size_t i = 0; i < face.size(); ++i) { + for (size_t x = 0; x < 2; ++x) { + size_t sourceIndex = face[(i + x) % face.size()]; + const QVector3D *srcVert = &outcome.vertices[sourceIndex]; + Vertex *dest = &m_edgeVertices[edgeVertexIndex]; + memset(dest, 0, sizeof(Vertex)); + dest->colorR = 0.0; + dest->colorG = 0.0; + dest->colorB = 0.0; + dest->posX = srcVert->x(); + dest->posY = srcVert->y(); + dest->posZ = srcVert->z(); + dest->metalness = m_defaultMetalness; + dest->roughness = m_defaultRoughness; + edgeVertexIndex++; + } + } + } + */ } MeshLoader::MeshLoader() : diff --git a/src/modelmeshbinder.cpp b/src/modelmeshbinder.cpp index 15578a7d..67b4356e 100644 --- a/src/modelmeshbinder.cpp +++ b/src/modelmeshbinder.cpp @@ -14,7 +14,7 @@ ModelMeshBinder::ModelMeshBinder() : m_renderTriangleVertexCount(0), m_renderEdgeVertexCount(0), m_newMeshComing(false), - m_showWireframes(false), + m_showWireframes(true), m_hasTexture(false), m_texture(nullptr), m_hasNormalMap(false), diff --git a/src/outcome.h b/src/outcome.h index 54b57345..a9e30e38 100644 --- a/src/outcome.h +++ b/src/outcome.h @@ -32,6 +32,7 @@ public: std::vector> triangleAndQuads; std::vector> triangles; std::vector triangleNormals; + std::vector triangleColors; const std::vector> *triangleSourceNodes() const { diff --git a/src/partwidget.cpp b/src/partwidget.cpp index 41a3f10d..2d0f5f5c 100644 --- a/src/partwidget.cpp +++ b/src/partwidget.cpp @@ -320,7 +320,7 @@ void PartWidget::showColorSettingPopup(const QPoint &pos) QPushButton *pickButton = new QPushButton(); initToolButtonWithoutFont(pickButton); QPalette palette = pickButton->palette(); - QColor choosenColor = part->hasColor ? part->color : Theme::white; + QColor choosenColor = part->hasColor ? part->color : Qt::white; palette.setColor(QPalette::Window, choosenColor); palette.setColor(QPalette::Button, choosenColor); pickButton->setPalette(palette); @@ -331,7 +331,7 @@ void PartWidget::showColorSettingPopup(const QPoint &pos) colorLayout->addStretch(); connect(colorEraser, &QPushButton::clicked, [=]() { - emit setPartColorState(m_partId, false, Theme::white); + emit setPartColorState(m_partId, false, Qt::white); emit groupOperationAdded(); });