Export working model as obj

master
Jeremy Hu 2018-03-20 15:56:49 +08:00
parent 4661e2bc94
commit 4c9767835f
9 changed files with 122 additions and 36 deletions

View File

@ -7,8 +7,8 @@ INCLUDEPATH += src
SOURCES += src/mainwindow.cpp SOURCES += src/mainwindow.cpp
HEADERS += src/mainwindow.h HEADERS += src/mainwindow.h
SOURCES += src/modelingwidget.cpp SOURCES += src/modelwidget.cpp
HEADERS += src/modelingwidget.h HEADERS += src/modelwidget.h
SOURCES += src/skeletoneditgraphicsview.cpp SOURCES += src/skeletoneditgraphicsview.cpp
HEADERS += src/skeletoneditgraphicsview.h HEADERS += src/skeletoneditgraphicsview.h

View File

@ -69,8 +69,8 @@ MainWindow::MainWindow()
QPushButton *changeTurnaroundButton = new QPushButton(" Change Turnaround "); QPushButton *changeTurnaroundButton = new QPushButton(" Change Turnaround ");
modelRightLayout->addWidget(changeTurnaroundButton); modelRightLayout->addWidget(changeTurnaroundButton);
QPushButton *exportPartsModelButton = new QPushButton(" Export "); QPushButton *exportModelButton = new QPushButton(" Export ");
modelRightLayout->addWidget(exportPartsModelButton); modelRightLayout->addWidget(exportModelButton);
QPushButton *newModelButton = new QPushButton(" New "); QPushButton *newModelButton = new QPushButton(" New ");
modelRightLayout->addWidget(newModelButton); modelRightLayout->addWidget(newModelButton);
@ -130,6 +130,9 @@ MainWindow::MainWindow()
connectResult = connect(m_sharePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons())); connectResult = connect(m_sharePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
assert(connectResult); assert(connectResult);
connectResult = connect(exportModelButton, SIGNAL(clicked()), this, SLOT(exportModel()));
assert(connectResult);
connectResult = connect(saveModelButton, SIGNAL(clicked()), this, SLOT(saveModel())); connectResult = connect(saveModelButton, SIGNAL(clicked()), this, SLOT(saveModel()));
assert(connectResult); assert(connectResult);
@ -139,6 +142,17 @@ MainWindow::MainWindow()
updatePageButtons(); updatePageButtons();
} }
void MainWindow::exportModel()
{
QString exportTo = QFileDialog::getSaveFileName(this,
tr("Export Model"), ".",
tr("Wavefront OBJ File (*.obj)"));
if (exportTo.isEmpty()) {
return;
}
m_skeletonWidget->modelWidget()->exportMeshAsObj(exportTo);
}
void MainWindow::loadModel() void MainWindow::loadModel()
{ {
QString filename = QFileDialog::getOpenFileName(this, QString filename = QFileDialog::getOpenFileName(this,

View File

@ -16,6 +16,7 @@ public slots:
void updatePageButtons(); void updatePageButtons();
void saveModel(); void saveModel();
void loadModel(); void loadModel();
void exportModel();
private: private:
QPushButton *m_modelPageButton; QPushButton *m_modelPageButton;
QPushButton *m_sharePageButton; QPushButton *m_sharePageButton;

View File

@ -2,6 +2,8 @@
#include "meshlite.h" #include "meshlite.h"
#include <assert.h> #include <assert.h>
#define MAX_VERTICES_PER_FACE 100
Mesh::Mesh(void *meshlite, int meshId) : Mesh::Mesh(void *meshlite, int meshId) :
m_triangleVertices(NULL), m_triangleVertices(NULL),
m_triangleVertexCount(0), m_triangleVertexCount(0),
@ -12,6 +14,30 @@ Mesh::Mesh(void *meshlite, int meshId) :
GLfloat *edgeVertexPositions = new GLfloat[edgeVertexPositionCount * 3]; GLfloat *edgeVertexPositions = new GLfloat[edgeVertexPositionCount * 3];
int loadedEdgeVertexPositionItemCount = meshlite_get_vertex_position_array(meshlite, meshId, edgeVertexPositions, edgeVertexPositionCount * 3); int loadedEdgeVertexPositionItemCount = meshlite_get_vertex_position_array(meshlite, meshId, edgeVertexPositions, edgeVertexPositionCount * 3);
int offset = 0;
while (offset < loadedEdgeVertexPositionItemCount) {
QVector3D position = QVector3D(edgeVertexPositions[offset], edgeVertexPositions[offset + 1], edgeVertexPositions[offset + 2]);
m_vertices.push_back(position);
offset += 3;
}
int faceCount = meshlite_get_face_count(meshlite, meshId);
int *faceVertexNumAndIndices = new int[faceCount * (1 + MAX_VERTICES_PER_FACE)];
int loadedFaceVertexNumAndIndicesItemCount = meshlite_get_face_index_array(meshlite, meshId, faceVertexNumAndIndices, faceCount * (1 + MAX_VERTICES_PER_FACE));
offset = 0;
while (offset < loadedFaceVertexNumAndIndicesItemCount) {
int indicesNum = faceVertexNumAndIndices[offset++];
assert(indicesNum >= 0 && indicesNum <= MAX_VERTICES_PER_FACE);
std::vector<int> face;
for (int i = 0; i < indicesNum && offset < loadedFaceVertexNumAndIndicesItemCount; i++) {
int index = faceVertexNumAndIndices[offset++];
assert(index >= 0 && index < loadedEdgeVertexPositionItemCount);
face.push_back(index);
}
m_faces.push_back(face);
}
delete[] faceVertexNumAndIndices;
faceVertexNumAndIndices = NULL;
int edgeCount = meshlite_get_halfedge_count(meshlite, meshId); int edgeCount = meshlite_get_halfedge_count(meshlite, meshId);
int *edgeIndices = new int[edgeCount * 2]; int *edgeIndices = new int[edgeCount * 2];
int loadedEdgeVertexIndexItemCount = meshlite_get_halfedge_index_array(meshlite, meshId, edgeIndices, edgeCount * 2); int loadedEdgeVertexIndexItemCount = meshlite_get_halfedge_index_array(meshlite, meshId, edgeIndices, edgeCount * 2);
@ -89,6 +115,16 @@ Mesh::~Mesh()
m_triangleVertexCount = 0; m_triangleVertexCount = 0;
} }
const std::vector<QVector3D> &Mesh::vertices()
{
return m_vertices;
}
const std::vector<std::vector<int>> &Mesh::faces()
{
return m_faces;
}
Vertex *Mesh::triangleVertices() Vertex *Mesh::triangleVertices()
{ {
return m_triangleVertices; return m_triangleVertices;

View File

@ -2,6 +2,8 @@
#define MESH_H #define MESH_H
#include <QObject> #include <QObject>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
#include <vector>
#include <QVector3D>
#pragma pack(push) #pragma pack(push)
#pragma pack(1) #pragma pack(1)
@ -28,11 +30,15 @@ public:
int triangleVertexCount(); int triangleVertexCount();
Vertex *edgeVertices(); Vertex *edgeVertices();
int edgeVertexCount(); int edgeVertexCount();
const std::vector<QVector3D> &vertices();
const std::vector<std::vector<int>> &faces();
private: private:
Vertex *m_triangleVertices; Vertex *m_triangleVertices;
int m_triangleVertexCount; int m_triangleVertexCount;
Vertex *m_edgeVertices; Vertex *m_edgeVertices;
int m_edgeVertexCount; int m_edgeVertexCount;
std::vector<QVector3D> m_vertices;
std::vector<std::vector<int>> m_faces;
}; };
#endif #endif

View File

@ -1,4 +1,5 @@
#include "modelingwidget.h" #include "modelwidget.h"
#include "ds3file.h"
#include <QMouseEvent> #include <QMouseEvent>
#include <QOpenGLShaderProgram> #include <QOpenGLShaderProgram>
#include <QCoreApplication> #include <QCoreApplication>
@ -6,9 +7,9 @@
// Modifed from http://doc.qt.io/qt-5/qtopengl-hellogl2-glwidget-cpp.html // Modifed from http://doc.qt.io/qt-5/qtopengl-hellogl2-glwidget-cpp.html
bool ModelingWidget::m_transparent = false; bool ModelWidget::m_transparent = false;
ModelingWidget::ModelingWidget(QWidget *parent) ModelWidget::ModelWidget(QWidget *parent)
: QOpenGLWidget(parent), : QOpenGLWidget(parent),
m_xRot(0), m_xRot(0),
m_yRot(0), m_yRot(0),
@ -34,7 +35,7 @@ ModelingWidget::ModelingWidget(QWidget *parent)
} }
} }
ModelingWidget::~ModelingWidget() ModelWidget::~ModelWidget()
{ {
cleanup(); cleanup();
delete m_mesh; delete m_mesh;
@ -48,7 +49,7 @@ static void qNormalizeAngle(int &angle)
angle -= 360 * 16; angle -= 360 * 16;
} }
void ModelingWidget::setXRotation(int angle) void ModelWidget::setXRotation(int angle)
{ {
qNormalizeAngle(angle); qNormalizeAngle(angle);
if (angle != m_xRot) { if (angle != m_xRot) {
@ -58,7 +59,7 @@ void ModelingWidget::setXRotation(int angle)
} }
} }
void ModelingWidget::setYRotation(int angle) void ModelWidget::setYRotation(int angle)
{ {
qNormalizeAngle(angle); qNormalizeAngle(angle);
if (angle != m_yRot) { if (angle != m_yRot) {
@ -68,7 +69,7 @@ void ModelingWidget::setYRotation(int angle)
} }
} }
void ModelingWidget::setZRotation(int angle) void ModelWidget::setZRotation(int angle)
{ {
qNormalizeAngle(angle); qNormalizeAngle(angle);
if (angle != m_zRot) { if (angle != m_zRot) {
@ -78,7 +79,7 @@ void ModelingWidget::setZRotation(int angle)
} }
} }
void ModelingWidget::cleanup() void ModelWidget::cleanup()
{ {
if (m_program == nullptr) if (m_program == nullptr)
return; return;
@ -153,7 +154,7 @@ static const char *fragmentShaderSource =
" gl_FragColor = vec4(col, 1.0);\n" " gl_FragColor = vec4(col, 1.0);\n"
"}\n"; "}\n";
void ModelingWidget::initializeGL() void ModelWidget::initializeGL()
{ {
// In this example the widget's corresponding top-level window can change // In this example the widget's corresponding top-level window can change
// several times during the widget's lifetime. Whenever this happens, the // several times during the widget's lifetime. Whenever this happens, the
@ -162,7 +163,7 @@ void ModelingWidget::initializeGL()
// aboutToBeDestroyed() signal, instead of the destructor. The emission of // aboutToBeDestroyed() signal, instead of the destructor. The emission of
// the signal will be followed by an invocation of initializeGL() where we // the signal will be followed by an invocation of initializeGL() where we
// can recreate all resources. // can recreate all resources.
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelingWidget::cleanup); connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelWidget::cleanup);
initializeOpenGLFunctions(); initializeOpenGLFunctions();
QColor bgcolor = QWidget::palette().color(QWidget::backgroundRole()); QColor bgcolor = QWidget::palette().color(QWidget::backgroundRole());
@ -199,7 +200,7 @@ void ModelingWidget::initializeGL()
m_program->release(); m_program->release();
} }
void ModelingWidget::paintGL() void ModelWidget::paintGL()
{ {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST); glEnable(GL_DEPTH_TEST);
@ -275,18 +276,18 @@ void ModelingWidget::paintGL()
m_program->release(); m_program->release();
} }
void ModelingWidget::resizeGL(int w, int h) void ModelWidget::resizeGL(int w, int h)
{ {
m_proj.setToIdentity(); m_proj.setToIdentity();
m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f); m_proj.perspective(45.0f, GLfloat(w) / h, 0.01f, 100.0f);
} }
void ModelingWidget::mousePressEvent(QMouseEvent *event) void ModelWidget::mousePressEvent(QMouseEvent *event)
{ {
m_lastPos = event->pos(); m_lastPos = event->pos();
} }
void ModelingWidget::mouseMoveEvent(QMouseEvent *event) void ModelWidget::mouseMoveEvent(QMouseEvent *event)
{ {
int dx = event->x() - m_lastPos.x(); int dx = event->x() - m_lastPos.x();
int dy = event->y() - m_lastPos.y(); int dy = event->y() - m_lastPos.y();
@ -301,7 +302,7 @@ void ModelingWidget::mouseMoveEvent(QMouseEvent *event)
m_lastPos = event->pos(); m_lastPos = event->pos();
} }
void ModelingWidget::updateMesh(Mesh *mesh) void ModelWidget::updateMesh(Mesh *mesh)
{ {
QMutexLocker lock(&m_meshMutex); QMutexLocker lock(&m_meshMutex);
if (mesh != m_mesh) { if (mesh != m_mesh) {
@ -312,3 +313,24 @@ void ModelingWidget::updateMesh(Mesh *mesh)
} }
} }
void ModelWidget::exportMeshAsObj(const QString &filename)
{
QMutexLocker lock(&m_meshMutex);
if (m_mesh) {
QFile file(filename);
if (file.open(QIODevice::WriteOnly)) {
QTextStream stream(&file);
stream << "# " << Ds3FileReader::m_applicationName << endl;
for (std::vector<const QVector3D>::iterator it = m_mesh->vertices().begin() ; it != m_mesh->vertices().end(); ++it) {
stream << "v " << (*it).x() << " " << (*it).y() << " " << (*it).z() << endl;
}
for (std::vector<const std::vector<int>>::iterator it = m_mesh->faces().begin() ; it != m_mesh->faces().end(); ++it) {
stream << "f";
for (std::vector<const int>::iterator subIt = (*it).begin() ; subIt != (*it).end(); ++subIt) {
stream << " " << (1 + *subIt);
}
stream << endl;
}
}
}
}

View File

@ -1,5 +1,5 @@
#ifndef MODELING_WIDGET_H #ifndef MODEL_WIDGET_H
#define MODELING_WIDGET_H #define MODEL_WIDGET_H
#include <QOpenGLWidget> #include <QOpenGLWidget>
#include <QOpenGLFunctions> #include <QOpenGLFunctions>
@ -11,18 +11,19 @@
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram) QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class ModelingWidget : public QOpenGLWidget, protected QOpenGLFunctions class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
{ {
Q_OBJECT Q_OBJECT
public: public:
ModelingWidget(QWidget *parent = 0); ModelWidget(QWidget *parent = 0);
~ModelingWidget(); ~ModelWidget();
static bool isTransparent() { return m_transparent; } static bool isTransparent() { return m_transparent; }
static void setTransparent(bool t) { m_transparent = t; } static void setTransparent(bool t) { m_transparent = t; }
void updateMesh(Mesh *mesh); void updateMesh(Mesh *mesh);
void exportMeshAsObj(const QString &filename);
public slots: public slots:
void setXRotation(int angle); void setXRotation(int angle);

View File

@ -30,11 +30,11 @@ SkeletonWidget::SkeletonWidget(QWidget *parent) :
m_graphicsView->setBackgroundBrush(QBrush(QWidget::palette().color(QWidget::backgroundRole()), Qt::SolidPattern)); m_graphicsView->setBackgroundBrush(QBrush(QWidget::palette().color(QWidget::backgroundRole()), Qt::SolidPattern));
m_modelingWidget = new ModelingWidget(this); m_modelWidget = new ModelWidget(this);
m_modelingWidget->setMinimumSize(128, 128); m_modelWidget->setMinimumSize(128, 128);
m_modelingWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum); m_modelWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_modelingWidget->setWindowFlags(Qt::Tool | Qt::Window); m_modelWidget->setWindowFlags(Qt::Tool | Qt::Window);
m_modelingWidget->setWindowTitle("3D Model"); m_modelWidget->setWindowTitle("3D Model");
QVBoxLayout *rightLayout = new QVBoxLayout; QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addSpacing(10); rightLayout->addSpacing(10);
@ -101,14 +101,19 @@ SkeletonEditGraphicsView *SkeletonWidget::graphicsView()
return m_graphicsView; return m_graphicsView;
} }
ModelWidget *SkeletonWidget::modelWidget()
{
return m_modelWidget;
}
void SkeletonWidget::showModelingWidgetAtCorner() void SkeletonWidget::showModelingWidgetAtCorner()
{ {
if (!m_modelingWidget->isVisible()) { if (!m_modelWidget->isVisible()) {
QPoint pos = QPoint(QApplication::desktop()->width(), QPoint pos = QPoint(QApplication::desktop()->width(),
QApplication::desktop()->height()); QApplication::desktop()->height());
m_modelingWidget->move(pos.x() - m_modelingWidget->width(), m_modelWidget->move(pos.x() - m_modelWidget->width(),
pos.y() - m_modelingWidget->height()); pos.y() - m_modelWidget->height());
m_modelingWidget->show(); m_modelWidget->show();
} }
} }
@ -116,7 +121,7 @@ void SkeletonWidget::meshReady()
{ {
Mesh *resultMesh = m_skeletonToMesh->takeResultMesh(); Mesh *resultMesh = m_skeletonToMesh->takeResultMesh();
showModelingWidgetAtCorner(); showModelingWidgetAtCorner();
m_modelingWidget->updateMesh(resultMesh); m_modelWidget->updateMesh(resultMesh);
delete m_skeletonToMesh; delete m_skeletonToMesh;
m_skeletonToMesh = NULL; m_skeletonToMesh = NULL;
if (m_skeletonDirty) { if (m_skeletonDirty) {

View File

@ -4,7 +4,7 @@
#include <QString> #include <QString>
#include <QVBoxLayout> #include <QVBoxLayout>
#include <QPushButton> #include <QPushButton>
#include "modelingwidget.h" #include "modelwidget.h"
#include "skeletontomesh.h" #include "skeletontomesh.h"
#include "turnaroundloader.h" #include "turnaroundloader.h"
#include "skeletoneditgraphicsview.h" #include "skeletoneditgraphicsview.h"
@ -15,6 +15,7 @@ class SkeletonWidget : public QWidget
public: public:
SkeletonWidget(QWidget *parent=0); SkeletonWidget(QWidget *parent=0);
SkeletonEditGraphicsView *graphicsView(); SkeletonEditGraphicsView *graphicsView();
ModelWidget *modelWidget();
public slots: public slots:
void skeletonChanged(); void skeletonChanged();
void meshReady(); void meshReady();
@ -23,7 +24,7 @@ public slots:
void changeTurnaround(); void changeTurnaround();
void showModelingWidgetAtCorner(); void showModelingWidgetAtCorner();
private: private:
ModelingWidget *m_modelingWidget; ModelWidget *m_modelWidget;
SkeletonEditGraphicsView *m_graphicsView; SkeletonEditGraphicsView *m_graphicsView;
SkeletonToMesh *m_skeletonToMesh; SkeletonToMesh *m_skeletonToMesh;
bool m_skeletonDirty; bool m_skeletonDirty;