/**************************************************************************** Copyright (C) 2002-2008 Gilles Debunne. All rights reserved. This file is part of the QGLViewer library version 2.3.6. http://www.libqglviewer.com - contact@libqglviewer.com This file may be used under the terms of the GNU General Public License versions 2.0 or 3.0 as published by the Free Software Foundation and appearing in the LICENSE file included in the packaging of this file. In addition, as a special exception, Gilles Debunne gives you certain additional rights, described in the file GPL_EXCEPTION in this package. libQGLViewer uses dual licensing. Commercial/proprietary software must purchase a libQGLViewer Commercial License. This file is provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. *****************************************************************************/ #include "simpleViewer.h" #include "../interfaces/visitor.h" #include "../glnodes/scenegroup.h" #include "../glnodes/shapes.h" #include "../libs/OBJLoader.h" #include #include #include #include #include #include #include #include #include #include #include using namespace std; #define BUFFER_OFFSET(i) ((char *)NULL + (i)) #define GRID_SIZE 10; namespace { const int numVerticesCube = 12*3; const double frame_limit = 5; const double inc_mult = 5; const double inc_offset = 1.05; const int numRowSphere = 20; const int numColSphere = numRowSphere+2; const int numVerticesSphere = numColSphere * numRowSphere + 2; const int numTriSphere = numColSphere*(numRowSphere-1)*2 + 2*numColSphere; const GLuint particleLimit = 1024; int m_lDirectionLocation; int m_normalMatrixLoc; QVector3D sun = QVector3D(0,-1,0); QMatrix4x4 sunRotate; SceneGroup* selection; PickedGeom selectedObj; struct ToolAnimation { double startFrame; int length; bool active; }; ToolAnimation swing; int currentPoint = 0; // VERY lazy way of tracking light balls } class SkyboxCamera : public qglviewer::Camera { virtual qreal zNear() const { return 0.001; } virtual qreal zFar() const { return 1000.0; } }; Viewer::Viewer() { activeColor = new QColor(255, 255, 255, 255); activeCell = nullptr; activeShape = 0; angle_mult = 0.1; } Viewer::~Viewer() { cleanup(); } void Viewer::cleanup() { makeCurrent(); // Delete shaders delete m_program; m_program = 0; delete objShader; objShader = 0; // Delete buffers glDeleteBuffers(NumBuffers, m_Buffers); glDeleteVertexArrays(NumVAOs, m_VAOs); doneCurrent(); } void Viewer::drawSkybox() { // Use the Skybox Shaders glActiveTexture(GL_TEXTURE0); m_program->bind(); s_texture->bind(); // Get projection and camera transformations QMatrix4x4 projectionMatrix; QMatrix4x4 modelViewMatrix; camera()->getProjectionMatrix(projectionMatrix); camera()->getModelViewMatrix(modelViewMatrix); // Increase size of skybox modelViewMatrix = QMatrix4x4(modelViewMatrix.normalMatrix()); modelViewMatrix.scale(300); float colorMult = 0.2 + std::fabs(0.8 * cos(std::fmod(angle_mult * frame + 300, 360) / 360 * M_PI)); m_program->setUniformValue(m_skyMultLoc, colorMult); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); m_program->setUniformValue(m_isSkyLoc, true); m_program->setUniformValue(m_drawTextLoc, true); m_program->setUniformValue(m_isLightLoc, false); m_program->setUniformValue(m_colorLocation, *(new QColor(0, 0, 0, 0))); glCullFace( GL_FRONT ); glBindVertexArray(m_VAOs[VAO_Cube]); glDrawArrays(GL_TRIANGLES, 0, 36); } void Viewer::loadToolObj() { objShader->bind(); // Load the obj file OBJLoader::Loader loader("src/data/sonic_screwdriver.obj"); // Create a GL object for each mesh extracted from the OBJ file const std::vector& meshes = loader.getMeshes(); const std::vector& materials = loader.getMaterials(); for (unsigned int i=0; ibind(); glClear(GL_COLOR_BUFFER_BIT); if(!isPickingActivated) drawSkybox(); glClear(GL_DEPTH_BUFFER_BIT); glCullFace( GL_BACK ); // Get projection and camera transformations QMatrix4x4 projectionMatrix; QMatrix4x4 modelViewMatrix; camera()->getProjectionMatrix(projectionMatrix); camera()->getModelViewMatrix(modelViewMatrix); modelViewMatrix.rotate(30,0,1,0); m_program->setUniformValue(m_projMatrixLocation, projectionMatrix); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); // Adjust sun position float rotAngle = std::fmod(angle_mult * 25 * frame, 360); sunRotate.rotate(rotAngle, 0, 0, 1); //sunRotate.rotate(15, 1, 0, 0); m_program->setUniformValue(m_lDirLoc, (QMatrix4x4(modelViewMatrix.normalMatrix())*sunRotate * sun)); objShader->bind(); objShader->setUniformValue(o_u_prjMatrix, projectionMatrix); objShader->setUniformValue(o_u_lDir, (QMatrix4x4(modelViewMatrix.normalMatrix())*sunRotate * sun)); m_program->bind(); selection->transform.setToIdentity(); selection->transform.rotate(rotAngle, 0, 1, 0); // Traverse the Scene in order to draw its components modelStack.push(modelViewMatrix); root.accept(*this); drawParticles(); drawUi(); sunRotate.setToIdentity(); //float rotAngle = (frame * angle_mult) % 360; } void Viewer::drawTool() { objShader->bind(); // Get projection and camera transformations QMatrix4x4 modelViewMatrix; //camera()->getModelViewMatrix(modelViewMatrix); QMatrix4x4 toolboxPos = QMatrix4x4(); float swingMult = 1; //scale.translate(QVector3D(0,1.5,0)); toolboxPos.translate(0.6, -0.25, -1.6); toolboxPos.rotate(-100, 0, 1, 0); if(swing.active) { swingMult = 0.5 + 0.5 * cos(fmin(swing.length, frame - swing.startFrame) * 2 * M_PI / swing.length); if(frame - swing.startFrame > swing.length) { swing.active = false; } } toolboxPos.rotate(swingMult * -65, 0, 0, 1); toolboxPos.scale(0.06); objShader->setUniformValue(o_u_mvMatrix, modelViewMatrix * toolboxPos); objShader->setUniformValue(o_u_nmMatrix, modelViewMatrix.normalMatrix()); // Draw the meshes for (unsigned int i=0; i<_meshesGL.size(); ++i) { // Set its material properties objShader->setUniformValue(o_u_kd, _meshesGL[i].diffuse); objShader->setUniformValue(o_u_ks, _meshesGL[i].specular); objShader->setUniformValue(o_u_kn, _meshesGL[i].specularExponent); objShader->setUniformValue(o_u_ka, _meshesGL[i].alpha); // Draw the mesh glBindVertexArray(_meshesGL[i].vao); glDrawArrays(GL_TRIANGLES, 0, _meshesGL[i].numVertices); } } void Viewer::drawUi(){ glClear(GL_DEPTH_BUFFER_BIT); // make ui always on top drawTool(); m_program->bind(); glCullFace(GL_BACK); QMatrix4x4 projectionMatrix; QMatrix4x4 uiViewMatrix; uiViewMatrix.translate(0, -1.45, -4); camera()->getProjectionMatrix(projectionMatrix); float colorMult = 0.2 + std::fabs(0.8 * cos(std::fmod(angle_mult * frame + 300, 360) / 360 * M_PI)); m_program->setUniformValue(m_isSkyLoc, false); m_program->setUniformValue(m_drawTextLoc, true); m_program->setUniformValue(m_isLightLoc, true); glBindVertexArray(m_VAOs[VAO_Cube]); uiViewMatrix.scale(.25, .25, .01); uiViewMatrix.translate(-TEX_LENGTH/2.0, 0, 0); for(int i = 0; ibind(); uiViewMatrix.translate(1.2, 0, 0); if(i == selectedTexture) uiViewMatrix.scale(1.2); m_program->setUniformValue(m_mvMatrixLocation, uiViewMatrix); glDrawArrays(GL_TRIANGLES, 0, 6); if(i == selectedTexture) uiViewMatrix.scale(1/1.2); } } void Viewer::drawParticles(){ m_program->bind(); QMatrix4x4 projectionMatrix; QMatrix4x4 modelViewMatrix; camera()->getProjectionMatrix(projectionMatrix); camera()->getModelViewMatrix(modelViewMatrix); glBindVertexArray(m_VAOs[VAO_Particle]); glBindBuffer(GL_ARRAY_BUFFER, VBO_Particle); glBindBuffer(GL_ARRAY_BUFFER, VBO_Particle_Positions); glBindBuffer(GL_ARRAY_BUFFER, VBO_Particle_Colors); glActiveTexture(GL_TEXTURE0); TexturePrograms[1]->bind(); m_program->setUniformValue(m_isSkyLoc, true); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix()); m_program->setUniformValue(m_colorLocation, QColor(255, 255, 255, 255)); m_program->setUniformValue(m_drawTextLoc, false); m_program->setUniformValue(m_isLightLoc, true); glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, particleLimit); } void Viewer::mouseMoveEvent(QMouseEvent* e) { //cout << "Viewer::mouseMoveEvent(QMouseEvent* e)" << endl; // Normal QGLViewer behavior. QGLViewer::mouseMoveEvent(e); } void Viewer::mousePressEvent(QMouseEvent* e) { // TODO: figure out how to get this weird offset ↓↓ frame position maybe? int x = this->x() + e->x() - 10; int y = this->parentWidget()->height() - e->y() - 23; std::cout << "--------------------------------------------------\nPicking shape at " << x << " (" << this->x() << " + " << e->x() << "), " << y << endl; std::cout << "Window geom: " << this->window()->size().width() << "w, " << this->window()->size().height() << "h" << endl; PickedGeom selectedGeom = pickGeom(x, y); if(!selectedGeom.position.isIdentity() && e->modifiers().testFlag(Qt::ControlModifier)) { std::cout << "Selecting cube" << endl; if(selectedObj.shape != nullptr && selectedObj.shape->getParent() != nullptr) { // Remove previous selection selectedObj.shape->getParent()->getChildren()->erase( std::remove(selectedObj.shape->getParent()->getChildren()->begin(), selectedObj.shape->getParent()->getChildren()->end(), selection), selectedObj.shape->getParent()->getChildren()->end()); } selectedObj.shape = selectedGeom.shape; selectedObj.shape->getParent()->addChild(selection); cubeSelected(true); startSwingAnimation(); } if(!selectedGeom.position.isIdentity() && e->modifiers().testFlag(Qt::ShiftModifier)) { Cube* c = new Cube; c->setType(selectedTexture); SceneGroup* container = new SceneGroup; container->transform = selectedGeom.position; container->addChild(c); root.addChild(container); startSwingAnimation(); } else{ QGLViewer::mousePressEvent(e); } } void Viewer::mouseReleaseEvent(QMouseEvent* e) { //cout << "Viewer::mouseReleaseEvent(QMouseEvent* e)" << endl; //m_program->setUniformValue(m_isPickingModeLoc, false); m_program->bind(); m_program->setUniformValue(m_isPickingModeLoc, false); isPickingActivated = false; QGLViewer::mouseReleaseEvent(e); } void Viewer::keyPressEvent(QKeyEvent* e) { switch ( e->key() ) { case Qt::Key_W: break; case Qt::Key_A: break; case Qt::Key_S: break; case Qt::Key_D: break; case Qt::Key_Q: break; case Qt::Key_E: break; case Qt::Key_1: // 0x31; yaay, fall-through cases! case Qt::Key_2: // 0x32 case Qt::Key_3: // 0x33 case Qt::Key_4: // 0x34 case Qt::Key_5: // 0x35 case Qt::Key_6: // 0x36 selectedTexture = e->key() - 0x31; if(selectedObj.shape != nullptr ){ selectedObj.shape->setType(selectedTexture); startSwingAnimation(); } break; default: e->ignore(); break; } } void Viewer::keyReleaseEvent(QKeyEvent* e){ switch ( e->key() ) { case Qt::Key_W: break; case Qt::Key_A: break; case Qt::Key_S: break; case Qt::Key_D: break; case Qt::Key_Q: break; case Qt::Key_E: break; default: e->ignore(); break; } } void Viewer::init() { identityMatrix.setToIdentity(); SkyboxCamera *_cam = new SkyboxCamera(); setCamera(_cam); // Our scene will be from -5 to 5 in X and Y (the grid will be 10x10). setSceneRadius(10); showEntireScene(); // Init OpenGL objects //setMouseBinding(Qt::NoModifier, Qt::LeftButton, CAMERA, LOOK_AROUND, true); connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &Viewer::cleanup); initializeOpenGLFunctions(); // Init shaders & geometry initShaders(); initGeometries(); initBuffers(); loadToolObj(); { // Default non existant cube selectedObj.shape = nullptr; QColor* c1 = new QColor(255, 0, 255, 255); QColor* c2 = new QColor(0, 255, 255, 255); QColor* c3 = new QColor(255, 255, 0, 255); Shape* s1 = new Sphere(); Shape* s2 = new Sphere(); Shape* s3 = new Sphere(); selection = new SceneGroup(); selection->addChild(s1); selection->addChild(s2); selection->addChild(s3); //SceneGroup *sc1 = new SceneGroup(); //sc1->addChild(selection); //root.addChild(sc1); s1->transform.rotate(360 * 1/3,0,1,0); s1->transform.translate(0.3,1,0); s1->transform.scale(0.05); s1->setColor(*c1); s2->transform.rotate(360 * 2/3,0,1,0); s2->transform.translate(0.3,1,0); s2->transform.scale(0.05); s2->setColor(*c2); s3->transform.rotate(360 * 3/3,0,1,0); s3->transform.translate(0.3,1,0); s3->transform.scale(0.05); s3->setColor(*c3); for(int i = 0; i < 10; i++){ for(int j = 0; j < 10; j++){ Shape* cube = new Cube(); SceneGroup *sc = new SceneGroup(); cube->setColor(*c1); cube->setType(TEX_WOODFLOOR); sc->addChild(cube); sc->transform.translate(-5+i, 0, -5+j); root.addChild(sc); } } } startTime = clock(); startAnimation(); } void Viewer::resetSphereColors(){ QColor* c1 = new QColor(255, 0, 255, 255); QColor* c2 = new QColor(0, 255, 255, 255); QColor* c3 = new QColor(255, 255, 0, 255); int i = 0;/* QColor* colors[3] = {c1, c2, c3}; while(selection.hasNext()) { Shape currentSphere = dynamic_cast(selection->getChild()); currentSphere->setColor(colors[i++]); }*/ } void Viewer::initShaders() { // Load vertex and fragment shaders m_program = new QOpenGLShaderProgram; colorPickerShaderProgram = m_program; if (!m_program->addShaderFromSourceFile(QOpenGLShader::Vertex, "src/shaders/basicShader.vert")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << m_program->log(); } if (!m_program->addShaderFromSourceFile(QOpenGLShader::Fragment, "src/shaders/basicShader.frag")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << m_program->log(); } m_program->link(); m_program->bind(); // Note: This is equivalent to glUseProgram(programId()); // Specify shader input paramters // The strings "vPosition", "mvMatrix", etc. have to match an attribute name in the vertex shader. { if ((m_vPositionLocation = m_program->attributeLocation("vPosition")) < 0) qDebug() << "Unable to find shader location for " << "vPosition"; if ((m_colorLocation = m_program->uniformLocation("color")) < 0) qDebug() << "Unable to find shader location for " << "color"; if ((m_useNormalMap = m_program->uniformLocation("useNormalMap")) < 0) qDebug() << "Unable to find shader location for " << "useNormalMap"; if ((m_texNormal = m_program->uniformLocation("texNormal")) < 0) qDebug() << "Unable to find shader location for " << "texNormal"; if ((m_texColor = m_program->uniformLocation("texCol")) < 0) qDebug() << "Unable to find shader location for " << "texCol"; if ((m_mvMatrixLocation = m_program->uniformLocation("mvMatrix")) < 0) qDebug() << "Unable to find shader location for " << "mvMatrix"; if ((m_projMatrixLocation = m_program->uniformLocation("projMatrix")) < 0) qDebug() << "Unable to find shader location for " << "projMatrix"; if ((m_lDirectionLocation = m_program->uniformLocation("lDirection")) < 0) qDebug() << "Unable to find m_shader location for" << "lDirection"; if ((m_normalMatrixLoc = m_program->uniformLocation("normalMatrix")) < 0) qDebug() << "Unable to find m_shader location for" << "normalMatrix"; if ((m_vNormalLocation = m_program->attributeLocation("vNormal")) < 0) qDebug() << "Unable to find m_shader location for" << "vNormal"; if ((s_vUvLocation = m_program->attributeLocation("vUv")) < 0) qDebug() << "Unable to find shader location for " << "vUv"; if ((m_isSkyLoc = m_program->uniformLocation("isSky")) < 0) qDebug() << "Unable to find m_shader location for" << "isSky"; if ((m_isPhongLoc = m_program->uniformLocation("isPhong")) < 0) qDebug() << "Unable to find m_shader location for" << "isPhong"; if ((m_lDirLoc = m_program->uniformLocation("lDirection")) < 0) qDebug() << "Unable to find m_shader location for" << "lDirection"; if ((m_skyMultLoc = m_program->uniformLocation("skyMult")) < 0) qDebug() << "Unable to find m_shader location for" << "skyMult"; if ((m_drawTextLoc = m_program->uniformLocation("drawTextures")) < 0) qDebug() << "Unable to find m_shader location for" << "drawTextures"; if ((m_isLightLoc = m_program->uniformLocation("isLightSource")) < 0) qDebug() << "Unable to find m_shader location for" << "isLightSource"; if ((m_point1Loc = m_program->uniformLocation("pointLight[0]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLight[0]"; if ((m_point2Loc = m_program->uniformLocation("pointLight[1]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLight[1]"; if ((m_point3Loc = m_program->uniformLocation("pointLight[2]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLight[2]"; if ((m_c1Loc = m_program->uniformLocation("pointLightCol[0]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLightCol[0]"; if ((m_c2Loc = m_program->uniformLocation("pointLightCol[1]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLightCol[1]"; if ((m_c3Loc = m_program->uniformLocation("pointLightCol[2]")) < 0) qDebug() << "Unable to find m_shader location for" << "pointLightCol[2]"; if ((m_isPickingModeLoc = m_program->uniformLocation("isPickingMode")) < 0) qDebug() << "Unable to find m_shader location for" << "isPickingMode" << m_program->log(); } m_program->setUniformValue(m_isPhongLoc, true); m_program->setUniformValue(m_drawTextLoc, false); m_program->setUniformValue(m_isPickingModeLoc, false); m_program->setUniformValue(m_useNormalMap, true); m_program->setUniformValue(m_texColor, 0); m_program->setUniformValue(m_texNormal, 1); objShader = new QOpenGLShaderProgram; if (!objShader->addShaderFromSourceFile(QOpenGLShader::Vertex, "src/shaders/objShader.vert")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << objShader->log(); } if (!objShader->addShaderFromSourceFile(QOpenGLShader::Fragment, "src/shaders/objShader.frag")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << objShader->log(); } objShader->link(); objShader->bind(); o_u_mvMatrix = objShader->uniformLocation("mvMatrix"); o_u_prjMatrix = objShader->uniformLocation("projMatrix"); o_u_nmMatrix = objShader->uniformLocation("normalMatrix"); o_u_isPhong = objShader->uniformLocation("isPhong"); o_u_lDir = objShader->uniformLocation("lDirection"); for(int i = 0; i < 3; i++) { std::ostringstream posAttr; std::ostringstream colAttr; posAttr << "pointLight[" << i << "]"; colAttr << "pointLightCol[" << i << "]"; o_u_pointLightPos[i] = objShader->uniformLocation(posAttr.str().c_str()); o_u_pointLightCol[i] = objShader->uniformLocation(colAttr.str().c_str()); } if ((o_u_ka = objShader->uniformLocation("alpha")) < 0) qDebug() << "Unable to find m_shader location for" << "alpha" << objShader->log(); o_u_kd = objShader->uniformLocation("Kd"); o_u_ks = objShader->uniformLocation("Ks"); o_u_kn = objShader->uniformLocation("Kn"); o_a_vPos = objShader->attributeLocation("vPosition"); o_a_vNorm = objShader->attributeLocation("vNormal"); objShader->setUniformValue(o_u_isPhong, true); m_program->bind(); s_texture = new QOpenGLTexture(QImage("src/data/skybox.jpg"));/*/ s_texture = new QOpenGLTexture(QImage("src/data/uvLayoutGrid.png"));//*/ s_texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); s_texture->setMagnificationFilter(QOpenGLTexture::Linear); // load remaining textures for(int i = 0; isetMinificationFilter(QOpenGLTexture::LinearMipMapLinear); TexturePrograms[i]->setMagnificationFilter(QOpenGLTexture::Linear); std::cout << "Binding " << NormalPaths[i].toStdString() << endl; TexturePrograms[TEX_LENGTH + i] = new QOpenGLTexture(QImage(NormalPaths[i])); TexturePrograms[TEX_LENGTH + i]->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); TexturePrograms[TEX_LENGTH + i]->setMagnificationFilter(QOpenGLTexture::Linear); }//*/ } void Viewer::initGeometries() { m_program->bind(); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glEnable( GL_BLEND ); glEnable( GL_CULL_FACE ); glFrontFace( GL_CCW ); glCullFace( GL_BACK ); glClearColor(0.0,0.0,0.0,0.0); // Create our VertexArrays Objects and VertexBuffer Objects glGenVertexArrays(NumVAOs, m_VAOs); glGenBuffers(NumBuffers, m_Buffers); // Create our pentagone object, store its vertices on the graphic card, and // bind the data to the vPosition attribute of the shader GLfloat verticesCube[numVerticesCube][3] = { // 12 triangles == 6 squares //Front, if Z is towards us { -0.5, 0.5, 0.5 }, { -0.5, -0.5, 0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, 0.5, 0.5 }, { -0.5, 0.5, 0.5 }, //Back { -0.5, 0.5, -0.5 }, { 0.5, 0.5, -0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, -0.5, -0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, 0.5, -0.5 }, //Right { -0.5, 0.5, 0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, -0.5, -0.5 }, { -0.5, -0.5, 0.5 }, { -0.5, 0.5, 0.5 }, //Left { 0.5, 0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, 0.5, -0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, 0.5, 0.5 }, { 0.5, -0.5, 0.5 }, //Top { -0.5, 0.5, 0.5 }, { 0.5, 0.5, 0.5 }, { 0.5, 0.5, -0.5 }, { 0.5, 0.5, -0.5 }, { -0.5, 0.5, -0.5 }, { -0.5, 0.5, 0.5 }, //Bottom { -0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { 0.5, -0.5, 0.5 }, { 0.5, -0.5, -0.5 }, { -0.5, -0.5, 0.5 }, { -0.5, -0.5, -0.5 } }; GLfloat uvs[numVerticesCube][2] = { { 1.0, .25 }, { 1.0, .50 }, { .75, .50 }, { .75, .50 }, { .75, .25 }, { 1.0, .25 }, { .25, .25 }, { .50, .25 }, { .50, .50 }, { .50, .50 }, { .25, .50 }, { .25, .25 }, { .00, .25}, { .25, .25}, { .25, .50}, { .25, .50}, { .00, .50}, { .00, .25}, { .75, .25}, { .50, .50}, { .50, .25}, { .50, .50}, { .75, .25}, { .75, .50}, { .25, .00 }, { .49, .00 }, { .49, .25 }, { .49, .25 }, { .25, .25 }, { .25, .00 }, { .25, .50 }, { .49, .75 }, { .49, .50 }, { .49, .75 }, { .25, .50 }, { .25, .75 }, }; GLfloat normals[numVerticesCube][3] = { { 0.0, 0.0, 1.0 }, {0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, { 0.0, 0.0, 1.0 }, {0.0, 0.0, 1.0}, {0.0, 0.0, 1.0}, { 0.0, 0.0, -1.0 }, {0.0, 0.0, -1.0}, {0.0, 0.0, -1.0}, { 0.0, 0.0, -1.0 }, {0.0, 0.0, -1.0}, {0.0, 0.0, -1.0}, { -1.0, 0.0, 0.0 }, {-1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, { -1.0, 0.0, 0.0 }, {-1.0, 0.0, 0.0}, {-1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, { 1.0, 0.0, 0.0 }, {1.0, 0.0, 0.0}, {1.0, 0.0, 0.0}, { 0.0, 1.0, 0.0 }, {0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, { 0.0, 1.0, 0.0 }, {0.0, 1.0, 0.0}, {0.0, 1.0, 0.0}, { 0.0, -1.0, 0.0 }, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0}, { 0.0, -1.0, 0.0 }, {0.0, -1.0, 0.0}, {0.0, -1.0, 0.0} }; GLfloat sphereVertices[numVerticesSphere][3]; GLfloat sphereNormals[numVerticesSphere][3]; GLuint sphereIndices[numTriSphere * 3][3]; // Create Sphere // Generate surrounding vertices unsigned int v = 0; float thetaInc = 2.0f*3.14159265f / static_cast(numColSphere); float phiInc = 3.14159265f / static_cast(numRowSphere+1); for (int row=0; row(row+1) * phiInc); for (int col=0; col 0 glVertexAttribDivisor(1, 1); // positions : one per quad (its center) -> 1 glVertexAttribDivisor(2, 1); // color : one per quad -> 1 //============================================================== // FIN DE CODE RÉFÉRENCÉ //============================================================== } void Viewer::initBuffers(){ glGenRenderbuffers(1, m_RenderBuffers); glBindRenderbuffer(GL_RENDERBUFFER, m_RenderBuffers[RenderBuffer_Main]); glRenderbufferStorage(GL_RENDERBUFFER, GL_RGB565, 1920, 1080); glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, m_RenderBuffers[RenderBuffer_Main]); } void Viewer::visit(Cube &s) { m_program->bind(); QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform); QColor* faceColor = new QColor; glBindVertexArray(m_VAOs[VAO_Cube]); glActiveTexture(GL_TEXTURE0); TexturePrograms[s.getType()]->bind(); glActiveTexture(GL_TEXTURE1); TexturePrograms[TEX_LENGTH + s.getType()]->bind(); m_program->setUniformValue(m_isSkyLoc, false); m_program->setUniformValue(m_drawTextLoc, true); m_program->setUniformValue(m_isLightLoc, false); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix()); int faces = floor(numVerticesCube/6); for(int i =0; isetRgb(s.getColor().rgb() + i); m_program->setUniformValue(m_colorLocation, *faceColor);/*/ QColor* sideColor = new QColor(sideColors[i]); m_program->setUniformValue(m_colorLocation, *sideColor);//*/ glDrawArrays(GL_TRIANGLES, i*6, 6); } delete faceColor; } void Viewer::visit(Sphere &s) { // std::cout << "Sphere found"; QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform); m_program->bind(); if(!isPickingActivated){ glBindVertexArray(m_VAOs[VAO_Sphere]); m_program->setUniformValue(m_isSkyLoc, false); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); m_program->setUniformValue(m_normalMatrixLoc, modelViewMatrix.normalMatrix()); m_program->setUniformValue(m_colorLocation, s.getColor()); m_program->setUniformValue(m_drawTextLoc, false); m_program->setUniformValue(m_isLightLoc, true); // This will save the current position of this light ball as the next point // This means point lights are technically 1 frame behind QVector3D point = QVector3D(0,0,0); point = modelViewMatrix * point; int pointLocs[3] = {m_point1Loc, m_point2Loc, m_point3Loc}; int pointCLocs[3] = {m_c1Loc, m_c2Loc, m_c3Loc}; m_program->setUniformValue(pointLocs[currentPoint], point); m_program->setUniformValue(pointCLocs[currentPoint], s.getColor()); objShader->bind(); objShader->setUniformValue(o_u_pointLightPos[currentPoint], point); objShader->setUniformValue(o_u_pointLightCol[currentPoint], s.getColor()); m_program->bind(); currentPoint = (currentPoint + 1) % 3; glDrawElements(GL_TRIANGLES, numTriSphere*3, GL_UNSIGNED_INT, 0); } } void Viewer::visit(SceneGroup &s) { // Build compound transformation matrix QMatrix4x4 currentMatrix = modelStack.top() * QMatrix4x4(s.transform); modelStack.push(currentMatrix); while(s.hasNext()) { // Get next leaf GlNode* current = s.getChild(); // Draw/Traverse child current->accept(*this); } // Return model matrix to previous state modelStack.pop(); } void Viewer::setPhong(bool on) { m_program->bind(); m_program->setUniformValue(m_isPhongLoc, on); objShader->bind(); objShader->setUniformValue(o_u_isPhong, on); if(on) std::cout << "Phong ON\n"; else std::cout << "Phong OFF\n"; this->update(); } void Viewer::setMagLinear(bool on) { m_program->bind(); if(on) { std::cout << "Linear ON" << endl; s_texture->setMagnificationFilter(QOpenGLTexture::Linear); } else { std::cout << "Nearest ON" << endl; s_texture->setMagnificationFilter(QOpenGLTexture::Nearest); } this->update(); } void Viewer::setMinLinear(bool on) { m_program->bind(); if(on) { std::cout << "Linear MipMap Linear ON" << endl; s_texture->setMinificationFilter(QOpenGLTexture::LinearMipMapLinear); } else { std::cout << "Nearest ON" << endl; s_texture->setMinificationFilter(QOpenGLTexture::Nearest); } this->update(); } void Viewer::toggleNormalMaps(bool state) { m_program->bind(); m_program->setUniformValue(m_useNormalMap, state); } void Viewer::startSwingAnimation() { swing.active = true; swing.startFrame = frame; swing.length = 30; } void Viewer::deleteSelected() { m_program->bind(); int pointCLocs[3] = {m_c1Loc, m_c2Loc, m_c3Loc}; m_program->setUniformValue(pointCLocs[0], QColor(0,0,0)); m_program->setUniformValue(pointCLocs[1], QColor(0,0,0)); m_program->setUniformValue(pointCLocs[2], QColor(0,0,0)); objShader->bind(); objShader->setUniformValue(o_u_pointLightCol[0], QColor(0,0,0)); objShader->setUniformValue(o_u_pointLightCol[1], QColor(0,0,0)); objShader->setUniformValue(o_u_pointLightCol[2], QColor(0,0,0)); m_program->bind(); // Remove Shape from its parent if(selectedObj.shape == nullptr) return; // selectedObj.shape->getParent()->getChildren()->erase( // std::remove(selectedObj.shape->getParent()->getChildren()->begin(), // selectedObj.shape->getParent()->getChildren()->end(), // selection), // selectedObj.shape->getParent()->getChildren()->end()); selectedObj.shape->getParent()->getParent()->getChildren()->erase( std::remove(selectedObj.shape->getParent()->getParent()->getChildren()->begin(), selectedObj.shape->getParent()->getParent()->getChildren()->end(), selectedObj.shape->getParent()), selectedObj.shape->getParent()->getParent()->getChildren()->end()); selectedObj.shape = nullptr; // Rebind to "null" cubeSelected(false); startSwingAnimation(); } void Viewer::changeColor(QColor c){ if(activeCell->getChildren()->size()){ Shape* shape = dynamic_cast (activeCell->childAt(0)); shape->setColor(c); } activeColor = new QColor(c); this->update(); } void Viewer::animate(){ clock_t time = clock(); double dt = 1/0.006;//time - startTime; frame += dt * 0.006 * frame_mult; // 60fps startTime = time; update(); } void Viewer::rotateSelectedObjXCCW() { rotateSelected(RotateDirection::X_CCW); } void Viewer::rotateSelectedObjXCW() { rotateSelected(RotateDirection::X_CW); } void Viewer::rotateSelectedObjYCCW() { rotateSelected(RotateDirection::Y_CCW); } void Viewer::rotateSelectedObjYCW() { rotateSelected(RotateDirection::Y_CW); } void Viewer::rotateSelectedObjZCCW() { rotateSelected(RotateDirection::Z_CCW); } void Viewer::rotateSelectedObjZCW() { rotateSelected(RotateDirection::Z_CW); } void Viewer::animationSpeedChange(int val) { frame_mult = fmax(double(val) / 10, 0.05); } void Viewer::rotateSelected(RotateDirection dir) { if(selectedObj.shape == nullptr || selectedObj.shape->getParent() == nullptr) return; switch(dir) { case X_CCW: selectedObj.shape->getParent()->transform.rotate(90, 1, 0, 0); break; case X_CW: selectedObj.shape->getParent()->transform.rotate(-90, 1, 0, 0); break; case Y_CCW: selectedObj.shape->getParent()->transform.rotate(90, 0, 1, 0); break; case Y_CW: selectedObj.shape->getParent()->transform.rotate(-90, 0, 1, 0); break; case Z_CCW: selectedObj.shape->getParent()->transform.rotate(90, 0, 0, 1); break; case Z_CW: selectedObj.shape->getParent()->transform.rotate(-90, 0, 0, 1); break; } } PickedGeom Viewer::pickGeom(int x, int y){ makeCurrent(); m_program->bind(); m_program->setUniformValue(m_isPickingModeLoc, true); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); glCullFace(GL_BACK); isPickingActivated = true; QMap mapColorToPosition; QMap mapColorToShape; QColor c; QRgb startColor = 1; // alpha must be 100%, glReadPixels doesn't resturn alpha unsigned char pixelData[3]; // Give each cube a color, let each cube manage their face-color assignment //std::cout << "Iterating through " << root.getChildren()->size() << " items"<size(); i++) { //std::cout << " iterating... " << i << endl; SceneGroup* current = dynamic_cast(root.childAt(i)); Shape* currentCube; if(current->getChildren()->size()) { currentCube = dynamic_cast(current->childAt(0)); } c.setRgb(startColor); currentCube->setColor(c); if(currentCube) for (int j = 0; j<3; j++) { for(int i = -1; i<=1; i+=2) { QMatrix4x4 currentTransform = QMatrix4x4(current->transform); int components[3] = {0, 0, 0}; components[j] = i; //std::cout << "Setting " << startColor << " to {" << components[0] << ", " << components[0] << ", " << components[1] << ", " << components[2] << "}\n"; currentTransform.translate(components[1], -components[2], -components[0]); mapColorToPosition.insert(startColor, currentTransform); mapColorToShape.insert(startColor, currentCube); startColor++; } } } root.accept(*this); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // for debugging purposes /*unsigned char pdata[512][512][4]; glReadPixels(x-256, y-256, 512, 512, GL_RGBA, GL_UNSIGNED_BYTE, pdata); QImage *im = new QImage(512, 512, QImage::Format_RGB32); for(int i = 0; i< 512; i++){ for(int j = 0; j< 512; j++){ QColor* pickedColor = new QColor(); pickedColor->setRgb(pdata[512-j][i][0], pdata[512-j][i][1], pdata[512-j][i][2]); if(i==256 && j == 256) pickedColor->setRgba(0xFFFFFFFF); if(i==256 && j == 256) std::cout<<"--- Color under cursor: " << (int)pdata[j][i][0] <<" "<< (int)pdata[j][i][1] <<" "<< (int)pdata[j][i][2] <<" "<< (int)pdata[j][i][3] << endl; pickedColor->setAlpha(255); im->setPixelColor(i, j, pickedColor->rgb()); } } im->save("./screenshot.bmp");//*/ glReadPixels(x, y, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData); QColor* pickedColor = new QColor(pixelData[0], pixelData[1], pixelData[2], pixelData[3]); unsigned int pickedInt = pickedColor->rgb() % 0x1000000; // rgb returns ARGB. go figure. std::cout << "Picked " << pickedInt << endl; QMatrix4x4 pickedPosition = mapColorToPosition.value(pickedInt, identityMatrix); Shape* pickedShape = mapColorToShape.value(pickedInt); mapColorToPosition.clear(); m_program->setUniformValue(m_isPickingModeLoc, false); isPickingActivated = false; glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT); doneCurrent(); PickedGeom result = PickedGeom(); result.position = pickedPosition; result.shape = pickedShape; return result; }