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
HEADERS += src/mainwindow.h
SOURCES += src/modelingwidget.cpp
HEADERS += src/modelingwidget.h
SOURCES += src/modelwidget.cpp
HEADERS += src/modelwidget.h
SOURCES += src/skeletoneditgraphicsview.cpp
HEADERS += src/skeletoneditgraphicsview.h

View File

@ -69,8 +69,8 @@ MainWindow::MainWindow()
QPushButton *changeTurnaroundButton = new QPushButton(" Change Turnaround ");
modelRightLayout->addWidget(changeTurnaroundButton);
QPushButton *exportPartsModelButton = new QPushButton(" Export ");
modelRightLayout->addWidget(exportPartsModelButton);
QPushButton *exportModelButton = new QPushButton(" Export ");
modelRightLayout->addWidget(exportModelButton);
QPushButton *newModelButton = new QPushButton(" New ");
modelRightLayout->addWidget(newModelButton);
@ -130,6 +130,9 @@ MainWindow::MainWindow()
connectResult = connect(m_sharePageButton, SIGNAL(clicked()), this, SLOT(updatePageButtons()));
assert(connectResult);
connectResult = connect(exportModelButton, SIGNAL(clicked()), this, SLOT(exportModel()));
assert(connectResult);
connectResult = connect(saveModelButton, SIGNAL(clicked()), this, SLOT(saveModel()));
assert(connectResult);
@ -139,6 +142,17 @@ MainWindow::MainWindow()
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()
{
QString filename = QFileDialog::getOpenFileName(this,

View File

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

View File

@ -2,6 +2,8 @@
#include "meshlite.h"
#include <assert.h>
#define MAX_VERTICES_PER_FACE 100
Mesh::Mesh(void *meshlite, int meshId) :
m_triangleVertices(NULL),
m_triangleVertexCount(0),
@ -12,6 +14,30 @@ Mesh::Mesh(void *meshlite, int meshId) :
GLfloat *edgeVertexPositions = new GLfloat[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 *edgeIndices = new int[edgeCount * 2];
int loadedEdgeVertexIndexItemCount = meshlite_get_halfedge_index_array(meshlite, meshId, edgeIndices, edgeCount * 2);
@ -89,6 +115,16 @@ Mesh::~Mesh()
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()
{
return m_triangleVertices;

View File

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

View File

@ -1,4 +1,5 @@
#include "modelingwidget.h"
#include "modelwidget.h"
#include "ds3file.h"
#include <QMouseEvent>
#include <QOpenGLShaderProgram>
#include <QCoreApplication>
@ -6,9 +7,9 @@
// 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),
m_xRot(0),
m_yRot(0),
@ -34,7 +35,7 @@ ModelingWidget::ModelingWidget(QWidget *parent)
}
}
ModelingWidget::~ModelingWidget()
ModelWidget::~ModelWidget()
{
cleanup();
delete m_mesh;
@ -48,7 +49,7 @@ static void qNormalizeAngle(int &angle)
angle -= 360 * 16;
}
void ModelingWidget::setXRotation(int angle)
void ModelWidget::setXRotation(int angle)
{
qNormalizeAngle(angle);
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);
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);
if (angle != m_zRot) {
@ -78,7 +79,7 @@ void ModelingWidget::setZRotation(int angle)
}
}
void ModelingWidget::cleanup()
void ModelWidget::cleanup()
{
if (m_program == nullptr)
return;
@ -153,7 +154,7 @@ static const char *fragmentShaderSource =
" gl_FragColor = vec4(col, 1.0);\n"
"}\n";
void ModelingWidget::initializeGL()
void ModelWidget::initializeGL()
{
// In this example the widget's corresponding top-level window can change
// 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
// the signal will be followed by an invocation of initializeGL() where we
// can recreate all resources.
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelingWidget::cleanup);
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &ModelWidget::cleanup);
initializeOpenGLFunctions();
QColor bgcolor = QWidget::palette().color(QWidget::backgroundRole());
@ -199,7 +200,7 @@ void ModelingWidget::initializeGL()
m_program->release();
}
void ModelingWidget::paintGL()
void ModelWidget::paintGL()
{
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glEnable(GL_DEPTH_TEST);
@ -275,18 +276,18 @@ void ModelingWidget::paintGL()
m_program->release();
}
void ModelingWidget::resizeGL(int w, int h)
void ModelWidget::resizeGL(int w, int h)
{
m_proj.setToIdentity();
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();
}
void ModelingWidget::mouseMoveEvent(QMouseEvent *event)
void ModelWidget::mouseMoveEvent(QMouseEvent *event)
{
int dx = event->x() - m_lastPos.x();
int dy = event->y() - m_lastPos.y();
@ -301,7 +302,7 @@ void ModelingWidget::mouseMoveEvent(QMouseEvent *event)
m_lastPos = event->pos();
}
void ModelingWidget::updateMesh(Mesh *mesh)
void ModelWidget::updateMesh(Mesh *mesh)
{
QMutexLocker lock(&m_meshMutex);
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
#define MODELING_WIDGET_H
#ifndef MODEL_WIDGET_H
#define MODEL_WIDGET_H
#include <QOpenGLWidget>
#include <QOpenGLFunctions>
@ -11,18 +11,19 @@
QT_FORWARD_DECLARE_CLASS(QOpenGLShaderProgram)
class ModelingWidget : public QOpenGLWidget, protected QOpenGLFunctions
class ModelWidget : public QOpenGLWidget, protected QOpenGLFunctions
{
Q_OBJECT
public:
ModelingWidget(QWidget *parent = 0);
~ModelingWidget();
ModelWidget(QWidget *parent = 0);
~ModelWidget();
static bool isTransparent() { return m_transparent; }
static void setTransparent(bool t) { m_transparent = t; }
void updateMesh(Mesh *mesh);
void exportMeshAsObj(const QString &filename);
public slots:
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_modelingWidget = new ModelingWidget(this);
m_modelingWidget->setMinimumSize(128, 128);
m_modelingWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_modelingWidget->setWindowFlags(Qt::Tool | Qt::Window);
m_modelingWidget->setWindowTitle("3D Model");
m_modelWidget = new ModelWidget(this);
m_modelWidget->setMinimumSize(128, 128);
m_modelWidget->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum);
m_modelWidget->setWindowFlags(Qt::Tool | Qt::Window);
m_modelWidget->setWindowTitle("3D Model");
QVBoxLayout *rightLayout = new QVBoxLayout;
rightLayout->addSpacing(10);
@ -101,14 +101,19 @@ SkeletonEditGraphicsView *SkeletonWidget::graphicsView()
return m_graphicsView;
}
ModelWidget *SkeletonWidget::modelWidget()
{
return m_modelWidget;
}
void SkeletonWidget::showModelingWidgetAtCorner()
{
if (!m_modelingWidget->isVisible()) {
if (!m_modelWidget->isVisible()) {
QPoint pos = QPoint(QApplication::desktop()->width(),
QApplication::desktop()->height());
m_modelingWidget->move(pos.x() - m_modelingWidget->width(),
pos.y() - m_modelingWidget->height());
m_modelingWidget->show();
m_modelWidget->move(pos.x() - m_modelWidget->width(),
pos.y() - m_modelWidget->height());
m_modelWidget->show();
}
}
@ -116,7 +121,7 @@ void SkeletonWidget::meshReady()
{
Mesh *resultMesh = m_skeletonToMesh->takeResultMesh();
showModelingWidgetAtCorner();
m_modelingWidget->updateMesh(resultMesh);
m_modelWidget->updateMesh(resultMesh);
delete m_skeletonToMesh;
m_skeletonToMesh = NULL;
if (m_skeletonDirty) {

View File

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