#include "..\Header\OpenGlViewer.h" #include #include #include ///////////////////////////////////////////////////////////////////////// // Defined values //opengl #define DEFAULT_MAJOR_VERSION 4 #define DEFAULT_MINOR_VERSION 5 #define DEAFAULT_BACKGROUND 0.5000f, 0.8000f, 1.0000f, 0.0000f //piplines #define VERTEX_INDEX_XYZ 0 #define VERTEX_INDEX_UV 1 #define VERTEX_COMPONENTS_XYZ 3 #define VERTEX_COMPONENTS_UV 2 #define VERTEX_SIZE_XYZ (sizeof(float) * VERTEX_COMPONENTS_XYZ) #define VERTEX_SIZE_UV (sizeof(float) * VERTEX_COMPONENTS_UV) #define VERTEX_OFFSET_XYZ 0 #define VERTEX_OFFSET_UV (VERTEX_SIZE_XYZ) ///////////////////////////////////////////////////////////////////////// // public constructor/destructor OpenGlViewer::OpenGlViewer(QWidget *parent) : QOpenGLWidget(parent) { QSurfaceFormat format; format.setRenderableType(QSurfaceFormat::OpenGL); format.setSamples(4); format.setProfile(QSurfaceFormat::CoreProfile); format.setVersion(DEFAULT_MAJOR_VERSION, DEFAULT_MINOR_VERSION); setFormat(format); //TODO: mouse, move, key, drag/drop, scroll, resize } OpenGlViewer::~OpenGlViewer() { glDeleteTextures(1, &m_oglTexture); glDeleteBuffers(1, &m_vertexBuffer); m_vertexArray.destroy(); delete m_program; deleteData(); } ///////////////////////////////////////////////////////////////////////// // private functions void OpenGlViewer::initializeGL() { initializeOpenGLFunctions(); printContextInformation(); // set Background glClearColor(DEAFAULT_BACKGROUND); //TODO: z-order? // draw vertices only from one side glEnable(GL_CULL_FACE); // Create texture glGenTextures(1, &m_oglTexture); glBindTexture(GL_TEXTURE_2D, m_oglTexture); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR); // Create Shader m_program = new QOpenGLShaderProgram(); m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, ":/shaders/simple.vert"); m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, ":/shaders/simple.frag"); m_program->link(); m_program->bind(); // get Uniform location //TODO: faster to give everything to shader and calculate there? m_uniformMVP = m_program->uniformLocation("MVP"); // Create Vertex Buffer glGenBuffers(1, &m_vertexBuffer); glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); // Create Vertex Array Object m_vertexArray.create(); m_vertexArray.bind(); m_program->enableAttributeArray(0); m_program->enableAttributeArray(1); m_program->setAttributeBuffer(VERTEX_INDEX_XYZ, GL_FLOAT, VERTEX_OFFSET_XYZ, VERTEX_COMPONENTS_XYZ, sizeof(Vertex)); m_program->setAttributeBuffer(VERTEX_INDEX_UV, GL_FLOAT, VERTEX_OFFSET_UV, VERTEX_COMPONENTS_UV, sizeof(Vertex)); // unbind everything m_vertexArray.release(); glBindBuffer(GL_ARRAY_BUFFER, 0); m_program->release(); } void OpenGlViewer::paintGL() { //TODO: paint here glClear(GL_COLOR_BUFFER_BIT); m_program->bind(); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, m_oglTexture); m_program->setUniformValue("textureSampler", 0); if (m_vModels != nullptr) { int tmp_offset(0); for (unsigned int modelIndex = 0; modelIndex < m_vModels->size(); modelIndex++) { // skip null, bones, shadowMesh, hidden things if (m_vModels->at(modelIndex)->type == null || m_vModels->at(modelIndex)->type == bone || m_vModels->at(modelIndex)->type == shadowMesh || m_vModels->at(modelIndex)->renderFlags == 1) continue; for (auto& segmentIterator : m_vModels->at(modelIndex)->segmList) { // set the texture std::uint32_t tmp_textureIndex = segmentIterator->textureIndex >= m_vTextures->size() ? m_vTextures->size() - 1 : segmentIterator->textureIndex; glTexImage2D( GL_TEXTURE_2D, 0, m_vTextures->at(tmp_textureIndex)->alpha ? GL_RGBA : GL_RGB, m_vTextures->at(tmp_textureIndex)->width, m_vTextures->at(tmp_textureIndex)->height, 0, m_vTextures->at(tmp_textureIndex)->alpha ? GL_BGRA : GL_BGR, GL_UNSIGNED_BYTE, m_vTextures->at(tmp_textureIndex)->data->data() ); glGenerateMipmap(GL_TEXTURE_2D); // give the MVP to the shader m_program->setUniformValue(m_uniformMVP, getMVPMatrix(modelIndex)); // calculate the number of vertex unsigned int tmp_vertexCount(0); for (auto&it : segmentIterator->polyIndices) tmp_vertexCount += (it.size() - 2) * 3; glDrawArrays(GL_TRIANGLES, tmp_offset, tmp_vertexCount); // increase the offset tmp_offset += tmp_vertexCount; } } } m_program->release(); this->frameSwapped(); } void OpenGlViewer::printContextInformation() { QString glType; QString glVersion; QString glProfile; glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL"; glVersion = reinterpret_cast(glGetString(GL_VERSION)); #define CASE(c) case QSurfaceFormat::c: glProfile = #c; break switch (format().profile()) { CASE(NoProfile); CASE(CoreProfile); CASE(CompatibilityProfile); } #undef CASE std::cout << glType.toStdString() << " - " << glVersion.toStdString() << " (" << glProfile.toStdString() << ")"; } QMatrix4x4 OpenGlViewer::getModelMatrix(unsigned int index) const { QMatrix4x4 tmp_parent; for (unsigned int loop = 0; loop < m_vModels->size(); loop++) { if (!strcmp(m_vModels->at(index)->parent.c_str(), m_vModels->at(loop)->name.c_str())) { tmp_parent = getModelMatrix(loop); break; } } return tmp_parent * m_vModels->at(index)->m4x4Translation; } QMatrix4x4 OpenGlViewer::getMVPMatrix(unsigned int index) const { QMatrix4x4 tmp_mvp; // projection tmp_mvp.perspective(m_fFOV, float(QWidget::width()) / float(QWidget::height()), m_fMinView, m_fMaxView); // view tmp_mvp.lookAt(QVector3D(m_fTranX, m_fTranY, m_fTranZ), QVector3D(m_fTranX, m_fTranY, m_fTranZ - 1), QVector3D(0, 0, 1)); // user controlled rotation tmp_mvp.rotate(m_fRotX, QVector3D(1, 0, 0)); tmp_mvp.rotate(m_fRotY, QVector3D(0, 1, 0)); tmp_mvp.rotate(m_fRotZ, QVector3D(0, 0, 1)); //scale to 1 float maxExtent = std::max(std::max(m_sceneBoundings.extents[0], m_sceneBoundings.extents[1]), m_sceneBoundings.extents[2]); tmp_mvp.scale(1 / maxExtent); // move to center tmp_mvp.translate(-m_sceneBoundings.center[0], -m_sceneBoundings.center[1], -m_sceneBoundings.center[2]); return tmp_mvp * getModelMatrix(index); } void OpenGlViewer::deleteData() { if (m_vModels != nullptr) { while (!m_vModels->empty()) { // remove the last Model Model* modelVectorElement = m_vModels->back(); m_vModels->pop_back(); while (!modelVectorElement->segmList.empty()) { // remove the last Segment Segment* segmentVectorElement = modelVectorElement->segmList.back(); modelVectorElement->segmList.pop_back(); // delete data from Segment delete[] segmentVectorElement->uv; delete[] segmentVectorElement->vertex; while (!segmentVectorElement->polyIndices.empty()) { // clear the poly vector and remove it from the list segmentVectorElement->polyIndices.back().clear(); segmentVectorElement->polyIndices.pop_back(); } // delete the actual Segment delete segmentVectorElement; } // delete the actual Model delete modelVectorElement; } // delete the Model's Vector delete m_vModels; } if (m_vTextures != nullptr) { while (!m_vTextures->empty()) { // remove the last texture TextureData* cursor = m_vTextures->back(); m_vTextures->pop_back(); cursor->data->clear(); delete cursor->data; //delete image delete cursor; } // delete the Textrue's Vector delete m_vTextures; } } ///////////////////////////////////////////////////////////////////////// // public functions void OpenGlViewer::setData(std::vector* models, std::vector* textures, BoundingBox bbox) { // new Data, so clean up the old things deleteData(); // save the variables m_vModels = models; m_vTextures = textures; m_sceneBoundings = bbox; // collect vertex data of all models std::vector tmp_bufferData; for (auto& modIt : *m_vModels) // for every model chunk { for (auto& segIt : modIt->segmList) // for every cluster { for (auto& mshIt : segIt->polyIndices) // for every polygon { if (mshIt.size() >= 3) // multipoly { // for every triangle of the multi polygon for (unsigned int tri = 0; tri < mshIt.size() - 2; tri++) { // for every edge of the triangle for (int triEdge = 0; triEdge < 3; triEdge++) { Vertex tempVertex; // every edge has 3 coordinates for (int j = 0; j < 3; j++) tempVertex.position[j] = (GLfloat)segIt->vertex[mshIt[tri + triEdge - ((tri % 2) * (triEdge - 1) * 2)] * 3 + j]; // and 2 UV if (segIt->uv == NULL) { tempVertex.uv[0] = 1.0; tempVertex.uv[1] = 1.0; } else { for (int j = 0; j < 2; j++) tempVertex.uv[j] = (GLfloat)segIt->uv[mshIt[tri + triEdge - ((tri % 2) * (triEdge - 1) * 2)] * 2 + j]; } tmp_bufferData.push_back(tempVertex); } } } else // this shouldn't happen (polygon with less then 3 vertex) { deleteData(); QMessageBox msg(this); msg.addButton(QMessageBox::Ok); msg.setText("You have polygons with less then 3 vertices!"); msg.setIcon(QMessageBox::Critical); msg.setWindowTitle("Open File Error"); msg.exec(); return; } } } } glBindBuffer(GL_ARRAY_BUFFER, m_vertexBuffer); glBufferData( GL_ARRAY_BUFFER, sizeof(Vertex) * tmp_bufferData.size(), tmp_bufferData.data(), GL_STATIC_DRAW ); glBindBuffer(GL_ARRAY_BUFFER, 0); tmp_bufferData.clear(); }