Support onion skin in pose editor
Also add more buttons to speed up the pose editing. Thanks @Toshiwoz for proposing this feature.master
parent
8c0156bc7a
commit
26353d530a
|
@ -25,3 +25,4 @@ Ruben Niculcea <https://github.com/RubenSandwich>
|
||||||
boynet <https://dust3d.discourse.group/u/boynet>
|
boynet <https://dust3d.discourse.group/u/boynet>
|
||||||
fornclake <https://www.reddit.com/user/fornclake>
|
fornclake <https://www.reddit.com/user/fornclake>
|
||||||
bvanevery <https://www.reddit.com/user/bvanevery>
|
bvanevery <https://www.reddit.com/user/bvanevery>
|
||||||
|
Toshio Araki <https://github.com/Toshiwoz>
|
|
@ -1,6 +1,6 @@
|
||||||
<a href="https://dust3d.org" target="_blank"><image src="https://raw.githubusercontent.com/huxingyi/dust3d/master/dust3d-logo.png" width="66" height="58"></a>
|
<a href="https://dust3d.org" target="_blank"><image src="https://raw.githubusercontent.com/huxingyi/dust3d/master/dust3d-logo.png" width="66" height="58"></a>
|
||||||
|
|
||||||
[![appveyor status](https://ci.appveyor.com/api/projects/status/github/huxingyi/dust3d?branch=master&svg=true)](https://ci.appveyor.com/project/huxingyi/dust3d) [![travis status](https://travis-ci.org/huxingyi/dust3d.svg?branch=master)](https://travis-ci.org/huxingyi/dust3d) [![readthedocs status](https://readthedocs.org/projects/dust3d/badge/?version=latest)](http://docs.dust3d.org/en/latest/?badge=latest) [![](https://img.shields.io/twitter/follow/jeremyhu2016.svg?label=%20%40jeremyhu2016&style=social)](https://twitter.com/jeremyhu2016) [![](https://img.shields.io/badge/Mailing%20List%20-Join-blue.svg)](https://www.freelists.org/list/dust3d) [![](https://img.shields.io/discourse/https/dust3d.discourse.group/status.svg)](https://dust3d.discourse.group/)
|
[![appveyor status](https://ci.appveyor.com/api/projects/status/github/huxingyi/dust3d?branch=master&svg=true)](https://ci.appveyor.com/project/huxingyi/dust3d) [![travis status](https://travis-ci.org/huxingyi/dust3d.svg?branch=master)](https://travis-ci.org/huxingyi/dust3d) [![readthedocs status](https://readthedocs.org/projects/dust3d/badge/?version=latest)](http://docs.dust3d.org/en/latest/?badge=latest) [![](https://img.shields.io/twitter/follow/jeremyhu2016.svg?label=%20%40jeremyhu2016&style=social)](https://twitter.com/jeremyhu2016) [![](https://img.shields.io/badge/mailing%20list%20-join-blue.svg)](https://www.freelists.org/list/dust3d) [![](https://img.shields.io/discourse/https/dust3d.discourse.group/status.svg)](https://dust3d.discourse.group/)
|
||||||
|
|
||||||
Overview
|
Overview
|
||||||
----------
|
----------
|
||||||
|
|
|
@ -11,7 +11,7 @@
|
||||||
#include "snapshot.h"
|
#include "snapshot.h"
|
||||||
#include "snapshotxml.h"
|
#include "snapshotxml.h"
|
||||||
|
|
||||||
const float PoseDocument::m_nodeRadius = 0.005;
|
const float PoseDocument::m_nodeRadius = 0.015;
|
||||||
const float PoseDocument::m_groundPlaneHalfThickness = 0.005 / 4;
|
const float PoseDocument::m_groundPlaneHalfThickness = 0.005 / 4;
|
||||||
const bool PoseDocument::m_hideRootAndVirtual = true;
|
const bool PoseDocument::m_hideRootAndVirtual = true;
|
||||||
const float PoseDocument::m_outcomeScaleFactor = 0.5;
|
const float PoseDocument::m_outcomeScaleFactor = 0.5;
|
||||||
|
@ -34,16 +34,32 @@ bool PoseDocument::originSettled() const
|
||||||
|
|
||||||
bool PoseDocument::isNodeEditable(QUuid nodeId) const
|
bool PoseDocument::isNodeEditable(QUuid nodeId) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(nodeId);
|
if (m_otherIds.find(nodeId) != m_otherIds.end())
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PoseDocument::isEdgeEditable(QUuid edgeId) const
|
bool PoseDocument::isEdgeEditable(QUuid edgeId) const
|
||||||
{
|
{
|
||||||
Q_UNUSED(edgeId);
|
if (m_otherIds.find(edgeId) != m_otherIds.end())
|
||||||
|
return false;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool PoseDocument::isNodeDeactivated(QUuid nodeId) const
|
||||||
|
{
|
||||||
|
if (m_otherIds.find(nodeId) != m_otherIds.end())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool PoseDocument::isEdgeDeactivated(QUuid edgeId) const
|
||||||
|
{
|
||||||
|
if (m_otherIds.find(edgeId) != m_otherIds.end())
|
||||||
|
return true;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
void PoseDocument::copyNodes(std::set<QUuid> nodeIdSet) const
|
void PoseDocument::copyNodes(std::set<QUuid> nodeIdSet) const
|
||||||
{
|
{
|
||||||
std::map<QString, std::map<QString, QString>> parameters;
|
std::map<QString, std::map<QString, QString>> parameters;
|
||||||
|
@ -129,11 +145,17 @@ void PoseDocument::updateTurnaround(const QImage &image)
|
||||||
emit turnaroundChanged();
|
emit turnaroundChanged();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PoseDocument::updateOtherFramesParameters(const std::vector<std::map<QString, std::map<QString, QString>>> &otherFramesParameters)
|
||||||
|
{
|
||||||
|
m_otherFramesParameters = otherFramesParameters;
|
||||||
|
}
|
||||||
|
|
||||||
void PoseDocument::reset()
|
void PoseDocument::reset()
|
||||||
{
|
{
|
||||||
nodeMap.clear();
|
nodeMap.clear();
|
||||||
edgeMap.clear();
|
edgeMap.clear();
|
||||||
partMap.clear();
|
partMap.clear();
|
||||||
|
m_otherIds.clear();
|
||||||
m_boneNameToIdsMap.clear();
|
m_boneNameToIdsMap.clear();
|
||||||
m_bonesPartId = QUuid();
|
m_bonesPartId = QUuid();
|
||||||
m_groundPartId = QUuid();
|
m_groundPartId = QUuid();
|
||||||
|
@ -148,20 +170,11 @@ void PoseDocument::clearHistories()
|
||||||
m_redoItems.clear();
|
m_redoItems.clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
void PoseDocument::updateBonesAndHeightAboveGroundLevelFromParameters(std::vector<RiggerBone> *bones,
|
||||||
const std::map<QString, std::map<QString, QString>> ¶meters)
|
float *heightAboveGroundLevel,
|
||||||
|
const std::map<QString, std::map<QString, QString>> ¶meters)
|
||||||
{
|
{
|
||||||
if (nullptr == rigBones || rigBones->empty()) {
|
for (auto &bone: *bones) {
|
||||||
m_riggerBones.clear();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (&m_riggerBones != rigBones)
|
|
||||||
m_riggerBones = *rigBones;
|
|
||||||
|
|
||||||
float heightAboveGroundLevel = 0;
|
|
||||||
std::vector<RiggerBone> bones = *rigBones;
|
|
||||||
for (auto &bone: bones) {
|
|
||||||
const auto findParameterResult = parameters.find(bone.name);
|
const auto findParameterResult = parameters.find(bone.name);
|
||||||
if (findParameterResult == parameters.end())
|
if (findParameterResult == parameters.end())
|
||||||
continue;
|
continue;
|
||||||
|
@ -194,7 +207,7 @@ void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
||||||
};
|
};
|
||||||
bone.tailPosition = toPosition;
|
bone.tailPosition = toPosition;
|
||||||
for (const auto &child: bone.children) {
|
for (const auto &child: bone.children) {
|
||||||
auto &childBone = bones[child];
|
auto &childBone = (*bones)[child];
|
||||||
childBone.headPosition = toPosition;
|
childBone.headPosition = toPosition;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -207,18 +220,70 @@ void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
||||||
{
|
{
|
||||||
auto findHeightAboveGroundLevel = map.find("heightAboveGroundLevel");
|
auto findHeightAboveGroundLevel = map.find("heightAboveGroundLevel");
|
||||||
if (findHeightAboveGroundLevel != map.end()) {
|
if (findHeightAboveGroundLevel != map.end()) {
|
||||||
heightAboveGroundLevel = valueOfKeyInMapOrEmpty(map, "heightAboveGroundLevel").toFloat();
|
*heightAboveGroundLevel = valueOfKeyInMapOrEmpty(map, "heightAboveGroundLevel").toFloat();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
updateRigBones(&bones, heightAboveGroundLevel);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const float heightAboveGroundLevel)
|
void PoseDocument::fromParameters(const std::vector<RiggerBone> *rigBones,
|
||||||
|
const std::map<QString, std::map<QString, QString>> ¶meters)
|
||||||
{
|
{
|
||||||
|
if (nullptr == rigBones || rigBones->empty()) {
|
||||||
|
m_riggerBones.clear();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (&m_riggerBones != rigBones)
|
||||||
|
m_riggerBones = *rigBones;
|
||||||
|
|
||||||
|
float heightAboveGroundLevel = 0;
|
||||||
|
std::vector<RiggerBone> bones = *rigBones;
|
||||||
|
updateBonesAndHeightAboveGroundLevelFromParameters(&bones,
|
||||||
|
&heightAboveGroundLevel,
|
||||||
|
parameters);
|
||||||
|
|
||||||
reset();
|
reset();
|
||||||
|
|
||||||
|
for (const auto &otherParameters: m_otherFramesParameters) {
|
||||||
|
float otherHeightAboveGroundLevel = 0;
|
||||||
|
std::vector<RiggerBone> otherBones = *rigBones;
|
||||||
|
updateBonesAndHeightAboveGroundLevelFromParameters(&otherBones,
|
||||||
|
&otherHeightAboveGroundLevel,
|
||||||
|
otherParameters);
|
||||||
|
|
||||||
|
std::map<QString, std::pair<QUuid, QUuid>> boneNameToIdsMap;
|
||||||
|
QUuid groundPartId;
|
||||||
|
QUuid bonesPartId;
|
||||||
|
QUuid groundEdgeId;
|
||||||
|
parametersToNodes(&otherBones,
|
||||||
|
otherHeightAboveGroundLevel,
|
||||||
|
&boneNameToIdsMap,
|
||||||
|
&groundPartId,
|
||||||
|
&bonesPartId,
|
||||||
|
&groundEdgeId,
|
||||||
|
true);
|
||||||
|
}
|
||||||
|
|
||||||
|
parametersToNodes(&bones,
|
||||||
|
heightAboveGroundLevel,
|
||||||
|
&m_boneNameToIdsMap,
|
||||||
|
&m_groundPartId,
|
||||||
|
&m_bonesPartId,
|
||||||
|
&m_groundEdgeId,
|
||||||
|
false);
|
||||||
|
|
||||||
|
emit parametersChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
void PoseDocument::parametersToNodes(const std::vector<RiggerBone> *rigBones,
|
||||||
|
const float heightAboveGroundLevel,
|
||||||
|
std::map<QString, std::pair<QUuid, QUuid>> *boneNameToIdsMap,
|
||||||
|
QUuid *groundPartId,
|
||||||
|
QUuid *bonesPartId,
|
||||||
|
QUuid *groundEdgeId,
|
||||||
|
bool isOther)
|
||||||
|
{
|
||||||
if (nullptr == rigBones || rigBones->empty()) {
|
if (nullptr == rigBones || rigBones->empty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -226,9 +291,9 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
std::set<QUuid> newAddedNodeIds;
|
std::set<QUuid> newAddedNodeIds;
|
||||||
std::set<QUuid> newAddedEdgeIds;
|
std::set<QUuid> newAddedEdgeIds;
|
||||||
|
|
||||||
m_bonesPartId = QUuid::createUuid();
|
*bonesPartId = QUuid::createUuid();
|
||||||
auto &bonesPart = partMap[m_bonesPartId];
|
auto &bonesPart = partMap[*bonesPartId];
|
||||||
bonesPart.id = m_bonesPartId;
|
bonesPart.id = *bonesPartId;
|
||||||
|
|
||||||
//qDebug() << "rigBones size:" << rigBones->size();
|
//qDebug() << "rigBones size:" << rigBones->size();
|
||||||
|
|
||||||
|
@ -248,7 +313,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
const auto &bone = (*rigBones)[edgePair.first];
|
const auto &bone = (*rigBones)[edgePair.first];
|
||||||
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_bonesPartId;
|
node.partId = *bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_nodeRadius);
|
node.setRadius(m_nodeRadius);
|
||||||
node.x = fromOutcomeX(bone.headPosition.x());
|
node.x = fromOutcomeX(bone.headPosition.x());
|
||||||
|
@ -267,7 +332,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
const auto &bone = (*rigBones)[edgePair.second];
|
const auto &bone = (*rigBones)[edgePair.second];
|
||||||
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
if (!bone.name.startsWith("Virtual_") || !m_hideRootAndVirtual) {
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_bonesPartId;
|
node.partId = *bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_nodeRadius);
|
node.setRadius(m_nodeRadius);
|
||||||
node.x = fromOutcomeX(bone.headPosition.x());
|
node.x = fromOutcomeX(bone.headPosition.x());
|
||||||
|
@ -286,7 +351,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
SkeletonEdge edge;
|
SkeletonEdge edge;
|
||||||
edge.partId = m_bonesPartId;
|
edge.partId = *bonesPartId;
|
||||||
edge.id = QUuid::createUuid();
|
edge.id = QUuid::createUuid();
|
||||||
edge.nodeIds.push_back(firstNodeId);
|
edge.nodeIds.push_back(firstNodeId);
|
||||||
edge.nodeIds.push_back(secondNodeId);
|
edge.nodeIds.push_back(secondNodeId);
|
||||||
|
@ -304,7 +369,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
const QUuid &firstNodeId = boneIndexToHeadNodeIdMap[i];
|
const QUuid &firstNodeId = boneIndexToHeadNodeIdMap[i];
|
||||||
|
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_bonesPartId;
|
node.partId = *bonesPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_nodeRadius / 2);
|
node.setRadius(m_nodeRadius / 2);
|
||||||
node.x = fromOutcomeX(bone.tailPosition.x());
|
node.x = fromOutcomeX(bone.tailPosition.x());
|
||||||
|
@ -312,10 +377,10 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
node.z = fromOutcomeZ(bone.tailPosition.z());
|
node.z = fromOutcomeZ(bone.tailPosition.z());
|
||||||
nodeMap[node.id] = node;
|
nodeMap[node.id] = node;
|
||||||
newAddedNodeIds.insert(node.id);
|
newAddedNodeIds.insert(node.id);
|
||||||
m_boneNameToIdsMap[bone.name] = {firstNodeId, node.id};
|
(*boneNameToIdsMap)[bone.name] = {firstNodeId, node.id};
|
||||||
|
|
||||||
SkeletonEdge edge;
|
SkeletonEdge edge;
|
||||||
edge.partId = m_bonesPartId;
|
edge.partId = *bonesPartId;
|
||||||
edge.id = QUuid::createUuid();
|
edge.id = QUuid::createUuid();
|
||||||
edge.nodeIds.push_back(firstNodeId);
|
edge.nodeIds.push_back(firstNodeId);
|
||||||
edge.nodeIds.push_back(node.id);
|
edge.nodeIds.push_back(node.id);
|
||||||
|
@ -328,7 +393,7 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
for (const auto &child: bone.children) {
|
for (const auto &child: bone.children) {
|
||||||
m_boneNameToIdsMap[bone.name] = {boneIndexToHeadNodeIdMap[i], boneIndexToHeadNodeIdMap[child]};
|
(*boneNameToIdsMap)[bone.name] = {boneIndexToHeadNodeIdMap[i], boneIndexToHeadNodeIdMap[child]};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -337,53 +402,62 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
nodeMap[findRootNodeId->second].setRadius(m_nodeRadius * 2);
|
nodeMap[findRootNodeId->second].setRadius(m_nodeRadius * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
m_groundPartId = QUuid::createUuid();
|
if (!isOther) {
|
||||||
auto &groundPart = partMap[m_groundPartId];
|
*groundPartId = QUuid::createUuid();
|
||||||
groundPart.id = m_groundPartId;
|
auto &groundPart = partMap[*groundPartId];
|
||||||
|
groundPart.id = *groundPartId;
|
||||||
|
|
||||||
float footBottomY = findFootBottomY();
|
float footBottomY = findFootBottomY();
|
||||||
float legHeight = findLegHeight();
|
float legHeight = findLegHeight();
|
||||||
float myHeightAboveGroundLevel = heightAboveGroundLevel * legHeight;
|
float myHeightAboveGroundLevel = heightAboveGroundLevel * legHeight;
|
||||||
float groundNodeY = footBottomY + m_groundPlaneHalfThickness + myHeightAboveGroundLevel;
|
float groundNodeY = footBottomY + m_groundPlaneHalfThickness + myHeightAboveGroundLevel;
|
||||||
|
|
||||||
std::pair<QUuid, QUuid> groundNodesPair;
|
std::pair<QUuid, QUuid> groundNodesPair;
|
||||||
{
|
{
|
||||||
SkeletonNode node;
|
SkeletonNode node;
|
||||||
node.partId = m_groundPartId;
|
node.partId = *groundPartId;
|
||||||
node.id = QUuid::createUuid();
|
node.id = QUuid::createUuid();
|
||||||
node.setRadius(m_groundPlaneHalfThickness);
|
node.setRadius(m_groundPlaneHalfThickness);
|
||||||
node.x = -100;
|
node.x = -100;
|
||||||
node.y = groundNodeY;
|
node.y = groundNodeY;
|
||||||
node.z = -100;
|
node.z = -100;
|
||||||
nodeMap[node.id] = node;
|
nodeMap[node.id] = node;
|
||||||
newAddedNodeIds.insert(node.id);
|
newAddedNodeIds.insert(node.id);
|
||||||
groundNodesPair.first = node.id;
|
groundNodesPair.first = node.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SkeletonNode node;
|
||||||
|
node.partId = *groundPartId;
|
||||||
|
node.id = QUuid::createUuid();
|
||||||
|
node.setRadius(m_groundPlaneHalfThickness);
|
||||||
|
node.x = 100;
|
||||||
|
node.y = groundNodeY;
|
||||||
|
node.z = 100;
|
||||||
|
nodeMap[node.id] = node;
|
||||||
|
newAddedNodeIds.insert(node.id);
|
||||||
|
groundNodesPair.second = node.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
SkeletonEdge edge;
|
||||||
|
edge.partId = *groundPartId;
|
||||||
|
edge.id = QUuid::createUuid();
|
||||||
|
edge.nodeIds.push_back(groundNodesPair.first);
|
||||||
|
edge.nodeIds.push_back(groundNodesPair.second);
|
||||||
|
edgeMap[edge.id] = edge;
|
||||||
|
*groundEdgeId = edge.id;
|
||||||
|
newAddedEdgeIds.insert(edge.id);
|
||||||
|
nodeMap[groundNodesPair.first].edgeIds.push_back(edge.id);
|
||||||
|
nodeMap[groundNodesPair.second].edgeIds.push_back(edge.id);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
if (isOther) {
|
||||||
SkeletonNode node;
|
for (const auto &nodeIt: newAddedNodeIds)
|
||||||
node.partId = m_groundPartId;
|
m_otherIds.insert(nodeIt);
|
||||||
node.id = QUuid::createUuid();
|
for (const auto &edgeIt: newAddedEdgeIds)
|
||||||
node.setRadius(m_groundPlaneHalfThickness);
|
m_otherIds.insert(edgeIt);
|
||||||
node.x = 100;
|
|
||||||
node.y = groundNodeY;
|
|
||||||
node.z = 100;
|
|
||||||
nodeMap[node.id] = node;
|
|
||||||
newAddedNodeIds.insert(node.id);
|
|
||||||
groundNodesPair.second = node.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
SkeletonEdge edge;
|
|
||||||
edge.partId = m_groundPartId;
|
|
||||||
edge.id = QUuid::createUuid();
|
|
||||||
edge.nodeIds.push_back(groundNodesPair.first);
|
|
||||||
edge.nodeIds.push_back(groundNodesPair.second);
|
|
||||||
edgeMap[edge.id] = edge;
|
|
||||||
m_groundEdgeId = edge.id;
|
|
||||||
newAddedEdgeIds.insert(edge.id);
|
|
||||||
nodeMap[groundNodesPair.first].edgeIds.push_back(edge.id);
|
|
||||||
nodeMap[groundNodesPair.second].edgeIds.push_back(edge.id);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const auto &nodeIt: newAddedNodeIds) {
|
for (const auto &nodeIt: newAddedNodeIds) {
|
||||||
|
@ -392,8 +466,6 @@ void PoseDocument::updateRigBones(const std::vector<RiggerBone> *rigBones, const
|
||||||
for (const auto &edgeIt: newAddedEdgeIds) {
|
for (const auto &edgeIt: newAddedEdgeIds) {
|
||||||
emit edgeAdded(edgeIt);
|
emit edgeAdded(edgeIt);
|
||||||
}
|
}
|
||||||
|
|
||||||
emit parametersChanged();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseDocument::moveNodeBy(QUuid nodeId, float x, float y, float z)
|
void PoseDocument::moveNodeBy(QUuid nodeId, float x, float y, float z)
|
||||||
|
|
|
@ -29,10 +29,12 @@ public:
|
||||||
bool originSettled() const override;
|
bool originSettled() const override;
|
||||||
bool isNodeEditable(QUuid nodeId) const override;
|
bool isNodeEditable(QUuid nodeId) const override;
|
||||||
bool isEdgeEditable(QUuid edgeId) const override;
|
bool isEdgeEditable(QUuid edgeId) const override;
|
||||||
|
bool isNodeDeactivated(QUuid nodeId) const override;
|
||||||
|
bool isEdgeDeactivated(QUuid edgeId) const override;
|
||||||
void copyNodes(std::set<QUuid> nodeIdSet) const override;
|
void copyNodes(std::set<QUuid> nodeIdSet) const override;
|
||||||
|
|
||||||
void updateTurnaround(const QImage &image);
|
void updateTurnaround(const QImage &image);
|
||||||
void updateRigBones(const std::vector<RiggerBone> *rigBones, const float heightAboveGroundLevel=0.0);
|
void updateOtherFramesParameters(const std::vector<std::map<QString, std::map<QString, QString>>> &otherFramesParameters);
|
||||||
void reset();
|
void reset();
|
||||||
|
|
||||||
void toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds=std::set<QUuid>()) const;
|
void toParameters(std::map<QString, std::map<QString, QString>> ¶meters, const std::set<QUuid> &limitNodeIds=std::set<QUuid>()) const;
|
||||||
|
@ -61,6 +63,16 @@ private:
|
||||||
float findFootBottomY() const;
|
float findFootBottomY() const;
|
||||||
float findFirstSpineY() const;
|
float findFirstSpineY() const;
|
||||||
float findLegHeight() const;
|
float findLegHeight() const;
|
||||||
|
void parametersToNodes(const std::vector<RiggerBone> *rigBones,
|
||||||
|
const float heightAboveGroundLevel,
|
||||||
|
std::map<QString, std::pair<QUuid, QUuid>> *boneNameToIdsMap,
|
||||||
|
QUuid *groundPartId,
|
||||||
|
QUuid *bonesPartId,
|
||||||
|
QUuid *groundEdgeId,
|
||||||
|
bool isOther=false);
|
||||||
|
void updateBonesAndHeightAboveGroundLevelFromParameters(std::vector<RiggerBone> *bones,
|
||||||
|
float *heightAboveGroundLevel,
|
||||||
|
const std::map<QString, std::map<QString, QString>> ¶meters);
|
||||||
|
|
||||||
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
std::map<QString, std::pair<QUuid, QUuid>> m_boneNameToIdsMap;
|
||||||
QUuid m_groundPartId;
|
QUuid m_groundPartId;
|
||||||
|
@ -69,6 +81,8 @@ private:
|
||||||
std::deque<PoseHistoryItem> m_undoItems;
|
std::deque<PoseHistoryItem> m_undoItems;
|
||||||
std::deque<PoseHistoryItem> m_redoItems;
|
std::deque<PoseHistoryItem> m_redoItems;
|
||||||
std::vector<RiggerBone> m_riggerBones;
|
std::vector<RiggerBone> m_riggerBones;
|
||||||
|
std::vector<std::map<QString, std::map<QString, QString>>> m_otherFramesParameters;
|
||||||
|
std::set<QUuid> m_otherIds;
|
||||||
|
|
||||||
static float fromOutcomeX(float x);
|
static float fromOutcomeX(float x);
|
||||||
static float toOutcomeX(float x);
|
static float toOutcomeX(float x);
|
||||||
|
|
|
@ -18,8 +18,6 @@
|
||||||
#include "shortcuts.h"
|
#include "shortcuts.h"
|
||||||
#include "imageforever.h"
|
#include "imageforever.h"
|
||||||
|
|
||||||
const float PoseEditWidget::m_frameDuration = 0.042; //(1.0 / 24)
|
|
||||||
|
|
||||||
PoseEditWidget::PoseEditWidget(const Document *document, QWidget *parent) :
|
PoseEditWidget::PoseEditWidget(const Document *document, QWidget *parent) :
|
||||||
QDialog(parent),
|
QDialog(parent),
|
||||||
m_document(document),
|
m_document(document),
|
||||||
|
@ -95,6 +93,18 @@ PoseEditWidget::PoseEditWidget(const Document *document, QWidget *parent) :
|
||||||
connect(m_nameEdit, &QLineEdit::textChanged, this, [=]() {
|
connect(m_nameEdit, &QLineEdit::textChanged, this, [=]() {
|
||||||
setUnsaveState();
|
setUnsaveState();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_durationEdit = new QDoubleSpinBox();
|
||||||
|
m_durationEdit->setDecimals(2);
|
||||||
|
m_durationEdit->setMaximum(60);
|
||||||
|
m_durationEdit->setMinimum(0);
|
||||||
|
m_durationEdit->setSingleStep(0.1);
|
||||||
|
m_durationEdit->setValue(m_duration);
|
||||||
|
|
||||||
|
connect(m_durationEdit, static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), this, [=](double value) {
|
||||||
|
setDuration((float)value);
|
||||||
|
});
|
||||||
|
|
||||||
QPushButton *saveButton = new QPushButton(tr("Save"));
|
QPushButton *saveButton = new QPushButton(tr("Save"));
|
||||||
connect(saveButton, &QPushButton::clicked, this, &PoseEditWidget::save);
|
connect(saveButton, &QPushButton::clicked, this, &PoseEditWidget::save);
|
||||||
saveButton->setDefault(true);
|
saveButton->setDefault(true);
|
||||||
|
@ -112,26 +122,67 @@ PoseEditWidget::PoseEditWidget(const Document *document, QWidget *parent) :
|
||||||
m_currentFrameSlider = new QSlider(Qt::Horizontal);
|
m_currentFrameSlider = new QSlider(Qt::Horizontal);
|
||||||
m_currentFrameSlider->setRange(0, m_frames.size() - 1);
|
m_currentFrameSlider->setRange(0, m_frames.size() - 1);
|
||||||
m_currentFrameSlider->setValue(m_currentFrame);
|
m_currentFrameSlider->setValue(m_currentFrame);
|
||||||
m_currentFrameSlider->hide();
|
//m_currentFrameSlider->hide();
|
||||||
connect(m_currentFrameSlider, static_cast<void (QSlider::*)(int)>(&QSlider::valueChanged), this, [=](int value) {
|
connect(m_currentFrameSlider, static_cast<void (QSlider::*)(int)>(&QSlider::valueChanged), this, [=](int value) {
|
||||||
setCurrentFrame(value);
|
setCurrentFrame(value);
|
||||||
});
|
});
|
||||||
|
|
||||||
connect(m_document, &Document::resultRigChanged, this, &PoseEditWidget::updatePoseDocument);
|
connect(m_document, &Document::resultRigChanged, this, &PoseEditWidget::updatePoseDocument);
|
||||||
|
|
||||||
|
QPushButton *moveToFirstFrameButton = new QPushButton(Theme::awesome()->icon(fa::angledoubleleft), "");
|
||||||
|
connect(moveToFirstFrameButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
setCurrentFrame(0);
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *moveToPreviousFrameButton = new QPushButton(Theme::awesome()->icon(fa::angleleft), "");
|
||||||
|
connect(moveToPreviousFrameButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
if (m_currentFrame > 0)
|
||||||
|
setCurrentFrame(m_currentFrame - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *moveToNextFrameButton = new QPushButton(Theme::awesome()->icon(fa::angleright), "");
|
||||||
|
connect(moveToNextFrameButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
if (m_currentFrame + 1 < (int)m_frames.size())
|
||||||
|
setCurrentFrame(m_currentFrame + 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *moveToLastFrameButton = new QPushButton(Theme::awesome()->icon(fa::angledoubleright), "");
|
||||||
|
connect(moveToLastFrameButton, &QPushButton::clicked, this, [=]() {
|
||||||
|
if (!m_frames.empty())
|
||||||
|
setCurrentFrame(m_frames.size() - 1);
|
||||||
|
});
|
||||||
|
|
||||||
|
QPushButton *insertAfterFrameButton = new QPushButton(Theme::awesome()->icon(fa::plus), "");
|
||||||
|
connect(insertAfterFrameButton, &QPushButton::clicked, this, &PoseEditWidget::insertFrameAfterCurrentFrame);
|
||||||
|
|
||||||
|
QPushButton *deleteFrameButton = new QPushButton(Theme::awesome()->icon(fa::trash), "");
|
||||||
|
connect(deleteFrameButton, &QPushButton::clicked, this, &PoseEditWidget::removeCurrentFrame);
|
||||||
|
|
||||||
|
QHBoxLayout *timelineLayout = new QHBoxLayout;
|
||||||
|
timelineLayout->addWidget(insertAfterFrameButton);
|
||||||
|
timelineLayout->addWidget(moveToFirstFrameButton);
|
||||||
|
timelineLayout->addWidget(moveToPreviousFrameButton);
|
||||||
|
timelineLayout->addWidget(moveToNextFrameButton);
|
||||||
|
timelineLayout->addWidget(moveToLastFrameButton);
|
||||||
|
timelineLayout->addWidget(m_framesSettingButton);
|
||||||
|
timelineLayout->addWidget(m_currentFrameSlider);
|
||||||
|
timelineLayout->addWidget(deleteFrameButton);
|
||||||
|
timelineLayout->setStretch(6, 1);
|
||||||
|
|
||||||
QHBoxLayout *baseInfoLayout = new QHBoxLayout;
|
QHBoxLayout *baseInfoLayout = new QHBoxLayout;
|
||||||
baseInfoLayout->addWidget(new QLabel(tr("Name")));
|
baseInfoLayout->addWidget(new QLabel(tr("Name")));
|
||||||
baseInfoLayout->addWidget(m_nameEdit);
|
baseInfoLayout->addWidget(m_nameEdit);
|
||||||
baseInfoLayout->addWidget(changeReferenceSheet);
|
baseInfoLayout->addSpacing(10);
|
||||||
baseInfoLayout->addWidget(m_framesSettingButton);
|
baseInfoLayout->addWidget(new QLabel(tr("Duration")));
|
||||||
baseInfoLayout->addWidget(m_currentFrameSlider);
|
baseInfoLayout->addWidget(m_durationEdit);
|
||||||
baseInfoLayout->addStretch();
|
baseInfoLayout->addStretch();
|
||||||
|
baseInfoLayout->addWidget(changeReferenceSheet);
|
||||||
baseInfoLayout->addWidget(saveButton);
|
baseInfoLayout->addWidget(saveButton);
|
||||||
baseInfoLayout->setStretch(4, 1);
|
|
||||||
|
|
||||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||||
mainLayout->addLayout(paramtersLayout);
|
mainLayout->addLayout(paramtersLayout);
|
||||||
mainLayout->addWidget(Theme::createHorizontalLineWidget());
|
mainLayout->addWidget(Theme::createHorizontalLineWidget());
|
||||||
|
mainLayout->addLayout(timelineLayout);
|
||||||
mainLayout->addLayout(baseInfoLayout);
|
mainLayout->addLayout(baseInfoLayout);
|
||||||
|
|
||||||
setLayout(mainLayout);
|
setLayout(mainLayout);
|
||||||
|
@ -183,7 +234,8 @@ void PoseEditWidget::showFramesSettingPopup(const QPoint &pos)
|
||||||
void PoseEditWidget::updateFramesSettingButton()
|
void PoseEditWidget::updateFramesSettingButton()
|
||||||
{
|
{
|
||||||
m_currentFrameSlider->setRange(0, m_frames.size() - 1);
|
m_currentFrameSlider->setRange(0, m_frames.size() - 1);
|
||||||
m_currentFrameSlider->setVisible(m_frames.size() > 1);
|
if (m_currentFrame != m_currentFrameSlider->value())
|
||||||
|
m_currentFrameSlider->setValue(m_currentFrame);
|
||||||
m_framesSettingButton->setText(tr("Frame: %1 / %2").arg(QString::number(m_currentFrame + 1).rightJustified(2, ' ')).arg(QString::number(m_frames.size()).leftJustified(2, ' ')));
|
m_framesSettingButton->setText(tr("Frame: %1 / %2").arg(QString::number(m_currentFrame + 1).rightJustified(2, ' ')).arg(QString::number(m_frames.size()).leftJustified(2, ' ')));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -200,7 +252,7 @@ void PoseEditWidget::syncFrameFromCurrent()
|
||||||
{
|
{
|
||||||
ensureEnoughFrames();
|
ensureEnoughFrames();
|
||||||
m_frames[m_currentFrame] = {m_currentAttributes, m_currentParameters};
|
m_frames[m_currentFrame] = {m_currentAttributes, m_currentParameters};
|
||||||
m_frames[m_currentFrame].first["duration"] = QString::number(m_frameDuration);
|
updateFramesDurations();
|
||||||
}
|
}
|
||||||
|
|
||||||
void PoseEditWidget::setFrameCount(int count)
|
void PoseEditWidget::setFrameCount(int count)
|
||||||
|
@ -211,12 +263,33 @@ void PoseEditWidget::setFrameCount(int count)
|
||||||
setUnsaveState();
|
setUnsaveState();
|
||||||
count = std::max(count, 1);
|
count = std::max(count, 1);
|
||||||
m_frames.resize(count);
|
m_frames.resize(count);
|
||||||
|
updateFramesDurations();
|
||||||
updateFramesSettingButton();
|
updateFramesSettingButton();
|
||||||
if (m_currentFrame >= count) {
|
if (m_currentFrame >= count) {
|
||||||
setCurrentFrame(count - 1);
|
setCurrentFrame(count - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PoseEditWidget::updateFramesDurations()
|
||||||
|
{
|
||||||
|
if (m_frames.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
float frameDuration = m_duration / m_frames.size();
|
||||||
|
for (auto &frame: m_frames)
|
||||||
|
frame.first["duration"] = QString::number(frameDuration);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PoseEditWidget::setDuration(float duration)
|
||||||
|
{
|
||||||
|
if (qFuzzyCompare(duration, m_duration))
|
||||||
|
return;
|
||||||
|
|
||||||
|
m_duration = duration;
|
||||||
|
setUnsaveState();
|
||||||
|
updateFramesDurations();
|
||||||
|
}
|
||||||
|
|
||||||
void PoseEditWidget::setCurrentFrame(int frame)
|
void PoseEditWidget::setCurrentFrame(int frame)
|
||||||
{
|
{
|
||||||
if (m_currentFrame == frame)
|
if (m_currentFrame == frame)
|
||||||
|
@ -229,6 +302,43 @@ void PoseEditWidget::setCurrentFrame(int frame)
|
||||||
updatePoseDocument();
|
updatePoseDocument();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void PoseEditWidget::insertFrameAfterCurrentFrame()
|
||||||
|
{
|
||||||
|
int currentFrame = m_currentFrame;
|
||||||
|
m_frames.resize(m_frames.size() + 1);
|
||||||
|
updateFramesDurations();
|
||||||
|
if (-1 != currentFrame) {
|
||||||
|
for (int index = m_frames.size() - 1; index > currentFrame; --index) {
|
||||||
|
m_frames[index] = m_frames[index - 1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
setUnsaveState();
|
||||||
|
setCurrentFrame(currentFrame + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void PoseEditWidget::removeCurrentFrame()
|
||||||
|
{
|
||||||
|
if (m_frames.size() <= 1)
|
||||||
|
return;
|
||||||
|
|
||||||
|
int currentFrame = m_currentFrame;
|
||||||
|
if (-1 != currentFrame) {
|
||||||
|
for (int index = currentFrame + 1; index < (int)m_frames.size(); ++index) {
|
||||||
|
m_frames[index - 1] = m_frames[index];
|
||||||
|
}
|
||||||
|
m_frames.resize(m_frames.size() - 1);
|
||||||
|
}
|
||||||
|
updateFramesDurations();
|
||||||
|
setUnsaveState();
|
||||||
|
if (currentFrame - 1 >= 0)
|
||||||
|
setCurrentFrame(currentFrame - 1);
|
||||||
|
else if (currentFrame < (int)m_frames.size()) {
|
||||||
|
m_currentFrame = -1;
|
||||||
|
setCurrentFrame(currentFrame);
|
||||||
|
} else
|
||||||
|
setCurrentFrame(0);
|
||||||
|
}
|
||||||
|
|
||||||
void PoseEditWidget::changeTurnaround()
|
void PoseEditWidget::changeTurnaround()
|
||||||
{
|
{
|
||||||
QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(),
|
QString fileName = QFileDialog::getOpenFileName(this, QString(), QString(),
|
||||||
|
@ -248,6 +358,13 @@ void PoseEditWidget::changeTurnaround()
|
||||||
|
|
||||||
void PoseEditWidget::updatePoseDocument()
|
void PoseEditWidget::updatePoseDocument()
|
||||||
{
|
{
|
||||||
|
m_otherFramesParameters.clear();
|
||||||
|
for (int i = 0; i < (int)m_frames.size(); ++i) {
|
||||||
|
if (m_currentFrame == i)
|
||||||
|
continue;
|
||||||
|
m_otherFramesParameters.push_back(m_frames[i].second);
|
||||||
|
}
|
||||||
|
m_poseDocument->updateOtherFramesParameters(m_otherFramesParameters);
|
||||||
m_poseDocument->fromParameters(m_document->resultRigBones(), m_currentParameters);
|
m_poseDocument->fromParameters(m_document->resultRigBones(), m_currentParameters);
|
||||||
m_poseDocument->clearHistories();
|
m_poseDocument->clearHistories();
|
||||||
m_poseDocument->saveHistoryItem();
|
m_poseDocument->saveHistoryItem();
|
||||||
|
@ -358,6 +475,14 @@ void PoseEditWidget::setEditPoseFrames(std::vector<std::pair<std::map<QString, Q
|
||||||
m_currentAttributes = frame.first;
|
m_currentAttributes = frame.first;
|
||||||
m_currentParameters = frame.second;
|
m_currentParameters = frame.second;
|
||||||
}
|
}
|
||||||
|
float totalDuration = 0;
|
||||||
|
for (const auto &frame: m_frames) {
|
||||||
|
float frameDuration = valueOfKeyInMapOrEmpty(frame.first, "duration").toFloat();
|
||||||
|
totalDuration += frameDuration;
|
||||||
|
}
|
||||||
|
if (qFuzzyIsNull(totalDuration))
|
||||||
|
totalDuration = 1.0;
|
||||||
|
m_durationEdit->setValue(totalDuration);
|
||||||
updatePoseDocument();
|
updatePoseDocument();
|
||||||
updatePreview();
|
updatePreview();
|
||||||
updateFramesSettingButton();
|
updateFramesSettingButton();
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <QCloseEvent>
|
#include <QCloseEvent>
|
||||||
#include <QLineEdit>
|
#include <QLineEdit>
|
||||||
#include <QSlider>
|
#include <QSlider>
|
||||||
|
#include <QDoubleSpinBox>
|
||||||
#include "posepreviewmanager.h"
|
#include "posepreviewmanager.h"
|
||||||
#include "document.h"
|
#include "document.h"
|
||||||
#include "modelwidget.h"
|
#include "modelwidget.h"
|
||||||
|
@ -27,7 +28,7 @@ public:
|
||||||
PoseEditWidget(const Document *document, QWidget *parent=nullptr);
|
PoseEditWidget(const Document *document, QWidget *parent=nullptr);
|
||||||
~PoseEditWidget();
|
~PoseEditWidget();
|
||||||
|
|
||||||
static const float m_frameDuration;
|
float m_duration = 1.0;
|
||||||
public slots:
|
public slots:
|
||||||
void updatePoseDocument();
|
void updatePoseDocument();
|
||||||
void updatePreview();
|
void updatePreview();
|
||||||
|
@ -37,7 +38,10 @@ public slots:
|
||||||
void setEditPoseFrames(std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> frames);
|
void setEditPoseFrames(std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> frames);
|
||||||
void setEditPoseTurnaroundImageId(QUuid imageId);
|
void setEditPoseTurnaroundImageId(QUuid imageId);
|
||||||
void setCurrentFrame(int frame);
|
void setCurrentFrame(int frame);
|
||||||
|
void insertFrameAfterCurrentFrame();
|
||||||
|
void removeCurrentFrame();
|
||||||
void setFrameCount(int count);
|
void setFrameCount(int count);
|
||||||
|
void setDuration(float duration);
|
||||||
void updateTitle();
|
void updateTitle();
|
||||||
void save();
|
void save();
|
||||||
void clearUnsaveState();
|
void clearUnsaveState();
|
||||||
|
@ -46,6 +50,7 @@ public slots:
|
||||||
private slots:
|
private slots:
|
||||||
void updateFramesSettingButton();
|
void updateFramesSettingButton();
|
||||||
void showFramesSettingPopup(const QPoint &pos);
|
void showFramesSettingPopup(const QPoint &pos);
|
||||||
|
void updateFramesDurations();
|
||||||
protected:
|
protected:
|
||||||
QSize sizeHint() const override;
|
QSize sizeHint() const override;
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
@ -60,11 +65,13 @@ private:
|
||||||
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> m_frames;
|
std::vector<std::pair<std::map<QString, QString>, std::map<QString, std::map<QString, QString>>>> m_frames;
|
||||||
std::map<QString, QString> m_currentAttributes;
|
std::map<QString, QString> m_currentAttributes;
|
||||||
std::map<QString, std::map<QString, QString>> m_currentParameters;
|
std::map<QString, std::map<QString, QString>> m_currentParameters;
|
||||||
|
std::vector<std::map<QString, std::map<QString, QString>>> m_otherFramesParameters;
|
||||||
int m_currentFrame = 0;
|
int m_currentFrame = 0;
|
||||||
QUuid m_poseId;
|
QUuid m_poseId;
|
||||||
bool m_unsaved = false;
|
bool m_unsaved = false;
|
||||||
QUuid m_imageId;
|
QUuid m_imageId;
|
||||||
QLineEdit *m_nameEdit = nullptr;
|
QLineEdit *m_nameEdit = nullptr;
|
||||||
|
QDoubleSpinBox *m_durationEdit = nullptr;
|
||||||
PoseDocument *m_poseDocument = nullptr;
|
PoseDocument *m_poseDocument = nullptr;
|
||||||
SkeletonGraphicsWidget *m_poseGraphicsWidget = nullptr;
|
SkeletonGraphicsWidget *m_poseGraphicsWidget = nullptr;
|
||||||
QPushButton *m_framesSettingButton = nullptr;
|
QPushButton *m_framesSettingButton = nullptr;
|
||||||
|
|
|
@ -246,6 +246,14 @@ public:
|
||||||
virtual bool originSettled() const = 0;
|
virtual bool originSettled() const = 0;
|
||||||
virtual bool isNodeEditable(QUuid nodeId) const = 0;
|
virtual bool isNodeEditable(QUuid nodeId) const = 0;
|
||||||
virtual bool isEdgeEditable(QUuid edgeId) const = 0;
|
virtual bool isEdgeEditable(QUuid edgeId) const = 0;
|
||||||
|
virtual bool isNodeDeactivated(QUuid nodeId) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
virtual bool isEdgeDeactivated(QUuid edgeId) const
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
};
|
||||||
virtual void copyNodes(std::set<QUuid> nodeIdSet) const = 0;
|
virtual void copyNodes(std::set<QUuid> nodeIdSet) const = 0;
|
||||||
|
|
||||||
public slots:
|
public slots:
|
||||||
|
|
|
@ -698,11 +698,15 @@ bool SkeletonGraphicsWidget::mouseMove(QMouseEvent *event)
|
||||||
QGraphicsItem *item = *it;
|
QGraphicsItem *item = *it;
|
||||||
if (item->data(0) == "node") {
|
if (item->data(0) == "node") {
|
||||||
SkeletonGraphicsNodeItem *nodeItem = (SkeletonGraphicsNodeItem *)item;
|
SkeletonGraphicsNodeItem *nodeItem = (SkeletonGraphicsNodeItem *)item;
|
||||||
|
if (nodeItem->deactivated())
|
||||||
|
continue;
|
||||||
QPointF origin = nodeItem->origin();
|
QPointF origin = nodeItem->origin();
|
||||||
float distance2 = pow(origin.x() - scenePos.x(), 2) + pow(origin.y() - scenePos.y(), 2);
|
float distance2 = pow(origin.x() - scenePos.x(), 2) + pow(origin.y() - scenePos.y(), 2);
|
||||||
itemDistance2MapWithMouse.push_back(std::make_pair(item, distance2));
|
itemDistance2MapWithMouse.push_back(std::make_pair(item, distance2));
|
||||||
} else if (item->data(0) == "edge") {
|
} else if (item->data(0) == "edge") {
|
||||||
SkeletonGraphicsEdgeItem *edgeItem = (SkeletonGraphicsEdgeItem *)item;
|
SkeletonGraphicsEdgeItem *edgeItem = (SkeletonGraphicsEdgeItem *)item;
|
||||||
|
if (edgeItem->deactivated())
|
||||||
|
continue;
|
||||||
if (edgeItem->firstItem() && edgeItem->secondItem()) {
|
if (edgeItem->firstItem() && edgeItem->secondItem()) {
|
||||||
QPointF firstOrigin = edgeItem->firstItem()->origin();
|
QPointF firstOrigin = edgeItem->firstItem()->origin();
|
||||||
QPointF secondOrigin = edgeItem->secondItem()->origin();
|
QPointF secondOrigin = edgeItem->secondItem()->origin();
|
||||||
|
@ -1748,6 +1752,10 @@ void SkeletonGraphicsWidget::nodeAdded(QUuid nodeId)
|
||||||
sideProfileItem->setMarkColor(markColor);
|
sideProfileItem->setMarkColor(markColor);
|
||||||
mainProfileItem->setId(nodeId);
|
mainProfileItem->setId(nodeId);
|
||||||
sideProfileItem->setId(nodeId);
|
sideProfileItem->setId(nodeId);
|
||||||
|
if (m_document->isNodeDeactivated(nodeId)) {
|
||||||
|
mainProfileItem->setDeactivated(true);
|
||||||
|
sideProfileItem->setDeactivated(true);
|
||||||
|
}
|
||||||
if (m_mainProfileOnly)
|
if (m_mainProfileOnly)
|
||||||
sideProfileItem->hide();
|
sideProfileItem->hide();
|
||||||
scene()->addItem(mainProfileItem);
|
scene()->addItem(mainProfileItem);
|
||||||
|
@ -1799,6 +1807,10 @@ void SkeletonGraphicsWidget::edgeAdded(QUuid edgeId)
|
||||||
sideProfileEdgeItem->setId(edgeId);
|
sideProfileEdgeItem->setId(edgeId);
|
||||||
mainProfileEdgeItem->setEndpoints(fromIt->second.first, toIt->second.first);
|
mainProfileEdgeItem->setEndpoints(fromIt->second.first, toIt->second.first);
|
||||||
sideProfileEdgeItem->setEndpoints(fromIt->second.second, toIt->second.second);
|
sideProfileEdgeItem->setEndpoints(fromIt->second.second, toIt->second.second);
|
||||||
|
if (m_document->isNodeDeactivated(edgeId)) {
|
||||||
|
mainProfileEdgeItem->setDeactivated(true);
|
||||||
|
sideProfileEdgeItem->setDeactivated(true);
|
||||||
|
}
|
||||||
if (m_mainProfileOnly)
|
if (m_mainProfileOnly)
|
||||||
sideProfileEdgeItem->hide();
|
sideProfileEdgeItem->hide();
|
||||||
scene()->addItem(mainProfileEdgeItem);
|
scene()->addItem(mainProfileEdgeItem);
|
||||||
|
|
|
@ -125,25 +125,28 @@ public:
|
||||||
m_profile(profile),
|
m_profile(profile),
|
||||||
m_hovered(false),
|
m_hovered(false),
|
||||||
m_checked(false),
|
m_checked(false),
|
||||||
m_markColor(Qt::transparent)
|
m_markColor(Qt::transparent),
|
||||||
|
m_deactivated(false)
|
||||||
{
|
{
|
||||||
setData(0, "node");
|
setData(0, "node");
|
||||||
setRadius(32);
|
setRadius(32);
|
||||||
}
|
}
|
||||||
void updateAppearance()
|
void updateAppearance()
|
||||||
{
|
{
|
||||||
QColor color = Theme::white;
|
QColor color = Qt::gray;
|
||||||
|
|
||||||
switch (m_profile)
|
if (!m_deactivated) {
|
||||||
{
|
switch (m_profile)
|
||||||
case SkeletonProfile::Unknown:
|
{
|
||||||
break;
|
case SkeletonProfile::Unknown:
|
||||||
case SkeletonProfile::Main:
|
break;
|
||||||
color = Theme::red;
|
case SkeletonProfile::Main:
|
||||||
break;
|
color = Theme::red;
|
||||||
case SkeletonProfile::Side:
|
break;
|
||||||
color = Theme::green;
|
case SkeletonProfile::Side:
|
||||||
break;
|
color = Theme::green;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor penColor = color;
|
QColor penColor = color;
|
||||||
|
@ -222,6 +225,15 @@ public:
|
||||||
m_checked = checked;
|
m_checked = checked;
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
|
void setDeactivated(bool deactivated)
|
||||||
|
{
|
||||||
|
m_deactivated = deactivated;
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
|
bool deactivated()
|
||||||
|
{
|
||||||
|
return m_deactivated;
|
||||||
|
}
|
||||||
bool checked()
|
bool checked()
|
||||||
{
|
{
|
||||||
return m_checked;
|
return m_checked;
|
||||||
|
@ -236,6 +248,7 @@ private:
|
||||||
bool m_hovered;
|
bool m_hovered;
|
||||||
bool m_checked;
|
bool m_checked;
|
||||||
QColor m_markColor;
|
QColor m_markColor;
|
||||||
|
bool m_deactivated;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkeletonGraphicsEdgeItem : public QGraphicsPolygonItem
|
class SkeletonGraphicsEdgeItem : public QGraphicsPolygonItem
|
||||||
|
@ -246,7 +259,8 @@ public:
|
||||||
m_secondItem(nullptr),
|
m_secondItem(nullptr),
|
||||||
m_hovered(false),
|
m_hovered(false),
|
||||||
m_checked(false),
|
m_checked(false),
|
||||||
m_profile(SkeletonProfile::Unknown)
|
m_profile(SkeletonProfile::Unknown),
|
||||||
|
m_deactivated(false)
|
||||||
{
|
{
|
||||||
setData(0, "edge");
|
setData(0, "edge");
|
||||||
}
|
}
|
||||||
|
@ -282,18 +296,20 @@ public:
|
||||||
polygon << line.p1() + offset1 << line.p1() + offset2 << line.p2() + offset2 << line.p2() + offset1;
|
polygon << line.p1() + offset1 << line.p1() + offset2 << line.p2() + offset2 << line.p2() + offset1;
|
||||||
setPolygon(polygon);
|
setPolygon(polygon);
|
||||||
|
|
||||||
QColor color = Theme::white;
|
QColor color = Qt::gray;
|
||||||
|
|
||||||
switch (m_firstItem->profile())
|
if (!m_deactivated) {
|
||||||
{
|
switch (m_firstItem->profile())
|
||||||
case SkeletonProfile::Unknown:
|
{
|
||||||
break;
|
case SkeletonProfile::Unknown:
|
||||||
case SkeletonProfile::Main:
|
break;
|
||||||
color = Theme::red;
|
case SkeletonProfile::Main:
|
||||||
break;
|
color = Theme::red;
|
||||||
case SkeletonProfile::Side:
|
break;
|
||||||
color = Theme::green;
|
case SkeletonProfile::Side:
|
||||||
break;
|
color = Theme::green;
|
||||||
|
break;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QColor penColor = color;
|
QColor penColor = color;
|
||||||
|
@ -324,6 +340,15 @@ public:
|
||||||
m_checked = checked;
|
m_checked = checked;
|
||||||
updateAppearance();
|
updateAppearance();
|
||||||
}
|
}
|
||||||
|
void setDeactivated(bool deactivated)
|
||||||
|
{
|
||||||
|
m_deactivated = deactivated;
|
||||||
|
updateAppearance();
|
||||||
|
}
|
||||||
|
bool deactivated()
|
||||||
|
{
|
||||||
|
return m_deactivated;
|
||||||
|
}
|
||||||
bool checked()
|
bool checked()
|
||||||
{
|
{
|
||||||
return m_checked;
|
return m_checked;
|
||||||
|
@ -340,6 +365,7 @@ private:
|
||||||
bool m_hovered;
|
bool m_hovered;
|
||||||
bool m_checked;
|
bool m_checked;
|
||||||
SkeletonProfile m_profile;
|
SkeletonProfile m_profile;
|
||||||
|
bool m_deactivated;
|
||||||
};
|
};
|
||||||
|
|
||||||
class SkeletonGraphicsWidget : public QGraphicsView
|
class SkeletonGraphicsWidget : public QGraphicsView
|
||||||
|
|
Loading…
Reference in New Issue