diff --git a/dust3d.pro b/dust3d.pro
index bd7b75f3..dbf711b9 100644
--- a/dust3d.pro
+++ b/dust3d.pro
@@ -410,6 +410,9 @@ HEADERS += src/intnumberwidget.h
SOURCES += src/imagepreviewwidget.cpp
HEADERS += src/imagepreviewwidget.h
+SOURCES += src/mousepicker.cpp
+HEADERS += src/mousepicker.h
+
SOURCES += src/main.cpp
HEADERS += src/version.h
diff --git a/languages/dust3d_zh_CN.ts b/languages/dust3d_zh_CN.ts
index d6e81582..704f62b3 100644
--- a/languages/dust3d_zh_CN.ts
+++ b/languages/dust3d_zh_CN.ts
@@ -362,6 +362,10 @@ Tips:
检查新版本...
+
+
+ 画刷
+
ExportPreviewWidget
diff --git a/shaders/pbr-qt.frag b/shaders/pbr-qt.frag
index 7a1ac35a..1c506292 100644
--- a/shaders/pbr-qt.frag
+++ b/shaders/pbr-qt.frag
@@ -75,6 +75,8 @@ uniform highp sampler2D metalnessRoughnessAmbientOcclusionMapId;
uniform highp int metalnessMapEnabled;
uniform highp int roughnessMapEnabled;
uniform highp int ambientOcclusionMapEnabled;
+uniform highp int mousePickEnabled;
+uniform highp vec3 mousePickTargetPosition;
const int MAX_LIGHTS = 8;
const int TYPE_POINT = 0;
@@ -320,6 +322,11 @@ void main()
if (textureEnabled == 1) {
color = texture2D(textureId, vertTexCoord).rgb;
}
+ if (mousePickEnabled == 1) {
+ if (distance(mousePickTargetPosition, vert) <= 0.1) {
+ color = color + vec3(0.99, 0.4, 0.13);
+ }
+ }
color = pow(color, vec3(gamma));
highp vec3 normal = vertNormal;
diff --git a/src/document.cpp b/src/document.cpp
index 66207f93..3b32dcb4 100644
--- a/src/document.cpp
+++ b/src/document.cpp
@@ -15,6 +15,7 @@
#include "motionsgenerator.h"
#include "skeletonside.h"
#include "scriptrunner.h"
+#include "mousepicker.h"
unsigned long Document::m_maxSnapshot = 1000;
@@ -64,7 +65,9 @@ Document::Document() :
m_meshGenerationId(0),
m_nextMeshGenerationId(1),
m_scriptRunner(nullptr),
- m_isScriptResultObsolete(false)
+ m_isScriptResultObsolete(false),
+ m_mousePicker(nullptr),
+ m_isMouseTargetResultObsolete(false)
{
connect(&Preferences::instance(), &Preferences::partColorChanged, this, &Document::applyPreferencePartColorChange);
connect(&Preferences::instance(), &Preferences::flatShadingChanged, this, &Document::applyPreferenceFlatShadingChange);
@@ -1922,6 +1925,56 @@ void Document::postProcessedMeshResultReady()
}
}
+void Document::pickMouseTarget(const QVector3D &nearPosition, const QVector3D &farPosition)
+{
+ m_mouseRayNear = nearPosition;
+ m_mouseRayFar = farPosition;
+
+ if (nullptr != m_mousePicker) {
+ m_isMouseTargetResultObsolete = true;
+ return;
+ }
+
+ m_isMouseTargetResultObsolete = false;
+
+ if (!m_currentOutcome) {
+ qDebug() << "MeshLoader is null";
+ return;
+ }
+
+ qDebug() << "Mouse picking..";
+
+ QThread *thread = new QThread;
+ m_mousePicker = new MousePicker(*m_currentOutcome, m_mouseRayNear, m_mouseRayFar);
+ m_mousePicker->moveToThread(thread);
+ connect(thread, &QThread::started, m_mousePicker, &MousePicker::process);
+ connect(m_mousePicker, &MousePicker::finished, this, &Document::mouseTargetReady);
+ connect(m_mousePicker, &MousePicker::finished, thread, &QThread::quit);
+ connect(thread, &QThread::finished, thread, &QThread::deleteLater);
+ thread->start();
+}
+
+void Document::mouseTargetReady()
+{
+ m_mouseTargetPosition = m_mousePicker->targetPosition();
+
+ delete m_mousePicker;
+ m_mousePicker = nullptr;
+
+ emit mouseTargetChanged();
+
+ qDebug() << "Mouse pick done";
+
+ if (m_isMouseTargetResultObsolete) {
+ pickMouseTarget(m_mouseRayNear, m_mouseRayFar);
+ }
+}
+
+const QVector3D &Document::mouseTargetPosition() const
+{
+ return m_mouseTargetPosition;
+}
+
const Outcome &Document::currentPostProcessedOutcome() const
{
return *m_postProcessedOutcome;
diff --git a/src/document.h b/src/document.h
index 28b735e0..96061789 100644
--- a/src/document.h
+++ b/src/document.h
@@ -30,6 +30,7 @@
class MaterialPreviewsGenerator;
class MotionsGenerator;
class ScriptRunner;
+class MousePicker;
class HistoryItem
{
@@ -471,6 +472,7 @@ signals:
void scriptRunning();
void scriptErrorChanged();
void scriptConsoleLogChanged();
+ void mouseTargetChanged();
public: // need initialize
QImage *textureGuideImage;
QImage *textureImage;
@@ -539,6 +541,7 @@ public:
const std::map> &variables() const;
const QString &scriptError() const;
const QString &scriptConsoleLog() const;
+ const QVector3D &mouseTargetPosition() const;
public slots:
void undo() override;
void redo() override;
@@ -577,6 +580,8 @@ public slots:
void materialPreviewsReady();
void generateMotions();
void motionsReady();
+ void pickMouseTarget(const QVector3D &nearPosition, const QVector3D &farPosition);
+ void mouseTargetReady();
void setPartLockState(QUuid partId, bool locked);
void setPartVisibleState(QUuid partId, bool visible);
void setPartSubdivState(QUuid partId, bool subdived);
@@ -721,6 +726,11 @@ private: // need initialize
std::map> m_mergedVariables;
ScriptRunner *m_scriptRunner;
bool m_isScriptResultObsolete;
+ MousePicker *m_mousePicker;
+ bool m_isMouseTargetResultObsolete;
+ QVector3D m_mouseRayNear;
+ QVector3D m_mouseRayFar;
+ QVector3D m_mouseTargetPosition;
QString m_scriptError;
QString m_scriptConsoleLog;
private:
diff --git a/src/documentwindow.cpp b/src/documentwindow.cpp
index 6b3dde76..7553454b 100644
--- a/src/documentwindow.cpp
+++ b/src/documentwindow.cpp
@@ -156,6 +156,10 @@ DocumentWindow::DocumentWindow() :
QPushButton *selectButton = new QPushButton(QChar(fa::mousepointer));
selectButton->setToolTip(tr("Select node on canvas"));
Theme::initAwesomeButton(selectButton);
+
+ QPushButton *paintButton = new QPushButton(QChar(fa::paintbrush));
+ paintButton->setToolTip(tr("Paint brush"));
+ Theme::initAwesomeButton(paintButton);
QPushButton *dragButton = new QPushButton(QChar(fa::handrocko));
dragButton->setToolTip(tr("Enter drag mode"));
@@ -228,6 +232,7 @@ DocumentWindow::DocumentWindow() :
toolButtonLayout->addWidget(addButton);
toolButtonLayout->addWidget(selectButton);
+ toolButtonLayout->addWidget(paintButton);
toolButtonLayout->addWidget(dragButton);
toolButtonLayout->addWidget(zoomInButton);
toolButtonLayout->addWidget(zoomOutButton);
@@ -278,6 +283,11 @@ DocumentWindow::DocumentWindow() :
m_modelRenderWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_modelRenderWidget->move(DocumentWindow::m_modelRenderWidgetInitialX, DocumentWindow::m_modelRenderWidgetInitialY);
+ connect(m_modelRenderWidget, &ModelWidget::mouseRayChanged, m_document, &Document::pickMouseTarget);
+ connect(m_document, &Document::mouseTargetChanged, this, [=]() {
+ m_modelRenderWidget->setMousePickTargetPositionInModelSpace(m_document->mouseTargetPosition());
+ });
+
m_graphicsWidget->setModelWidget(m_modelRenderWidget);
containerWidget->setModelWidget(m_modelRenderWidget);
@@ -767,6 +777,10 @@ DocumentWindow::DocumentWindow() :
connect(selectButton, &QPushButton::clicked, [=]() {
m_document->setEditMode(SkeletonDocumentEditMode::Select);
});
+
+ connect(paintButton, &QPushButton::clicked, [=]() {
+ m_document->setEditMode(SkeletonDocumentEditMode::Paint);
+ });
connect(dragButton, &QPushButton::clicked, [=]() {
m_document->setEditMode(SkeletonDocumentEditMode::Drag);
@@ -792,6 +806,10 @@ DocumentWindow::DocumentWindow() :
connect(m_radiusLockButton, &QPushButton::clicked, [=]() {
m_document->setRadiusLockState(!m_document->radiusLocked);
});
+
+ connect(m_document, &Document::editModeChanged, this, [=]() {
+ m_modelRenderWidget->enableMousePicking(SkeletonDocumentEditMode::Paint == m_document->editMode);
+ });
m_partListDockerVisibleSwitchConnection = connect(m_document, &Document::skeletonChanged, [=]() {
if (m_graphicsWidget->hasItems()) {
@@ -973,6 +991,7 @@ DocumentWindow::DocumentWindow() :
connect(graphicsWidget, &SkeletonGraphicsWidget::cursorChanged, [=]() {
m_modelRenderWidget->setCursor(graphicsWidget->cursor());
+ containerWidget->setCursor(graphicsWidget->cursor());
//m_skeletonRenderWidget->setCursor(graphicsWidget->cursor());
});
diff --git a/src/documentwindow.h b/src/documentwindow.h
index 5cf6c9e6..339d9354 100644
--- a/src/documentwindow.h
+++ b/src/documentwindow.h
@@ -26,6 +26,7 @@ signals:
void initialized();
void uninialized();
void waitingExportFinished(const QString &filename, bool succeed);
+ void mouseTargetVertexPositionChanged(const QVector3D &position);
public:
DocumentWindow();
~DocumentWindow();
diff --git a/src/graphicscontainerwidget.cpp b/src/graphicscontainerwidget.cpp
index b0aed1fd..289a22d4 100644
--- a/src/graphicscontainerwidget.cpp
+++ b/src/graphicscontainerwidget.cpp
@@ -2,6 +2,7 @@
GraphicsContainerWidget::GraphicsContainerWidget()
{
+ setMouseTracking(true);
}
void GraphicsContainerWidget::resizeEvent(QResizeEvent *event)
diff --git a/src/modelshaderprogram.cpp b/src/modelshaderprogram.cpp
index 94d55fcb..f985c0af 100644
--- a/src/modelshaderprogram.cpp
+++ b/src/modelshaderprogram.cpp
@@ -53,6 +53,8 @@ ModelShaderProgram::ModelShaderProgram(bool usePBR)
m_roughnessMapEnabledLoc = this->uniformLocation("roughnessMapEnabled");
m_ambientOcclusionMapEnabledLoc = this->uniformLocation("ambientOcclusionMapEnabled");
m_metalnessRoughnessAmbientOcclusionMapIdLoc = this->uniformLocation("metalnessRoughnessAmbientOcclusionMapId");
+ m_mousePickEnabledLoc = this->uniformLocation("mousePickEnabled");
+ m_mousePickTargetPositionLoc = this->uniformLocation("mousePickTargetPosition");
}
int ModelShaderProgram::projectionMatrixLoc()
@@ -120,3 +122,12 @@ int ModelShaderProgram::metalnessRoughnessAmbientOcclusionMapIdLoc()
return m_metalnessRoughnessAmbientOcclusionMapIdLoc;
}
+int ModelShaderProgram::mousePickEnabledLoc()
+{
+ return m_mousePickEnabledLoc;
+}
+
+int ModelShaderProgram::mousePickTargetPositionLoc()
+{
+ return m_mousePickTargetPositionLoc;
+}
diff --git a/src/modelshaderprogram.h b/src/modelshaderprogram.h
index f317be53..d5cd496a 100644
--- a/src/modelshaderprogram.h
+++ b/src/modelshaderprogram.h
@@ -20,6 +20,8 @@ public:
int roughnessMapEnabledLoc();
int ambientOcclusionMapEnabledLoc();
int metalnessRoughnessAmbientOcclusionMapIdLoc();
+ int mousePickEnabledLoc();
+ int mousePickTargetPositionLoc();
static const QString &loadShaderSource(const QString &name);
private:
int m_projectionMatrixLoc;
@@ -35,6 +37,8 @@ private:
int m_roughnessMapEnabledLoc;
int m_ambientOcclusionMapEnabledLoc;
int m_metalnessRoughnessAmbientOcclusionMapIdLoc;
+ int m_mousePickEnabledLoc;
+ int m_mousePickTargetPositionLoc;
};
#endif
diff --git a/src/modelwidget.cpp b/src/modelwidget.cpp
index b56d886c..d0d2dc8c 100644
--- a/src/modelwidget.cpp
+++ b/src/modelwidget.cpp
@@ -10,6 +10,7 @@
// Modifed from http://doc.qt.io/qt-5/qtopengl-hellogl2-glwidget-cpp.html
bool ModelWidget::m_transparent = true;
+const QVector3D ModelWidget::m_cameraPosition = QVector3D(0, 0, -4.0);
ModelWidget::ModelWidget(QWidget *parent) :
QOpenGLWidget(parent),
@@ -19,7 +20,8 @@ ModelWidget::ModelWidget(QWidget *parent) :
m_program(nullptr),
m_moveStarted(false),
m_moveEnabled(true),
- m_zoomEnabled(true)
+ m_zoomEnabled(true),
+ m_mousePickingEnabled(false)
{
// --transparent causes the clear color to be transparent. Therefore, on systems that
// support it, the widget will become transparent apart from the logo.
@@ -130,7 +132,7 @@ void ModelWidget::initializeGL()
// Our camera never changes in this example.
m_camera.setToIdentity();
// FIXME: if change here, please also change the camera pos in PBR shader
- m_camera.translate(0, 0, -4.0);
+ m_camera.translate(m_cameraPosition.x(), m_cameraPosition.y(), m_cameraPosition.z());
// Light position is fixed.
// FIXME: PBR render no longer use this parameter
@@ -162,6 +164,15 @@ void ModelWidget::paintGL()
m_program->setUniformValue(m_program->textureEnabledLoc(), 0);
m_program->setUniformValue(m_program->normalMapEnabledLoc(), 0);
+ if (m_mousePickingEnabled && !m_mousePickTargetPositionInModelSpace.isNull()) {
+ m_program->setUniformValue(m_program->mousePickEnabledLoc(), 1);
+ m_program->setUniformValue(m_program->mousePickTargetPositionLoc(),
+ m_world * m_mousePickTargetPositionInModelSpace);
+ } else {
+ m_program->setUniformValue(m_program->mousePickEnabledLoc(), 0);
+ m_program->setUniformValue(m_program->mousePickTargetPositionLoc(), QVector3D());
+ }
+
m_meshBinder.paint(m_program);
m_program->release();
@@ -173,6 +184,20 @@ void ModelWidget::resizeGL(int w, int h)
m_projection.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f);
}
+std::pair ModelWidget::screenPositionToMouseRay(const QPoint &screenPosition)
+{
+ auto modelView = m_camera * m_world;
+ float x = qMax(qMin(screenPosition.x(), width() - 1), 0);
+ float y = qMax(qMin(screenPosition.y(), height() - 1), 0);
+ QVector3D nearScreen = QVector3D(x, height() - y, 0.0);
+ QVector3D farScreen = QVector3D(x, height() - y, 1.0);
+ auto viewPort = QRect(0, 0, width(), height());
+ auto nearPosition = nearScreen.unproject(modelView, m_projection, viewPort);
+ auto farPosition = farScreen.unproject(modelView, m_projection, viewPort);
+ qDebug() << "near:" << nearPosition << "far:" << farPosition << "x:" << x << "y:" << y;
+ return std::make_pair(nearPosition, farPosition);
+}
+
void ModelWidget::toggleWireframe()
{
if (m_meshBinder.isWireframesVisible())
@@ -217,11 +242,17 @@ bool ModelWidget::inputMouseReleaseEventFromOtherWidget(QMouseEvent *event)
bool ModelWidget::inputMouseMoveEventFromOtherWidget(QMouseEvent *event)
{
+ QPoint pos = convertInputPosFromOtherWidget(event);
+
+ if (m_mousePickingEnabled) {
+ auto segment = screenPositionToMouseRay(pos);
+ emit mouseRayChanged(segment.first, segment.second);
+ }
+
if (!m_moveStarted) {
return false;
}
- QPoint pos = convertInputPosFromOtherWidget(event);
int dx = pos.x() - m_lastPos.x();
int dy = pos.y() - m_lastPos.y();
@@ -275,6 +306,12 @@ void ModelWidget::zoom(float delta)
setGeometry(geometry().marginsAdded(margins));
}
+void ModelWidget::setMousePickTargetPositionInModelSpace(QVector3D position)
+{
+ m_mousePickTargetPositionInModelSpace = position;
+ update();
+}
+
void ModelWidget::updateMesh(MeshLoader *mesh)
{
m_meshBinder.updateMesh(mesh);
@@ -291,6 +328,11 @@ void ModelWidget::enableZoom(bool enabled)
m_zoomEnabled = enabled;
}
+void ModelWidget::enableMousePicking(bool enabled)
+{
+ m_mousePickingEnabled = enabled;
+}
+
void ModelWidget::mousePressEvent(QMouseEvent *event)
{
inputMousePressEventFromOtherWidget(event);
diff --git a/src/modelwidget.h b/src/modelwidget.h
index e5d2e970..ddc964c7 100644
--- a/src/modelwidget.h
+++ b/src/modelwidget.h
@@ -17,6 +17,8 @@ class SkeletonGraphicsFunctions;
class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
+signals:
+ void mouseRayChanged(const QVector3D &near, const QVector3D &far);
public:
ModelWidget(QWidget *parent = 0);
~ModelWidget();
@@ -33,6 +35,7 @@ public:
void toggleWireframe();
void enableMove(bool enabled);
void enableZoom(bool enabled);
+ void enableMousePicking(bool enabled);
bool inputMousePressEventFromOtherWidget(QMouseEvent *event);
bool inputMouseMoveEventFromOtherWidget(QMouseEvent *event);
bool inputWheelEventFromOtherWidget(QWheelEvent *event);
@@ -44,6 +47,7 @@ public slots:
void setZRotation(int angle);
void cleanup();
void zoom(float delta);
+ void setMousePickTargetPositionInModelSpace(QVector3D position);
signals:
void xRotationChanged(int angle);
void yRotationChanged(int angle);
@@ -68,6 +72,8 @@ private:
bool m_moveStarted;
bool m_moveEnabled;
bool m_zoomEnabled;
+ bool m_mousePickingEnabled;
+ QVector3D m_mousePickTargetPositionInModelSpace;
private:
QPoint m_lastPos;
ModelMeshBinder m_meshBinder;
@@ -75,8 +81,10 @@ private:
QMatrix4x4 m_camera;
QMatrix4x4 m_world;
static bool m_transparent;
+ static const QVector3D m_cameraPosition;
QPoint m_moveStartPos;
QRect m_moveStartGeometry;
+ std::pair screenPositionToMouseRay(const QPoint &screenPosition);
};
#endif
diff --git a/src/mousepicker.cpp b/src/mousepicker.cpp
new file mode 100644
index 00000000..cb271e6a
--- /dev/null
+++ b/src/mousepicker.cpp
@@ -0,0 +1,90 @@
+#include
+#include "mousepicker.h"
+
+MousePicker::MousePicker(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar) :
+ m_outcome(outcome),
+ m_mouseRayNear(mouseRayNear),
+ m_mouseRayFar(mouseRayFar)
+{
+}
+
+MousePicker::~MousePicker()
+{
+}
+
+void MousePicker::process()
+{
+ float minDistance2 = std::numeric_limits::max();
+ for (size_t i = 0; i < m_outcome.triangles.size(); ++i) {
+ const auto &triangleIndices = m_outcome.triangles[i];
+ std::vector triangle = {
+ m_outcome.vertices[triangleIndices[0]],
+ m_outcome.vertices[triangleIndices[1]],
+ m_outcome.vertices[triangleIndices[2]],
+ };
+ const auto &triangleNormal = m_outcome.triangleNormals[i];
+ QVector3D intersection;
+ if (intersectSegmentAndTriangle(m_mouseRayNear, m_mouseRayFar,
+ triangle,
+ triangleNormal,
+ &intersection)) {
+ float distance2 = (intersection - m_mouseRayNear).lengthSquared();
+ if (distance2 < minDistance2) {
+ m_targetPosition = intersection;
+ minDistance2 = distance2;
+ }
+ }
+ }
+
+ emit finished();
+}
+
+const QVector3D &MousePicker::targetPosition()
+{
+ return m_targetPosition;
+}
+
+bool MousePicker::intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
+ const QVector3D &pointOnPlane, const QVector3D &planeNormal,
+ QVector3D *intersection)
+{
+ auto u = segmentPoint1 - segmentPoint0;
+ auto w = segmentPoint0 - pointOnPlane;
+ auto d = QVector3D::dotProduct(planeNormal, u);
+ auto n = QVector3D::dotProduct(-planeNormal, w);
+ if (qAbs(d) < 0.00000001)
+ return false;
+ auto s = n / d;
+ if (s < 0 || s > 1 || qIsNaN(s) || qIsInf(s))
+ return false;
+ if (nullptr != intersection)
+ *intersection = segmentPoint0 + s * u;
+ return true;
+}
+
+bool MousePicker::intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
+ const std::vector &triangle,
+ const QVector3D &triangleNormal,
+ QVector3D *intersection)
+{
+ QVector3D possibleIntersection;
+ if (!intersectSegmentAndPlane(segmentPoint0, segmentPoint1,
+ triangle[0], triangleNormal, &possibleIntersection)) {
+ return false;
+ }
+ auto ray = (segmentPoint0 - segmentPoint1).normalized();
+ std::vector normals;
+ for (size_t i = 0; i < 3; ++i) {
+ size_t j = (i + 1) % 3;
+ normals.push_back(QVector3D::normal(possibleIntersection, triangle[i], triangle[j]));
+ }
+ if (QVector3D::dotProduct(normals[0], ray) <= 0)
+ return false;
+ if (QVector3D::dotProduct(normals[0], normals[1]) <= 0)
+ return false;
+ if (QVector3D::dotProduct(normals[0], normals[2]) <= 0)
+ return false;
+ if (nullptr != intersection)
+ *intersection = possibleIntersection;
+ return true;
+}
diff --git a/src/mousepicker.h b/src/mousepicker.h
new file mode 100644
index 00000000..d5c1ae1b
--- /dev/null
+++ b/src/mousepicker.h
@@ -0,0 +1,33 @@
+#ifndef DUST3D_MOUSE_PICKER_H
+#define DUST3D_MOUSE_PICKER_H
+#include
+#include
+#include
+#include "outcome.h"
+
+class MousePicker : public QObject
+{
+ Q_OBJECT
+public:
+ MousePicker(const Outcome &outcome, const QVector3D &mouseRayNear, const QVector3D &mouseRayFar);
+ ~MousePicker();
+ const QVector3D &targetPosition();
+signals:
+ void finished();
+public slots:
+ void process();
+private:
+ Outcome m_outcome;
+ QVector3D m_mouseRayNear;
+ QVector3D m_mouseRayFar;
+ QVector3D m_targetPosition;
+ static bool intersectSegmentAndPlane(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
+ const QVector3D &pointOnPlane, const QVector3D &planeNormal,
+ QVector3D *intersection=nullptr);
+ static bool intersectSegmentAndTriangle(const QVector3D &segmentPoint0, const QVector3D &segmentPoint1,
+ const std::vector &triangle,
+ const QVector3D &triangleNormal,
+ QVector3D *intersection=nullptr);
+};
+
+#endif
diff --git a/src/skeletondocument.h b/src/skeletondocument.h
index a63fede5..af15c95b 100644
--- a/src/skeletondocument.h
+++ b/src/skeletondocument.h
@@ -285,6 +285,7 @@ enum class SkeletonDocumentEditMode
{
Add = 0,
Select,
+ Paint,
Drag,
ZoomIn,
ZoomOut
diff --git a/src/skeletongraphicswidget.cpp b/src/skeletongraphicswidget.cpp
index 4fc3ffde..872e75fb 100644
--- a/src/skeletongraphicswidget.cpp
+++ b/src/skeletongraphicswidget.cpp
@@ -598,6 +598,9 @@ void SkeletonGraphicsWidget::updateCursor()
case SkeletonDocumentEditMode::Select:
setCursor(QCursor(Theme::awesome()->icon(fa::mousepointer).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize), Theme::toolIconFontSize / 5, 0));
break;
+ case SkeletonDocumentEditMode::Paint:
+ setCursor(QCursor(Theme::awesome()->icon(fa::paintbrush).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize)));
+ break;
case SkeletonDocumentEditMode::Drag:
setCursor(QCursor(Theme::awesome()->icon(m_dragStarted ? fa::handrocko : fa::handpapero).pixmap(Theme::toolIconFontSize, Theme::toolIconFontSize)));
break;