Export working model as obj
parent
4661e2bc94
commit
4c9767835f
|
@ -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
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -16,6 +16,7 @@ public slots:
|
|||
void updatePageButtons();
|
||||
void saveModel();
|
||||
void loadModel();
|
||||
void exportModel();
|
||||
private:
|
||||
QPushButton *m_modelPageButton;
|
||||
QPushButton *m_sharePageButton;
|
||||
|
|
36
src/mesh.cpp
36
src/mesh.cpp
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue