#include "..\Header\GeometryEngine.h" #include "..\Header\MshFile.h" #include "..\Header\OglViewerWidget.h" #include "..\Header\MainWindow.h" #include #include ///////////////////////////////////////////////////////////////////////// // public constructor/destructor GeometryEngine::GeometryEngine(QObject *parent) : QObject(parent) , m_indexBuf(QOpenGLBuffer::IndexBuffer) { initializeOpenGLFunctions(); m_defaultMaterial = FileInterface::getDefaultMaterial(); } GeometryEngine::~GeometryEngine() { clearData(); delete m_defaultMaterial->texture0; delete m_defaultMaterial; } ///////////////////////////////////////////////////////////////////////// // private functions void GeometryEngine::clearData() { if (m_arrayBuf.isCreated()) m_arrayBuf.destroy(); if (m_indexBuf.isCreated()) m_indexBuf.destroy(); if (m_materials != Q_NULLPTR) { for (auto it : *m_materials) { if (it.texture0 != Q_NULLPTR) delete it.texture0; if (it.texture1 != Q_NULLPTR) delete it.texture1; } m_materials->clear(); delete m_materials; } m_drawList.clear(); } ///////////////////////////////////////////////////////////////////////// // public slots void GeometryEngine::loadFile(QString filePath) { // cleanup old stuff and recreate buffers clearData(); m_arrayBuf.create(); m_indexBuf.create(); //reset view emit requestResetView(); emit sendMessage("loading file..", 0); try { QVector* models; QVector vertexData; QVector indexData; // open file and get the information MshFile file(filePath, this); models = file.getModels(); m_materials = file.getMaterials(); m_boundings = file.getBoundingBox(); // collect data unsigned int indexOffset(0); unsigned int vertexOffset(0); for (auto& modelIterator : *models) { for (auto& segmentIterator : modelIterator->segmList) { // get draw information DrawInformation new_info; new_info.offset = indexOffset; new_info.size = segmentIterator->indices.size(); new_info.textureIndex = segmentIterator->textureIndex; new_info.modelMatrix = modelIterator->m4x4Translation; new_info.modelMatrix.rotate(modelIterator->quadRotation); // add offset to indices, no need to do it for the first one (maybe it's very big) if (vertexOffset != 0) for (auto& it : segmentIterator->indices) it += vertexOffset; // save data vertexData += segmentIterator->vertices; indexData += segmentIterator->indices; if (segmentIterator->textureIndex < (unsigned) m_materials->size() && m_materials->at(segmentIterator->textureIndex).transparent) m_drawList.push_back(new_info); else m_drawList.push_front(new_info); // update offset indexOffset += new_info.size; vertexOffset += segmentIterator->vertices.size(); } } // Transfer vertex data to VBO 0 m_arrayBuf.bind(); m_arrayBuf.allocate(vertexData.data(), vertexData.size() * sizeof(VertexData)); // Transfer index data to VBO 1 m_indexBuf.bind(); m_indexBuf.allocate(indexData.data(), indexData.size() * sizeof(GLuint)); emit requestUpdate(); emit sendMessage("done..", 0); emit sendFileInfo(filePath.right(filePath.size() - filePath.lastIndexOf(QRegExp("/|\\\\")) - 1), m_materials, vertexData.size(), indexData.size() / 3); } catch (std::invalid_argument e) { clearData(); emit sendMessage(QString(e.what()), 2); } } void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program, bool wireframe) { if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated()) return; // Setup // Tell OpenGL which VBOs to use m_arrayBuf.bind(); m_indexBuf.bind(); // Allways normalize by this QMatrix4x4 normMatrix; float maxExtent = std::max(std::max(m_boundings.extents[0], m_boundings.extents[1]), m_boundings.extents[2]); normMatrix.scale(1 / maxExtent); normMatrix.translate(-m_boundings.center[0], -m_boundings.center[1], -m_boundings.center[2]); program->setUniformValue("norm_matrix", normMatrix); // Allways use texture unit 0 program->setUniformValue("texture", 0); // Offset for position quintptr offset = 0; // Tell OpenGL programmable pipeline how to locate vertex position data int vertexLocation = program->attributeLocation("a_position"); program->enableAttributeArray(vertexLocation); program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); // Offset for texture coordinate offset += sizeof(QVector3D); // Tell OpenGL programmable pipeline how to locate vertex texture coordinate data int texcoordLocation = program->attributeLocation("a_texcoord"); program->enableAttributeArray(texcoordLocation); program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData)); //Offset for normal offset += sizeof(QVector2D); // Tell OpenGL programmable pipeline how to locate vertex normal data int normLocation = program->attributeLocation("a_normal"); program->enableAttributeArray(normLocation); program->setAttributeBuffer(normLocation, GL_FLOAT, offset, 3, sizeof(VertexData)); // Paint for (auto& it : m_drawList) { bool tmp_transparent(false); bool tmp_specular(false); float shininess(0.0); QVector3D specularColor; // bind the correct texture if (it.textureIndex < (unsigned) m_materials->size() && m_materials->at(it.textureIndex).texture0 != Q_NULLPTR) { m_materials->at(it.textureIndex).texture0->bind(); tmp_transparent = m_materials->at(it.textureIndex).transparent; tmp_specular = m_materials->at(it.textureIndex).flags[7]; shininess = m_materials->at(it.textureIndex).shininess; specularColor = m_materials->at(it.textureIndex).specularColor.toVector3D(); } else { m_defaultMaterial->texture0->bind(); tmp_transparent = m_defaultMaterial->transparent; } // Set model matrix program->setUniformValue("m_matrix", it.modelMatrix); // Set normal matrix program->setUniformValue("n_matrix", (normMatrix * it.modelMatrix).normalMatrix()); // set some more values program->setUniformValue("b_transparent", tmp_transparent); program->setUniformValue("b_specular", tmp_specular); // set some material attributes program->setUniformValue("materialShininess", shininess); program->setUniformValue("materialSpecularColor", specularColor); // Draw cube geometry using indices from VBO 1 if(wireframe) glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint))); glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); } }