LOG750-LAB2/src/viewer/simpleViewer.cpp
2016-12-06 01:43:14 -05:00

1346 lines
44 KiB
C++

/****************************************************************************
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 <math.h>
#include <sstream>
#include <qopengl.h>
#include <QOpenGLShaderProgram>
#include <QCoreApplication>
#include <iostream>
#include <ctime>
#include <stack>
#include <QMouseEvent>
#include <typeinfo>
#include <time.h>
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<OBJLoader::Mesh>& meshes = loader.getMeshes();
const std::vector<OBJLoader::Material>& materials = loader.getMaterials();
for (unsigned int i=0; i<meshes.size(); ++i)
{
if (meshes[i].vertices.size()==0)
continue;
MeshGL meshGL;
meshGL.numVertices = meshes[i].vertices.size();
// Set material properties of the mesh
const float *Kd = materials[meshes[i].materialID].Kd;
const float *Ks = materials[meshes[i].materialID].Ks;
meshGL.diffuse = QVector3D(Kd[0], Kd[1], Kd[2]);
meshGL.specular = QVector3D(Ks[0], Ks[1], Ks[2]);
meshGL.specularExponent = materials[meshes[i].materialID].Kn;
meshGL.alpha = materials[meshes[i].materialID].d;
// Create its VAO and VBO object
glGenVertexArrays(1, &meshGL.vao);
glGenBuffers(1, &meshGL.vbo);
// Fill VBO with vertices data
GLsizei dataSize = meshes[i].vertices.size() * sizeof(OBJLoader::Vertex);
GLsizei stride = sizeof(OBJLoader::Vertex);
GLsizeiptr positionOffset = 0;
GLsizeiptr normalOffset = sizeof(OBJLoader::Vertex::position);
//GLsizeiptr uvOffset = normalOffset + sizeof(OBJLoader::Vertex::normal);
glBindBuffer(GL_ARRAY_BUFFER, meshGL.vbo);
glBufferData(GL_ARRAY_BUFFER, dataSize, &meshes[i].vertices[0], GL_STATIC_DRAW);
// Set VAO that binds the shader vertices inputs to the buffer data
glBindVertexArray(meshGL.vao);
glVertexAttribPointer(o_a_vPos, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(positionOffset));
glEnableVertexAttribArray(o_a_vPos);
glVertexAttribPointer(o_a_vNorm, 3, GL_FLOAT, GL_FALSE, stride, BUFFER_OFFSET(normalOffset));
glEnableVertexAttribArray(o_a_vNorm);
// Add it to the list
_meshesGL.push_back(meshGL);
}
}
void Viewer::draw()
{
// Bind our vertex/fragment shaders
m_program->bind();
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; i<TEX_LENGTH; i++)
{
glActiveTexture(GL_TEXTURE0);
TexturePrograms[i]->bind();
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<Shape*>(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; i<TEX_LENGTH; i++){
std::cout << "Binding " << TexturePaths[i].toStdString() << endl;
TexturePrograms[i] = new QOpenGLTexture(QImage(TexturePaths[i]));
TexturePrograms[i]->setMinificationFilter(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<float>(numColSphere);
float phiInc = 3.14159265f / static_cast<float>(numRowSphere+1);
for (int row=0; row<numRowSphere; ++row)
{
float phi = 3.14159265f - (static_cast<float>(row+1) * phiInc);
for (int col=0; col<numColSphere; ++col, ++v)
{
float theta = col*thetaInc;
sphereVertices[v][0] = 0.5*sin(theta)*sin(phi);
sphereVertices[v][1] = 0.5*cos(phi);
sphereVertices[v][2] = 0.5*cos(theta)*sin(phi);
sphereNormals[v][0] = sphereVertices[v][0]*2.0f; // Multiply by 2 because sphere radius is 0.5
sphereNormals[v][1] = sphereVertices[v][1]*2.0f;
sphereNormals[v][2] = sphereVertices[v][2]*2.0f;
}
}
// Generate cap vertices
sphereVertices[numColSphere*numRowSphere+0][0] = 0.0f;
sphereVertices[numColSphere*numRowSphere+0][1] = -0.5f;
sphereVertices[numColSphere*numRowSphere+0][2] = 0.0f;
sphereVertices[numColSphere*numRowSphere+1][0] = 0.0f;
sphereVertices[numColSphere*numRowSphere+1][1] = 0.5f;
sphereVertices[numColSphere*numRowSphere+1][2] = 0.0f;
sphereNormals[numColSphere*numRowSphere+0][0] = 0.0f;
sphereNormals[numColSphere*numRowSphere+0][1] = -1.0f;
sphereNormals[numColSphere*numRowSphere+0][2] = 0.0f;
sphereNormals[numColSphere*numRowSphere+1][0] = 0.0f;
sphereNormals[numColSphere*numRowSphere+1][1] = 1.0f;
sphereNormals[numColSphere*numRowSphere+1][2] = 0.0f;
// Generate surrounding indices (faces)
unsigned int tri = 0;
for (int row=0; row<numRowSphere-1; ++row)
{
unsigned int rowStart = row*numColSphere;
unsigned int topRowStart = rowStart + numColSphere;
for (int col=0; col<numColSphere; ++col, tri += 2)
{
// Compute quad vertices
unsigned int v = rowStart + col;
unsigned int vi = (col<numColSphere-1) ? v+1 : rowStart;
unsigned int vj = topRowStart + col;
unsigned int vji = (col<numColSphere-1) ? vj+1 : topRowStart;
// Add to indices
sphereIndices[tri+0][0] = v;
sphereIndices[tri+0][1] = vi;
sphereIndices[tri+0][2] = vj;
sphereIndices[tri+1][0] = vi;
sphereIndices[tri+1][1] = vji;
sphereIndices[tri+1][2] = vj;
}
}
// Generate cap indices (faces)
for (int col=0; col<numColSphere; ++col, tri += 2)
{
sphereIndices[tri+0][0] = numColSphere*numRowSphere;
sphereIndices[tri+0][1] = (col<numColSphere-1) ? col+1 : 0;
sphereIndices[tri+0][2] = col;
unsigned int rowStart = (numRowSphere-1)*numColSphere;
sphereIndices[tri+1][0] = numColSphere*numRowSphere+1;
sphereIndices[tri+1][1] = rowStart + col;
sphereIndices[tri+1][2] = (col<numColSphere-1) ? (rowStart + col + 1) : rowStart;
}
// Prep buffers
glGenBuffers(NumBuffers, m_Buffers);
// Fill cube vertex VBO
GLsizeiptr offsetVertices = 0;
GLsizeiptr offsetNormals = sizeof(verticesCube);
GLsizeiptr offsetUV = offsetNormals + sizeof(normals);
GLsizeiptr dataSize = offsetUV + sizeof(uvs);
glBindVertexArray(m_VAOs[VAO_Cube]);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Cube]);
glBufferData(GL_ARRAY_BUFFER, dataSize,
NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, offsetVertices, sizeof(verticesCube), verticesCube);
glBufferSubData(GL_ARRAY_BUFFER, offsetNormals, sizeof(normals), normals);
glBufferSubData(GL_ARRAY_BUFFER, offsetUV, sizeof(uvs), uvs);
glVertexAttribPointer(m_vPositionLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vPositionLocation);
glVertexAttribPointer(m_vNormalLocation, 3, GL_FLOAT, GL_TRUE, 0, BUFFER_OFFSET(offsetNormals));
glEnableVertexAttribArray(m_vNormalLocation);
glVertexAttribPointer(s_vUvLocation, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offsetUV));
glEnableVertexAttribArray(s_vUvLocation);
// Fill Sphere VBO
GLsizeiptr offsetSphereV = 0;
GLsizeiptr offsetSphereN = offsetSphereV + sizeof(sphereVertices);
GLsizeiptr sphereDataSize = offsetSphereN + sizeof(sphereNormals);
glBindVertexArray(m_VAOs[VAO_Sphere]);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Sphere]);
glBufferData(GL_ARRAY_BUFFER, sphereDataSize,
NULL, GL_STATIC_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, offsetSphereV, sizeof(sphereVertices), sphereVertices);
glBufferSubData(GL_ARRAY_BUFFER, offsetSphereN, sizeof(sphereNormals), sphereNormals);
glVertexAttribPointer(m_vPositionLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vPositionLocation);
glVertexAttribPointer(m_vNormalLocation, 3, GL_FLOAT, GL_TRUE, 0, BUFFER_OFFSET(offsetNormals));
glEnableVertexAttribArray(m_vNormalLocation);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, m_Buffers[EBO_Sphere]);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(sphereIndices), sphereIndices, GL_STATIC_DRAW);
// Fill Particle VBO
//==============================================================
// CODE RÉFÉRENCÉ
// http://www.opengl-tutorial.org/intermediate-tutorials/billboards-particles/particles-instancing/
//==============================================================
GLfloat verticesParticle[] = {
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f,
-0.5f, 0.5f, 0.0f,
0.5f, 0.5f, 0.0f,
};
GLfloat particlePositions[particleLimit][4] = {}; // x, y, z and time, for shader's lifetime calculation
GLubyte particleColors[particleLimit][4] = {};
srand((unsigned int) time(NULL));
for(int i = 0; i < particleLimit; i++){
double r = rand() / (RAND_MAX);
double g = rand() / (RAND_MAX);
double b = rand() / (RAND_MAX);
particlePositions[i][0] = r*10;
particlePositions[i][1] = g*10;
particlePositions[i][2] = b*10;
particlePositions[i][3] = 0;
particleColors[i][0] = r;
particleColors[i][1] = g;
particleColors[i][2] = b;
particleColors[i][3] = 1;
}
glBindVertexArray(m_VAOs[VAO_Particle]);
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Particle]);
glBufferData(GL_ARRAY_BUFFER, sizeof(verticesParticle), verticesParticle, GL_STATIC_DRAW);
// particle position buffer
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Particle_Positions]);
glBufferData(GL_ARRAY_BUFFER, sizeof(particlePositions), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(particlePositions), particlePositions);
// particle color buffer
glBindBuffer(GL_ARRAY_BUFFER, m_Buffers[VBO_Particle_Colors]);
glBufferData(GL_ARRAY_BUFFER, sizeof(particleColors), NULL, GL_STREAM_DRAW);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(particleColors), particleColors);
glVertexAttribPointer(m_vPositionLocation, 3, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0));
glEnableVertexAttribArray(m_vPositionLocation);
glVertexAttribPointer(m_vNormalLocation, 3, GL_FLOAT, GL_TRUE, 0, BUFFER_OFFSET(offsetNormals));
glEnableVertexAttribArray(m_vNormalLocation);
glVertexAttribPointer(s_vUvLocation, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(offsetUV));
glEnableVertexAttribArray(s_vUvLocation);//*/
glVertexAttribDivisor(0, 0); // particles vertices : always reuse the same 4 vertices -> 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; i<faces; i++)
{
faceColor->setRgb(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<Shape*> (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<QRgb, QMatrix4x4> mapColorToPosition;
QMap<QRgb, Shape*> 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"<<endl;
for(int i = 0; i<root.getChildren()->size(); i++)
{
//std::cout << " iterating... " << i << endl;
SceneGroup* current = dynamic_cast<SceneGroup*>(root.childAt(i));
Shape* currentCube;
if(current->getChildren()->size())
{
currentCube = dynamic_cast<Shape*>(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;
}