Add skeleton edit UI
parent
283e76b1b6
commit
d3e82ea306
12
dust3d.pro
12
dust3d.pro
|
@ -12,6 +12,18 @@ HEADERS += src/modelingwidget.h
|
|||
SOURCES += src/skeletoneditwidget.cpp
|
||||
HEADERS += src/skeletoneditwidget.h
|
||||
|
||||
SOURCES += src/skeletoneditgraphicsview.cpp
|
||||
HEADERS += src/skeletoneditgraphicsview.h
|
||||
|
||||
SOURCES += src/skeletoneditnodeitem.cpp
|
||||
HEADERS += src/skeletoneditnodeitem.h
|
||||
|
||||
SOURCES += src/skeletoneditedgeitem.cpp
|
||||
HEADERS += src/skeletoneditedgeitem.h
|
||||
|
||||
SOURCES += src/skeletontomesh.cpp
|
||||
HEADERS += src/skeletontomesh.h
|
||||
|
||||
SOURCES += src/mesh.cpp
|
||||
HEADERS += src/mesh.h
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#include "mainwindow.h"
|
||||
#include "skeletoneditwidget.h"
|
||||
#include <QVBoxLayout>
|
||||
#include <QPushButton>
|
||||
#include <QButtonGroup>
|
||||
#include <QGridLayout>
|
||||
#include <QToolBar>
|
||||
#include <QThread>
|
||||
#include <assert.h>
|
||||
#include "mainwindow.h"
|
||||
#include "skeletoneditwidget.h"
|
||||
#include "meshlite.h"
|
||||
#include "skeletontomesh.h"
|
||||
|
||||
MainWindow::MainWindow()
|
||||
{
|
||||
|
@ -36,14 +40,15 @@ MainWindow::MainWindow()
|
|||
motionButton->adjustSize();
|
||||
modelButton->adjustSize();
|
||||
|
||||
SkeletonEditWidget *skeletonEditWidget = new SkeletonEditWidget;
|
||||
ModelingWidget *modelViewWidget = new ModelingWidget;
|
||||
modelViewWidget->setFixedSize(128, 128);
|
||||
m_skeletonEditWidget = new SkeletonEditWidget;
|
||||
|
||||
m_modelingWidget = new ModelingWidget;
|
||||
m_modelingWidget->setFixedSize(128, 128);
|
||||
|
||||
QPushButton *changeTurnaroundButton = new QPushButton("Change turnaround..");
|
||||
|
||||
QVBoxLayout *rightLayout = new QVBoxLayout;
|
||||
rightLayout->addWidget(modelViewWidget);
|
||||
rightLayout->addWidget(m_modelingWidget);
|
||||
rightLayout->addSpacing(10);
|
||||
rightLayout->addWidget(changeTurnaroundButton);
|
||||
rightLayout->addStretch();
|
||||
|
@ -61,7 +66,7 @@ MainWindow::MainWindow()
|
|||
|
||||
QHBoxLayout *middleLayout = new QHBoxLayout;
|
||||
middleLayout->addLayout(leftLayout);
|
||||
middleLayout->addWidget(skeletonEditWidget);
|
||||
middleLayout->addWidget(m_skeletonEditWidget);
|
||||
middleLayout->addLayout(rightLayout);
|
||||
|
||||
QVBoxLayout *mainLayout = new QVBoxLayout;
|
||||
|
@ -74,5 +79,36 @@ MainWindow::MainWindow()
|
|||
|
||||
setCentralWidget(centralWidget);
|
||||
setWindowTitle(tr("Dust 3D"));
|
||||
|
||||
bool connectResult;
|
||||
|
||||
connectResult = connect(addAction, SIGNAL(triggered(bool)), m_skeletonEditWidget->graphicsView(), SLOT(turnOnAddNodeMode()));
|
||||
assert(connectResult);
|
||||
|
||||
connectResult = connectResult = connect(selectAction, SIGNAL(triggered(bool)), m_skeletonEditWidget->graphicsView(), SLOT(turnOffAddNodeMode()));
|
||||
assert(connectResult);
|
||||
|
||||
connectResult = connect(m_skeletonEditWidget->graphicsView(), SIGNAL(nodesChanged()), this, SLOT(skeletonChanged()));
|
||||
assert(connectResult);
|
||||
}
|
||||
|
||||
void MainWindow::meshReady()
|
||||
{
|
||||
SkeletonToMesh *worker = dynamic_cast<SkeletonToMesh *>(sender());
|
||||
if (worker) {
|
||||
m_modelingWidget->updateMesh(worker->takeResultMesh());
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::skeletonChanged()
|
||||
{
|
||||
QThread *thread = new QThread;
|
||||
SkeletonToMesh *worker = new SkeletonToMesh(m_skeletonEditWidget->graphicsView());
|
||||
worker->moveToThread(thread);
|
||||
connect(thread, SIGNAL(started()), worker, SLOT(process()));
|
||||
connect(worker, SIGNAL(finished()), thread, SLOT(quit()));
|
||||
connect(worker, SIGNAL(finished()), this, SLOT(meshReady()));
|
||||
connect(worker, SIGNAL(finished()), worker, SLOT(deleteLater()));
|
||||
connect(thread, SIGNAL(finished()), thread, SLOT(deleteLater()));
|
||||
thread->start();
|
||||
}
|
||||
|
|
|
@ -1,17 +1,20 @@
|
|||
#ifndef MAIN_WINDOW_H
|
||||
#define MAIN_WINDOW_H
|
||||
|
||||
#include <QMainWindow>
|
||||
#include "modelingwidget.h"
|
||||
#include "skeletoneditwidget.h"
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
MainWindow();
|
||||
|
||||
public slots:
|
||||
void skeletonChanged();
|
||||
void meshReady();
|
||||
private:
|
||||
ModelingWidget *modelingWidget;
|
||||
ModelingWidget *m_modelingWidget;
|
||||
SkeletonEditWidget *m_skeletonEditWidget;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -3,7 +3,6 @@
|
|||
#include <QOpenGLShaderProgram>
|
||||
#include <QCoreApplication>
|
||||
#include <math.h>
|
||||
#include "meshlite.h"
|
||||
|
||||
// Modifed from http://doc.qt.io/qt-5/qtopengl-hellogl2-glwidget-cpp.html
|
||||
|
||||
|
@ -15,7 +14,9 @@ ModelingWidget::ModelingWidget(QWidget *parent)
|
|||
m_yRot(0),
|
||||
m_zRot(0),
|
||||
m_program(0),
|
||||
m_mesh(NULL)
|
||||
m_renderVertexCount(0),
|
||||
m_mesh(NULL),
|
||||
m_meshUpdated(false)
|
||||
{
|
||||
m_core = QSurfaceFormat::defaultFormat().profile() == QSurfaceFormat::CoreProfile;
|
||||
// --transparent causes the clear color to be transparent. Therefore, on systems that
|
||||
|
@ -25,16 +26,6 @@ ModelingWidget::ModelingWidget(QWidget *parent)
|
|||
fmt.setAlphaBufferSize(8);
|
||||
setFormat(fmt);
|
||||
}
|
||||
|
||||
void *lite = meshlite_create_context();
|
||||
int first = meshlite_import(lite, "../assets/cube.obj");
|
||||
int second = meshlite_import(lite, "../assets/ball.obj");
|
||||
meshlite_scale(lite, first, 0.65);
|
||||
int merged = meshlite_union(lite, first, second);
|
||||
int triangulate = meshlite_triangulate(lite, merged);
|
||||
//meshlite_export(lite, triangulate, "/Users/jeremy/testlib.obj");
|
||||
Mesh *mesh = new Mesh(lite, triangulate);
|
||||
updateMesh(mesh);
|
||||
}
|
||||
|
||||
ModelingWidget::~ModelingWidget()
|
||||
|
@ -96,7 +87,8 @@ void ModelingWidget::cleanup()
|
|||
if (m_program == nullptr)
|
||||
return;
|
||||
makeCurrent();
|
||||
m_modelVbo.destroy();
|
||||
if (m_modelVbo.isCreated())
|
||||
m_modelVbo.destroy();
|
||||
delete m_program;
|
||||
m_program = 0;
|
||||
doneCurrent();
|
||||
|
@ -169,7 +161,8 @@ void ModelingWidget::initializeGL()
|
|||
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelingWidget::cleanup);
|
||||
|
||||
initializeOpenGLFunctions();
|
||||
glClearColor(0.2078, 0.2078, 0.2078, m_transparent ? 0 : 1);
|
||||
QColor bgcolor = QWidget::palette().color(QWidget::backgroundRole());
|
||||
glClearColor(bgcolor.redF(), bgcolor.greenF(), bgcolor.blueF(), m_transparent ? 0 : 1);
|
||||
|
||||
m_program = new QOpenGLShaderProgram;
|
||||
m_program->addShaderFromSourceCode(QOpenGLShader::Vertex, m_core ? vertexShaderSourceCore : vertexShaderSource);
|
||||
|
@ -189,15 +182,10 @@ void ModelingWidget::initializeGL()
|
|||
// at all. Nonetheless the below code works in all cases and makes
|
||||
// sure there is a VAO when one is needed.
|
||||
m_vao.create();
|
||||
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
|
||||
|
||||
// Setup our vertex buffer object.
|
||||
m_modelVbo.create();
|
||||
m_modelVbo.bind();
|
||||
m_modelVbo.allocate(m_mesh->vertices(), m_mesh->vertexCount() * sizeof(Vertex));
|
||||
//QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
|
||||
|
||||
// Store the vertex attribute bindings for the program.
|
||||
setupVertexAttribs();
|
||||
|
||||
|
||||
// Our camera never changes in this example.
|
||||
m_camera.setToIdentity();
|
||||
|
@ -232,13 +220,34 @@ void ModelingWidget::paintGL()
|
|||
m_world.rotate(m_zRot / 16.0f, 0, 0, 1);
|
||||
|
||||
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vao);
|
||||
|
||||
{
|
||||
QMutexLocker lock(&m_meshMutex);
|
||||
if (m_meshUpdated) {
|
||||
if (m_mesh) {
|
||||
// Setup our vertex buffer object.
|
||||
if (m_modelVbo.isCreated())
|
||||
m_modelVbo.destroy();
|
||||
m_modelVbo.create();
|
||||
m_modelVbo.bind();
|
||||
m_modelVbo.allocate(m_mesh->vertices(), m_mesh->vertexCount() * sizeof(Vertex));
|
||||
m_renderVertexCount = m_mesh->vertexCount();
|
||||
setupVertexAttribs();
|
||||
} else {
|
||||
m_renderVertexCount = 0;
|
||||
}
|
||||
m_meshUpdated = false;
|
||||
}
|
||||
}
|
||||
|
||||
m_program->bind();
|
||||
m_program->setUniformValue(m_projMatrixLoc, m_proj);
|
||||
m_program->setUniformValue(m_mvMatrixLoc, m_camera * m_world);
|
||||
QMatrix3x3 normalMatrix = m_world.normalMatrix();
|
||||
m_program->setUniformValue(m_normalMatrixLoc, normalMatrix);
|
||||
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_mesh->vertexCount());
|
||||
if (m_renderVertexCount > 0)
|
||||
glDrawArrays(GL_TRIANGLES, 0, m_renderVertexCount);
|
||||
|
||||
m_program->release();
|
||||
}
|
||||
|
@ -275,6 +284,8 @@ void ModelingWidget::updateMesh(Mesh *mesh)
|
|||
if (mesh != m_mesh) {
|
||||
delete m_mesh;
|
||||
m_mesh = mesh;
|
||||
m_meshUpdated = true;
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -55,6 +55,7 @@ private:
|
|||
QOpenGLVertexArrayObject m_vao;
|
||||
QOpenGLBuffer m_modelVbo;
|
||||
QOpenGLShaderProgram *m_program;
|
||||
int m_renderVertexCount;
|
||||
int m_projMatrixLoc;
|
||||
int m_mvMatrixLoc;
|
||||
int m_normalMatrixLoc;
|
||||
|
@ -66,6 +67,7 @@ private:
|
|||
|
||||
Mesh *m_mesh;
|
||||
QMutex m_meshMutex;
|
||||
bool m_meshUpdated;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
#include <QPen>
|
||||
#include "skeletoneditedgeitem.h"
|
||||
|
||||
SkeletonEditEdgeItem::SkeletonEditEdgeItem(QGraphicsItem *parent) :
|
||||
QGraphicsLineItem(parent),
|
||||
m_firstNode(NULL),
|
||||
m_secondNode(NULL)
|
||||
{
|
||||
QPen pen(Qt::darkGray);
|
||||
pen.setWidth(15);
|
||||
setPen(pen);
|
||||
}
|
||||
|
||||
void SkeletonEditEdgeItem::setNodes(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second)
|
||||
{
|
||||
m_firstNode = first;
|
||||
m_secondNode = second;
|
||||
updatePosition();
|
||||
}
|
||||
|
||||
void SkeletonEditEdgeItem::updatePosition()
|
||||
{
|
||||
if (m_firstNode && m_secondNode) {
|
||||
QLineF line(m_firstNode->origin(), m_secondNode->origin());
|
||||
setLine(line);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,17 @@
|
|||
#ifndef SKELETON_EDIT_EDGE_ITEM_H
|
||||
#define SKELETON_EDIT_EDGE_ITEM_H
|
||||
#include <QGraphicsEllipseItem>
|
||||
#include "skeletoneditnodeitem.h"
|
||||
|
||||
class SkeletonEditEdgeItem : public QGraphicsLineItem
|
||||
{
|
||||
public:
|
||||
SkeletonEditEdgeItem(QGraphicsItem *parent = 0);
|
||||
void setNodes(SkeletonEditNodeItem *first, SkeletonEditNodeItem *second);
|
||||
void updatePosition();
|
||||
private:
|
||||
SkeletonEditNodeItem *m_firstNode;
|
||||
SkeletonEditNodeItem *m_secondNode;
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,181 @@
|
|||
#include <QGraphicsPixmapItem>
|
||||
#include "skeletoneditgraphicsview.h"
|
||||
#include "skeletoneditnodeitem.h"
|
||||
#include "skeletoneditedgeitem.h"
|
||||
|
||||
qreal SkeletonEditGraphicsView::m_initialNodeSize = 128;
|
||||
qreal SkeletonEditGraphicsView::m_minimalNodeSize = 32;
|
||||
|
||||
SkeletonEditGraphicsView::SkeletonEditGraphicsView(QWidget *parent) :
|
||||
QGraphicsView(parent),
|
||||
m_pendingNodeItem(NULL),
|
||||
m_pendingEdgeItem(NULL),
|
||||
m_inAddNodeMode(true),
|
||||
m_nextStartNodeItem(NULL),
|
||||
m_lastHoverNodeItem(NULL)
|
||||
{
|
||||
setScene(new QGraphicsScene());
|
||||
|
||||
setMouseTracking(true);
|
||||
|
||||
QImage image("../assets/male_werewolf_turnaround_lineart_by_jennette_brown.png");
|
||||
m_backgroundItem = new QGraphicsPixmapItem(QPixmap::fromImage(image));
|
||||
scene()->addItem(m_backgroundItem);
|
||||
|
||||
m_pendingNodeItem = new QGraphicsEllipseItem(0, 0, m_initialNodeSize, m_initialNodeSize);
|
||||
scene()->addItem(m_pendingNodeItem);
|
||||
|
||||
m_pendingEdgeItem = new QGraphicsLineItem(0, 0, 0, 0);
|
||||
scene()->addItem(m_pendingEdgeItem);
|
||||
|
||||
applyAddNodeMode();
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::toggleAddNodeMode()
|
||||
{
|
||||
m_inAddNodeMode = !m_inAddNodeMode;
|
||||
applyAddNodeMode();
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::applyAddNodeMode()
|
||||
{
|
||||
m_pendingNodeItem->setVisible(m_inAddNodeMode);
|
||||
m_pendingEdgeItem->setVisible(m_inAddNodeMode);
|
||||
setMouseTracking(true);
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::turnOffAddNodeMode()
|
||||
{
|
||||
m_inAddNodeMode = false;
|
||||
applyAddNodeMode();
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::turnOnAddNodeMode()
|
||||
{
|
||||
m_inAddNodeMode = true;
|
||||
applyAddNodeMode();
|
||||
}
|
||||
|
||||
SkeletonEditNodeItem *SkeletonEditGraphicsView::findNodeItemByPos(QPointF pos)
|
||||
{
|
||||
QList<QGraphicsItem *>::iterator it;
|
||||
QList<QGraphicsItem *> list = scene()->items();
|
||||
for (it = list.begin(); it != list.end(); ++it) {
|
||||
SkeletonEditNodeItem *nodeItem = dynamic_cast<SkeletonEditNodeItem *>(*it);
|
||||
if (nodeItem) {
|
||||
SkeletonEditNodeItem *nodeItem = (SkeletonEditNodeItem *)(*it);
|
||||
if (nodeItem->rect().contains(pos)) {
|
||||
return nodeItem;
|
||||
}
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::mousePressEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (!m_inAddNodeMode) {
|
||||
if (m_lastHoverNodeItem) {
|
||||
setNextStartNodeItem(m_lastHoverNodeItem);
|
||||
m_lastHoverNodeItem = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
if (event->button() == Qt::LeftButton) {
|
||||
if (m_inAddNodeMode) {
|
||||
SkeletonEditNodeItem *newNode = new SkeletonEditNodeItem(m_pendingNodeItem->rect());
|
||||
scene()->addItem(newNode);
|
||||
if (m_nextStartNodeItem) {
|
||||
SkeletonEditEdgeItem *newEdge = new SkeletonEditEdgeItem();
|
||||
newEdge->setNodes(newNode, m_nextStartNodeItem);
|
||||
scene()->addItem(newEdge);
|
||||
}
|
||||
setNextStartNodeItem(newNode);
|
||||
emit nodesChanged();
|
||||
}
|
||||
} else if (event->button() == Qt::RightButton) {
|
||||
if (m_inAddNodeMode) {
|
||||
toggleAddNodeMode();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QWidget::mouseMoveEvent(event);
|
||||
QPointF pos = mapToScene(event->pos());
|
||||
QPointF moveTo = QPointF(pos.x() - m_pendingNodeItem->rect().width() / 2, pos.y() - m_pendingNodeItem->rect().height() / 2);
|
||||
if (moveTo.x() < 0)
|
||||
moveTo.setX(0);
|
||||
if (moveTo.y() < 0)
|
||||
moveTo.setY(0);
|
||||
if (moveTo.x() + m_pendingNodeItem->rect().width() >= m_backgroundItem->boundingRect().width())
|
||||
moveTo.setX(m_backgroundItem->boundingRect().width() - m_pendingNodeItem->rect().width());
|
||||
if (moveTo.y() + m_pendingNodeItem->rect().height() >= m_backgroundItem->boundingRect().height())
|
||||
moveTo.setY(m_backgroundItem->boundingRect().height() - m_pendingNodeItem->rect().height());
|
||||
QSizeF oldSize = m_pendingNodeItem->rect().size();
|
||||
m_pendingNodeItem->setRect(moveTo.x(), moveTo.y(),
|
||||
oldSize.width(),
|
||||
oldSize.height());
|
||||
if (m_nextStartNodeItem) {
|
||||
m_pendingEdgeItem->setLine(QLineF(m_nextStartNodeItem->origin(), QPointF(moveTo.x() + m_pendingNodeItem->rect().width() / 2,
|
||||
moveTo.y() + m_pendingNodeItem->rect().height() / 2)));
|
||||
}
|
||||
if (!m_inAddNodeMode) {
|
||||
SkeletonEditNodeItem *hoverNodeItem = findNodeItemByPos(pos);
|
||||
if (hoverNodeItem) {
|
||||
hoverNodeItem->setHighlighted(true);
|
||||
}
|
||||
if (hoverNodeItem != m_lastHoverNodeItem) {
|
||||
if (m_lastHoverNodeItem)
|
||||
m_lastHoverNodeItem->setHighlighted(false);
|
||||
m_lastHoverNodeItem = hoverNodeItem;
|
||||
}
|
||||
} else {
|
||||
if (m_lastHoverNodeItem) {
|
||||
m_lastHoverNodeItem->setHighlighted(false);
|
||||
m_lastHoverNodeItem = NULL;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
QWidget::wheelEvent(event);
|
||||
qreal delta = event->delta();
|
||||
QSizeF oldSize = m_pendingNodeItem->rect().size();
|
||||
QPointF originPt = QPointF(m_pendingNodeItem->rect().left() + oldSize.width() / 2,
|
||||
m_pendingNodeItem->rect().top() + oldSize.height() / 2);
|
||||
QSizeF newSize = QSizeF(oldSize.width() + delta, oldSize.height() + delta);
|
||||
if (newSize.width() < m_minimalNodeSize || newSize.height() < m_minimalNodeSize) {
|
||||
newSize.setWidth(m_minimalNodeSize);
|
||||
newSize.setHeight(m_minimalNodeSize);
|
||||
}
|
||||
QPointF newLeftTop = QPointF(originPt.x() - newSize.width() / 2,
|
||||
originPt.y() - newSize.height() / 2);
|
||||
if (newLeftTop.x() < 0 || newLeftTop.x() + newSize.width() >= m_backgroundItem->boundingRect().width())
|
||||
return;
|
||||
if (newLeftTop.y() < 0 || newLeftTop.y() + newSize.height() >= m_backgroundItem->boundingRect().height())
|
||||
return;
|
||||
m_pendingNodeItem->setRect(newLeftTop.x(),
|
||||
newLeftTop.y(),
|
||||
newSize.width(),
|
||||
newSize.height());
|
||||
}
|
||||
|
||||
void SkeletonEditGraphicsView::setNextStartNodeItem(SkeletonEditNodeItem *item)
|
||||
{
|
||||
if (m_nextStartNodeItem != item) {
|
||||
if (m_nextStartNodeItem)
|
||||
m_nextStartNodeItem->setIsNextStartNode(false);
|
||||
}
|
||||
m_nextStartNodeItem = item;
|
||||
if (m_nextStartNodeItem)
|
||||
m_nextStartNodeItem->setIsNextStartNode(true);
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
#ifndef SKELETON_EDIT_GRAPHICS_VIEW_H
|
||||
#define SKELETON_EDIT_GRAPHICS_VIEW_H
|
||||
#include <QGraphicsView>
|
||||
#include <QMouseEvent>
|
||||
#include "skeletoneditnodeitem.h"
|
||||
#include "skeletoneditedgeitem.h"
|
||||
|
||||
class SkeletonEditGraphicsView : public QGraphicsView
|
||||
{
|
||||
Q_OBJECT
|
||||
signals:
|
||||
void nodesChanged();
|
||||
public slots:
|
||||
void turnOffAddNodeMode();
|
||||
void turnOnAddNodeMode();
|
||||
public:
|
||||
SkeletonEditGraphicsView(QWidget *parent = 0);
|
||||
protected:
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
void wheelEvent(QWheelEvent *event);
|
||||
void mouseReleaseEvent(QMouseEvent *event);
|
||||
void mousePressEvent(QMouseEvent *event);
|
||||
private:
|
||||
QGraphicsPixmapItem *m_backgroundItem;
|
||||
QGraphicsEllipseItem *m_pendingNodeItem;
|
||||
QGraphicsLineItem *m_pendingEdgeItem;
|
||||
static qreal m_initialNodeSize;
|
||||
static qreal m_minimalNodeSize;
|
||||
bool m_inAddNodeMode;
|
||||
SkeletonEditNodeItem *m_nextStartNodeItem;
|
||||
SkeletonEditNodeItem *m_lastHoverNodeItem;
|
||||
void toggleAddNodeMode();
|
||||
void applyAddNodeMode();
|
||||
SkeletonEditNodeItem *findNodeItemByPos(QPointF pos);
|
||||
void setNextStartNodeItem(SkeletonEditNodeItem *item);
|
||||
|
||||
};
|
||||
|
||||
#endif
|
|
@ -0,0 +1,39 @@
|
|||
#include <QPen>
|
||||
#include "skeletoneditnodeitem.h"
|
||||
|
||||
SkeletonEditNodeItem::SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *parent) :
|
||||
QGraphicsEllipseItem(rect, parent),
|
||||
m_highlighted(false),
|
||||
m_isNextStartNode(false)
|
||||
{
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
QPointF SkeletonEditNodeItem::origin()
|
||||
{
|
||||
return QPointF(rect().left() + rect().width() / 2,
|
||||
rect().top() + rect().height() / 2);
|
||||
}
|
||||
|
||||
void SkeletonEditNodeItem::setHighlighted(bool highlighted)
|
||||
{
|
||||
m_highlighted = highlighted;
|
||||
if (m_highlighted) {
|
||||
setBrush(QBrush(Qt::gray));
|
||||
} else {
|
||||
setBrush(QBrush(Qt::transparent));
|
||||
}
|
||||
}
|
||||
|
||||
void SkeletonEditNodeItem::setIsNextStartNode(bool isNextStartNode)
|
||||
{
|
||||
m_isNextStartNode = isNextStartNode;
|
||||
updateBorder();
|
||||
}
|
||||
|
||||
void SkeletonEditNodeItem::updateBorder()
|
||||
{
|
||||
QPen pen(m_isNextStartNode ? Qt::black : Qt::darkGray);
|
||||
pen.setWidth(15);
|
||||
setPen(pen);
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
#ifndef SKELETON_EDIT_NODE_ITEM_H
|
||||
#define SKELETON_EDIT_NODE_ITEM_H
|
||||
#include <QGraphicsEllipseItem>
|
||||
|
||||
class SkeletonEditNodeItem : public QGraphicsEllipseItem
|
||||
{
|
||||
public:
|
||||
SkeletonEditNodeItem(const QRectF &rect, QGraphicsItem *parent = 0);
|
||||
QPointF origin();
|
||||
void setHighlighted(bool highlited);
|
||||
void setIsNextStartNode(bool isNextStartNode);
|
||||
private:
|
||||
bool m_highlighted;
|
||||
bool m_isNextStartNode;
|
||||
void updateBorder();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -6,23 +6,34 @@
|
|||
|
||||
// Modifed from http://doc.qt.io/qt-5/qtwidgets-graphicsview-chip-view-cpp.html
|
||||
|
||||
SkeletonEditWidget::SkeletonEditWidget(QFrame *parent)
|
||||
: QFrame(parent)
|
||||
SkeletonEditWidget::SkeletonEditWidget(QFrame *parent) :
|
||||
QFrame(parent)
|
||||
{
|
||||
//setFrameStyle(Sunken | StyledPanel);
|
||||
m_graphicsView = new SkeletonEditGraphicsView(this);
|
||||
m_graphicsView->setRenderHint(QPainter::Antialiasing, false);
|
||||
m_graphicsView->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
m_graphicsView->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
|
||||
|
||||
graphicsView = new QGraphicsView(this);
|
||||
graphicsView->setRenderHint(QPainter::Antialiasing, false);
|
||||
|
||||
scene = new QGraphicsScene();
|
||||
graphicsView->setScene(scene);
|
||||
|
||||
QImage image("../assets/male_werewolf_turnaround_lineart_by_jennette_brown.png");
|
||||
QGraphicsPixmapItem *backgroundItem = new QGraphicsPixmapItem(QPixmap::fromImage(image));
|
||||
scene->addItem(backgroundItem);
|
||||
m_graphicsView->setBackgroundBrush(QBrush(QWidget::palette().color(QWidget::backgroundRole()), Qt::SolidPattern));
|
||||
|
||||
QGridLayout *mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(graphicsView, 0, 0, 1, 1);
|
||||
mainLayout->addWidget(m_graphicsView, 0, 0, 1, 1);
|
||||
|
||||
setLayout(mainLayout);
|
||||
}
|
||||
|
||||
SkeletonEditGraphicsView *SkeletonEditWidget::graphicsView()
|
||||
{
|
||||
return m_graphicsView;
|
||||
}
|
||||
|
||||
void SkeletonEditWidget::resizeEvent(QResizeEvent *event)
|
||||
{
|
||||
QFrame::resizeEvent(event);
|
||||
m_graphicsView->fitInView(QRectF(0, 0, m_graphicsView->scene()->width(), m_graphicsView->scene()->height()), Qt::KeepAspectRatio);
|
||||
}
|
||||
|
||||
void SkeletonEditWidget::mouseMoveEvent(QMouseEvent *event)
|
||||
{
|
||||
QFrame::mouseMoveEvent(event);
|
||||
}
|
||||
|
|
|
@ -3,15 +3,22 @@
|
|||
#include <QFrame>
|
||||
#include <QGraphicsView>
|
||||
#include <QGraphicsScene>
|
||||
#include <QGraphicsPixmapItem>
|
||||
#include <QMouseEvent>
|
||||
#include <QGraphicsEllipseItem>
|
||||
#include "skeletoneditgraphicsview.h"
|
||||
|
||||
class SkeletonEditWidget : public QFrame
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SkeletonEditWidget(QFrame *parent = 0);
|
||||
SkeletonEditGraphicsView *graphicsView();
|
||||
protected:
|
||||
void resizeEvent(QResizeEvent *event);
|
||||
void mouseMoveEvent(QMouseEvent *event);
|
||||
private:
|
||||
QGraphicsView *graphicsView;
|
||||
QGraphicsScene *scene;
|
||||
SkeletonEditGraphicsView *m_graphicsView;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
#include "skeletontomesh.h"
|
||||
#include "meshlite.h"
|
||||
|
||||
// Modified from https://wiki.qt.io/QThreads_general_usage
|
||||
|
||||
SkeletonToMesh::SkeletonToMesh(SkeletonEditGraphicsView *graphicsView) :
|
||||
m_mesh(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
SkeletonToMesh::~SkeletonToMesh()
|
||||
{
|
||||
delete m_mesh;
|
||||
}
|
||||
|
||||
Mesh *SkeletonToMesh::takeResultMesh()
|
||||
{
|
||||
Mesh *mesh = m_mesh;
|
||||
m_mesh = NULL;
|
||||
return mesh;
|
||||
}
|
||||
|
||||
void SkeletonToMesh::process()
|
||||
{
|
||||
void *lite = meshlite_create_context();
|
||||
int first = meshlite_import(lite, "../assets/cube.obj");
|
||||
int second = meshlite_import(lite, "../assets/ball.obj");
|
||||
meshlite_scale(lite, first, 0.65);
|
||||
int merged = meshlite_union(lite, first, second);
|
||||
int triangulate = meshlite_triangulate(lite, merged);
|
||||
//meshlite_export(lite, triangulate, "/Users/jeremy/testlib.obj");
|
||||
m_mesh = new Mesh(lite, triangulate);
|
||||
emit finished();
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
#ifndef SKELETON_TO_MESH_H
|
||||
#define SKELETON_TO_MESH_H
|
||||
#include <QObject>
|
||||
#include <QList>
|
||||
#include "skeletoneditgraphicsview.h"
|
||||
#include "mesh.h"
|
||||
|
||||
class SkeletonToMesh : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
SkeletonToMesh(SkeletonEditGraphicsView *graphicsView);
|
||||
~SkeletonToMesh();
|
||||
Mesh *takeResultMesh();
|
||||
signals:
|
||||
void finished();
|
||||
public slots:
|
||||
void process();
|
||||
private:
|
||||
Mesh *m_mesh;
|
||||
};
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue