/**************************************************************************** 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 #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; enum Buffer_IDs { ArrayBuffer, NumBuffers }; int vUVLocation; GLuint Buffers[NumBuffers]; } class SkyboxCamera : public qglviewer::Camera { virtual qreal zNear() const { return 0.01; } virtual qreal zFar() const { return 100.0; } }; Viewer::Viewer() { activeColor = new QColor(255, 255, 255, 255); activeCell = nullptr; activeShape = 0; } Viewer::~Viewer() { cleanup(); } void Viewer::cleanup() { makeCurrent(); // Delete shaders delete m_program; m_program = 0; // Delete buffers glDeleteBuffers(NumBuffers, m_Buffers); glDeleteVertexArrays(NumVAOs, m_VAOs); doneCurrent(); } void Viewer::drawSkybox() { // Use the Skybox Shaders skyboxRenderShaderProgram->bind(); s_texture->bind(); // Get projection and camera transformations QMatrix4x4 projectionMatrix; QMatrix4x4 modelViewMatrix; camera()->getProjectionMatrix(projectionMatrix); camera()->getModelViewMatrix(modelViewMatrix); // Increase size of skybox modelViewMatrix.scale(100); skyboxRenderShaderProgram->setUniformValue(s_projMatrixLocation, projectionMatrix); skyboxRenderShaderProgram->setUniformValue(s_mvMatrixLocation, modelViewMatrix); // skyboxRenderShaderProgram->setAttributeValue(s_colorLocation, ); int faces = floor(numVerticesCube/6); for(int i = 0; i < faces; i++){ // 6 vertexes par face glBindVertexArray(m_VAOs[VAO_Cube]); glDrawArrays(GL_TRIANGLES, i*6, 6); } } void Viewer::draw() { drawSkybox(); // Bind our vertex/fragment shaders m_program->bind(); // Get projection and camera transformations QMatrix4x4 projectionMatrix; QMatrix4x4 modelViewMatrix; camera()->getProjectionMatrix(projectionMatrix); camera()->getModelViewMatrix(modelViewMatrix); // Prepare a transformation stack // stack modelStack; //modelViewMatrix.rotate(45, 0, 1, 0); // uncomment this and the cube translation in init() // to see the cube spin /*rot = QQuaternion::fromAxisAndAngle(1, 0, 1, 90/60 * frame); modelViewMatrix.rotate(rot); projectionMatrix.translate(0, -5, 0); projectionMatrix.rotate(15, 1, 0, 0);//*/ m_program->setUniformValue(m_projMatrixLocation, projectionMatrix); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); // Traverse the Scene in order to draw its components modelStack.push(modelViewMatrix); //root.accept(*this); frame++; update(); } void Viewer::mouseMoveEvent(QMouseEvent* e) { //cout << "Viewer::mouseMoveEvent(QMouseEvent* e)" << endl; // Normal QGLViewer behavior. QGLViewer::mouseMoveEvent(e); } void Viewer::mousePressEvent(QMouseEvent* e) { // Auto Return, but old code left in as reference // 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() + 21; 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; Shape* selectedShape = pickGeom(x, y); // OpenGL coords start at the window's bottom-left, not the frame's. ugh. QGLViewer::mousePressEvent(e); } void Viewer::deselect(){ std::cout << "Deselecting cell " << activeCell << endl; if(activeCell != nullptr && activeCell->getChildren()->size()){ std::cout << "Cell has children..." << endl; Shape* shape = dynamic_cast (activeCell->childAt(0)); QColor newColor = shape->getColor(); std::cout << newColor.Rgb << endl; newColor.setAlpha(180); shape->setColor(newColor); }else{ std::cout << "Cell has no children, moving on" << endl; } this->update(); } void Viewer::mouseReleaseEvent(QMouseEvent* e) { //cout << "Viewer::mouseReleaseEvent(QMouseEvent* e)" << endl; QGLViewer::mouseReleaseEvent(e); } void Viewer::init() { SkyboxCamera *_cam = new SkyboxCamera(); setCamera(_cam); //camera()->setType(qglviewer::Camera::PERSPECTIVE); //setMouseBinding(Qt::NoModifier, Qt::LeftButton, CAMERA, SCREEN_ROTATE); //setMouseBinding(Qt::AltModifier, Qt::LeftButton, CAMERA, NO_MOUSE_ACTION); //setMouseBinding(Qt::NoModifier, Qt::MouseButton(Qt::LeftButton + Qt::MidButton), CAMERA, NO_MOUSE_ACTION); //setMouseBinding(Qt::ControlModifier, Qt::MouseButton(Qt::LeftButton + Qt::MidButton), CAMERA, NO_MOUSE_ACTION); //setMouseBinding(Qt::ShiftModifier, Qt::MouseButton(Qt::LeftButton + Qt::MidButton), CAMERA, NO_MOUSE_ACTION); // Our scene will be from -5 to 5 in X and Y (the grid will be 10x10). setSceneRadius(5); showEntireScene(); // Init OpenGL objects connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &Viewer::cleanup); initializeOpenGLFunctions(); // Init shaders & geometry initShaders(); initGeometries(); { Shape* cube = new Cube(); cube->setColor(*activeColor); // uncomment this and the quaternion transformation in draw() // to see the cube rotate. This is how we can easily make the sun. // cube->transform.translate(3, 0, 0); SceneGroup *c = new SceneGroup(); c->addChild(cube); root.addChild(c); } } 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_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"; /* * Adding Texture Shader */ /* textureRenderShaderprogram = new QOpenGLShaderProgram; if (!textureRenderShaderprogram->addShaderFromSourceFile(QOpenGLShader::Vertex, "src/shaders/textureShader.vert")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << textureRenderShaderprogram->log(); } if (!textureRenderShaderprogram->addShaderFromSourceFile(QOpenGLShader::Fragment, "src/shaders/textureShader.frag")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << textureRenderShaderprogram->log(); } textureRenderShaderprogram->link(); */ /* * Adding Skybox Shaders * */ skyboxRenderShaderProgram = new QOpenGLShaderProgram; if (!skyboxRenderShaderProgram->addShaderFromSourceFile(QOpenGLShader::Vertex, "src/shaders/skyboxShader.vert")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << skyboxRenderShaderProgram->log(); } if (!skyboxRenderShaderProgram->addShaderFromSourceFile(QOpenGLShader::Fragment, "src/shaders/skyboxShader.frag")) { cerr << "Unable to load Shader" << endl << "Log file:" << endl; qDebug() << skyboxRenderShaderProgram->log(); } skyboxRenderShaderProgram->link(); skyboxRenderShaderProgram->bind(); // if ((s_texCoordsLocation = m_program->attributeLocation("texCoords")) < 0) // qDebug() << "Unable to find shader location for " << "vPosition"; if ((s_vPositionLocation = skyboxRenderShaderProgram->attributeLocation("vPosition")) < 0) qDebug() << "Unable to find shader location for " << "vPosition"; if ((s_projMatrixLocation = skyboxRenderShaderProgram->uniformLocation("projMatrix")) < 0) qDebug() << "Unable to find shader location for " << "projMatrix"; if ((s_mvMatrixLocation = skyboxRenderShaderProgram->uniformLocation("mvMatrix")) < 0) qDebug() << "Unable to find shader location for " << "mvMatrix"; if ((s_vUvLocation = skyboxRenderShaderProgram->attributeLocation("vUv")) < 0) qDebug() << "Unable to find shader location for " << "vUv"; 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); } // Creates the basic shapes in memory. We only have 3, so we just prep them all in advance. void Viewer::initGeometries() { 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 }, }; glBindVertexArray(m_VAOs[VAO_Cube]); glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Cube]); glGenBuffers(NumBuffers, Buffers); glBindBuffer(GL_ARRAY_BUFFER, Buffers[ArrayBuffer]); glBufferData(GL_ARRAY_BUFFER, sizeof(verticesCube) + sizeof(uvs)/* + sizeof(normals)*/, NULL, GL_STATIC_DRAW); glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(verticesCube), verticesCube); glBufferSubData(GL_ARRAY_BUFFER, sizeof(verticesCube), sizeof(uvs), uvs); //glBufferSubData(GL_ARRAY_BUFFER, sizeof(vertices)+sizeof(uvs), sizeof(normals), normals); // glBindVertexArray(m_VAOs[VAO_Cube]); // glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Cube]); // glBufferData(GL_ARRAY_BUFFER, sizeof(verticesCube), verticesCube, GL_STATIC_DRAW); glVertexAttribPointer(m_vPositionLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0)); glEnableVertexAttribArray(m_vPositionLocation); glVertexAttribPointer(s_vUvLocation, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(verticesCube))); glEnableVertexAttribArray(s_vUvLocation); } void Viewer::visit(Cube &s) { QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform); int faces = floor(numVerticesCube/6); for(int i = 0; i < faces; i++){ // 6 vertexes par face glBindVertexArray(m_VAOs[VAO_Cube]); m_program->setUniformValue(m_mvMatrixLocation, modelViewMatrix); m_program->setUniformValue(m_colorLocation, s.getColor()); glDrawArrays(GL_TRIANGLES, i*6, 6); } } 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::changeColor(QColor c){ if(activeCell->getChildren()->size()){ Shape* shape = dynamic_cast (activeCell->childAt(0)); shape->setColor(c); } activeColor = new QColor(c); this->update(); } Shape* Viewer::pickGeom(int x, int y){ QMap mapColorToShape; QColor c; QRgb startColor = 0xFF0001; // alpha must be 100%, glReadPixels doesn't resturn alpha unsigned char pixelData[3]; // Traverse tree /* TODO: Make this recurse through SceneGroups, with like "populateMap(map, root, color)" * Right now it's fine because we have simple Minecraft rules * but could be important in the future */ QOpenGLShaderProgram *lastshader = m_program; //colorPickerShaderProgram->bind(); std::cout << "Iterating through " << root.getChildren()->size() << "items"<size(); i(root.childAt(i)); Shape* currentCube; if(current->getChildren()->size()) { currentCube = dynamic_cast(current->childAt(0)); } if(currentCube) { c.setRgb(startColor); mapColorToShape.insert(c.rgb(), currentCube); std::cout << "Setting " << currentCube << " to " << c.red() << " " << c.green() << " " << c.blue() << " " << c.alpha() << endl; currentCube->setColor(c); startColor+=6; } } update(); glPixelStorei(GL_UNPACK_ALIGNMENT, 1); // for debugging purposes /*QImage *im = new QImage(128,128, QImage::Format_RGB32); for(int i = 0; i< 128; i++){ for(int j = 0; j< 128; j++){ glReadPixels(x-64+i, y+64-j, 1, 1, GL_RGBA, GL_UNSIGNED_BYTE, pixelData); QColor* pickedColor = new QColor(pixelData[0], pixelData[1], pixelData[2]); if(i==64&&j==64) pickedColor->setRgba(0xFFFFFFFF); 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]); unsigned int pickedInt = pickedColor->rgb(); Shape* pickedShape = mapColorToShape.value(pickedInt - (pickedInt % 6) + 1); std::cout << "Picked Color: " << pickedColor->red() << " " << pickedColor->green() << " " << pickedColor->blue() << " " << pickedColor->alpha() << endl; std::cout << "Picked Shape: " << pickedShape << endl; //lastshader->bind(); return pickedShape; }