224 lines
5.2 KiB
C
224 lines
5.2 KiB
C
|
#ifndef DUST3D_SKELETON_DOCUMENT_H
|
||
|
#define DUST3D_SKELETON_DOCUMENT_H
|
||
|
#include <QUuid>
|
||
|
#include <QObject>
|
||
|
#include <QString>
|
||
|
#include <cmath>
|
||
|
#include <QImage>
|
||
|
#include "bonemark.h"
|
||
|
#include "theme.h"
|
||
|
#include "meshloader.h"
|
||
|
|
||
|
class SkeletonNode
|
||
|
{
|
||
|
public:
|
||
|
SkeletonNode(const QUuid &withId=QUuid()) :
|
||
|
x(0),
|
||
|
y(0),
|
||
|
z(0),
|
||
|
radius(0),
|
||
|
boneMark(BoneMark::None)
|
||
|
{
|
||
|
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||
|
}
|
||
|
void setRadius(float toRadius)
|
||
|
{
|
||
|
if (toRadius < 0)
|
||
|
toRadius = 0.005;
|
||
|
else if (toRadius > 1)
|
||
|
toRadius = 1;
|
||
|
radius = toRadius;
|
||
|
}
|
||
|
QUuid id;
|
||
|
QUuid partId;
|
||
|
QString name;
|
||
|
float x;
|
||
|
float y;
|
||
|
float z;
|
||
|
float radius;
|
||
|
BoneMark boneMark;
|
||
|
std::vector<QUuid> edgeIds;
|
||
|
};
|
||
|
|
||
|
class SkeletonEdge
|
||
|
{
|
||
|
public:
|
||
|
SkeletonEdge(const QUuid &withId=QUuid())
|
||
|
{
|
||
|
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||
|
}
|
||
|
QUuid id;
|
||
|
QUuid partId;
|
||
|
QString name;
|
||
|
std::vector<QUuid> nodeIds;
|
||
|
QUuid neighborOf(QUuid nodeId) const
|
||
|
{
|
||
|
if (nodeIds.size() != 2)
|
||
|
return QUuid();
|
||
|
return nodeIds[0] == nodeId ? nodeIds[1] : nodeIds[0];
|
||
|
}
|
||
|
};
|
||
|
|
||
|
class SkeletonPart
|
||
|
{
|
||
|
public:
|
||
|
~SkeletonPart()
|
||
|
{
|
||
|
delete m_previewMesh;
|
||
|
}
|
||
|
QUuid id;
|
||
|
QString name;
|
||
|
bool visible;
|
||
|
bool locked;
|
||
|
bool subdived;
|
||
|
bool disabled;
|
||
|
bool xMirrored;
|
||
|
bool zMirrored;
|
||
|
float deformThickness;
|
||
|
float deformWidth;
|
||
|
bool rounded;
|
||
|
QColor color;
|
||
|
bool hasColor;
|
||
|
QUuid componentId;
|
||
|
std::vector<QUuid> nodeIds;
|
||
|
bool dirty;
|
||
|
bool wrapped;
|
||
|
QUuid materialId;
|
||
|
SkeletonPart(const QUuid &withId=QUuid()) :
|
||
|
visible(true),
|
||
|
locked(false),
|
||
|
subdived(false),
|
||
|
disabled(false),
|
||
|
xMirrored(false),
|
||
|
zMirrored(false),
|
||
|
deformThickness(1.0),
|
||
|
deformWidth(1.0),
|
||
|
rounded(false),
|
||
|
color(Theme::white),
|
||
|
hasColor(false),
|
||
|
dirty(true),
|
||
|
wrapped(false)
|
||
|
{
|
||
|
id = withId.isNull() ? QUuid::createUuid() : withId;
|
||
|
}
|
||
|
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;
|
||
|
}
|
||
|
bool deformThicknessAdjusted() const
|
||
|
{
|
||
|
return fabs(deformThickness - 1.0) >= 0.01;
|
||
|
}
|
||
|
bool deformWidthAdjusted() const
|
||
|
{
|
||
|
return fabs(deformWidth - 1.0) >= 0.01;
|
||
|
}
|
||
|
bool deformAdjusted() const
|
||
|
{
|
||
|
return deformThicknessAdjusted() || deformWidthAdjusted();
|
||
|
}
|
||
|
bool 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;
|
||
|
zMirrored = other.zMirrored;
|
||
|
deformThickness = other.deformThickness;
|
||
|
deformWidth = other.deformWidth;
|
||
|
rounded = other.rounded;
|
||
|
color = other.color;
|
||
|
hasColor = other.hasColor;
|
||
|
wrapped = other.wrapped;
|
||
|
componentId = other.componentId;
|
||
|
dirty = other.dirty;
|
||
|
materialId = other.materialId;
|
||
|
}
|
||
|
void updatePreviewMesh(MeshLoader *previewMesh)
|
||
|
{
|
||
|
delete m_previewMesh;
|
||
|
m_previewMesh = previewMesh;
|
||
|
}
|
||
|
MeshLoader *takePreviewMesh() const
|
||
|
{
|
||
|
if (nullptr == m_previewMesh)
|
||
|
return nullptr;
|
||
|
return new MeshLoader(*m_previewMesh);
|
||
|
}
|
||
|
private:
|
||
|
Q_DISABLE_COPY(SkeletonPart);
|
||
|
MeshLoader *m_previewMesh = nullptr;
|
||
|
};
|
||
|
|
||
|
enum class SkeletonDocumentEditMode
|
||
|
{
|
||
|
Add = 0,
|
||
|
Select,
|
||
|
Drag,
|
||
|
ZoomIn,
|
||
|
ZoomOut
|
||
|
};
|
||
|
|
||
|
enum class SkeletonProfile
|
||
|
{
|
||
|
Unknown = 0,
|
||
|
Main,
|
||
|
Side
|
||
|
};
|
||
|
|
||
|
class SkeletonDocument : public QObject
|
||
|
{
|
||
|
Q_OBJECT
|
||
|
public:
|
||
|
float originX = 0;
|
||
|
float originY = 0;
|
||
|
float originZ = 0;
|
||
|
SkeletonDocumentEditMode editMode = SkeletonDocumentEditMode::Select;
|
||
|
bool xlocked = false;
|
||
|
bool ylocked = false;
|
||
|
bool zlocked = false;
|
||
|
bool radiusLocked = false;
|
||
|
QImage turnaround;
|
||
|
|
||
|
virtual const SkeletonNode *findNode(QUuid nodeId) const = 0;
|
||
|
virtual const SkeletonEdge *findEdge(QUuid edgeId) const = 0;
|
||
|
virtual const SkeletonPart *findPart(QUuid partId) const = 0;
|
||
|
virtual const SkeletonEdge *findEdgeByNodes(QUuid firstNodeId, QUuid secondNodeId) const = 0;
|
||
|
virtual bool undoable() const = 0;
|
||
|
virtual bool redoable() const = 0;
|
||
|
virtual bool hasPastableNodesInClipboard() const = 0;
|
||
|
virtual bool originSettled() const = 0;
|
||
|
virtual bool isNodeEditable(QUuid nodeId) const = 0;
|
||
|
virtual bool isEdgeEditable(QUuid edgeId) const = 0;
|
||
|
virtual void findAllNeighbors(QUuid nodeId, std::set<QUuid> &neighbors) const = 0;
|
||
|
virtual void copyNodes(std::set<QUuid> nodeIdSet) const = 0;
|
||
|
|
||
|
public slots:
|
||
|
virtual void undo() = 0;
|
||
|
virtual void redo() = 0;
|
||
|
virtual void paste() = 0;
|
||
|
};
|
||
|
|
||
|
#endif
|