#include "..\Header\GeometryEngine.h" #include "..\Header\MshFile.h" ///////////////////////////////////////////////////////////////////////// // public constructor/destructor GeometryEngine::GeometryEngine() : m_indexBuf(QOpenGLBuffer::IndexBuffer) { initializeOpenGLFunctions(); loadFile("..\\Release\\Msh\\5-Poly.msh"); } GeometryEngine::~GeometryEngine() { clearData(); } ///////////////////////////////////////////////////////////////////////// // private functions void GeometryEngine::loadFile(const char* filePath) { // cleanup old stuff and recreate buffers clearData(); m_arrayBuf.create(); m_indexBuf.create(); //reset view emit requestResetView(); try { //TODO normalize QVector* models; QVector* textureNames; QVector vertexData; QVector indexData; // open file and get the information MshFile file(filePath); models = file.getModels(); textureNames = file.getTextureNames(); // 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; // add offset to indices for (auto& it : segmentIterator->indices) it += vertexOffset; // save data vertexData += segmentIterator->vertices; indexData += segmentIterator->indices; m_drawList.push_back(new_info); // update offset indexOffset += new_info.size; vertexOffset += segmentIterator->vertices.size(); } } //TODO: cleanup old stuff // 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)); // get textures path std::string path = filePath; while (path.back() != '/' && path.back() != '\\') path.pop_back(); // load the textures for(auto& it : *textureNames) loadTexture(std::string(path + it).c_str()); } catch (std::invalid_argument e) { //TODO: make a cool message box auto msg = e.what(); } } void GeometryEngine::loadTexture(const char* filePath) { QImage img; if (!img.load(filePath)) { img = QImage(1, 1, QImage::Format_RGB32); img.fill(Qt::red); } // Load image to OglTexture QOpenGLTexture* new_texture = new QOpenGLTexture(img.mirrored()); // Set nearest filtering mode for texture minification new_texture->setMinificationFilter(QOpenGLTexture::Nearest); // Set bilinear filtering mode for texture magnification new_texture->setMagnificationFilter(QOpenGLTexture::Linear); // Wrap texture coordinates by repeating // f.ex. texture coordinate (1.1, 1.2) is same as (0.1, 0.2) new_texture->setWrapMode(QOpenGLTexture::Repeat); m_textures.push_back(new_texture); } void GeometryEngine::clearData() { if (m_arrayBuf.isCreated()) m_arrayBuf.destroy(); if (m_indexBuf.isCreated()) m_indexBuf.destroy(); for (auto it : m_textures) delete it; m_textures.clear(); m_drawList.clear(); } ///////////////////////////////////////////////////////////////////////// // public functions void GeometryEngine::drawGeometry(QOpenGLShaderProgram *program) { if (!m_arrayBuf.isCreated() || !m_indexBuf.isCreated()) return; // Setup // Tell OpenGL which VBOs to use m_arrayBuf.bind(); m_indexBuf.bind(); // 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)); // Paint for (auto& it : m_drawList) { // bind the correct texture if (it.textureIndex < m_textures.size()) m_textures.at(it.textureIndex)->bind(); else m_textures.last()->bind(); // Set model matrix program->setUniformValue("m_matrix", it.modelMatrix); // Draw cube geometry using indices from VBO 1 glDrawElements(GL_TRIANGLES, it.size, GL_UNSIGNED_INT, (void*)(it.offset * sizeof(GLuint))); } }