2018-04-02 06:05:06 +00:00
|
|
|
#include <QMutexLocker>
|
|
|
|
#include <QFile>
|
|
|
|
#include <QTextStream>
|
2018-04-26 02:23:22 +00:00
|
|
|
#include <QFileInfo>
|
|
|
|
#include <map>
|
|
|
|
#include <QDebug>
|
|
|
|
#include <QDir>
|
2018-04-02 06:05:06 +00:00
|
|
|
#include "modelmeshbinder.h"
|
|
|
|
#include "ds3file.h"
|
|
|
|
|
|
|
|
ModelMeshBinder::ModelMeshBinder() :
|
2018-04-15 12:48:54 +00:00
|
|
|
m_mesh(nullptr),
|
2018-09-18 07:20:51 +00:00
|
|
|
m_newMesh(nullptr),
|
2018-04-02 06:05:06 +00:00
|
|
|
m_renderTriangleVertexCount(0),
|
|
|
|
m_renderEdgeVertexCount(0),
|
2018-09-18 07:20:51 +00:00
|
|
|
m_newMeshComing(false),
|
2018-05-10 09:16:22 +00:00
|
|
|
m_showWireframes(false),
|
|
|
|
m_hasTexture(false),
|
|
|
|
m_texture(nullptr)
|
2018-04-02 06:05:06 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
ModelMeshBinder::~ModelMeshBinder()
|
|
|
|
{
|
|
|
|
delete m_mesh;
|
2018-09-18 07:20:51 +00:00
|
|
|
delete m_newMesh;
|
2018-05-10 09:16:22 +00:00
|
|
|
delete m_texture;
|
2018-04-02 06:05:06 +00:00
|
|
|
}
|
|
|
|
|
2018-05-07 17:16:58 +00:00
|
|
|
void ModelMeshBinder::updateMesh(MeshLoader *mesh)
|
2018-04-02 06:05:06 +00:00
|
|
|
{
|
2018-09-18 07:20:51 +00:00
|
|
|
QMutexLocker lock(&m_newMeshMutex);
|
2018-04-02 06:05:06 +00:00
|
|
|
if (mesh != m_mesh) {
|
2018-09-18 07:20:51 +00:00
|
|
|
delete m_newMesh;
|
|
|
|
m_newMesh = mesh;
|
|
|
|
m_newMeshComing = true;
|
2018-04-02 06:05:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModelMeshBinder::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;
|
2018-04-12 08:34:00 +00:00
|
|
|
for (std::vector<QVector3D>::const_iterator it = m_mesh->vertices().begin() ; it != m_mesh->vertices().end(); ++it) {
|
2018-04-02 06:05:06 +00:00
|
|
|
stream << "v " << (*it).x() << " " << (*it).y() << " " << (*it).z() << endl;
|
|
|
|
}
|
2018-04-12 08:34:00 +00:00
|
|
|
for (std::vector<std::vector<int>>::const_iterator it = m_mesh->faces().begin() ; it != m_mesh->faces().end(); ++it) {
|
2018-04-02 06:05:06 +00:00
|
|
|
stream << "f";
|
2018-04-12 08:34:00 +00:00
|
|
|
for (std::vector<int>::const_iterator subIt = (*it).begin() ; subIt != (*it).end(); ++subIt) {
|
2018-04-02 06:05:06 +00:00
|
|
|
stream << " " << (1 + *subIt);
|
|
|
|
}
|
|
|
|
stream << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-09-05 03:14:36 +00:00
|
|
|
void ModelMeshBinder::exportMeshAsObjPlusMaterials(const QString &filename)
|
2018-04-26 02:23:22 +00:00
|
|
|
{
|
|
|
|
QMutexLocker lock(&m_meshMutex);
|
|
|
|
if (m_mesh) {
|
|
|
|
QFileInfo nameInfo(filename);
|
|
|
|
QString mtlFilenameWithoutPath = nameInfo.baseName() + ".mtl";
|
|
|
|
QString mtlFilename = nameInfo.path() + QDir::separator() + mtlFilenameWithoutPath;
|
|
|
|
std::map<QString, QColor> colorNameMap;
|
|
|
|
QString lastColorName;
|
|
|
|
|
|
|
|
qDebug() << "export obj to " << filename;
|
|
|
|
qDebug() << "export mtl to " << mtlFilename;
|
|
|
|
|
|
|
|
QFile file(filename);
|
|
|
|
if (file.open(QIODevice::WriteOnly)) {
|
|
|
|
QTextStream stream(&file);
|
|
|
|
stream << "# " << Ds3FileReader::m_applicationName << endl;
|
|
|
|
stream << "mtllib " << mtlFilenameWithoutPath << endl;
|
|
|
|
for (std::vector<QVector3D>::const_iterator it = m_mesh->triangulatedVertices().begin() ; it != m_mesh->triangulatedVertices().end(); ++it) {
|
|
|
|
stream << "v " << (*it).x() << " " << (*it).y() << " " << (*it).z() << endl;
|
|
|
|
}
|
|
|
|
for (std::vector<TriangulatedFace>::const_iterator it = m_mesh->triangulatedFaces().begin() ; it != m_mesh->triangulatedFaces().end(); ++it) {
|
|
|
|
QString colorName = it->color.name();
|
|
|
|
colorName = "rgb" + colorName.remove(QChar('#'));
|
|
|
|
if (colorNameMap.find(colorName) == colorNameMap.end())
|
|
|
|
colorNameMap[colorName] = it->color;
|
|
|
|
if (lastColorName != colorName) {
|
|
|
|
lastColorName = colorName;
|
|
|
|
stream << "usemtl " << colorName << endl;
|
|
|
|
}
|
|
|
|
stream << "f" << " " << (1 + it->indicies[0]) << " " << (1 + it->indicies[1]) << " " << (1 + it->indicies[2]) << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
QFile mtlFile(mtlFilename);
|
|
|
|
if (mtlFile.open(QIODevice::WriteOnly)) {
|
|
|
|
QTextStream stream(&mtlFile);
|
|
|
|
stream << "# " << Ds3FileReader::m_applicationName << endl;
|
|
|
|
for (const auto &it: colorNameMap) {
|
|
|
|
stream << "newmtl " << it.first << endl;
|
|
|
|
stream << "Ka" << " " << it.second.redF() << " " << it.second.greenF() << " " << it.second.blueF() << endl;
|
|
|
|
stream << "Kd" << " " << it.second.redF() << " " << it.second.greenF() << " " << it.second.blueF() << endl;
|
|
|
|
stream << "Ks" << " 0.0 0.0 0.0" << endl;
|
|
|
|
stream << "illum" << " 1" << endl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-04-02 06:05:06 +00:00
|
|
|
void ModelMeshBinder::initialize()
|
|
|
|
{
|
|
|
|
m_vaoTriangle.create();
|
|
|
|
m_vaoEdge.create();
|
|
|
|
}
|
|
|
|
|
2018-05-10 09:16:22 +00:00
|
|
|
void ModelMeshBinder::paint(ModelShaderProgram *program)
|
2018-04-02 06:05:06 +00:00
|
|
|
{
|
2018-09-18 07:20:51 +00:00
|
|
|
MeshLoader *newMesh = nullptr;
|
|
|
|
bool hasNewMesh = false;
|
|
|
|
if (m_newMeshComing) {
|
|
|
|
QMutexLocker lock(&m_newMeshMutex);
|
|
|
|
if (m_newMeshComing) {
|
|
|
|
newMesh = m_newMesh;
|
|
|
|
m_newMesh = nullptr;
|
|
|
|
m_newMeshComing = false;
|
|
|
|
hasNewMesh = true;
|
|
|
|
}
|
|
|
|
}
|
2018-04-02 06:05:06 +00:00
|
|
|
{
|
|
|
|
QMutexLocker lock(&m_meshMutex);
|
2018-09-18 07:20:51 +00:00
|
|
|
if (hasNewMesh) {
|
|
|
|
delete m_mesh;
|
|
|
|
m_mesh = newMesh;
|
2018-04-02 06:05:06 +00:00
|
|
|
if (m_mesh) {
|
2018-05-10 09:16:22 +00:00
|
|
|
m_hasTexture = nullptr != m_mesh->textureImage();
|
|
|
|
delete m_texture;
|
|
|
|
m_texture = nullptr;
|
|
|
|
if (m_hasTexture) {
|
|
|
|
m_texture = new QOpenGLTexture(*m_mesh->textureImage());
|
|
|
|
}
|
2018-04-02 06:05:06 +00:00
|
|
|
{
|
|
|
|
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTriangle);
|
|
|
|
if (m_vboTriangle.isCreated())
|
|
|
|
m_vboTriangle.destroy();
|
|
|
|
m_vboTriangle.create();
|
|
|
|
m_vboTriangle.bind();
|
|
|
|
m_vboTriangle.allocate(m_mesh->triangleVertices(), m_mesh->triangleVertexCount() * sizeof(Vertex));
|
|
|
|
m_renderTriangleVertexCount = m_mesh->triangleVertexCount();
|
|
|
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
|
|
|
f->glEnableVertexAttribArray(0);
|
|
|
|
f->glEnableVertexAttribArray(1);
|
|
|
|
f->glEnableVertexAttribArray(2);
|
2018-05-10 09:16:22 +00:00
|
|
|
f->glEnableVertexAttribArray(3);
|
2018-10-04 12:51:01 +00:00
|
|
|
f->glEnableVertexAttribArray(4);
|
|
|
|
f->glEnableVertexAttribArray(5);
|
|
|
|
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
|
|
|
|
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
2018-04-02 06:05:06 +00:00
|
|
|
m_vboTriangle.release();
|
|
|
|
}
|
|
|
|
{
|
|
|
|
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoEdge);
|
|
|
|
if (m_vboEdge.isCreated())
|
|
|
|
m_vboEdge.destroy();
|
|
|
|
m_vboEdge.create();
|
|
|
|
m_vboEdge.bind();
|
|
|
|
m_vboEdge.allocate(m_mesh->edgeVertices(), m_mesh->edgeVertexCount() * sizeof(Vertex));
|
|
|
|
m_renderEdgeVertexCount = m_mesh->edgeVertexCount();
|
|
|
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
|
|
|
f->glEnableVertexAttribArray(0);
|
|
|
|
f->glEnableVertexAttribArray(1);
|
|
|
|
f->glEnableVertexAttribArray(2);
|
2018-05-10 09:16:22 +00:00
|
|
|
f->glEnableVertexAttribArray(3);
|
2018-10-04 12:51:01 +00:00
|
|
|
f->glEnableVertexAttribArray(4);
|
|
|
|
f->glEnableVertexAttribArray(5);
|
|
|
|
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), 0);
|
|
|
|
f->glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(3 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(6 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(3, 2, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(9 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(11 * sizeof(GLfloat)));
|
|
|
|
f->glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(Vertex), reinterpret_cast<void *>(12 * sizeof(GLfloat)));
|
2018-04-02 06:05:06 +00:00
|
|
|
m_vboEdge.release();
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
m_renderTriangleVertexCount = 0;
|
|
|
|
m_renderEdgeVertexCount = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2018-04-07 11:51:33 +00:00
|
|
|
|
2018-04-11 15:06:30 +00:00
|
|
|
if (m_showWireframes) {
|
2018-04-07 11:51:33 +00:00
|
|
|
if (m_renderEdgeVertexCount > 0) {
|
|
|
|
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoEdge);
|
2018-04-12 08:34:00 +00:00
|
|
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
2018-05-10 09:16:22 +00:00
|
|
|
program->setUniformValue(program->textureEnabledLoc(), 0);
|
2018-04-12 08:34:00 +00:00
|
|
|
f->glDrawArrays(GL_LINES, 0, m_renderEdgeVertexCount);
|
2018-04-07 11:51:33 +00:00
|
|
|
}
|
2018-04-02 06:05:06 +00:00
|
|
|
}
|
|
|
|
if (m_renderTriangleVertexCount > 0) {
|
|
|
|
QOpenGLVertexArrayObject::Binder vaoBinder(&m_vaoTriangle);
|
2018-04-12 08:34:00 +00:00
|
|
|
QOpenGLFunctions *f = QOpenGLContext::currentContext()->functions();
|
2018-05-10 09:16:22 +00:00
|
|
|
if (m_hasTexture) {
|
|
|
|
if (m_texture)
|
|
|
|
m_texture->bind(0);
|
|
|
|
program->setUniformValue(program->textureIdLoc(), 0);
|
|
|
|
program->setUniformValue(program->textureEnabledLoc(), 1);
|
|
|
|
} else {
|
|
|
|
program->setUniformValue(program->textureEnabledLoc(), 0);
|
|
|
|
}
|
2018-04-12 08:34:00 +00:00
|
|
|
f->glDrawArrays(GL_TRIANGLES, 0, m_renderTriangleVertexCount);
|
2018-04-02 06:05:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void ModelMeshBinder::cleanup()
|
|
|
|
{
|
|
|
|
if (m_vboTriangle.isCreated())
|
|
|
|
m_vboTriangle.destroy();
|
|
|
|
if (m_vboEdge.isCreated())
|
|
|
|
m_vboEdge.destroy();
|
2018-05-12 10:07:46 +00:00
|
|
|
delete m_texture;
|
|
|
|
m_texture = nullptr;
|
2018-04-02 06:05:06 +00:00
|
|
|
}
|
2018-04-07 11:51:33 +00:00
|
|
|
|
2018-04-11 15:06:30 +00:00
|
|
|
void ModelMeshBinder::showWireframes()
|
2018-04-07 11:51:33 +00:00
|
|
|
{
|
2018-04-11 15:06:30 +00:00
|
|
|
m_showWireframes = true;
|
2018-04-07 11:51:33 +00:00
|
|
|
}
|
|
|
|
|
2018-04-11 15:06:30 +00:00
|
|
|
void ModelMeshBinder::hideWireframes()
|
2018-04-07 11:51:33 +00:00
|
|
|
{
|
2018-04-11 15:06:30 +00:00
|
|
|
m_showWireframes = false;
|
2018-04-07 11:51:33 +00:00
|
|
|
}
|
2018-04-15 12:48:54 +00:00
|
|
|
|
|
|
|
bool ModelMeshBinder::isWireframesVisible()
|
|
|
|
{
|
|
|
|
return m_showWireframes;
|
|
|
|
}
|