diff --git a/application/application.pro b/application/application.pro index 14de8384..6ec3b93f 100644 --- a/application/application.pro +++ b/application/application.pro @@ -189,8 +189,6 @@ HEADERS += sources/preferences.h SOURCES += sources/preferences.cc HEADERS += sources/preview_grid_view.h SOURCES += sources/preview_grid_view.cc -HEADERS += sources/skeleton_document.h -SOURCES += sources/skeleton_document.cc HEADERS += sources/skeleton_graphics_widget.h SOURCES += sources/skeleton_graphics_widget.cc HEADERS += sources/skeleton_ik_mover.h @@ -203,8 +201,8 @@ HEADERS += sources/theme.h SOURCES += sources/theme.cc HEADERS += sources/toolbar_button.h SOURCES += sources/toolbar_button.cc -HEADERS += sources/tube_uv_preview_image_generator.h -SOURCES += sources/tube_uv_preview_image_generator.cc +HEADERS += sources/uv_preview_image_generator.h +SOURCES += sources/uv_preview_image_generator.cc HEADERS += sources/turnaround_loader.h SOURCES += sources/turnaround_loader.cc HEADERS += sources/updates_check_widget.h @@ -243,8 +241,6 @@ SOURCES += ../dust3d/base/ds3_file.cc HEADERS += ../dust3d/base/math.h HEADERS += ../dust3d/base/matrix4x4.h HEADERS += ../dust3d/base/object.h -HEADERS += ../dust3d/base/part_base.h -SOURCES += ../dust3d/base/part_base.cc HEADERS += ../dust3d/base/part_target.h SOURCES += ../dust3d/base/part_target.cc HEADERS += ../dust3d/base/position_key.h diff --git a/application/sources/component_property_widget.cc b/application/sources/component_property_widget.cc index c01fe500..5c8d72b4 100644 --- a/application/sources/component_property_widget.cc +++ b/application/sources/component_property_widget.cc @@ -188,12 +188,29 @@ ComponentPropertyWidget::ComponentPropertyWidget(Document* document, cutFaceGroupBox->setLayout(cutFaceLayout); } + QGroupBox* skinGroupBox = nullptr; + if (nullptr != m_part) { + QCheckBox* useImageBox = new QCheckBox(); + Theme::initCheckbox(useImageBox); + useImageBox->setText(tr("Use image")); + useImageBox->setChecked(m_part->rounded); + + QHBoxLayout* skinLayout = new QHBoxLayout; + skinLayout->addStretch(); + skinLayout->addWidget(useImageBox); + + skinGroupBox = new QGroupBox(tr("Skin")); + skinGroupBox->setLayout(skinLayout); + } + QVBoxLayout* mainLayout = new QVBoxLayout; mainLayout->addLayout(colorLayout); if (nullptr != deformGroupBox) mainLayout->addWidget(deformGroupBox); if (nullptr != cutFaceGroupBox) mainLayout->addWidget(cutFaceGroupBox); + if (nullptr != skinGroupBox) + mainLayout->addWidget(skinGroupBox); mainLayout->setSizeConstraint(QLayout::SetFixedSize); connect(this, &ComponentPropertyWidget::setPartColorState, m_document, &Document::setPartColorState); diff --git a/application/sources/document.cc b/application/sources/document.cc index 021e23be..7d38c4f9 100644 --- a/application/sources/document.cc +++ b/application/sources/document.cc @@ -21,8 +21,16 @@ unsigned long Document::m_maxSnapshot = 1000; +void SkeletonNode::setRadius(float toRadius) +{ + if (toRadius < MeshGenerator::m_minimalRadius) + toRadius = MeshGenerator::m_minimalRadius; + else if (toRadius > 1) + toRadius = 1; + radius = toRadius; +} + Document::Document() - : SkeletonDocument() { } @@ -44,6 +52,1363 @@ Document::~Document() delete m_resultTextureMesh; } +const SkeletonNode* Document::findNode(dust3d::Uuid nodeId) const +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) + return nullptr; + return &it->second; +} + +const SkeletonEdge* Document::findEdge(dust3d::Uuid edgeId) const +{ + auto it = edgeMap.find(edgeId); + if (it == edgeMap.end()) + return nullptr; + return &it->second; +} + +const SkeletonPart* Document::findPart(dust3d::Uuid partId) const +{ + auto it = partMap.find(partId); + if (it == partMap.end()) + return nullptr; + return &it->second; +} + +const SkeletonEdge* Document::findEdgeByNodes(dust3d::Uuid firstNodeId, dust3d::Uuid secondNodeId) const +{ + const SkeletonNode* firstNode = nullptr; + firstNode = findNode(firstNodeId); + if (nullptr == firstNode) { + return nullptr; + } + for (auto edgeIdIt = firstNode->edgeIds.begin(); edgeIdIt != firstNode->edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + continue; + } + if (std::find(edgeIt->second.nodeIds.begin(), edgeIt->second.nodeIds.end(), secondNodeId) != edgeIt->second.nodeIds.end()) + return &edgeIt->second; + } + return nullptr; +} + +void Document::findAllNeighbors(dust3d::Uuid nodeId, std::set& neighbors) const +{ + const auto& node = findNode(nodeId); + if (nullptr == node) { + return; + } + for (const auto& edgeId : node->edgeIds) { + const auto& edge = findEdge(edgeId); + if (nullptr == edge) { + continue; + } + const auto& neighborNodeId = edge->neighborOf(nodeId); + if (neighborNodeId.isNull()) { + continue; + } + if (neighbors.find(neighborNodeId) != neighbors.end()) { + continue; + } + neighbors.insert(neighborNodeId); + findAllNeighbors(neighborNodeId, neighbors); + } +} + +bool Document::isNodeConnectable(dust3d::Uuid nodeId) const +{ + const auto& node = findNode(nodeId); + if (nullptr == node) + return false; + if (node->edgeIds.size() < 2) + return true; + return false; +} + +void Document::reduceNode(dust3d::Uuid nodeId) +{ + const SkeletonNode* node = findNode(nodeId); + if (nullptr == node) { + return; + } + if (node->edgeIds.size() != 2) { + return; + } + dust3d::Uuid firstEdgeId = node->edgeIds[0]; + dust3d::Uuid secondEdgeId = node->edgeIds[1]; + const SkeletonEdge* firstEdge = findEdge(firstEdgeId); + if (nullptr == firstEdge) { + return; + } + const SkeletonEdge* secondEdge = findEdge(secondEdgeId); + if (nullptr == secondEdge) { + return; + } + dust3d::Uuid firstNeighborNodeId = firstEdge->neighborOf(nodeId); + dust3d::Uuid secondNeighborNodeId = secondEdge->neighborOf(nodeId); + removeNode(nodeId); + addEdge(firstNeighborNodeId, secondNeighborNodeId); +} + +void Document::breakEdge(dust3d::Uuid edgeId) +{ + const SkeletonEdge* edge = findEdge(edgeId); + if (nullptr == edge) { + return; + } + if (edge->nodeIds.size() != 2) { + return; + } + dust3d::Uuid firstNodeId = edge->nodeIds[0]; + dust3d::Uuid secondNodeId = edge->nodeIds[1]; + const SkeletonNode* firstNode = findNode(firstNodeId); + if (nullptr == firstNode) { + return; + } + const SkeletonNode* secondNode = findNode(secondNodeId); + if (nullptr == secondNode) { + return; + } + QVector3D firstOrigin(firstNode->getX(), firstNode->getY(), firstNode->getZ()); + QVector3D secondOrigin(secondNode->getX(), secondNode->getY(), secondNode->getZ()); + QVector3D middleOrigin = (firstOrigin + secondOrigin) / 2; + float middleRadius = (firstNode->radius + secondNode->radius) / 2; + removeEdge(edgeId); + dust3d::Uuid middleNodeId = createNode(dust3d::Uuid::createUuid(), middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); + if (middleNodeId.isNull()) { + return; + } + addEdge(middleNodeId, secondNodeId); +} + +void Document::reverseEdge(dust3d::Uuid edgeId) +{ + SkeletonEdge* edge = (SkeletonEdge*)findEdge(edgeId); + if (nullptr == edge) { + return; + } + if (edge->nodeIds.size() != 2) { + return; + } + std::swap(edge->nodeIds[0], edge->nodeIds[1]); + auto part = partMap.find(edge->partId); + if (part != partMap.end()) + part->second.dirty = true; + emit edgeReversed(edgeId); + emit skeletonChanged(); +} + +void Document::removeEdge(dust3d::Uuid edgeId) +{ + const SkeletonEdge* edge = findEdge(edgeId); + if (nullptr == edge) { + return; + } + if (isPartReadonly(edge->partId)) + return; + const SkeletonPart* oldPart = findPart(edge->partId); + if (nullptr == oldPart) { + return; + } + QString nextPartName = oldPart->name; + dust3d::Uuid oldPartId = oldPart->id; + std::vector> groups; + splitPartByEdge(&groups, edgeId); + std::vector> newPartNodeNumMap; + std::vector newPartIds; + for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { + const auto newUuid = dust3d::Uuid::createUuid(); + SkeletonPart& part = partMap[newUuid]; + part.id = newUuid; + part.copyAttributes(*oldPart); + part.name = nextPartName; + for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + continue; + } + nodeIt->second.partId = part.id; + part.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + continue; + } + edgeIt->second.partId = part.id; + } + } + addPartToComponent(part.id, findComponentParentId(part.componentId)); + newPartNodeNumMap.push_back({ part.id, part.nodeIds.size() }); + newPartIds.push_back(part.id); + emit partAdded(part.id); + } + for (auto nodeIdIt = edge->nodeIds.begin(); nodeIdIt != edge->nodeIds.end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + continue; + } + nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), edgeId), nodeIt->second.edgeIds.end()); + emit nodeOriginChanged(nodeIt->first); + } + edgeMap.erase(edgeId); + emit edgeRemoved(edgeId); + removePart(oldPartId); + + if (!newPartNodeNumMap.empty()) { + std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&](const std::pair& first, const std::pair& second) { + return first.second > second.second; + }); + updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); + } + + emit skeletonChanged(); +} + +void Document::removeNode(dust3d::Uuid nodeId) +{ + const SkeletonNode* node = findNode(nodeId); + if (nullptr == node) { + return; + } + if (isPartReadonly(node->partId)) + return; + const SkeletonPart* oldPart = findPart(node->partId); + if (nullptr == oldPart) { + return; + } + QString nextPartName = oldPart->name; + dust3d::Uuid oldPartId = oldPart->id; + std::vector> groups; + splitPartByNode(&groups, nodeId); + std::vector> newPartNodeNumMap; + std::vector newPartIds; + for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { + const auto newUuid = dust3d::Uuid::createUuid(); + SkeletonPart& part = partMap[newUuid]; + part.id = newUuid; + part.copyAttributes(*oldPart); + part.name = nextPartName; + for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + continue; + } + nodeIt->second.partId = part.id; + part.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + continue; + } + edgeIt->second.partId = part.id; + } + } + addPartToComponent(part.id, findComponentParentId(part.componentId)); + newPartNodeNumMap.push_back({ part.id, part.nodeIds.size() }); + newPartIds.push_back(part.id); + emit partAdded(part.id); + } + for (auto edgeIdIt = node->edgeIds.begin(); edgeIdIt != node->edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + continue; + } + dust3d::Uuid neighborId = edgeIt->second.neighborOf(nodeId); + auto nodeIt = nodeMap.find(neighborId); + if (nodeIt == nodeMap.end()) { + continue; + } + nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), *edgeIdIt), nodeIt->second.edgeIds.end()); + edgeMap.erase(*edgeIdIt); + emit edgeRemoved(*edgeIdIt); + } + nodeMap.erase(nodeId); + emit nodeRemoved(nodeId); + removePart(oldPartId); + + if (!newPartNodeNumMap.empty()) { + std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&](const std::pair& first, const std::pair& second) { + return first.second > second.second; + }); + updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); + } + + emit skeletonChanged(); +} + +void Document::addNode(float x, float y, float z, float radius, dust3d::Uuid fromNodeId) +{ + createNode(dust3d::Uuid::createUuid(), x, y, z, radius, fromNodeId); +} + +void Document::addNodeWithId(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId) +{ + createNode(nodeId, x, y, z, radius, fromNodeId); +} + +dust3d::Uuid Document::createNode(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId) +{ + dust3d::Uuid partId; + const SkeletonNode* fromNode = nullptr; + bool newPartAdded = false; + if (fromNodeId.isNull()) { + const auto newUuid = dust3d::Uuid::createUuid(); + SkeletonPart& part = partMap[newUuid]; + part.id = newUuid; + partId = part.id; + emit partAdded(partId); + newPartAdded = true; + } else { + fromNode = findNode(fromNodeId); + if (nullptr == fromNode) { + return dust3d::Uuid(); + } + partId = fromNode->partId; + if (isPartReadonly(partId)) + return dust3d::Uuid(); + auto part = partMap.find(partId); + if (part != partMap.end()) + part->second.dirty = true; + } + SkeletonNode node(nodeId); + node.partId = partId; + node.setRadius(radius); + node.setX(x); + node.setY(y); + node.setZ(z); + nodeMap[node.id] = node; + partMap[partId].nodeIds.push_back(node.id); + + emit nodeAdded(node.id); + + if (nullptr != fromNode) { + SkeletonEdge edge; + edge.partId = partId; + edge.nodeIds.push_back(fromNode->id); + edge.nodeIds.push_back(node.id); + edgeMap[edge.id] = edge; + + nodeMap[node.id].edgeIds.push_back(edge.id); + nodeMap[fromNode->id].edgeIds.push_back(edge.id); + + emit edgeAdded(edge.id); + } + + if (newPartAdded) + addPartToComponent(partId, m_currentCanvasComponentId); + + emit skeletonChanged(); + + return node.id; +} + +void Document::joinNodeAndNeiborsToGroup(std::vector* group, dust3d::Uuid nodeId, std::set* visitMap, dust3d::Uuid noUseEdgeId) +{ + if (nodeId.isNull() || visitMap->find(nodeId) != visitMap->end()) + return; + const SkeletonNode* node = findNode(nodeId); + if (nullptr == node) { + return; + } + visitMap->insert(nodeId); + group->push_back(nodeId); + for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { + if (noUseEdgeId == *edgeIt) + continue; + const SkeletonEdge* edge = findEdge(*edgeIt); + if (nullptr == edge) { + continue; + } + for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { + joinNodeAndNeiborsToGroup(group, *nodeIt, visitMap, noUseEdgeId); + } + } +} + +void Document::splitPartByNode(std::vector>* groups, dust3d::Uuid nodeId) +{ + const SkeletonNode* node = findNode(nodeId); + std::set visitMap; + visitMap.insert(nodeId); + for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { + std::vector group; + const SkeletonEdge* edge = findEdge(*edgeIt); + if (nullptr == edge) { + continue; + } + joinNodeAndNeiborsToGroup(&group, edge->neighborOf(nodeId), &visitMap, *edgeIt); + if (!group.empty()) + groups->push_back(group); + } +} + +void Document::splitPartByEdge(std::vector>* groups, dust3d::Uuid edgeId) +{ + const SkeletonEdge* edge = findEdge(edgeId); + if (nullptr == edge) { + return; + } + std::set visitMap; + for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { + std::vector group; + joinNodeAndNeiborsToGroup(&group, *nodeIt, &visitMap, edgeId); + if (!group.empty()) + groups->push_back(group); + } +} + +const SkeletonComponent* Document::findComponentParent(dust3d::Uuid componentId) const +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return nullptr; + } + + if (component->second.parentId.isNull()) + return &rootComponent; + + return (SkeletonComponent*)findComponent(component->second.parentId); +} + +dust3d::Uuid Document::findComponentParentId(dust3d::Uuid componentId) const +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return dust3d::Uuid(); + } + + return component->second.parentId; +} + +void Document::moveComponentUp(dust3d::Uuid componentId) +{ + SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); + if (nullptr == parent) + return; + + dust3d::Uuid parentId = findComponentParentId(componentId); + + parent->moveChildUp(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void Document::moveComponentDown(dust3d::Uuid componentId) +{ + SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); + if (nullptr == parent) + return; + + dust3d::Uuid parentId = findComponentParentId(componentId); + + parent->moveChildDown(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void Document::moveComponentToTop(dust3d::Uuid componentId) +{ + SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); + if (nullptr == parent) + return; + + dust3d::Uuid parentId = findComponentParentId(componentId); + + parent->moveChildToTop(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void Document::moveComponentToBottom(dust3d::Uuid componentId) +{ + SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); + if (nullptr == parent) + return; + + dust3d::Uuid parentId = findComponentParentId(componentId); + + parent->moveChildToBottom(componentId); + parent->dirty = true; + emit componentChildrenChanged(parentId); + emit skeletonChanged(); +} + +void Document::renameComponent(dust3d::Uuid componentId, QString name) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return; + } + + if (component->second.name == name) + return; + + if (!name.trimmed().isEmpty()) + component->second.name = name; + emit componentNameChanged(componentId); + emit optionsChanged(); +} + +void Document::setComponentExpandState(dust3d::Uuid componentId, bool expanded) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return; + } + + if (component->second.expanded == expanded) + return; + + component->second.expanded = expanded; + emit componentExpandStateChanged(componentId); + emit optionsChanged(); +} + +void Document::ungroupComponent(const dust3d::Uuid& componentId) +{ + if (componentId.isNull()) + return; + SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); + if (nullptr == component) { + qDebug() << "Component not found:" << componentId.toString(); + return; + } + if (component->childrenIds.empty()) + return; + auto childrenIds = component->childrenIds; + SkeletonComponent* newParent = (SkeletonComponent*)findComponentParent(componentId); + if (nullptr == newParent) { + qDebug() << "Expected parent component to be found, component:" << componentId.toString(); + return; + } + auto newParentId = newParent->id; + newParent->replaceChildWithOthers(componentId, childrenIds); + for (const auto& childId : childrenIds) { + SkeletonComponent* child = (SkeletonComponent*)findComponent(childId); + if (nullptr == child) + continue; + child->parentId = newParentId; + } + componentMap.erase(componentId); + emit componentRemoved(componentId); + emit componentChildrenChanged(newParentId); + emit skeletonChanged(); +} + +void Document::groupComponents(const std::vector& componentIds) +{ + if (componentIds.empty()) + return; + + dust3d::Uuid newParentId; + + SkeletonComponent newParent(dust3d::Uuid::createUuid()); + newParentId = newParent.id; + + auto it = componentIds.begin(); + + SkeletonComponent* oldParent = (SkeletonComponent*)findComponentParent(*it); + if (nullptr == oldParent) { + qDebug() << "Expected parent component to be found, component:" << it->toString(); + return; + } + auto oldParentId = oldParent->id; + oldParent->replaceChild(*it, newParentId); + for (++it; it != componentIds.end(); ++it) { + oldParent->removeChild(*it); + } + + for (const auto& componentId : componentIds) { + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + continue; + } + component->second.parentId = newParentId; + newParent.addChild(componentId); + } + + newParent.parentId = oldParentId; + newParent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); + componentMap.emplace(newParentId, std::move(newParent)); + + emit componentChildrenChanged(oldParentId); + emit componentAdded(newParentId); + emit skeletonChanged(); +} + +void Document::createNewChildComponent(dust3d::Uuid parentComponentId) +{ + SkeletonComponent* parentComponent = (SkeletonComponent*)findComponent(parentComponentId); + if (!parentComponent->linkToPartId.isNull()) { + parentComponentId = parentComponent->parentId; + parentComponent = (SkeletonComponent*)findComponent(parentComponentId); + } + + SkeletonComponent newComponent(dust3d::Uuid::createUuid()); + newComponent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); + + parentComponent->addChild(newComponent.id); + newComponent.parentId = parentComponentId; + + auto newComponentId = newComponent.id; + componentMap.emplace(newComponentId, std::move(newComponent)); + + emit componentChildrenChanged(parentComponentId); + emit componentAdded(newComponentId); + emit optionsChanged(); +} + +void Document::removePart(dust3d::Uuid partId) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + + if (!part->second.componentId.isNull()) { + removeComponent(part->second.componentId); + return; + } + + removePartDontCareComponent(partId); +} + +void Document::removePartDontCareComponent(dust3d::Uuid partId) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + + std::vector removedNodeIds; + std::vector removedEdgeIds; + + for (auto nodeIt = nodeMap.begin(); nodeIt != nodeMap.end();) { + if (nodeIt->second.partId != partId) { + nodeIt++; + continue; + } + removedNodeIds.push_back(nodeIt->second.id); + nodeIt = nodeMap.erase(nodeIt); + } + + for (auto edgeIt = edgeMap.begin(); edgeIt != edgeMap.end();) { + if (edgeIt->second.partId != partId) { + edgeIt++; + continue; + } + removedEdgeIds.push_back(edgeIt->second.id); + edgeIt = edgeMap.erase(edgeIt); + } + + partMap.erase(part); + + for (const auto& nodeId : removedNodeIds) { + emit nodeRemoved(nodeId); + } + for (const auto& edgeId : removedEdgeIds) { + emit edgeRemoved(edgeId); + } + emit partRemoved(partId); +} + +void Document::addPartToComponent(dust3d::Uuid partId, dust3d::Uuid componentId) +{ + SkeletonComponent child(dust3d::Uuid::createUuid()); + + if (!componentId.isNull()) { + auto parentComponent = componentMap.find(componentId); + if (parentComponent == componentMap.end()) { + componentId = dust3d::Uuid(); + rootComponent.addChild(child.id); + } else { + parentComponent->second.addChild(child.id); + } + } else { + rootComponent.addChild(child.id); + } + + partMap[partId].componentId = child.id; + child.linkToPartId = partId; + child.parentId = componentId; + auto childId = child.id; + componentMap.emplace(childId, std::move(child)); + + emit componentChildrenChanged(componentId); + emit componentAdded(childId); +} + +void Document::removeComponent(dust3d::Uuid componentId) +{ + removeComponentRecursively(componentId); + emit skeletonChanged(); +} + +void Document::removeComponentRecursively(dust3d::Uuid componentId) +{ + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return; + } + + if (!component->second.linkToPartId.isNull()) { + removePartDontCareComponent(component->second.linkToPartId); + } + + auto childrenIds = component->second.childrenIds; + for (const auto& childId : childrenIds) { + removeComponentRecursively(childId); + } + + dust3d::Uuid parentId = component->second.parentId; + if (!parentId.isNull()) { + auto parentComponent = componentMap.find(parentId); + if (parentComponent != componentMap.end()) { + parentComponent->second.dirty = true; + parentComponent->second.removeChild(componentId); + } + } else { + rootComponent.removeChild(componentId); + } + + componentMap.erase(component); + emit componentRemoved(componentId); + emit componentChildrenChanged(parentId); +} + +void Document::setCurrentCanvasComponentId(dust3d::Uuid componentId) +{ + m_currentCanvasComponentId = componentId; + const SkeletonComponent* component = findComponent(m_currentCanvasComponentId); + if (nullptr == component) { + m_currentCanvasComponentId = dust3d::Uuid(); + } else { + if (!component->linkToPartId.isNull()) { + m_currentCanvasComponentId = component->parentId; + component = findComponent(m_currentCanvasComponentId); + } + } +} + +void Document::addComponent(dust3d::Uuid parentId) +{ + SkeletonComponent component(dust3d::Uuid::createUuid()); + + if (!parentId.isNull()) { + auto parentComponent = componentMap.find(parentId); + if (parentComponent == componentMap.end()) { + return; + } + parentComponent->second.addChild(component.id); + } else { + rootComponent.addChild(component.id); + } + + component.parentId = parentId; + auto componentId = component.id; + componentMap.emplace(componentId, std::move(component)); + + emit componentChildrenChanged(parentId); + emit componentAdded(componentId); +} + +bool Document::isDescendantComponent(dust3d::Uuid componentId, dust3d::Uuid suspiciousId) +{ + const SkeletonComponent* loopComponent = findComponentParent(suspiciousId); + while (nullptr != loopComponent) { + if (loopComponent->id == componentId) + return true; + loopComponent = findComponentParent(loopComponent->parentId); + } + return false; +} + +void Document::moveComponent(dust3d::Uuid componentId, dust3d::Uuid toParentId) +{ + if (componentId == toParentId) + return; + + auto component = componentMap.find(componentId); + if (component == componentMap.end()) { + return; + } + + if (component->second.parentId == toParentId) + return; + + if (isDescendantComponent(componentId, toParentId)) + return; + + if (component->second.parentId.isNull()) { + rootComponent.removeChild(componentId); + emit componentChildrenChanged(rootComponent.id); + } else { + auto oldParent = componentMap.find(component->second.parentId); + if (oldParent != componentMap.end()) { + oldParent->second.dirty = true; + oldParent->second.removeChild(componentId); + emit componentChildrenChanged(oldParent->second.id); + } + } + + component->second.parentId = toParentId; + + if (toParentId.isNull()) { + rootComponent.addChild(componentId); + emit componentChildrenChanged(rootComponent.id); + } else { + auto newParent = componentMap.find(toParentId); + if (newParent != componentMap.end()) { + newParent->second.dirty = true; + newParent->second.addChild(componentId); + emit componentChildrenChanged(newParent->second.id); + } + } + + emit skeletonChanged(); +} + +void Document::setPartLockState(dust3d::Uuid partId, bool locked) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + if (part->second.locked == locked) + return; + part->second.locked = locked; + emit partLockStateChanged(partId); + emit optionsChanged(); +} + +void Document::setPartVisibleState(dust3d::Uuid partId, bool visible) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + if (part->second.visible == visible) + return; + part->second.visible = visible; + emit partVisibleStateChanged(partId); + emit optionsChanged(); +} + +void Document::setPartDisableState(dust3d::Uuid partId, bool disabled) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + if (part->second.disabled == disabled) + return; + part->second.disabled = disabled; + part->second.dirty = true; + emit partDisableStateChanged(partId); + emit skeletonChanged(); +} + +void Document::setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid& imageId) +{ + auto part = partMap.find(partId); + if (part == partMap.end()) { + return; + } + if (part->second.colorImageId == imageId) + return; + part->second.colorImageId = imageId; + part->second.dirty = true; + emit partColorImageChanged(partId); + emit optionsChanged(); +} + +void Document::collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const +{ + const SkeletonComponent* component = findComponent(componentId); + if (nullptr == component) + return; + + if (!component->linkToPartId.isNull()) { + partIds.push_back(component->linkToPartId); + return; + } + + for (const auto& childId : component->childrenIds) { + collectComponentDescendantParts(childId, partIds); + } +} + +void Document::collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector& componentIds) const +{ + const SkeletonComponent* component = findComponent(componentId); + if (nullptr == component) + return; + + if (!component->linkToPartId.isNull()) { + return; + } + + for (const auto& childId : component->childrenIds) { + componentIds.push_back(childId); + collectComponentDescendantComponents(childId, componentIds); + } +} + +void Document::hideOtherComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + std::set partIdSet; + for (const auto& partId : partIds) { + partIdSet.insert(partId); + } + for (const auto& part : partMap) { + if (partIdSet.find(part.first) != partIdSet.end()) + continue; + setPartVisibleState(part.first, false); + } +} + +void Document::lockOtherComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + std::set partIdSet; + for (const auto& partId : partIds) { + partIdSet.insert(partId); + } + for (const auto& part : partMap) { + if (partIdSet.find(part.first) != partIdSet.end()) + continue; + setPartLockState(part.first, true); + } +} + +void Document::hideAllComponents() +{ + for (const auto& part : partMap) { + setPartVisibleState(part.first, false); + } +} + +void Document::showAllComponents() +{ + for (const auto& part : partMap) { + setPartVisibleState(part.first, true); + } +} + +void Document::showOrHideAllComponents() +{ + bool foundVisiblePart = false; + for (const auto& part : partMap) { + if (part.second.visible) { + foundVisiblePart = true; + } + } + if (foundVisiblePart) + hideAllComponents(); + else + showAllComponents(); +} + +void Document::collapseAllComponents() +{ + for (const auto& component : componentMap) { + if (!component.second.linkToPartId.isNull()) + continue; + setComponentExpandState(component.first, false); + } +} + +void Document::expandAllComponents() +{ + for (const auto& component : componentMap) { + if (!component.second.linkToPartId.isNull()) + continue; + setComponentExpandState(component.first, true); + } +} + +void Document::lockAllComponents() +{ + for (const auto& part : partMap) { + setPartLockState(part.first, true); + } +} + +void Document::unlockAllComponents() +{ + for (const auto& part : partMap) { + setPartLockState(part.first, false); + } +} + +void Document::hideDescendantComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto& partId : partIds) { + setPartVisibleState(partId, false); + } +} + +void Document::showDescendantComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto& partId : partIds) { + setPartVisibleState(partId, true); + } +} + +void Document::lockDescendantComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto& partId : partIds) { + setPartLockState(partId, true); + } +} + +void Document::unlockDescendantComponents(dust3d::Uuid componentId) +{ + std::vector partIds; + collectComponentDescendantParts(componentId, partIds); + for (const auto& partId : partIds) { + setPartLockState(partId, false); + } +} + +void Document::scaleNodeByAddRadius(dust3d::Uuid nodeId, float amount) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + return; + } + if (isPartReadonly(it->second.partId)) + return; + if (radiusLocked) + return; + it->second.setRadius(it->second.radius + amount); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeRadiusChanged(nodeId); + emit skeletonChanged(); +} + +bool Document::isPartReadonly(dust3d::Uuid partId) const +{ + const SkeletonPart* part = findPart(partId); + if (nullptr == part) { + return true; + } + return part->locked || !part->visible; +} + +void Document::moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + return; + } + if (m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId)) + return; + bool changed = false; + if (!(m_allPositionRelatedLocksEnabled && xlocked)) { + it->second.addX(x); + changed = true; + } + if (!(m_allPositionRelatedLocksEnabled && ylocked)) { + it->second.addY(y); + changed = true; + } + if (!(m_allPositionRelatedLocksEnabled && zlocked)) { + it->second.addZ(z); + changed = true; + } + if (!changed) + return; + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +void Document::moveOriginBy(float x, float y, float z) +{ + if (!(m_allPositionRelatedLocksEnabled && xlocked)) + addOriginX(x); + if (!(m_allPositionRelatedLocksEnabled && ylocked)) + addOriginY(y); + if (!(m_allPositionRelatedLocksEnabled && zlocked)) + addOriginZ(z); + markAllDirty(); + emit originChanged(); + emit skeletonChanged(); +} + +void Document::setNodeOrigin(dust3d::Uuid nodeId, float x, float y, float z) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + return; + } + if ((m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId))) + return; + if (!(m_allPositionRelatedLocksEnabled && xlocked)) + it->second.setX(x); + if (!(m_allPositionRelatedLocksEnabled && ylocked)) + it->second.setY(y); + if (!(m_allPositionRelatedLocksEnabled && zlocked)) + it->second.setZ(z); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +void Document::setNodeRadius(dust3d::Uuid nodeId, float radius) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + return; + } + if (isPartReadonly(it->second.partId)) + return; + if (!radiusLocked) + it->second.setRadius(radius); + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeRadiusChanged(nodeId); + emit skeletonChanged(); +} + +void Document::switchNodeXZ(dust3d::Uuid nodeId) +{ + auto it = nodeMap.find(nodeId); + if (it == nodeMap.end()) { + return; + } + if (isPartReadonly(it->second.partId)) + return; + { + float oldX = it->second.getX(); + float oldZ = it->second.getZ(); + it->second.setX(oldZ); + it->second.setZ(oldX); + } + auto part = partMap.find(it->second.partId); + if (part != partMap.end()) + part->second.dirty = true; + emit nodeOriginChanged(nodeId); + emit skeletonChanged(); +} + +const SkeletonComponent* Document::findComponent(dust3d::Uuid componentId) const +{ + if (componentId.isNull()) + return &rootComponent; + auto it = componentMap.find(componentId); + if (it == componentMap.end()) + return nullptr; + return &it->second; +} + +void Document::addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId) +{ + if (findEdgeByNodes(fromNodeId, toNodeId)) { + return; + } + + const SkeletonNode* fromNode = nullptr; + const SkeletonNode* toNode = nullptr; + bool toPartRemoved = false; + + fromNode = findNode(fromNodeId); + if (nullptr == fromNode) { + return; + } + + if (isPartReadonly(fromNode->partId)) + return; + + toNode = findNode(toNodeId); + if (nullptr == toNode) { + return; + } + + if (isPartReadonly(toNode->partId)) + return; + + dust3d::Uuid toPartId = toNode->partId; + + auto fromPart = partMap.find(fromNode->partId); + if (fromPart == partMap.end()) { + return; + } + + fromPart->second.dirty = true; + + if (fromNode->partId != toNode->partId) { + toPartRemoved = true; + std::vector toGroup; + std::set visitMap; + joinNodeAndNeiborsToGroup(&toGroup, toNodeId, &visitMap); + for (auto nodeIdIt = toGroup.begin(); nodeIdIt != toGroup.end(); nodeIdIt++) { + auto nodeIt = nodeMap.find(*nodeIdIt); + if (nodeIt == nodeMap.end()) { + continue; + } + nodeIt->second.partId = fromNode->partId; + fromPart->second.nodeIds.push_back(nodeIt->first); + for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { + auto edgeIt = edgeMap.find(*edgeIdIt); + if (edgeIt == edgeMap.end()) { + continue; + } + edgeIt->second.partId = fromNode->partId; + } + } + } + + SkeletonEdge edge; + edge.partId = fromNode->partId; + edge.nodeIds.push_back(fromNode->id); + edge.nodeIds.push_back(toNodeId); + edgeMap[edge.id] = edge; + + nodeMap[toNodeId].edgeIds.push_back(edge.id); + nodeMap[fromNode->id].edgeIds.push_back(edge.id); + + emit edgeAdded(edge.id); + + if (toPartRemoved) { + updateLinkedPart(toPartId, fromNode->partId); + removePart(toPartId); + } + + emit skeletonChanged(); +} + +void Document::updateLinkedPart(dust3d::Uuid oldPartId, dust3d::Uuid newPartId) +{ + for (auto& partIt : partMap) { + if (partIt.second.cutFaceLinkedId == oldPartId) { + partIt.second.dirty = true; + partIt.second.setCutFaceLinkedId(newPartId); + } + } + std::set dirtyPartIds; + for (auto& nodeIt : nodeMap) { + if (nodeIt.second.cutFaceLinkedId == oldPartId) { + dirtyPartIds.insert(nodeIt.second.partId); + nodeIt.second.setCutFaceLinkedId(newPartId); + } + } + for (const auto& partId : dirtyPartIds) { + SkeletonPart* part = (SkeletonPart*)findPart(partId); + if (nullptr == part) + continue; + part->dirty = true; + } +} + +void Document::enableAllPositionRelatedLocks() +{ + m_allPositionRelatedLocksEnabled = true; +} + +void Document::disableAllPositionRelatedLocks() +{ + m_allPositionRelatedLocksEnabled = false; +} + +void Document::resetDirtyFlags() +{ + for (auto& part : partMap) { + part.second.dirty = false; + } + for (auto& component : componentMap) { + component.second.dirty = false; + } +} + +void Document::markAllDirty() +{ + for (auto& part : partMap) { + part.second.dirty = true; + } +} + +void Document::setXlockState(bool locked) +{ + if (xlocked == locked) + return; + xlocked = locked; + emit xlockStateChanged(); +} + +void Document::setYlockState(bool locked) +{ + if (ylocked == locked) + return; + ylocked = locked; + emit ylockStateChanged(); +} + +void Document::setZlockState(bool locked) +{ + if (zlocked == locked) + return; + zlocked = locked; + emit zlockStateChanged(); +} + +void Document::setRadiusLockState(bool locked) +{ + if (radiusLocked == locked) + return; + radiusLocked = locked; + emit radiusLockStateChanged(); +} + +void Document::setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image) +{ + SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); + if (nullptr == component) + return; + component->isPreviewImageDecorationObsolete = true; + component->previewImage = std::move(image); +} + +void Document::setComponentPreviewPixmap(const dust3d::Uuid& componentId, const QPixmap& pixmap) +{ + SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); + if (nullptr == component) + return; + component->previewPixmap = pixmap; + emit componentPreviewPixmapChanged(componentId); +} + +void Document::setComponentPreviewMesh(const dust3d::Uuid& componentId, std::unique_ptr mesh) +{ + SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); + if (nullptr == component) + return; + component->updatePreviewMesh(std::move(mesh)); + emit componentPreviewMeshChanged(componentId); +} + void Document::uiReady() { qDebug() << "uiReady"; @@ -193,7 +1558,7 @@ void Document::updateTextureAmbientOcclusionImage(QImage* image) textureAmbientOcclusionImage = image; } -void Document::setEditMode(SkeletonDocumentEditMode mode) +void Document::setEditMode(DocumentEditMode mode) { if (editMode == mode) return; @@ -235,8 +1600,6 @@ void Document::toSnapshot(dust3d::Snapshot* snapshot, const std::setsecond.base == base) - return; - part->second.base = base; - part->second.dirty = true; - emit partBaseChanged(partId); - emit skeletonChanged(); -} - void Document::setPartDeformWidth(dust3d::Uuid partId, float width) { auto part = partMap.find(partId); diff --git a/application/sources/document.h b/application/sources/document.h index 03977fdb..0c5b8809 100644 --- a/application/sources/document.h +++ b/application/sources/document.h @@ -1,10 +1,10 @@ #ifndef DUST3D_APPLICATION_DOCUMENT_H_ #define DUST3D_APPLICATION_DOCUMENT_H_ +#include "debug.h" #include "material_layer.h" #include "model_mesh.h" #include "monochrome_mesh.h" -#include "skeleton_document.h" #include "theme.h" #include #include @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include #include #include @@ -20,6 +22,535 @@ #include #include +class SkeletonNode { +public: + SkeletonNode(const dust3d::Uuid& withId = dust3d::Uuid()) + : radius(0) + , cutRotation(0.0) + , cutFace(dust3d::CutFace::Quad) + , hasCutFaceSettings(false) + , m_x(0) + , m_y(0) + , m_z(0) + { + id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; + } + void setRadius(float toRadius); + void setCutRotation(float toRotation) + { + if (toRotation < -1) + toRotation = -1; + else if (toRotation > 1) + toRotation = 1; + cutRotation = toRotation; + hasCutFaceSettings = true; + } + void setCutFace(dust3d::CutFace face) + { + cutFace = face; + cutFaceLinkedId = dust3d::Uuid(); + hasCutFaceSettings = true; + } + void setCutFaceLinkedId(const dust3d::Uuid& linkedId) + { + if (linkedId.isNull()) { + clearCutFaceSettings(); + return; + } + cutFace = dust3d::CutFace::UserDefined; + cutFaceLinkedId = linkedId; + hasCutFaceSettings = true; + } + void clearCutFaceSettings() + { + cutFace = dust3d::CutFace::Quad; + cutFaceLinkedId = dust3d::Uuid(); + cutRotation = 0; + hasCutFaceSettings = false; + } + float getX(bool rotated = false) const + { + if (rotated) + return m_y; + return m_x; + } + float getY(bool rotated = false) const + { + if (rotated) + return m_x; + return m_y; + } + float getZ(bool rotated = false) const + { + (void)rotated; + return m_z; + } + void setX(float x) + { + m_x = x; + } + void setY(float y) + { + m_y = y; + } + void setZ(float z) + { + m_z = z; + } + void addX(float x) + { + m_x += x; + } + void addY(float y) + { + m_y += y; + } + void addZ(float z) + { + m_z += z; + } + dust3d::Uuid id; + dust3d::Uuid partId; + QString name; + float radius; + float cutRotation; + dust3d::CutFace cutFace; + dust3d::Uuid cutFaceLinkedId; + bool hasCutFaceSettings; + std::vector edgeIds; + +private: + float m_x; + float m_y; + float m_z; +}; + +class SkeletonEdge { +public: + SkeletonEdge(const dust3d::Uuid& withId = dust3d::Uuid()) + { + id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; + } + dust3d::Uuid id; + dust3d::Uuid partId; + QString name; + std::vector nodeIds; + dust3d::Uuid neighborOf(dust3d::Uuid nodeId) const + { + if (nodeIds.size() != 2) + return dust3d::Uuid(); + return nodeIds[0] == nodeId ? nodeIds[1] : nodeIds[0]; + } +}; + +class SkeletonPart { +public: + dust3d::Uuid id; + QString name; + bool visible; + bool locked; + bool subdived; + bool disabled; + bool xMirrored; + float deformThickness; + float deformWidth; + bool deformUnified; + bool rounded; + bool chamfered; + QColor color; + bool hasColor; + dust3d::Uuid componentId; + std::vector nodeIds; + bool dirty; + float cutRotation; + dust3d::CutFace cutFace; + dust3d::Uuid cutFaceLinkedId; + dust3d::Uuid materialId; + dust3d::PartTarget target; + float colorSolubility; + float metalness; + float roughness; + float hollowThickness; + bool countershaded; + bool smooth; + dust3d::Uuid colorImageId; + SkeletonPart(const dust3d::Uuid& withId = dust3d::Uuid()) + : visible(true) + , locked(false) + , subdived(false) + , disabled(false) + , xMirrored(false) + , deformThickness(1.0) + , deformWidth(1.0) + , deformUnified(false) + , rounded(false) + , chamfered(false) + , color(Qt::white) + , hasColor(false) + , dirty(true) + , cutRotation(0.0) + , cutFace(dust3d::CutFace::Quad) + , target(dust3d::PartTarget::Model) + , colorSolubility(0.0) + , metalness(0.0) + , roughness(1.0) + , hollowThickness(0.0) + , countershaded(false) + , smooth(false) + { + id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; + } + bool hasPolyFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasSmoothFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasSubdivFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasRoundEndFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasMirrorFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasChamferFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasRotationFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasHollowFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasCutFaceFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasLayerFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasTargetFunction() const + { + return true; + } + bool hasBaseFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasCombineModeFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasDeformFunction() const + { + return dust3d::PartTarget::Model == target; + } + bool hasColorFunction() const + { + return dust3d::PartTarget::Model == target; + } + void setDeformThickness(float toThickness) + { + if (toThickness < 0) + toThickness = 0; + else if (toThickness > 2) + toThickness = 2; + deformThickness = toThickness; + } + void setDeformWidth(float toWidth) + { + if (toWidth < 0) + toWidth = 0; + else if (toWidth > 2) + toWidth = 2; + deformWidth = toWidth; + } + void setCutRotation(float toRotation) + { + if (toRotation < -1) + toRotation = -1; + else if (toRotation > 1) + toRotation = 1; + cutRotation = toRotation; + } + void setCutFace(dust3d::CutFace face) + { + cutFace = face; + cutFaceLinkedId = dust3d::Uuid(); + } + void setCutFaceLinkedId(const dust3d::Uuid& linkedId) + { + if (linkedId.isNull()) { + setCutFace(dust3d::CutFace::Quad); + return; + } + cutFace = dust3d::CutFace::UserDefined; + cutFaceLinkedId = linkedId; + } + 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() || deformUnified; + } + bool colorSolubilityAdjusted() const + { + return fabs(colorSolubility - 0.0) >= 0.01; + } + bool metalnessAdjusted() const + { + return fabs(metalness - 0.0) >= 0.01; + } + bool roughnessAdjusted() const + { + return fabs(roughness - 1.0) >= 0.01; + } + bool cutRotationAdjusted() const + { + return fabs(cutRotation - 0.0) >= 0.01; + } + bool hollowThicknessAdjusted() const + { + return fabs(hollowThickness - 0.0) >= 0.01; + } + bool cutFaceAdjusted() const + { + return cutFace != dust3d::CutFace::Quad; + } + bool cutAdjusted() const + { + return cutRotationAdjusted() || cutFaceAdjusted() || hollowThicknessAdjusted(); + } + bool materialAdjusted() const + { + return !materialId.isNull(); + } + bool isEditVisible() const + { + return visible && !disabled; + } + void copyAttributes(const SkeletonPart& other) + { + visible = other.visible; + locked = other.locked; + subdived = other.subdived; + disabled = other.disabled; + xMirrored = other.xMirrored; + deformThickness = other.deformThickness; + deformWidth = other.deformWidth; + rounded = other.rounded; + chamfered = other.chamfered; + color = other.color; + hasColor = other.hasColor; + cutRotation = other.cutRotation; + cutFace = other.cutFace; + cutFaceLinkedId = other.cutFaceLinkedId; + componentId = other.componentId; + dirty = other.dirty; + materialId = other.materialId; + target = other.target; + colorSolubility = other.colorSolubility; + countershaded = other.countershaded; + metalness = other.metalness; + roughness = other.roughness; + deformUnified = other.deformUnified; + smooth = other.smooth; + hollowThickness = other.hollowThickness; + } + +private: + Q_DISABLE_COPY(SkeletonPart); +}; + +enum class DocumentEditMode { + Add = 0, + Select, + Paint, + Drag, + ZoomIn, + ZoomOut +}; + +enum class SkeletonProfile { + Unknown = 0, + Main, + Side +}; + +class SkeletonComponent { +public: + SkeletonComponent() + { + } + SkeletonComponent(const dust3d::Uuid& withId, const QString& linkData = QString(), const QString& linkDataType = QString()) + { + id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; + if (!linkData.isEmpty()) { + if ("partId" == linkDataType) { + linkToPartId = dust3d::Uuid(linkData.toUtf8().constData()); + } + } + } + dust3d::Uuid id; + QString name; + dust3d::Uuid linkToPartId; + dust3d::Uuid parentId; + bool expanded = true; + dust3d::CombineMode combineMode = dust3d::CombineMode::Normal; + bool dirty = true; + std::vector childrenIds; + bool isPreviewMeshObsolete = false; + std::unique_ptr previewImage; + bool isPreviewImageDecorationObsolete = false; + QPixmap previewPixmap; + QString linkData() const + { + return linkToPartId.isNull() ? QString() : QString(linkToPartId.toString().c_str()); + } + QString linkDataType() const + { + return linkToPartId.isNull() ? QString() : QString("partId"); + } + void addChild(dust3d::Uuid childId) + { + if (m_childrenIdSet.find(childId) != m_childrenIdSet.end()) + return; + m_childrenIdSet.insert(childId); + childrenIds.push_back(childId); + } + void replaceChildWithOthers(const dust3d::Uuid& childId, const std::vector& others) + { + if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) + return; + m_childrenIdSet.erase(childId); + std::vector candidates; + for (const auto& it : others) { + if (m_childrenIdSet.find(it) == m_childrenIdSet.end()) { + m_childrenIdSet.insert(it); + candidates.emplace_back(it); + } + } + for (size_t i = 0; i < childrenIds.size(); ++i) { + if (childId == childrenIds[i]) { + size_t newAddSize = candidates.size() - 1; + if (newAddSize > 0) { + size_t oldSize = childrenIds.size(); + childrenIds.resize(childrenIds.size() + newAddSize); + for (int j = (int)oldSize - 1; j > (int)i; --j) { + childrenIds[j + newAddSize] = childrenIds[j]; + } + } + for (size_t k = 0; k < candidates.size(); ++k) + childrenIds[i + k] = candidates[k]; + break; + } + } + } + void removeChild(dust3d::Uuid childId) + { + if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) + return; + m_childrenIdSet.erase(childId); + auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (findResult != childrenIds.end()) + childrenIds.erase(findResult); + } + void replaceChild(dust3d::Uuid childId, dust3d::Uuid newId) + { + if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) + return; + if (m_childrenIdSet.find(newId) != m_childrenIdSet.end()) + return; + m_childrenIdSet.erase(childId); + m_childrenIdSet.insert(newId); + auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (findResult != childrenIds.end()) + *findResult = newId; + } + void moveChildUp(dust3d::Uuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == 0) + return; + std::swap(childrenIds[index - 1], childrenIds[index]); + } + void moveChildDown(dust3d::Uuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == (int)childrenIds.size() - 1) + return; + std::swap(childrenIds[index], childrenIds[index + 1]); + } + void moveChildToTop(dust3d::Uuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == 0) + return; + for (int i = index; i >= 1; i--) + std::swap(childrenIds[i - 1], childrenIds[i]); + } + void moveChildToBottom(dust3d::Uuid childId) + { + auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); + if (it == childrenIds.end()) { + return; + } + + auto index = std::distance(childrenIds.begin(), it); + if (index == (int)childrenIds.size() - 1) + return; + for (int i = index; i <= (int)childrenIds.size() - 2; i++) + std::swap(childrenIds[i], childrenIds[i + 1]); + } + void updatePreviewMesh(std::unique_ptr mesh) + { + m_previewMesh = std::move(mesh); + isPreviewMeshObsolete = true; + } + ModelMesh* takePreviewMesh() const + { + if (nullptr == m_previewMesh) + return nullptr; + return new ModelMesh(*m_previewMesh); + } + +private: + std::unique_ptr m_previewMesh; + std::set m_childrenIdSet; +}; + class MaterialPreviewsGenerator; class TextureGenerator; class MeshGenerator; @@ -66,7 +597,7 @@ enum class DocumentToSnapshotFor { Materials }; -class Document : public SkeletonDocument { +class Document : public QObject { Q_OBJECT signals: void nodeCutRotationChanged(dust3d::Uuid nodeId); @@ -80,7 +611,6 @@ signals: void postProcessedResultChanged(); void partSubdivStateChanged(dust3d::Uuid partId); void partXmirrorStateChanged(dust3d::Uuid partId); - void partBaseChanged(dust3d::Uuid partId); void partDeformThicknessChanged(dust3d::Uuid partId); void partDeformWidthChanged(dust3d::Uuid partId); void partDeformUnifyStateChanged(dust3d::Uuid partId); @@ -118,6 +648,33 @@ signals: void postProcessing(); void textureGenerating(); void textureChanged(); + void partAdded(dust3d::Uuid partId); + void nodeAdded(dust3d::Uuid nodeId); + void edgeAdded(dust3d::Uuid edgeId); + void partRemoved(dust3d::Uuid partId); + void partLockStateChanged(dust3d::Uuid partId); + void partVisibleStateChanged(dust3d::Uuid partId); + void partDisableStateChanged(dust3d::Uuid partId); + void partColorImageChanged(const dust3d::Uuid& partId); + void componentNameChanged(dust3d::Uuid componentId); + void componentChildrenChanged(dust3d::Uuid componentId); + void componentRemoved(dust3d::Uuid componentId); + void componentAdded(dust3d::Uuid componentId); + void componentExpandStateChanged(dust3d::Uuid componentId); + void componentPreviewMeshChanged(const dust3d::Uuid& componentId); + void componentPreviewPixmapChanged(const dust3d::Uuid& componentId); + void nodeRemoved(dust3d::Uuid nodeId); + void edgeRemoved(dust3d::Uuid edgeId); + void nodeRadiusChanged(dust3d::Uuid nodeId); + void nodeOriginChanged(dust3d::Uuid nodeId); + void edgeReversed(dust3d::Uuid edgeId); + void originChanged(); + void skeletonChanged(); + void optionsChanged(); + void xlockStateChanged(); + void ylockStateChanged(); + void zlockStateChanged(); + void radiusLockStateChanged(); public: // need initialize QImage* textureImage = nullptr; @@ -133,6 +690,18 @@ public: // need initialize bool weldEnabled = true; float brushMetalness = ModelMesh::m_defaultMetalness; float brushRoughness = ModelMesh::m_defaultRoughness; + DocumentEditMode editMode = DocumentEditMode::Select; + bool xlocked = false; + bool ylocked = false; + bool zlocked = false; + bool radiusLocked = false; + QImage turnaround; + QByteArray turnaroundPngByteArray; + std::map partMap; + std::map nodeMap; + std::map edgeMap; + std::map componentMap; + SkeletonComponent rootComponent; public: Document(); @@ -140,13 +709,13 @@ public: std::map materialMap; std::vector materialIdList; - bool undoable() const override; - bool redoable() const override; - bool hasPastableNodesInClipboard() const override; - bool originSettled() const override; - bool isNodeEditable(dust3d::Uuid nodeId) const override; - bool isEdgeEditable(dust3d::Uuid edgeId) const override; - void copyNodes(std::set nodeIdSet) const override; + bool undoable() const; + bool redoable() const; + bool hasPastableNodesInClipboard() const; + bool originSettled() const; + bool isNodeEditable(dust3d::Uuid nodeId) const; + bool isEdgeEditable(dust3d::Uuid edgeId) const; + void copyNodes(std::set nodeIdSet) const; void toSnapshot(dust3d::Snapshot* snapshot, const std::set& limitNodeIds = std::set(), DocumentToSnapshotFor forWhat = DocumentToSnapshotFor::Document, const std::set& limitMaterialIds = std::set()) const; @@ -179,15 +748,72 @@ public: bool isPostProcessing() const; bool isTextureGenerating() const; void collectCutFaceList(std::vector& cutFaces) const; + float getOriginX(bool rotated = false) const + { + if (rotated) + return m_originY; + return m_originX; + } + float getOriginY(bool rotated = false) const + { + if (rotated) + return m_originX; + return m_originY; + } + float getOriginZ(bool rotated = false) const + { + (void)rotated; + return m_originZ; + } + void setOriginX(float originX) + { + m_originX = originX; + } + void setOriginY(float originY) + { + m_originY = originY; + } + void setOriginZ(float originZ) + { + m_originZ = originZ; + } + void addOriginX(float originX) + { + m_originX += originX; + } + void addOriginY(float originY) + { + m_originY += originY; + } + void addOriginZ(float originZ) + { + m_originZ += originZ; + } + const SkeletonNode* findNode(dust3d::Uuid nodeId) const; + const SkeletonEdge* findEdge(dust3d::Uuid edgeId) const; + const SkeletonPart* findPart(dust3d::Uuid partId) const; + const SkeletonEdge* findEdgeByNodes(dust3d::Uuid firstNodeId, dust3d::Uuid secondNodeId) const; + void findAllNeighbors(dust3d::Uuid nodeId, std::set& neighbors) const; + bool isNodeConnectable(dust3d::Uuid nodeId) const; + const SkeletonComponent* findComponent(dust3d::Uuid componentId) const; + const SkeletonComponent* findComponentParent(dust3d::Uuid componentId) const; + dust3d::Uuid findComponentParentId(dust3d::Uuid componentId) const; + void collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const; + void collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector& componentIds) const; + void setComponentPreviewMesh(const dust3d::Uuid& componentId, std::unique_ptr mesh); + void setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image); + void resetDirtyFlags(); + void markAllDirty(); + public slots: - void undo() override; - void redo() override; - void paste() override; + void undo(); + void redo(); + void paste(); void setNodeCutRotation(dust3d::Uuid nodeId, float cutRotation); void setNodeCutFace(dust3d::Uuid nodeId, dust3d::CutFace cutFace); void setNodeCutFaceLinkedId(dust3d::Uuid nodeId, dust3d::Uuid linkedId); void clearNodeCutFaceSettings(dust3d::Uuid nodeId); - void setEditMode(SkeletonDocumentEditMode mode); + void setEditMode(DocumentEditMode mode); void uiReady(); void generateMesh(); void regenerateMesh(); @@ -200,7 +826,6 @@ public slots: void materialPreviewsReady(); void setPartSubdivState(dust3d::Uuid partId, bool subdived); void setPartXmirrorState(dust3d::Uuid partId, bool mirrored); - void setPartBase(dust3d::Uuid partId, dust3d::PartBase base); void setPartDeformThickness(dust3d::Uuid partId, float thickness); void setPartDeformWidth(dust3d::Uuid partId, float width); void setPartDeformUnified(dust3d::Uuid partId, bool unified); @@ -231,11 +856,73 @@ public slots: void removeMaterial(dust3d::Uuid materialId); void setMaterialLayers(dust3d::Uuid materialId, std::vector layers); void renameMaterial(dust3d::Uuid materialId, QString name); + void removeNode(dust3d::Uuid nodeId); + void removeEdge(dust3d::Uuid edgeId); + void removePart(dust3d::Uuid partId); + void addNodeWithId(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); + void addNode(float x, float y, float z, float radius, dust3d::Uuid fromNodeId); + void scaleNodeByAddRadius(dust3d::Uuid nodeId, float amount); + void moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z); + void setNodeOrigin(dust3d::Uuid nodeId, float x, float y, float z); + void setNodeRadius(dust3d::Uuid nodeId, float radius); + void switchNodeXZ(dust3d::Uuid nodeId); + void moveOriginBy(float x, float y, float z); + void addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId); + void moveComponentUp(dust3d::Uuid componentId); + void moveComponentDown(dust3d::Uuid componentId); + void moveComponentToTop(dust3d::Uuid componentId); + void moveComponentToBottom(dust3d::Uuid componentId); + void renameComponent(dust3d::Uuid componentId, QString name); + void removeComponent(dust3d::Uuid componentId); + void addComponent(dust3d::Uuid parentId); + void moveComponent(dust3d::Uuid componentId, dust3d::Uuid toParentId); + void setCurrentCanvasComponentId(dust3d::Uuid componentId); + void groupComponents(const std::vector& componentIds); + void ungroupComponent(const dust3d::Uuid& componentId); + void createNewChildComponent(dust3d::Uuid parentComponentId); + void setComponentExpandState(dust3d::Uuid componentId, bool expanded); + void hideOtherComponents(dust3d::Uuid componentId); + void lockOtherComponents(dust3d::Uuid componentId); + void hideAllComponents(); + void showAllComponents(); + void showOrHideAllComponents(); + void collapseAllComponents(); + void expandAllComponents(); + void lockAllComponents(); + void unlockAllComponents(); + void hideDescendantComponents(dust3d::Uuid componentId); + void showDescendantComponents(dust3d::Uuid componentId); + void lockDescendantComponents(dust3d::Uuid componentId); + void unlockDescendantComponents(dust3d::Uuid componentId); + void setComponentPreviewPixmap(const dust3d::Uuid& componentId, const QPixmap& pixmap); + void setPartLockState(dust3d::Uuid partId, bool locked); + void setPartVisibleState(dust3d::Uuid partId, bool visible); + void setPartDisableState(dust3d::Uuid partId, bool disabled); + void setPartColorImage(const dust3d::Uuid& partId, const dust3d::Uuid& imageId); + void enableAllPositionRelatedLocks(); + void disableAllPositionRelatedLocks(); + bool isPartReadonly(dust3d::Uuid partId) const; + void breakEdge(dust3d::Uuid edgeId); + void reduceNode(dust3d::Uuid nodeId); + void reverseEdge(dust3d::Uuid edgeId); + void setXlockState(bool locked); + void setYlockState(bool locked); + void setZlockState(bool locked); + void setRadiusLockState(bool locked); private: void resolveSnapshotBoundingBox(const dust3d::Snapshot& snapshot, QRectF* mainProfile, QRectF* sideProfile); void settleOrigin(); void checkExportReadyState(); + void splitPartByNode(std::vector>* groups, dust3d::Uuid nodeId); + void joinNodeAndNeiborsToGroup(std::vector* group, dust3d::Uuid nodeId, std::set* visitMap, dust3d::Uuid noUseEdgeId = dust3d::Uuid()); + void splitPartByEdge(std::vector>* groups, dust3d::Uuid edgeId); + void removePartDontCareComponent(dust3d::Uuid partId); + void addPartToComponent(dust3d::Uuid partId, dust3d::Uuid componentId); + bool isDescendantComponent(dust3d::Uuid componentId, dust3d::Uuid suspiciousId); + void removeComponentRecursively(dust3d::Uuid componentId); + void updateLinkedPart(dust3d::Uuid oldPartId, dust3d::Uuid newPartId); + dust3d::Uuid createNode(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); bool m_isResultMeshObsolete = false; MeshGenerator* m_meshGenerator = nullptr; @@ -256,6 +943,11 @@ private: quint64 m_meshGenerationId = 0; quint64 m_nextMeshGenerationId = 0; void* m_generatedCacheContext = nullptr; + float m_originX = 0; + float m_originY = 0; + float m_originZ = 0; + dust3d::Uuid m_currentCanvasComponentId; + bool m_allPositionRelatedLocksEnabled = true; private: static unsigned long m_maxSnapshot; diff --git a/application/sources/document_window.cc b/application/sources/document_window.cc index bf81f2f2..78dec2e1 100644 --- a/application/sources/document_window.cc +++ b/application/sources/document_window.cc @@ -511,11 +511,11 @@ DocumentWindow::DocumentWindow() canvasGraphicsWidget, &SkeletonGraphicsWidget::turnaroundChanged); connect(addButton, &QPushButton::clicked, [=]() { - m_document->setEditMode(SkeletonDocumentEditMode::Add); + m_document->setEditMode(DocumentEditMode::Add); }); connect(selectButton, &QPushButton::clicked, [=]() { - m_document->setEditMode(SkeletonDocumentEditMode::Select); + m_document->setEditMode(DocumentEditMode::Select); }); connect(m_xLockButton, &QPushButton::clicked, [=]() { diff --git a/application/sources/monochrome_opengl_vertex.h b/application/sources/monochrome_opengl_vertex.h index 3bd04367..14cb8e6e 100644 --- a/application/sources/monochrome_opengl_vertex.h +++ b/application/sources/monochrome_opengl_vertex.h @@ -10,9 +10,9 @@ typedef struct GLfloat posX; GLfloat posY; GLfloat posZ; - GLfloat colorR = 0.0; - GLfloat colorG = 0.0; - GLfloat colorB = 0.0; + GLfloat colorR = 24.0 / 255.0; + GLfloat colorG = 29.0 / 255.0; + GLfloat colorB = 49.0 / 255.0; GLfloat alpha = 1.0; } MonochromeOpenGLVertex; #pragma pack(pop) diff --git a/application/sources/skeleton_document.cc b/application/sources/skeleton_document.cc deleted file mode 100644 index 829327b8..00000000 --- a/application/sources/skeleton_document.cc +++ /dev/null @@ -1,1345 +0,0 @@ -#include "skeleton_document.h" -#include - -const SkeletonNode* SkeletonDocument::findNode(dust3d::Uuid nodeId) const -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) - return nullptr; - return &it->second; -} - -const SkeletonEdge* SkeletonDocument::findEdge(dust3d::Uuid edgeId) const -{ - auto it = edgeMap.find(edgeId); - if (it == edgeMap.end()) - return nullptr; - return &it->second; -} - -const SkeletonPart* SkeletonDocument::findPart(dust3d::Uuid partId) const -{ - auto it = partMap.find(partId); - if (it == partMap.end()) - return nullptr; - return &it->second; -} - -const SkeletonEdge* SkeletonDocument::findEdgeByNodes(dust3d::Uuid firstNodeId, dust3d::Uuid secondNodeId) const -{ - const SkeletonNode* firstNode = nullptr; - firstNode = findNode(firstNodeId); - if (nullptr == firstNode) { - return nullptr; - } - for (auto edgeIdIt = firstNode->edgeIds.begin(); edgeIdIt != firstNode->edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - continue; - } - if (std::find(edgeIt->second.nodeIds.begin(), edgeIt->second.nodeIds.end(), secondNodeId) != edgeIt->second.nodeIds.end()) - return &edgeIt->second; - } - return nullptr; -} - -void SkeletonDocument::findAllNeighbors(dust3d::Uuid nodeId, std::set& neighbors) const -{ - const auto& node = findNode(nodeId); - if (nullptr == node) { - return; - } - for (const auto& edgeId : node->edgeIds) { - const auto& edge = findEdge(edgeId); - if (nullptr == edge) { - continue; - } - const auto& neighborNodeId = edge->neighborOf(nodeId); - if (neighborNodeId.isNull()) { - continue; - } - if (neighbors.find(neighborNodeId) != neighbors.end()) { - continue; - } - neighbors.insert(neighborNodeId); - findAllNeighbors(neighborNodeId, neighbors); - } -} - -bool SkeletonDocument::isNodeConnectable(dust3d::Uuid nodeId) const -{ - const auto& node = findNode(nodeId); - if (nullptr == node) - return false; - if (node->edgeIds.size() < 2) - return true; - return false; -} - -void SkeletonDocument::reduceNode(dust3d::Uuid nodeId) -{ - const SkeletonNode* node = findNode(nodeId); - if (nullptr == node) { - return; - } - if (node->edgeIds.size() != 2) { - return; - } - dust3d::Uuid firstEdgeId = node->edgeIds[0]; - dust3d::Uuid secondEdgeId = node->edgeIds[1]; - const SkeletonEdge* firstEdge = findEdge(firstEdgeId); - if (nullptr == firstEdge) { - return; - } - const SkeletonEdge* secondEdge = findEdge(secondEdgeId); - if (nullptr == secondEdge) { - return; - } - dust3d::Uuid firstNeighborNodeId = firstEdge->neighborOf(nodeId); - dust3d::Uuid secondNeighborNodeId = secondEdge->neighborOf(nodeId); - removeNode(nodeId); - addEdge(firstNeighborNodeId, secondNeighborNodeId); -} - -void SkeletonDocument::breakEdge(dust3d::Uuid edgeId) -{ - const SkeletonEdge* edge = findEdge(edgeId); - if (nullptr == edge) { - return; - } - if (edge->nodeIds.size() != 2) { - return; - } - dust3d::Uuid firstNodeId = edge->nodeIds[0]; - dust3d::Uuid secondNodeId = edge->nodeIds[1]; - const SkeletonNode* firstNode = findNode(firstNodeId); - if (nullptr == firstNode) { - return; - } - const SkeletonNode* secondNode = findNode(secondNodeId); - if (nullptr == secondNode) { - return; - } - QVector3D firstOrigin(firstNode->getX(), firstNode->getY(), firstNode->getZ()); - QVector3D secondOrigin(secondNode->getX(), secondNode->getY(), secondNode->getZ()); - QVector3D middleOrigin = (firstOrigin + secondOrigin) / 2; - float middleRadius = (firstNode->radius + secondNode->radius) / 2; - removeEdge(edgeId); - dust3d::Uuid middleNodeId = createNode(dust3d::Uuid::createUuid(), middleOrigin.x(), middleOrigin.y(), middleOrigin.z(), middleRadius, firstNodeId); - if (middleNodeId.isNull()) { - return; - } - addEdge(middleNodeId, secondNodeId); -} - -void SkeletonDocument::reverseEdge(dust3d::Uuid edgeId) -{ - SkeletonEdge* edge = (SkeletonEdge*)findEdge(edgeId); - if (nullptr == edge) { - return; - } - if (edge->nodeIds.size() != 2) { - return; - } - std::swap(edge->nodeIds[0], edge->nodeIds[1]); - auto part = partMap.find(edge->partId); - if (part != partMap.end()) - part->second.dirty = true; - emit edgeReversed(edgeId); - emit skeletonChanged(); -} - -void SkeletonDocument::removeEdge(dust3d::Uuid edgeId) -{ - const SkeletonEdge* edge = findEdge(edgeId); - if (nullptr == edge) { - return; - } - if (isPartReadonly(edge->partId)) - return; - const SkeletonPart* oldPart = findPart(edge->partId); - if (nullptr == oldPart) { - return; - } - QString nextPartName = oldPart->name; - dust3d::Uuid oldPartId = oldPart->id; - std::vector> groups; - splitPartByEdge(&groups, edgeId); - std::vector> newPartNodeNumMap; - std::vector newPartIds; - for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { - const auto newUuid = dust3d::Uuid::createUuid(); - SkeletonPart& part = partMap[newUuid]; - part.id = newUuid; - part.copyAttributes(*oldPart); - part.name = nextPartName; - for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - continue; - } - nodeIt->second.partId = part.id; - part.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - continue; - } - edgeIt->second.partId = part.id; - } - } - addPartToComponent(part.id, findComponentParentId(part.componentId)); - newPartNodeNumMap.push_back({ part.id, part.nodeIds.size() }); - newPartIds.push_back(part.id); - emit partAdded(part.id); - } - for (auto nodeIdIt = edge->nodeIds.begin(); nodeIdIt != edge->nodeIds.end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - continue; - } - nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), edgeId), nodeIt->second.edgeIds.end()); - emit nodeOriginChanged(nodeIt->first); - } - edgeMap.erase(edgeId); - emit edgeRemoved(edgeId); - removePart(oldPartId); - - if (!newPartNodeNumMap.empty()) { - std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&](const std::pair& first, const std::pair& second) { - return first.second > second.second; - }); - updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); - } - - emit skeletonChanged(); -} - -void SkeletonDocument::removeNode(dust3d::Uuid nodeId) -{ - const SkeletonNode* node = findNode(nodeId); - if (nullptr == node) { - return; - } - if (isPartReadonly(node->partId)) - return; - const SkeletonPart* oldPart = findPart(node->partId); - if (nullptr == oldPart) { - return; - } - QString nextPartName = oldPart->name; - dust3d::Uuid oldPartId = oldPart->id; - std::vector> groups; - splitPartByNode(&groups, nodeId); - std::vector> newPartNodeNumMap; - std::vector newPartIds; - for (auto groupIt = groups.begin(); groupIt != groups.end(); groupIt++) { - const auto newUuid = dust3d::Uuid::createUuid(); - SkeletonPart& part = partMap[newUuid]; - part.id = newUuid; - part.copyAttributes(*oldPart); - part.name = nextPartName; - for (auto nodeIdIt = (*groupIt).begin(); nodeIdIt != (*groupIt).end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - continue; - } - nodeIt->second.partId = part.id; - part.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - continue; - } - edgeIt->second.partId = part.id; - } - } - addPartToComponent(part.id, findComponentParentId(part.componentId)); - newPartNodeNumMap.push_back({ part.id, part.nodeIds.size() }); - newPartIds.push_back(part.id); - emit partAdded(part.id); - } - for (auto edgeIdIt = node->edgeIds.begin(); edgeIdIt != node->edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - continue; - } - dust3d::Uuid neighborId = edgeIt->second.neighborOf(nodeId); - auto nodeIt = nodeMap.find(neighborId); - if (nodeIt == nodeMap.end()) { - continue; - } - nodeIt->second.edgeIds.erase(std::remove(nodeIt->second.edgeIds.begin(), nodeIt->second.edgeIds.end(), *edgeIdIt), nodeIt->second.edgeIds.end()); - edgeMap.erase(*edgeIdIt); - emit edgeRemoved(*edgeIdIt); - } - nodeMap.erase(nodeId); - emit nodeRemoved(nodeId); - removePart(oldPartId); - - if (!newPartNodeNumMap.empty()) { - std::sort(newPartNodeNumMap.begin(), newPartNodeNumMap.end(), [&](const std::pair& first, const std::pair& second) { - return first.second > second.second; - }); - updateLinkedPart(oldPartId, newPartNodeNumMap[0].first); - } - - emit skeletonChanged(); -} - -void SkeletonDocument::addNode(float x, float y, float z, float radius, dust3d::Uuid fromNodeId) -{ - createNode(dust3d::Uuid::createUuid(), x, y, z, radius, fromNodeId); -} - -void SkeletonDocument::addNodeWithId(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId) -{ - createNode(nodeId, x, y, z, radius, fromNodeId); -} - -dust3d::Uuid SkeletonDocument::createNode(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId) -{ - dust3d::Uuid partId; - const SkeletonNode* fromNode = nullptr; - bool newPartAdded = false; - if (fromNodeId.isNull()) { - const auto newUuid = dust3d::Uuid::createUuid(); - SkeletonPart& part = partMap[newUuid]; - part.id = newUuid; - partId = part.id; - emit partAdded(partId); - newPartAdded = true; - } else { - fromNode = findNode(fromNodeId); - if (nullptr == fromNode) { - return dust3d::Uuid(); - } - partId = fromNode->partId; - if (isPartReadonly(partId)) - return dust3d::Uuid(); - auto part = partMap.find(partId); - if (part != partMap.end()) - part->second.dirty = true; - } - SkeletonNode node(nodeId); - node.partId = partId; - node.setRadius(radius); - node.setX(x); - node.setY(y); - node.setZ(z); - nodeMap[node.id] = node; - partMap[partId].nodeIds.push_back(node.id); - - emit nodeAdded(node.id); - - if (nullptr != fromNode) { - SkeletonEdge edge; - edge.partId = partId; - edge.nodeIds.push_back(fromNode->id); - edge.nodeIds.push_back(node.id); - edgeMap[edge.id] = edge; - - nodeMap[node.id].edgeIds.push_back(edge.id); - nodeMap[fromNode->id].edgeIds.push_back(edge.id); - - emit edgeAdded(edge.id); - } - - if (newPartAdded) - addPartToComponent(partId, m_currentCanvasComponentId); - - emit skeletonChanged(); - - return node.id; -} - -void SkeletonDocument::joinNodeAndNeiborsToGroup(std::vector* group, dust3d::Uuid nodeId, std::set* visitMap, dust3d::Uuid noUseEdgeId) -{ - if (nodeId.isNull() || visitMap->find(nodeId) != visitMap->end()) - return; - const SkeletonNode* node = findNode(nodeId); - if (nullptr == node) { - return; - } - visitMap->insert(nodeId); - group->push_back(nodeId); - for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { - if (noUseEdgeId == *edgeIt) - continue; - const SkeletonEdge* edge = findEdge(*edgeIt); - if (nullptr == edge) { - continue; - } - for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { - joinNodeAndNeiborsToGroup(group, *nodeIt, visitMap, noUseEdgeId); - } - } -} - -void SkeletonDocument::splitPartByNode(std::vector>* groups, dust3d::Uuid nodeId) -{ - const SkeletonNode* node = findNode(nodeId); - std::set visitMap; - visitMap.insert(nodeId); - for (auto edgeIt = node->edgeIds.begin(); edgeIt != node->edgeIds.end(); edgeIt++) { - std::vector group; - const SkeletonEdge* edge = findEdge(*edgeIt); - if (nullptr == edge) { - continue; - } - joinNodeAndNeiborsToGroup(&group, edge->neighborOf(nodeId), &visitMap, *edgeIt); - if (!group.empty()) - groups->push_back(group); - } -} - -void SkeletonDocument::splitPartByEdge(std::vector>* groups, dust3d::Uuid edgeId) -{ - const SkeletonEdge* edge = findEdge(edgeId); - if (nullptr == edge) { - return; - } - std::set visitMap; - for (auto nodeIt = edge->nodeIds.begin(); nodeIt != edge->nodeIds.end(); nodeIt++) { - std::vector group; - joinNodeAndNeiborsToGroup(&group, *nodeIt, &visitMap, edgeId); - if (!group.empty()) - groups->push_back(group); - } -} - -const SkeletonComponent* SkeletonDocument::findComponentParent(dust3d::Uuid componentId) const -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return nullptr; - } - - if (component->second.parentId.isNull()) - return &rootComponent; - - return (SkeletonComponent*)findComponent(component->second.parentId); -} - -dust3d::Uuid SkeletonDocument::findComponentParentId(dust3d::Uuid componentId) const -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return dust3d::Uuid(); - } - - return component->second.parentId; -} - -void SkeletonDocument::moveComponentUp(dust3d::Uuid componentId) -{ - SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); - if (nullptr == parent) - return; - - dust3d::Uuid parentId = findComponentParentId(componentId); - - parent->moveChildUp(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void SkeletonDocument::moveComponentDown(dust3d::Uuid componentId) -{ - SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); - if (nullptr == parent) - return; - - dust3d::Uuid parentId = findComponentParentId(componentId); - - parent->moveChildDown(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void SkeletonDocument::moveComponentToTop(dust3d::Uuid componentId) -{ - SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); - if (nullptr == parent) - return; - - dust3d::Uuid parentId = findComponentParentId(componentId); - - parent->moveChildToTop(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void SkeletonDocument::moveComponentToBottom(dust3d::Uuid componentId) -{ - SkeletonComponent* parent = (SkeletonComponent*)findComponentParent(componentId); - if (nullptr == parent) - return; - - dust3d::Uuid parentId = findComponentParentId(componentId); - - parent->moveChildToBottom(componentId); - parent->dirty = true; - emit componentChildrenChanged(parentId); - emit skeletonChanged(); -} - -void SkeletonDocument::renameComponent(dust3d::Uuid componentId, QString name) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return; - } - - if (component->second.name == name) - return; - - if (!name.trimmed().isEmpty()) - component->second.name = name; - emit componentNameChanged(componentId); - emit optionsChanged(); -} - -void SkeletonDocument::setComponentExpandState(dust3d::Uuid componentId, bool expanded) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return; - } - - if (component->second.expanded == expanded) - return; - - component->second.expanded = expanded; - emit componentExpandStateChanged(componentId); - emit optionsChanged(); -} - -void SkeletonDocument::ungroupComponent(const dust3d::Uuid& componentId) -{ - if (componentId.isNull()) - return; - SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); - if (nullptr == component) { - dust3dDebug << "Component not found:" << componentId.toString(); - return; - } - if (component->childrenIds.empty()) - return; - auto childrenIds = component->childrenIds; - SkeletonComponent* newParent = (SkeletonComponent*)findComponentParent(componentId); - if (nullptr == newParent) { - dust3dDebug << "Expected parent component to be found, component:" << componentId.toString(); - return; - } - auto newParentId = newParent->id; - newParent->replaceChildWithOthers(componentId, childrenIds); - for (const auto& childId : childrenIds) { - SkeletonComponent* child = (SkeletonComponent*)findComponent(childId); - if (nullptr == child) - continue; - child->parentId = newParentId; - } - componentMap.erase(componentId); - emit componentRemoved(componentId); - emit componentChildrenChanged(newParentId); - emit skeletonChanged(); -} - -void SkeletonDocument::groupComponents(const std::vector& componentIds) -{ - if (componentIds.empty()) - return; - - dust3d::Uuid newParentId; - - SkeletonComponent newParent(dust3d::Uuid::createUuid()); - newParentId = newParent.id; - - auto it = componentIds.begin(); - - SkeletonComponent* oldParent = (SkeletonComponent*)findComponentParent(*it); - if (nullptr == oldParent) { - dust3dDebug << "Expected parent component to be found, component:" << it->toString(); - return; - } - auto oldParentId = oldParent->id; - oldParent->replaceChild(*it, newParentId); - for (++it; it != componentIds.end(); ++it) { - oldParent->removeChild(*it); - } - - for (const auto& componentId : componentIds) { - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - continue; - } - component->second.parentId = newParentId; - newParent.addChild(componentId); - } - - newParent.parentId = oldParentId; - newParent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); - componentMap.emplace(newParentId, std::move(newParent)); - - emit componentChildrenChanged(oldParentId); - emit componentAdded(newParentId); - emit skeletonChanged(); -} - -void SkeletonDocument::createNewChildComponent(dust3d::Uuid parentComponentId) -{ - SkeletonComponent* parentComponent = (SkeletonComponent*)findComponent(parentComponentId); - if (!parentComponent->linkToPartId.isNull()) { - parentComponentId = parentComponent->parentId; - parentComponent = (SkeletonComponent*)findComponent(parentComponentId); - } - - SkeletonComponent newComponent(dust3d::Uuid::createUuid()); - newComponent.name = tr("Group") + " " + QString::number(componentMap.size() - partMap.size() + 1); - - parentComponent->addChild(newComponent.id); - newComponent.parentId = parentComponentId; - - auto newComponentId = newComponent.id; - componentMap.emplace(newComponentId, std::move(newComponent)); - - emit componentChildrenChanged(parentComponentId); - emit componentAdded(newComponentId); - emit optionsChanged(); -} - -void SkeletonDocument::removePart(dust3d::Uuid partId) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - return; - } - - if (!part->second.componentId.isNull()) { - removeComponent(part->second.componentId); - return; - } - - removePartDontCareComponent(partId); -} - -void SkeletonDocument::removePartDontCareComponent(dust3d::Uuid partId) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - return; - } - - std::vector removedNodeIds; - std::vector removedEdgeIds; - - for (auto nodeIt = nodeMap.begin(); nodeIt != nodeMap.end();) { - if (nodeIt->second.partId != partId) { - nodeIt++; - continue; - } - removedNodeIds.push_back(nodeIt->second.id); - nodeIt = nodeMap.erase(nodeIt); - } - - for (auto edgeIt = edgeMap.begin(); edgeIt != edgeMap.end();) { - if (edgeIt->second.partId != partId) { - edgeIt++; - continue; - } - removedEdgeIds.push_back(edgeIt->second.id); - edgeIt = edgeMap.erase(edgeIt); - } - - partMap.erase(part); - - for (const auto& nodeId : removedNodeIds) { - emit nodeRemoved(nodeId); - } - for (const auto& edgeId : removedEdgeIds) { - emit edgeRemoved(edgeId); - } - emit partRemoved(partId); -} - -void SkeletonDocument::addPartToComponent(dust3d::Uuid partId, dust3d::Uuid componentId) -{ - SkeletonComponent child(dust3d::Uuid::createUuid()); - - if (!componentId.isNull()) { - auto parentComponent = componentMap.find(componentId); - if (parentComponent == componentMap.end()) { - componentId = dust3d::Uuid(); - rootComponent.addChild(child.id); - } else { - parentComponent->second.addChild(child.id); - } - } else { - rootComponent.addChild(child.id); - } - - partMap[partId].componentId = child.id; - child.linkToPartId = partId; - child.parentId = componentId; - auto childId = child.id; - componentMap.emplace(childId, std::move(child)); - - emit componentChildrenChanged(componentId); - emit componentAdded(childId); -} - -void SkeletonDocument::removeComponent(dust3d::Uuid componentId) -{ - removeComponentRecursively(componentId); - emit skeletonChanged(); -} - -void SkeletonDocument::removeComponentRecursively(dust3d::Uuid componentId) -{ - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return; - } - - if (!component->second.linkToPartId.isNull()) { - removePartDontCareComponent(component->second.linkToPartId); - } - - auto childrenIds = component->second.childrenIds; - for (const auto& childId : childrenIds) { - removeComponentRecursively(childId); - } - - dust3d::Uuid parentId = component->second.parentId; - if (!parentId.isNull()) { - auto parentComponent = componentMap.find(parentId); - if (parentComponent != componentMap.end()) { - parentComponent->second.dirty = true; - parentComponent->second.removeChild(componentId); - } - } else { - rootComponent.removeChild(componentId); - } - - componentMap.erase(component); - emit componentRemoved(componentId); - emit componentChildrenChanged(parentId); -} - -void SkeletonDocument::setCurrentCanvasComponentId(dust3d::Uuid componentId) -{ - m_currentCanvasComponentId = componentId; - const SkeletonComponent* component = findComponent(m_currentCanvasComponentId); - if (nullptr == component) { - m_currentCanvasComponentId = dust3d::Uuid(); - } else { - if (!component->linkToPartId.isNull()) { - m_currentCanvasComponentId = component->parentId; - component = findComponent(m_currentCanvasComponentId); - } - } -} - -void SkeletonDocument::addComponent(dust3d::Uuid parentId) -{ - SkeletonComponent component(dust3d::Uuid::createUuid()); - - if (!parentId.isNull()) { - auto parentComponent = componentMap.find(parentId); - if (parentComponent == componentMap.end()) { - return; - } - parentComponent->second.addChild(component.id); - } else { - rootComponent.addChild(component.id); - } - - component.parentId = parentId; - auto componentId = component.id; - componentMap.emplace(componentId, std::move(component)); - - emit componentChildrenChanged(parentId); - emit componentAdded(componentId); -} - -bool SkeletonDocument::isDescendantComponent(dust3d::Uuid componentId, dust3d::Uuid suspiciousId) -{ - const SkeletonComponent* loopComponent = findComponentParent(suspiciousId); - while (nullptr != loopComponent) { - if (loopComponent->id == componentId) - return true; - loopComponent = findComponentParent(loopComponent->parentId); - } - return false; -} - -void SkeletonDocument::moveComponent(dust3d::Uuid componentId, dust3d::Uuid toParentId) -{ - if (componentId == toParentId) - return; - - auto component = componentMap.find(componentId); - if (component == componentMap.end()) { - return; - } - - if (component->second.parentId == toParentId) - return; - - if (isDescendantComponent(componentId, toParentId)) - return; - - if (component->second.parentId.isNull()) { - rootComponent.removeChild(componentId); - emit componentChildrenChanged(rootComponent.id); - } else { - auto oldParent = componentMap.find(component->second.parentId); - if (oldParent != componentMap.end()) { - oldParent->second.dirty = true; - oldParent->second.removeChild(componentId); - emit componentChildrenChanged(oldParent->second.id); - } - } - - component->second.parentId = toParentId; - - if (toParentId.isNull()) { - rootComponent.addChild(componentId); - emit componentChildrenChanged(rootComponent.id); - } else { - auto newParent = componentMap.find(toParentId); - if (newParent != componentMap.end()) { - newParent->second.dirty = true; - newParent->second.addChild(componentId); - emit componentChildrenChanged(newParent->second.id); - } - } - - emit skeletonChanged(); -} - -void SkeletonDocument::setPartLockState(dust3d::Uuid partId, bool locked) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - return; - } - if (part->second.locked == locked) - return; - part->second.locked = locked; - emit partLockStateChanged(partId); - emit optionsChanged(); -} - -void SkeletonDocument::setPartVisibleState(dust3d::Uuid partId, bool visible) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - return; - } - if (part->second.visible == visible) - return; - part->second.visible = visible; - emit partVisibleStateChanged(partId); - emit optionsChanged(); -} - -void SkeletonDocument::setPartDisableState(dust3d::Uuid partId, bool disabled) -{ - auto part = partMap.find(partId); - if (part == partMap.end()) { - return; - } - if (part->second.disabled == disabled) - return; - part->second.disabled = disabled; - part->second.dirty = true; - emit partDisableStateChanged(partId); - emit skeletonChanged(); -} - -void SkeletonDocument::collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const -{ - const SkeletonComponent* component = findComponent(componentId); - if (nullptr == component) - return; - - if (!component->linkToPartId.isNull()) { - partIds.push_back(component->linkToPartId); - return; - } - - for (const auto& childId : component->childrenIds) { - collectComponentDescendantParts(childId, partIds); - } -} - -void SkeletonDocument::collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector& componentIds) const -{ - const SkeletonComponent* component = findComponent(componentId); - if (nullptr == component) - return; - - if (!component->linkToPartId.isNull()) { - return; - } - - for (const auto& childId : component->childrenIds) { - componentIds.push_back(childId); - collectComponentDescendantComponents(childId, componentIds); - } -} - -void SkeletonDocument::hideOtherComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - std::set partIdSet; - for (const auto& partId : partIds) { - partIdSet.insert(partId); - } - for (const auto& part : partMap) { - if (partIdSet.find(part.first) != partIdSet.end()) - continue; - setPartVisibleState(part.first, false); - } -} - -void SkeletonDocument::lockOtherComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - std::set partIdSet; - for (const auto& partId : partIds) { - partIdSet.insert(partId); - } - for (const auto& part : partMap) { - if (partIdSet.find(part.first) != partIdSet.end()) - continue; - setPartLockState(part.first, true); - } -} - -void SkeletonDocument::hideAllComponents() -{ - for (const auto& part : partMap) { - setPartVisibleState(part.first, false); - } -} - -void SkeletonDocument::showAllComponents() -{ - for (const auto& part : partMap) { - setPartVisibleState(part.first, true); - } -} - -void SkeletonDocument::showOrHideAllComponents() -{ - bool foundVisiblePart = false; - for (const auto& part : partMap) { - if (part.second.visible) { - foundVisiblePart = true; - } - } - if (foundVisiblePart) - hideAllComponents(); - else - showAllComponents(); -} - -void SkeletonDocument::collapseAllComponents() -{ - for (const auto& component : componentMap) { - if (!component.second.linkToPartId.isNull()) - continue; - setComponentExpandState(component.first, false); - } -} - -void SkeletonDocument::expandAllComponents() -{ - for (const auto& component : componentMap) { - if (!component.second.linkToPartId.isNull()) - continue; - setComponentExpandState(component.first, true); - } -} - -void SkeletonDocument::lockAllComponents() -{ - for (const auto& part : partMap) { - setPartLockState(part.first, true); - } -} - -void SkeletonDocument::unlockAllComponents() -{ - for (const auto& part : partMap) { - setPartLockState(part.first, false); - } -} - -void SkeletonDocument::hideDescendantComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto& partId : partIds) { - setPartVisibleState(partId, false); - } -} - -void SkeletonDocument::showDescendantComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto& partId : partIds) { - setPartVisibleState(partId, true); - } -} - -void SkeletonDocument::lockDescendantComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto& partId : partIds) { - setPartLockState(partId, true); - } -} - -void SkeletonDocument::unlockDescendantComponents(dust3d::Uuid componentId) -{ - std::vector partIds; - collectComponentDescendantParts(componentId, partIds); - for (const auto& partId : partIds) { - setPartLockState(partId, false); - } -} - -void SkeletonDocument::scaleNodeByAddRadius(dust3d::Uuid nodeId, float amount) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - return; - } - if (isPartReadonly(it->second.partId)) - return; - if (radiusLocked) - return; - it->second.setRadius(it->second.radius + amount); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeRadiusChanged(nodeId); - emit skeletonChanged(); -} - -bool SkeletonDocument::isPartReadonly(dust3d::Uuid partId) const -{ - const SkeletonPart* part = findPart(partId); - if (nullptr == part) { - return true; - } - return part->locked || !part->visible; -} - -void SkeletonDocument::moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - return; - } - if (m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId)) - return; - bool changed = false; - if (!(m_allPositionRelatedLocksEnabled && xlocked)) { - it->second.addX(x); - changed = true; - } - if (!(m_allPositionRelatedLocksEnabled && ylocked)) { - it->second.addY(y); - changed = true; - } - if (!(m_allPositionRelatedLocksEnabled && zlocked)) { - it->second.addZ(z); - changed = true; - } - if (!changed) - return; - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - -void SkeletonDocument::moveOriginBy(float x, float y, float z) -{ - if (!(m_allPositionRelatedLocksEnabled && xlocked)) - addOriginX(x); - if (!(m_allPositionRelatedLocksEnabled && ylocked)) - addOriginY(y); - if (!(m_allPositionRelatedLocksEnabled && zlocked)) - addOriginZ(z); - markAllDirty(); - emit originChanged(); - emit skeletonChanged(); -} - -void SkeletonDocument::setNodeOrigin(dust3d::Uuid nodeId, float x, float y, float z) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - return; - } - if ((m_allPositionRelatedLocksEnabled && isPartReadonly(it->second.partId))) - return; - if (!(m_allPositionRelatedLocksEnabled && xlocked)) - it->second.setX(x); - if (!(m_allPositionRelatedLocksEnabled && ylocked)) - it->second.setY(y); - if (!(m_allPositionRelatedLocksEnabled && zlocked)) - it->second.setZ(z); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - -void SkeletonDocument::setNodeRadius(dust3d::Uuid nodeId, float radius) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - return; - } - if (isPartReadonly(it->second.partId)) - return; - if (!radiusLocked) - it->second.setRadius(radius); - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeRadiusChanged(nodeId); - emit skeletonChanged(); -} - -void SkeletonDocument::switchNodeXZ(dust3d::Uuid nodeId) -{ - auto it = nodeMap.find(nodeId); - if (it == nodeMap.end()) { - return; - } - if (isPartReadonly(it->second.partId)) - return; - { - float oldX = it->second.getX(); - float oldZ = it->second.getZ(); - it->second.setX(oldZ); - it->second.setZ(oldX); - } - auto part = partMap.find(it->second.partId); - if (part != partMap.end()) - part->second.dirty = true; - emit nodeOriginChanged(nodeId); - emit skeletonChanged(); -} - -const SkeletonComponent* SkeletonDocument::findComponent(dust3d::Uuid componentId) const -{ - if (componentId.isNull()) - return &rootComponent; - auto it = componentMap.find(componentId); - if (it == componentMap.end()) - return nullptr; - return &it->second; -} - -void SkeletonDocument::addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId) -{ - if (findEdgeByNodes(fromNodeId, toNodeId)) { - return; - } - - const SkeletonNode* fromNode = nullptr; - const SkeletonNode* toNode = nullptr; - bool toPartRemoved = false; - - fromNode = findNode(fromNodeId); - if (nullptr == fromNode) { - return; - } - - if (isPartReadonly(fromNode->partId)) - return; - - toNode = findNode(toNodeId); - if (nullptr == toNode) { - return; - } - - if (isPartReadonly(toNode->partId)) - return; - - dust3d::Uuid toPartId = toNode->partId; - - auto fromPart = partMap.find(fromNode->partId); - if (fromPart == partMap.end()) { - return; - } - - fromPart->second.dirty = true; - - if (fromNode->partId != toNode->partId) { - toPartRemoved = true; - std::vector toGroup; - std::set visitMap; - joinNodeAndNeiborsToGroup(&toGroup, toNodeId, &visitMap); - for (auto nodeIdIt = toGroup.begin(); nodeIdIt != toGroup.end(); nodeIdIt++) { - auto nodeIt = nodeMap.find(*nodeIdIt); - if (nodeIt == nodeMap.end()) { - continue; - } - nodeIt->second.partId = fromNode->partId; - fromPart->second.nodeIds.push_back(nodeIt->first); - for (auto edgeIdIt = nodeIt->second.edgeIds.begin(); edgeIdIt != nodeIt->second.edgeIds.end(); edgeIdIt++) { - auto edgeIt = edgeMap.find(*edgeIdIt); - if (edgeIt == edgeMap.end()) { - continue; - } - edgeIt->second.partId = fromNode->partId; - } - } - } - - SkeletonEdge edge; - edge.partId = fromNode->partId; - edge.nodeIds.push_back(fromNode->id); - edge.nodeIds.push_back(toNodeId); - edgeMap[edge.id] = edge; - - nodeMap[toNodeId].edgeIds.push_back(edge.id); - nodeMap[fromNode->id].edgeIds.push_back(edge.id); - - emit edgeAdded(edge.id); - - if (toPartRemoved) { - updateLinkedPart(toPartId, fromNode->partId); - removePart(toPartId); - } - - emit skeletonChanged(); -} - -void SkeletonDocument::updateLinkedPart(dust3d::Uuid oldPartId, dust3d::Uuid newPartId) -{ - for (auto& partIt : partMap) { - if (partIt.second.cutFaceLinkedId == oldPartId) { - partIt.second.dirty = true; - partIt.second.setCutFaceLinkedId(newPartId); - } - } - std::set dirtyPartIds; - for (auto& nodeIt : nodeMap) { - if (nodeIt.second.cutFaceLinkedId == oldPartId) { - dirtyPartIds.insert(nodeIt.second.partId); - nodeIt.second.setCutFaceLinkedId(newPartId); - } - } - for (const auto& partId : dirtyPartIds) { - SkeletonPart* part = (SkeletonPart*)findPart(partId); - if (nullptr == part) - continue; - part->dirty = true; - } -} - -void SkeletonDocument::enableAllPositionRelatedLocks() -{ - m_allPositionRelatedLocksEnabled = true; -} - -void SkeletonDocument::disableAllPositionRelatedLocks() -{ - m_allPositionRelatedLocksEnabled = false; -} - -void SkeletonDocument::resetDirtyFlags() -{ - for (auto& part : partMap) { - part.second.dirty = false; - } - for (auto& component : componentMap) { - component.second.dirty = false; - } -} - -void SkeletonDocument::markAllDirty() -{ - for (auto& part : partMap) { - part.second.dirty = true; - } -} - -void SkeletonDocument::setXlockState(bool locked) -{ - if (xlocked == locked) - return; - xlocked = locked; - emit xlockStateChanged(); -} - -void SkeletonDocument::setYlockState(bool locked) -{ - if (ylocked == locked) - return; - ylocked = locked; - emit ylockStateChanged(); -} - -void SkeletonDocument::setZlockState(bool locked) -{ - if (zlocked == locked) - return; - zlocked = locked; - emit zlockStateChanged(); -} - -void SkeletonDocument::setRadiusLockState(bool locked) -{ - if (radiusLocked == locked) - return; - radiusLocked = locked; - emit radiusLockStateChanged(); -} - -void SkeletonDocument::setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image) -{ - SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); - if (nullptr == component) - return; - component->isPreviewImageDecorationObsolete = true; - component->previewImage = std::move(image); -} - -void SkeletonDocument::setComponentPreviewPixmap(const dust3d::Uuid& componentId, const QPixmap& pixmap) -{ - SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); - if (nullptr == component) - return; - component->previewPixmap = pixmap; - emit componentPreviewPixmapChanged(componentId); -} - -void SkeletonDocument::setComponentPreviewMesh(const dust3d::Uuid& componentId, std::unique_ptr mesh) -{ - SkeletonComponent* component = (SkeletonComponent*)findComponent(componentId); - if (nullptr == component) - return; - component->updatePreviewMesh(std::move(mesh)); - emit componentPreviewMeshChanged(componentId); -} diff --git a/application/sources/skeleton_document.h b/application/sources/skeleton_document.h deleted file mode 100644 index 9c794710..00000000 --- a/application/sources/skeleton_document.h +++ /dev/null @@ -1,757 +0,0 @@ -#ifndef DUST3D_APPLICATION_SKELETON_DOCUMENT_H_ -#define DUST3D_APPLICATION_SKELETON_DOCUMENT_H_ - -#include "debug.h" -#include "mesh_generator.h" -#include "model_mesh.h" -#include "theme.h" -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -class SkeletonNode { -public: - SkeletonNode(const dust3d::Uuid& withId = dust3d::Uuid()) - : radius(0) - , cutRotation(0.0) - , cutFace(dust3d::CutFace::Quad) - , hasCutFaceSettings(false) - , m_x(0) - , m_y(0) - , m_z(0) - { - id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; - } - void setRadius(float toRadius) - { - if (toRadius < MeshGenerator::m_minimalRadius) - toRadius = MeshGenerator::m_minimalRadius; - else if (toRadius > 1) - toRadius = 1; - radius = toRadius; - } - void setCutRotation(float toRotation) - { - if (toRotation < -1) - toRotation = -1; - else if (toRotation > 1) - toRotation = 1; - cutRotation = toRotation; - hasCutFaceSettings = true; - } - void setCutFace(dust3d::CutFace face) - { - cutFace = face; - cutFaceLinkedId = dust3d::Uuid(); - hasCutFaceSettings = true; - } - void setCutFaceLinkedId(const dust3d::Uuid& linkedId) - { - if (linkedId.isNull()) { - clearCutFaceSettings(); - return; - } - cutFace = dust3d::CutFace::UserDefined; - cutFaceLinkedId = linkedId; - hasCutFaceSettings = true; - } - void clearCutFaceSettings() - { - cutFace = dust3d::CutFace::Quad; - cutFaceLinkedId = dust3d::Uuid(); - cutRotation = 0; - hasCutFaceSettings = false; - } - float getX(bool rotated = false) const - { - if (rotated) - return m_y; - return m_x; - } - float getY(bool rotated = false) const - { - if (rotated) - return m_x; - return m_y; - } - float getZ(bool rotated = false) const - { - (void)rotated; - return m_z; - } - void setX(float x) - { - m_x = x; - } - void setY(float y) - { - m_y = y; - } - void setZ(float z) - { - m_z = z; - } - void addX(float x) - { - m_x += x; - } - void addY(float y) - { - m_y += y; - } - void addZ(float z) - { - m_z += z; - } - dust3d::Uuid id; - dust3d::Uuid partId; - QString name; - float radius; - float cutRotation; - dust3d::CutFace cutFace; - dust3d::Uuid cutFaceLinkedId; - bool hasCutFaceSettings; - std::vector edgeIds; - -private: - float m_x; - float m_y; - float m_z; -}; - -class SkeletonEdge { -public: - SkeletonEdge(const dust3d::Uuid& withId = dust3d::Uuid()) - { - id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; - } - dust3d::Uuid id; - dust3d::Uuid partId; - QString name; - std::vector nodeIds; - dust3d::Uuid neighborOf(dust3d::Uuid nodeId) const - { - if (nodeIds.size() != 2) - return dust3d::Uuid(); - return nodeIds[0] == nodeId ? nodeIds[1] : nodeIds[0]; - } -}; - -class SkeletonPart { -public: - dust3d::Uuid id; - QString name; - bool visible; - bool locked; - bool subdived; - bool disabled; - bool xMirrored; - dust3d::PartBase base; - float deformThickness; - float deformWidth; - bool deformUnified; - bool rounded; - bool chamfered; - QColor color; - bool hasColor; - dust3d::Uuid componentId; - std::vector nodeIds; - bool dirty; - float cutRotation; - dust3d::CutFace cutFace; - dust3d::Uuid cutFaceLinkedId; - dust3d::Uuid materialId; - dust3d::PartTarget target; - float colorSolubility; - float metalness; - float roughness; - float hollowThickness; - bool countershaded; - bool smooth; - SkeletonPart(const dust3d::Uuid& withId = dust3d::Uuid()) - : visible(true) - , locked(false) - , subdived(false) - , disabled(false) - , xMirrored(false) - , base(dust3d::PartBase::Average) - , deformThickness(1.0) - , deformWidth(1.0) - , deformUnified(false) - , rounded(false) - , chamfered(false) - , color(Qt::white) - , hasColor(false) - , dirty(true) - , cutRotation(0.0) - , cutFace(dust3d::CutFace::Quad) - , target(dust3d::PartTarget::Model) - , colorSolubility(0.0) - , metalness(0.0) - , roughness(1.0) - , hollowThickness(0.0) - , countershaded(false) - , smooth(false) - { - id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; - } - bool hasPolyFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasSmoothFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasSubdivFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasRoundEndFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasMirrorFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasChamferFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasRotationFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasHollowFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasCutFaceFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasLayerFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasTargetFunction() const - { - return true; - } - bool hasBaseFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasCombineModeFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasDeformFunction() const - { - return dust3d::PartTarget::Model == target; - } - bool hasColorFunction() const - { - return dust3d::PartTarget::Model == target; - } - void setDeformThickness(float toThickness) - { - if (toThickness < 0) - toThickness = 0; - else if (toThickness > 2) - toThickness = 2; - deformThickness = toThickness; - } - void setDeformWidth(float toWidth) - { - if (toWidth < 0) - toWidth = 0; - else if (toWidth > 2) - toWidth = 2; - deformWidth = toWidth; - } - void setCutRotation(float toRotation) - { - if (toRotation < -1) - toRotation = -1; - else if (toRotation > 1) - toRotation = 1; - cutRotation = toRotation; - } - void setCutFace(dust3d::CutFace face) - { - cutFace = face; - cutFaceLinkedId = dust3d::Uuid(); - } - void setCutFaceLinkedId(const dust3d::Uuid& linkedId) - { - if (linkedId.isNull()) { - setCutFace(dust3d::CutFace::Quad); - return; - } - cutFace = dust3d::CutFace::UserDefined; - cutFaceLinkedId = linkedId; - } - 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() || deformUnified; - } - bool colorSolubilityAdjusted() const - { - return fabs(colorSolubility - 0.0) >= 0.01; - } - bool metalnessAdjusted() const - { - return fabs(metalness - 0.0) >= 0.01; - } - bool roughnessAdjusted() const - { - return fabs(roughness - 1.0) >= 0.01; - } - bool cutRotationAdjusted() const - { - return fabs(cutRotation - 0.0) >= 0.01; - } - bool hollowThicknessAdjusted() const - { - return fabs(hollowThickness - 0.0) >= 0.01; - } - bool cutFaceAdjusted() const - { - return cutFace != dust3d::CutFace::Quad; - } - bool cutAdjusted() const - { - return cutRotationAdjusted() || cutFaceAdjusted() || hollowThicknessAdjusted(); - } - bool materialAdjusted() const - { - return !materialId.isNull(); - } - bool isEditVisible() const - { - return visible && !disabled; - } - void copyAttributes(const SkeletonPart& other) - { - visible = other.visible; - locked = other.locked; - subdived = other.subdived; - disabled = other.disabled; - xMirrored = other.xMirrored; - base = other.base; - deformThickness = other.deformThickness; - deformWidth = other.deformWidth; - rounded = other.rounded; - chamfered = other.chamfered; - color = other.color; - hasColor = other.hasColor; - cutRotation = other.cutRotation; - cutFace = other.cutFace; - cutFaceLinkedId = other.cutFaceLinkedId; - componentId = other.componentId; - dirty = other.dirty; - materialId = other.materialId; - target = other.target; - colorSolubility = other.colorSolubility; - countershaded = other.countershaded; - metalness = other.metalness; - roughness = other.roughness; - deformUnified = other.deformUnified; - smooth = other.smooth; - hollowThickness = other.hollowThickness; - } - -private: - Q_DISABLE_COPY(SkeletonPart); -}; - -enum class SkeletonDocumentEditMode { - Add = 0, - Select, - Paint, - Drag, - ZoomIn, - ZoomOut -}; - -enum class SkeletonProfile { - Unknown = 0, - Main, - Side -}; - -class SkeletonComponent { -public: - SkeletonComponent() - { - } - SkeletonComponent(const dust3d::Uuid& withId, const QString& linkData = QString(), const QString& linkDataType = QString()) - { - id = withId.isNull() ? dust3d::Uuid::createUuid() : withId; - if (!linkData.isEmpty()) { - if ("partId" == linkDataType) { - linkToPartId = dust3d::Uuid(linkData.toUtf8().constData()); - } - } - } - dust3d::Uuid id; - QString name; - dust3d::Uuid linkToPartId; - dust3d::Uuid parentId; - bool expanded = true; - dust3d::CombineMode combineMode = dust3d::CombineMode::Normal; - bool dirty = true; - std::vector childrenIds; - bool isPreviewMeshObsolete = false; - std::unique_ptr previewImage; - bool isPreviewImageDecorationObsolete = false; - QPixmap previewPixmap; - QString linkData() const - { - return linkToPartId.isNull() ? QString() : QString(linkToPartId.toString().c_str()); - } - QString linkDataType() const - { - return linkToPartId.isNull() ? QString() : QString("partId"); - } - void addChild(dust3d::Uuid childId) - { - if (m_childrenIdSet.find(childId) != m_childrenIdSet.end()) - return; - m_childrenIdSet.insert(childId); - childrenIds.push_back(childId); - } - void replaceChildWithOthers(const dust3d::Uuid& childId, const std::vector& others) - { - if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) - return; - m_childrenIdSet.erase(childId); - std::vector candidates; - for (const auto& it : others) { - if (m_childrenIdSet.find(it) == m_childrenIdSet.end()) { - m_childrenIdSet.insert(it); - candidates.emplace_back(it); - } - } - for (size_t i = 0; i < childrenIds.size(); ++i) { - if (childId == childrenIds[i]) { - size_t newAddSize = candidates.size() - 1; - if (newAddSize > 0) { - size_t oldSize = childrenIds.size(); - childrenIds.resize(childrenIds.size() + newAddSize); - for (int j = (int)oldSize - 1; j > (int)i; --j) { - childrenIds[j + newAddSize] = childrenIds[j]; - } - } - for (size_t k = 0; k < candidates.size(); ++k) - childrenIds[i + k] = candidates[k]; - break; - } - } - } - void removeChild(dust3d::Uuid childId) - { - if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) - return; - m_childrenIdSet.erase(childId); - auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (findResult != childrenIds.end()) - childrenIds.erase(findResult); - } - void replaceChild(dust3d::Uuid childId, dust3d::Uuid newId) - { - if (m_childrenIdSet.find(childId) == m_childrenIdSet.end()) - return; - if (m_childrenIdSet.find(newId) != m_childrenIdSet.end()) - return; - m_childrenIdSet.erase(childId); - m_childrenIdSet.insert(newId); - auto findResult = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (findResult != childrenIds.end()) - *findResult = newId; - } - void moveChildUp(dust3d::Uuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == 0) - return; - std::swap(childrenIds[index - 1], childrenIds[index]); - } - void moveChildDown(dust3d::Uuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == (int)childrenIds.size() - 1) - return; - std::swap(childrenIds[index], childrenIds[index + 1]); - } - void moveChildToTop(dust3d::Uuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == 0) - return; - for (int i = index; i >= 1; i--) - std::swap(childrenIds[i - 1], childrenIds[i]); - } - void moveChildToBottom(dust3d::Uuid childId) - { - auto it = std::find(childrenIds.begin(), childrenIds.end(), childId); - if (it == childrenIds.end()) { - return; - } - - auto index = std::distance(childrenIds.begin(), it); - if (index == (int)childrenIds.size() - 1) - return; - for (int i = index; i <= (int)childrenIds.size() - 2; i++) - std::swap(childrenIds[i], childrenIds[i + 1]); - } - void updatePreviewMesh(std::unique_ptr mesh) - { - m_previewMesh = std::move(mesh); - isPreviewMeshObsolete = true; - } - ModelMesh* takePreviewMesh() const - { - if (nullptr == m_previewMesh) - return nullptr; - return new ModelMesh(*m_previewMesh); - } - -private: - std::unique_ptr m_previewMesh; - std::set m_childrenIdSet; -}; - -class SkeletonDocument : public QObject { - Q_OBJECT -signals: - void partAdded(dust3d::Uuid partId); - void nodeAdded(dust3d::Uuid nodeId); - void edgeAdded(dust3d::Uuid edgeId); - void partRemoved(dust3d::Uuid partId); - void partLockStateChanged(dust3d::Uuid partId); - void partVisibleStateChanged(dust3d::Uuid partId); - void partDisableStateChanged(dust3d::Uuid partId); - void componentNameChanged(dust3d::Uuid componentId); - void componentChildrenChanged(dust3d::Uuid componentId); - void componentRemoved(dust3d::Uuid componentId); - void componentAdded(dust3d::Uuid componentId); - void componentExpandStateChanged(dust3d::Uuid componentId); - void componentPreviewMeshChanged(const dust3d::Uuid& componentId); - void componentPreviewPixmapChanged(const dust3d::Uuid& componentId); - void nodeRemoved(dust3d::Uuid nodeId); - void edgeRemoved(dust3d::Uuid edgeId); - void nodeRadiusChanged(dust3d::Uuid nodeId); - void nodeOriginChanged(dust3d::Uuid nodeId); - void edgeReversed(dust3d::Uuid edgeId); - void originChanged(); - void skeletonChanged(); - void optionsChanged(); - void xlockStateChanged(); - void ylockStateChanged(); - void zlockStateChanged(); - void radiusLockStateChanged(); - -public: - SkeletonDocumentEditMode editMode = SkeletonDocumentEditMode::Select; - bool xlocked = false; - bool ylocked = false; - bool zlocked = false; - bool radiusLocked = false; - QImage turnaround; - QByteArray turnaroundPngByteArray; - std::map partMap; - std::map nodeMap; - std::map edgeMap; - std::map componentMap; - SkeletonComponent rootComponent; - - const SkeletonNode* findNode(dust3d::Uuid nodeId) const; - const SkeletonEdge* findEdge(dust3d::Uuid edgeId) const; - const SkeletonPart* findPart(dust3d::Uuid partId) const; - const SkeletonEdge* findEdgeByNodes(dust3d::Uuid firstNodeId, dust3d::Uuid secondNodeId) const; - void findAllNeighbors(dust3d::Uuid nodeId, std::set& neighbors) const; - bool isNodeConnectable(dust3d::Uuid nodeId) const; - const SkeletonComponent* findComponent(dust3d::Uuid componentId) const; - const SkeletonComponent* findComponentParent(dust3d::Uuid componentId) const; - dust3d::Uuid findComponentParentId(dust3d::Uuid componentId) const; - void collectComponentDescendantParts(dust3d::Uuid componentId, std::vector& partIds) const; - void collectComponentDescendantComponents(dust3d::Uuid componentId, std::vector& componentIds) const; - void setComponentPreviewMesh(const dust3d::Uuid& componentId, std::unique_ptr mesh); - void setComponentPreviewImage(const dust3d::Uuid& componentId, std::unique_ptr image); - void resetDirtyFlags(); - void markAllDirty(); - - virtual bool undoable() const = 0; - virtual bool redoable() const = 0; - virtual bool hasPastableNodesInClipboard() const = 0; - virtual bool originSettled() const = 0; - virtual bool isNodeEditable(dust3d::Uuid nodeId) const = 0; - virtual bool isEdgeEditable(dust3d::Uuid edgeId) const = 0; - virtual bool isNodeDeactivated(dust3d::Uuid nodeId) const - { - (void)nodeId; - return false; - }; - virtual bool isEdgeDeactivated(dust3d::Uuid edgeId) const - { - (void)edgeId; - return false; - }; - virtual void copyNodes(std::set nodeIdSet) const = 0; - - float getOriginX(bool rotated = false) const - { - if (rotated) - return m_originY; - return m_originX; - } - float getOriginY(bool rotated = false) const - { - if (rotated) - return m_originX; - return m_originY; - } - float getOriginZ(bool rotated = false) const - { - (void)rotated; - return m_originZ; - } - void setOriginX(float originX) - { - m_originX = originX; - } - void setOriginY(float originY) - { - m_originY = originY; - } - void setOriginZ(float originZ) - { - m_originZ = originZ; - } - void addOriginX(float originX) - { - m_originX += originX; - } - void addOriginY(float originY) - { - m_originY += originY; - } - void addOriginZ(float originZ) - { - m_originZ += originZ; - } - -public slots: - virtual void undo() = 0; - virtual void redo() = 0; - virtual void paste() = 0; - - void removeNode(dust3d::Uuid nodeId); - void removeEdge(dust3d::Uuid edgeId); - void removePart(dust3d::Uuid partId); - void addNodeWithId(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); - void addNode(float x, float y, float z, float radius, dust3d::Uuid fromNodeId); - void scaleNodeByAddRadius(dust3d::Uuid nodeId, float amount); - void moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z); - void setNodeOrigin(dust3d::Uuid nodeId, float x, float y, float z); - void setNodeRadius(dust3d::Uuid nodeId, float radius); - void switchNodeXZ(dust3d::Uuid nodeId); - void moveOriginBy(float x, float y, float z); - void addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId); - void moveComponentUp(dust3d::Uuid componentId); - void moveComponentDown(dust3d::Uuid componentId); - void moveComponentToTop(dust3d::Uuid componentId); - void moveComponentToBottom(dust3d::Uuid componentId); - void renameComponent(dust3d::Uuid componentId, QString name); - void removeComponent(dust3d::Uuid componentId); - void addComponent(dust3d::Uuid parentId); - void moveComponent(dust3d::Uuid componentId, dust3d::Uuid toParentId); - void setCurrentCanvasComponentId(dust3d::Uuid componentId); - void groupComponents(const std::vector& componentIds); - void ungroupComponent(const dust3d::Uuid& componentId); - void createNewChildComponent(dust3d::Uuid parentComponentId); - void setComponentExpandState(dust3d::Uuid componentId, bool expanded); - void hideOtherComponents(dust3d::Uuid componentId); - void lockOtherComponents(dust3d::Uuid componentId); - void hideAllComponents(); - void showAllComponents(); - void showOrHideAllComponents(); - void collapseAllComponents(); - void expandAllComponents(); - void lockAllComponents(); - void unlockAllComponents(); - void hideDescendantComponents(dust3d::Uuid componentId); - void showDescendantComponents(dust3d::Uuid componentId); - void lockDescendantComponents(dust3d::Uuid componentId); - void unlockDescendantComponents(dust3d::Uuid componentId); - void setComponentPreviewPixmap(const dust3d::Uuid& componentId, const QPixmap& pixmap); - void setPartLockState(dust3d::Uuid partId, bool locked); - void setPartVisibleState(dust3d::Uuid partId, bool visible); - void setPartDisableState(dust3d::Uuid partId, bool disabled); - void enableAllPositionRelatedLocks(); - void disableAllPositionRelatedLocks(); - bool isPartReadonly(dust3d::Uuid partId) const; - void breakEdge(dust3d::Uuid edgeId); - void reduceNode(dust3d::Uuid nodeId); - void reverseEdge(dust3d::Uuid edgeId); - void setXlockState(bool locked); - void setYlockState(bool locked); - void setZlockState(bool locked); - void setRadiusLockState(bool locked); - -private: - float m_originX = 0; - float m_originY = 0; - float m_originZ = 0; - - dust3d::Uuid m_currentCanvasComponentId; - bool m_allPositionRelatedLocksEnabled = true; - - void splitPartByNode(std::vector>* groups, dust3d::Uuid nodeId); - void joinNodeAndNeiborsToGroup(std::vector* group, dust3d::Uuid nodeId, std::set* visitMap, dust3d::Uuid noUseEdgeId = dust3d::Uuid()); - void splitPartByEdge(std::vector>* groups, dust3d::Uuid edgeId); - void removePartDontCareComponent(dust3d::Uuid partId); - void addPartToComponent(dust3d::Uuid partId, dust3d::Uuid componentId); - bool isDescendantComponent(dust3d::Uuid componentId, dust3d::Uuid suspiciousId); - void removeComponentRecursively(dust3d::Uuid componentId); - void updateLinkedPart(dust3d::Uuid oldPartId, dust3d::Uuid newPartId); - dust3d::Uuid createNode(dust3d::Uuid nodeId, float x, float y, float z, float radius, dust3d::Uuid fromNodeId); -}; - -#endif diff --git a/application/sources/skeleton_graphics_widget.cc b/application/sources/skeleton_graphics_widget.cc index e241936c..2e955110 100644 --- a/application/sources/skeleton_graphics_widget.cc +++ b/application/sources/skeleton_graphics_widget.cc @@ -13,7 +13,7 @@ #include #include -SkeletonGraphicsWidget::SkeletonGraphicsWidget(const SkeletonDocument* document) +SkeletonGraphicsWidget::SkeletonGraphicsWidget(const Document* document) : m_document(document) { setRenderHint(QPainter::Antialiasing, false); @@ -101,20 +101,20 @@ void SkeletonGraphicsWidget::shortcutEscape() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Add == m_document->editMode || SkeletonDocumentEditMode::Paint == m_document->editMode) { - emit setEditMode(SkeletonDocumentEditMode::Select); + if (DocumentEditMode::Add == m_document->editMode || DocumentEditMode::Paint == m_document->editMode) { + emit setEditMode(DocumentEditMode::Select); return; } } void SkeletonGraphicsWidget::showContextMenu(const QPoint& pos) { - if (SkeletonDocumentEditMode::Add == m_document->editMode) { - emit setEditMode(SkeletonDocumentEditMode::Select); + if (DocumentEditMode::Add == m_document->editMode) { + emit setEditMode(DocumentEditMode::Select); return; } - if (SkeletonDocumentEditMode::Select != m_document->editMode) { + if (DocumentEditMode::Select != m_document->editMode) { return; } @@ -122,19 +122,19 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint& pos) QAction addAction(tr("Add..."), this); connect(&addAction, &QAction::triggered, [=]() { - emit setEditMode(SkeletonDocumentEditMode::Add); + emit setEditMode(DocumentEditMode::Add); }); contextMenu.addAction(&addAction); QAction undoAction(tr("Undo"), this); if (m_document->undoable()) { - connect(&undoAction, &QAction::triggered, m_document, &SkeletonDocument::undo); + connect(&undoAction, &QAction::triggered, m_document, &Document::undo); contextMenu.addAction(&undoAction); } QAction redoAction(tr("Redo"), this); if (m_document->redoable()) { - connect(&redoAction, &QAction::triggered, m_document, &SkeletonDocument::redo); + connect(&redoAction, &QAction::triggered, m_document, &Document::redo); contextMenu.addAction(&redoAction); } @@ -182,7 +182,7 @@ void SkeletonGraphicsWidget::showContextMenu(const QPoint& pos) QAction pasteAction(tr("Paste"), this); if (m_document->hasPastableNodesInClipboard()) { - connect(&pasteAction, &QAction::triggered, m_document, &SkeletonDocument::paste); + connect(&pasteAction, &QAction::triggered, m_document, &Document::paste); contextMenu.addAction(&pasteAction); } @@ -657,7 +657,7 @@ const QImage* SkeletonGraphicsWidget::loadedTurnaroundImage() const void SkeletonGraphicsWidget::updateCursor() { - if (SkeletonDocumentEditMode::Add != m_document->editMode) { + if (DocumentEditMode::Add != m_document->editMode) { m_cursorEdgeItem->hide(); m_cursorNodeItem->hide(); } @@ -670,7 +670,7 @@ void SkeletonGraphicsWidget::updateCursor() void SkeletonGraphicsWidget::editModeChanged() { updateCursor(); - if (SkeletonDocumentEditMode::Add == m_document->editMode) { + if (DocumentEditMode::Add == m_document->editMode) { SkeletonGraphicsNodeItem* choosenNodeItem = nullptr; if (!m_rangeSelectionSet.empty()) { std::set nodeItems; @@ -771,7 +771,7 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent* event) return true; } - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_rangeSelectionStarted) { QPointF mouseScenePos = mouseEventScenePos(event); m_selectionItem->updateRange(m_rangeSelectionStartPos, mouseScenePos); @@ -782,7 +782,7 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent* event) } } - if (SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Add == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode || DocumentEditMode::Add == m_document->editMode) { // // > For overlapping nodes, you can make it a bit better by selecting the node center nearest the mouse, rather than simply checking against the wider circle. @@ -872,7 +872,7 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent* event) hoverPart(hoveredPartId); } - if (SkeletonDocumentEditMode::Add == m_document->editMode) { + if (DocumentEditMode::Add == m_document->editMode) { QPointF mouseScenePos = mouseEventScenePos(event); m_cursorNodeItem->setOrigin(mouseScenePos); if (m_addFromNodeItem) { @@ -889,7 +889,7 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent* event) return true; } - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_moveStarted) { if (m_checkedOriginItem) { QPointF mouseScenePos = mouseEventScenePos(event); @@ -1200,12 +1200,12 @@ bool SkeletonGraphicsWidget::wheel(QWheelEvent* event) delta = 1; else delta = -1; - if (SkeletonDocumentEditMode::Add == m_document->editMode) { + if (DocumentEditMode::Add == m_document->editMode) { if (m_cursorNodeItem->isVisible()) { m_cursorNodeItem->setRadius(m_cursorNodeItem->radius() + delta); return true; } - } else if (SkeletonDocumentEditMode::Select == m_document->editMode) { + } else if (DocumentEditMode::Select == m_document->editMode) { if (!m_rangeSelectionSet.empty()) { if (QGuiApplication::queryKeyboardModifiers().testFlag(Qt::ControlModifier)) { scaleSelected(delta); @@ -1347,13 +1347,13 @@ QPointF SkeletonGraphicsWidget::mouseEventScenePos(QMouseEvent* event) bool SkeletonGraphicsWidget::mousePress(QMouseEvent* event) { if (event->button() == Qt::LeftButton) { - if (SkeletonDocumentEditMode::ZoomIn == m_document->editMode) { + if (DocumentEditMode::ZoomIn == m_document->editMode) { ViewportAnchor lastAnchor = transformationAnchor(); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); scale(1.25, 1.25); setTransformationAnchor(lastAnchor); return true; - } else if (SkeletonDocumentEditMode::ZoomOut == m_document->editMode) { + } else if (DocumentEditMode::ZoomOut == m_document->editMode) { ViewportAnchor lastAnchor = transformationAnchor(); setTransformationAnchor(QGraphicsView::AnchorUnderMouse); scale(0.8, 0.8); @@ -1363,20 +1363,20 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent* event) // setTransform(QTransform()); //} return true; - } else if (SkeletonDocumentEditMode::Drag == m_document->editMode) { + } else if (DocumentEditMode::Drag == m_document->editMode) { if (!m_dragStarted) { m_lastGlobalPos = event->globalPos(); m_dragStarted = true; updateCursor(); } - } else if (SkeletonDocumentEditMode::Add == m_document->editMode) { + } else if (DocumentEditMode::Add == m_document->editMode) { if (m_cursorNodeItem->isVisible()) { if (m_addFromNodeItem) { if (m_hoveredNodeItem && m_addFromNodeItem && m_hoveredNodeItem != m_addFromNodeItem && m_hoveredNodeItem->profile() == m_addFromNodeItem->profile() && !m_document->findEdgeByNodes(m_addFromNodeItem->id(), m_hoveredNodeItem->id()) && m_document->isNodeEditable(m_hoveredNodeItem->id())) { if (m_document->isNodeConnectable(m_hoveredNodeItem->id())) { emit addEdge(m_addFromNodeItem->id(), m_hoveredNodeItem->id()); emit groupOperationAdded(); - emit setEditMode(SkeletonDocumentEditMode::Select); + emit setEditMode(DocumentEditMode::Select); return true; } } @@ -1410,7 +1410,7 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent* event) emit groupOperationAdded(); return true; } - } else if (SkeletonDocumentEditMode::Select == m_document->editMode) { + } else if (DocumentEditMode::Select == m_document->editMode) { bool processed = false; if (m_hoveredOriginItem != m_checkedOriginItem) { if (m_checkedOriginItem) { @@ -1467,7 +1467,7 @@ bool SkeletonGraphicsWidget::mousePress(QMouseEvent* event) } if (event->button() == Qt::LeftButton) { - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (!m_rangeSelectionStarted) { m_rangeSelectionStartPos = mouseEventScenePos(event); m_rangeSelectionStarted = true; @@ -1644,10 +1644,10 @@ void SkeletonGraphicsWidget::shortcutDelete() void SkeletonGraphicsWidget::shortcutAddMode() { - if (SkeletonDocumentEditMode::Add == m_document->editMode) { - emit setEditMode(SkeletonDocumentEditMode::Select); + if (DocumentEditMode::Add == m_document->editMode) { + emit setEditMode(DocumentEditMode::Select); } else { - emit setEditMode(SkeletonDocumentEditMode::Add); + emit setEditMode(DocumentEditMode::Add); } } @@ -1708,12 +1708,12 @@ void SkeletonGraphicsWidget::shortcutPaste() void SkeletonGraphicsWidget::shortcutSelectMode() { - emit setEditMode(SkeletonDocumentEditMode::Select); + emit setEditMode(DocumentEditMode::Select); } void SkeletonGraphicsWidget::shortcutPaintMode() { - emit setEditMode(SkeletonDocumentEditMode::Paint); + emit setEditMode(DocumentEditMode::Paint); } void SkeletonGraphicsWidget::shortcutZoomRenderedModelByMinus10() @@ -1729,10 +1729,10 @@ void SkeletonGraphicsWidget::shortcutZoomSelectedByMinus1() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) { + if (DocumentEditMode::Select == m_document->editMode && hasSelection()) { zoomSelected(-1); emit groupOperationAdded(); - } else if (SkeletonDocumentEditMode::Add == m_document->editMode) { + } else if (DocumentEditMode::Add == m_document->editMode) { if (m_cursorNodeItem->isVisible()) { m_cursorNodeItem->setRadius(m_cursorNodeItem->radius() + -1); } @@ -1752,10 +1752,10 @@ void SkeletonGraphicsWidget::shortcutZoomSelectedBy1() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode && hasSelection()) { + if (DocumentEditMode::Select == m_document->editMode && hasSelection()) { zoomSelected(1); emit groupOperationAdded(); - } else if (SkeletonDocumentEditMode::Add == m_document->editMode) { + } else if (DocumentEditMode::Add == m_document->editMode) { if (m_cursorNodeItem->isVisible()) { m_cursorNodeItem->setRadius(m_cursorNodeItem->radius() + 1); } @@ -1767,7 +1767,7 @@ void SkeletonGraphicsWidget::shortcutRotateSelectedByMinus1() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && hasSelection()) { + if ((DocumentEditMode::Select == m_document->editMode) && hasSelection()) { rotateSelected(-1); emit groupOperationAdded(); } @@ -1778,7 +1778,7 @@ void SkeletonGraphicsWidget::shortcutRotateSelectedBy1() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && hasSelection()) { + if ((DocumentEditMode::Select == m_document->editMode) && hasSelection()) { rotateSelected(1); emit groupOperationAdded(); } @@ -1789,7 +1789,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToLeft() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_checkedOriginItem) { moveCheckedOrigin(-1, 0); emit groupOperationAdded(); @@ -1805,7 +1805,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToRight() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_checkedOriginItem) { moveCheckedOrigin(1, 0); emit groupOperationAdded(); @@ -1821,7 +1821,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToUp() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_checkedOriginItem) { moveCheckedOrigin(0, -1); emit groupOperationAdded(); @@ -1837,7 +1837,7 @@ void SkeletonGraphicsWidget::shortcutMoveSelectedToDown() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (m_checkedOriginItem) { moveCheckedOrigin(0, 1); emit groupOperationAdded(); @@ -1853,7 +1853,7 @@ void SkeletonGraphicsWidget::shortcutScaleSelectedByMinus1() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && hasSelection()) { + if ((DocumentEditMode::Select == m_document->editMode) && hasSelection()) { scaleSelected(-1); emit groupOperationAdded(); } @@ -1864,7 +1864,7 @@ void SkeletonGraphicsWidget::shortcutScaleSelectedBy1() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && hasSelection()) { + if ((DocumentEditMode::Select == m_document->editMode) && hasSelection()) { scaleSelected(1); emit groupOperationAdded(); } @@ -1875,7 +1875,7 @@ void SkeletonGraphicsWidget::shortcutSwitchProfileOnSelected() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && hasSelection()) { + if ((DocumentEditMode::Select == m_document->editMode) && hasSelection()) { switchProfileOnRangeSelection(); } } @@ -1885,7 +1885,7 @@ void SkeletonGraphicsWidget::shortcutShowOrHideSelectedPart() if (!isVisible()) return; - if (SkeletonDocumentEditMode::Select == m_document->editMode) { + if (DocumentEditMode::Select == m_document->editMode) { if (!m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partVisible = part && part->visible; @@ -1902,7 +1902,7 @@ void SkeletonGraphicsWidget::shortcutEnableOrDisableSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partDisabled = part && part->disabled; emit setPartDisableState(m_lastCheckedPart, !partDisabled); @@ -1915,7 +1915,7 @@ void SkeletonGraphicsWidget::shortcutLockOrUnlockSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partLocked = part && part->locked; emit setPartLockState(m_lastCheckedPart, !partLocked); @@ -1928,7 +1928,7 @@ void SkeletonGraphicsWidget::shortcutXmirrorOnOrOffSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partXmirrored = part && part->xMirrored; emit setPartXmirrorState(m_lastCheckedPart, !partXmirrored); @@ -1941,7 +1941,7 @@ void SkeletonGraphicsWidget::shortcutSubdivedOrNotSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partSubdived = part && part->subdived; emit setPartSubdivState(m_lastCheckedPart, !partSubdived); @@ -1954,7 +1954,7 @@ void SkeletonGraphicsWidget::shortcutChamferedOrNotSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partChamfered = part && part->chamfered; emit setPartChamferState(m_lastCheckedPart, !partChamfered); @@ -1975,7 +1975,7 @@ void SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart() if (!isVisible()) return; - if ((SkeletonDocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { + if ((DocumentEditMode::Select == m_document->editMode) && !m_lastCheckedPart.isNull()) { const SkeletonPart* part = m_document->findPart(m_lastCheckedPart); bool partRounded = part && part->rounded; emit setPartRoundState(m_lastCheckedPart, !partRounded); @@ -1986,10 +1986,10 @@ void SkeletonGraphicsWidget::shortcutRoundEndOrNotSelectedPart() bool SkeletonGraphicsWidget::keyPress(QKeyEvent* event) { if (event->key() == Qt::Key_Space) { - if (SkeletonDocumentEditMode::ZoomIn == m_document->editMode || SkeletonDocumentEditMode::ZoomOut == m_document->editMode || SkeletonDocumentEditMode::Select == m_document->editMode || SkeletonDocumentEditMode::Add == m_document->editMode) { + if (DocumentEditMode::ZoomIn == m_document->editMode || DocumentEditMode::ZoomOut == m_document->editMode || DocumentEditMode::Select == m_document->editMode || DocumentEditMode::Add == m_document->editMode) { m_inTempDragMode = true; m_modeBeforeEnterTempDragMode = m_document->editMode; - emit setEditMode(SkeletonDocumentEditMode::Drag); + emit setEditMode(DocumentEditMode::Drag); return true; } } @@ -2044,10 +2044,6 @@ void SkeletonGraphicsWidget::nodeAdded(dust3d::Uuid nodeId) sideProfileItem->setRadius(sceneRadiusFromUnified(node->radius)); mainProfileItem->setId(nodeId); sideProfileItem->setId(nodeId); - if (m_document->isNodeDeactivated(nodeId)) { - mainProfileItem->setDeactivated(true); - sideProfileItem->setDeactivated(true); - } scene()->addItem(mainProfileItem); scene()->addItem(sideProfileItem); nodeItemMap[nodeId] = std::make_pair(mainProfileItem, sideProfileItem); @@ -2115,10 +2111,6 @@ void SkeletonGraphicsWidget::edgeAdded(dust3d::Uuid edgeId) sideProfileEdgeItem->setId(edgeId); mainProfileEdgeItem->setEndpoints(fromIt->second.first, toIt->second.first); sideProfileEdgeItem->setEndpoints(fromIt->second.second, toIt->second.second); - if (m_document->isNodeDeactivated(edgeId)) { - mainProfileEdgeItem->setDeactivated(true); - sideProfileEdgeItem->setDeactivated(true); - } scene()->addItem(mainProfileEdgeItem); scene()->addItem(sideProfileEdgeItem); edgeItemMap[edgeId] = std::make_pair(mainProfileEdgeItem, sideProfileEdgeItem); diff --git a/application/sources/skeleton_graphics_widget.h b/application/sources/skeleton_graphics_widget.h index 5d8f3d5e..23b55c2d 100644 --- a/application/sources/skeleton_graphics_widget.h +++ b/application/sources/skeleton_graphics_widget.h @@ -1,8 +1,8 @@ #ifndef DUST3D_APPLICATION_SKELETON_GRAPHICS_VIEW_H_ #define DUST3D_APPLICATION_SKELETON_GRAPHICS_VIEW_H_ +#include "document.h" #include "model_widget.h" -#include "skeleton_document.h" #include "skeleton_ik_mover.h" #include "theme.h" #include "turnaround_loader.h" @@ -398,7 +398,7 @@ signals: void moveNodeBy(dust3d::Uuid nodeId, float x, float y, float z); void removeNode(dust3d::Uuid nodeId); void removePart(dust3d::Uuid partId); - void setEditMode(SkeletonDocumentEditMode mode); + void setEditMode(DocumentEditMode mode); void removeEdge(dust3d::Uuid edgeId); void addEdge(dust3d::Uuid fromNodeId, dust3d::Uuid toNodeId); void cursorChanged(); @@ -442,7 +442,7 @@ signals: void loadedTurnaroundImageChanged(); public: - SkeletonGraphicsWidget(const SkeletonDocument* document); + SkeletonGraphicsWidget(const Document* document); std::map> nodeItemMap; std::map> edgeItemMap; bool mouseMove(QMouseEvent* event); @@ -600,7 +600,7 @@ private: bool isFloatEqual(float a, float b); private: - const SkeletonDocument* m_document = nullptr; + const Document* m_document = nullptr; QGraphicsPixmapItem* m_backgroundItem = nullptr; bool m_turnaroundChanged = false; TurnaroundLoader* m_turnaroundLoader = nullptr; @@ -629,7 +629,7 @@ private: bool m_eventForwardingToModelWidget = false; ModelWidget* m_modelWidget = nullptr; bool m_inTempDragMode = false; - SkeletonDocumentEditMode m_modeBeforeEnterTempDragMode = SkeletonDocumentEditMode::Select; + DocumentEditMode m_modeBeforeEnterTempDragMode = DocumentEditMode::Select; float m_turnaroundOpacity = 0.25f; bool m_rotated = false; QImage* m_backgroundImage = nullptr; diff --git a/application/sources/tube_uv_preview_image_generator.cc b/application/sources/tube_uv_preview_image_generator.cc deleted file mode 100644 index 05e6bc68..00000000 --- a/application/sources/tube_uv_preview_image_generator.cc +++ /dev/null @@ -1,20 +0,0 @@ -#include "tube_uv_preview_image_generator.h" - -const size_t TubeUvPreviewImageGenerator::m_uvImageSize = 1024; - -TubeUvPreviewImageGenerator::TubeUvPreviewImageGenerator(std::vector>&& faceUvs) - : m_faceUvs(faceUvs) -{ -} - -void TubeUvPreviewImageGenerator::generate() -{ - m_previewImage = std::make_unique(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32); - // TODO: -} - -void TubeUvPreviewImageGenerator::process() -{ - generate(); - emit finished(); -} diff --git a/application/sources/uv_preview_image_generator.cc b/application/sources/uv_preview_image_generator.cc new file mode 100644 index 00000000..ef43c334 --- /dev/null +++ b/application/sources/uv_preview_image_generator.cc @@ -0,0 +1,20 @@ +#include "uv_preview_image_generator.h" + +const size_t UvPreviewImageGenerator::m_uvImageSize = 1024; + +UvPreviewImageGenerator::UvPreviewImageGenerator(std::vector>&& faceUvs) + : m_faceUvs(faceUvs) +{ +} + +void UvPreviewImageGenerator::generate() +{ + m_previewImage = std::make_unique(m_uvImageSize, m_uvImageSize, QImage::Format_ARGB32); + // TODO: +} + +void UvPreviewImageGenerator::process() +{ + generate(); + emit finished(); +} diff --git a/application/sources/tube_uv_preview_image_generator.h b/application/sources/uv_preview_image_generator.h similarity index 58% rename from application/sources/tube_uv_preview_image_generator.h rename to application/sources/uv_preview_image_generator.h index 7109058c..cef44526 100644 --- a/application/sources/tube_uv_preview_image_generator.h +++ b/application/sources/uv_preview_image_generator.h @@ -1,5 +1,5 @@ -#ifndef DUST3D_APPLICATION_TUBE_UV_PREVIEW_IMAGE_GENERATOR_H_ -#define DUST3D_APPLICATION_TUBE_UV_PREVIEW_IMAGE_GENERATOR_H_ +#ifndef DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ +#define DUST3D_APPLICATION_TUBE_PREVIEW_IMAGE_GENERATOR_H_ #include #include @@ -7,10 +7,10 @@ #include #include -class TubeUvPreviewImageGenerator : public QObject { +class UvPreviewImageGenerator : public QObject { Q_OBJECT public: - TubeUvPreviewImageGenerator(std::vector>&& faceUvs); + UvPreviewImageGenerator(std::vector>&& faceUvs); void generate(); signals: void finished(); diff --git a/dust3d/base/part_base.cc b/dust3d/base/part_base.cc deleted file mode 100644 index e5318685..00000000 --- a/dust3d/base/part_base.cc +++ /dev/null @@ -1,31 +0,0 @@ -/* - * Copyright (c) 2016-2021 Jeremy HU . All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#include - -namespace dust3d { - -IMPL_PartBaseFromString - IMPL_PartBaseToString - IMPL_PartBaseToDispName - -} diff --git a/dust3d/base/part_base.h b/dust3d/base/part_base.h deleted file mode 100644 index d6b7626d..00000000 --- a/dust3d/base/part_base.h +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (c) 2016-2021 Jeremy HU . All rights reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a copy - * of this software and associated documentation files (the "Software"), to deal - * in the Software without restriction, including without limitation the rights - * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - * copies of the Software, and to permit persons to whom the Software is - * furnished to do so, subject to the following conditions: - - * The above copyright notice and this permission notice shall be included in all - * copies or substantial portions of the Software. - - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE - * SOFTWARE. - */ - -#ifndef DUST3D_BASE_PART_BASE_H_ -#define DUST3D_BASE_PART_BASE_H_ - -#include - -namespace dust3d { - -enum class PartBase { - XYZ = 0, - Average, - YZ, - XY, - ZX, - Count -}; -PartBase PartBaseFromString(const char* baseString); -#define IMPL_PartBaseFromString \ - PartBase PartBaseFromString(const char* baseString) \ - { \ - std::string base = baseString; \ - if (base == "XYZ") \ - return PartBase::XYZ; \ - if (base == "Average") \ - return PartBase::Average; \ - if (base == "YZ") \ - return PartBase::YZ; \ - if (base == "XY") \ - return PartBase::XY; \ - if (base == "ZX") \ - return PartBase::ZX; \ - return PartBase::XYZ; \ - } -const char* PartBaseToString(PartBase base); -#define IMPL_PartBaseToString \ - const char* PartBaseToString(PartBase base) \ - { \ - switch (base) { \ - case PartBase::XYZ: \ - return "XYZ"; \ - case PartBase::Average: \ - return "Average"; \ - case PartBase::YZ: \ - return "YZ"; \ - case PartBase::XY: \ - return "XY"; \ - case PartBase::ZX: \ - return "ZX"; \ - default: \ - return "XYZ"; \ - } \ - } -std::string PartBaseToDispName(PartBase base); -#define IMPL_PartBaseToDispName \ - std::string PartBaseToDispName(PartBase base) \ - { \ - switch (base) { \ - case PartBase::XYZ: \ - return std::string("Dynamic"); \ - case PartBase::Average: \ - return std::string("Average"); \ - case PartBase::YZ: \ - return std::string("Side Plane"); \ - case PartBase::XY: \ - return std::string("Front Plane"); \ - case PartBase::ZX: \ - return std::string("Top Plane"); \ - default: \ - return std::string("Dynamic"); \ - } \ - } - -} - -#endif diff --git a/dust3d/mesh/mesh_generator.cc b/dust3d/mesh/mesh_generator.cc index ac2068ae..2eb1b5a5 100644 --- a/dust3d/mesh/mesh_generator.cc +++ b/dust3d/mesh/mesh_generator.cc @@ -21,7 +21,6 @@ */ #include -#include #include #include #include @@ -591,7 +590,6 @@ std::unique_ptr MeshGenerator::combinePartMesh(const std::st float cutRotation = 0.0; float hollowThickness = 0.0; auto target = PartTargetFromString(String::valueOrEmpty(part, "target").c_str()); - auto base = PartBaseFromString(String::valueOrEmpty(part, "base").c_str()); std::string searchPartIdString = __mirrorFromPartId.empty() ? partIdString : __mirrorFromPartId;