mirror of
https://github.com/ConjureETS/LOG750-LAB2.git
synced 2026-03-24 03:21:19 +00:00
954 lines
31 KiB
C++
954 lines
31 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 <math.h>
|
|
|
|
#include <qopengl.h>
|
|
#include <QOpenGLShaderProgram>
|
|
|
|
#include <qopengl.h>
|
|
|
|
#include <iostream>
|
|
#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;
|
|
|
|
int m_lDirectionLocation;
|
|
int m_normalMatrixLoc;
|
|
|
|
QVector3D sun = QVector3D(0,-1,0);
|
|
QMatrix4x4 sunRotate;
|
|
|
|
SceneGroup* selection;
|
|
PickedGeom selectedObj;
|
|
|
|
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 buffers
|
|
glDeleteBuffers(NumBuffers, m_Buffers);
|
|
glDeleteVertexArrays(NumVAOs, m_VAOs);
|
|
|
|
doneCurrent();
|
|
}
|
|
|
|
void Viewer::drawSkybox()
|
|
{
|
|
// Use the Skybox Shaders
|
|
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.scale(100);
|
|
|
|
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::draw()
|
|
{
|
|
// Bind our vertex/fragment shaders
|
|
m_program->bind();
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT);
|
|
|
|
if(!isPickingActivated)
|
|
drawSkybox();
|
|
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 * frame, 360);
|
|
sunRotate.rotate(rotAngle, 0, 0, 1);
|
|
//sunRotate.rotate(15, 1, 0, 0);
|
|
|
|
m_program->setUniformValue(m_lDirLoc, (sunRotate * sun));
|
|
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);
|
|
|
|
drawUi();
|
|
|
|
sunRotate.setToIdentity();
|
|
//float rotAngle = (frame * angle_mult) % 360;
|
|
}
|
|
|
|
void Viewer::drawUi(){
|
|
|
|
glCullFace(GL_FRONT);
|
|
glClear(GL_DEPTH_BUFFER_BIT); // make ui always on top
|
|
|
|
QMatrix4x4 projectionMatrix;
|
|
QMatrix4x4 uiViewMatrix;
|
|
|
|
uiViewMatrix.translate(0, -1.5, -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++)
|
|
{
|
|
TexturePrograms[i]->bind();
|
|
m_program->setUniformValue(m_mvMatrixLocation, uiViewMatrix);
|
|
uiViewMatrix.translate(1.2, 0, 0);
|
|
glDrawArrays(GL_TRIANGLES, 0, 36);
|
|
}
|
|
|
|
}
|
|
|
|
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->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);
|
|
}
|
|
|
|
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);
|
|
}
|
|
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::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(5);
|
|
showEntireScene();
|
|
|
|
// Init OpenGL objects
|
|
connect(context(), &QOpenGLContext::aboutToBeDestroyed, this, &Viewer::cleanup);
|
|
initializeOpenGLFunctions();
|
|
|
|
// Init shaders & geometry
|
|
initShaders();
|
|
initGeometries();
|
|
initBuffers();
|
|
|
|
|
|
{
|
|
// Default non existant cube
|
|
selectedObj.shape = new Cube();
|
|
|
|
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_GRASS);
|
|
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_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);
|
|
|
|
|
|
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);
|
|
}//*/
|
|
}
|
|
|
|
// 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 },
|
|
|
|
};
|
|
|
|
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);
|
|
|
|
/*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(sizeof(offsetNormals)));
|
|
glEnableVertexAttribArray(m_vNormalLocation);
|
|
|
|
glVertexAttribPointer(s_vUvLocation, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(sizeof(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);
|
|
}
|
|
|
|
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)
|
|
{
|
|
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
|
QColor* faceColor = new QColor;
|
|
|
|
glBindVertexArray(m_VAOs[VAO_Cube]);
|
|
TexturePrograms[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;
|
|
//glDrawArrays(GL_TRIANGLES, 0, 36);
|
|
}
|
|
|
|
void Viewer::visit(Sphere &s)
|
|
{
|
|
// std::cout << "Sphere found";
|
|
QMatrix4x4 modelViewMatrix = modelStack.top() * QMatrix4x4(s.transform);
|
|
|
|
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());
|
|
|
|
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);
|
|
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::deleteSelected() {
|
|
// Remove Shape from its parent
|
|
|
|
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()->getChildren()->erase(
|
|
std::remove(selectedObj.shape->getParent()->getChildren()->begin(),
|
|
selectedObj.shape->getParent()->getChildren()->end(),
|
|
selectedObj.shape),
|
|
selectedObj.shape->getParent()->getChildren()->end());
|
|
|
|
selectedObj.shape = new Cube(); // Rebind to "null"
|
|
|
|
cubeSelected(false);
|
|
}
|
|
|
|
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 = time - startTime;
|
|
frame += dt * 0.006 * frame_mult; // 60fps
|
|
startTime = time;
|
|
update();
|
|
}
|
|
|
|
void Viewer::startAniumation(){}
|
|
|
|
void Viewer::stopAnimation(){}
|
|
|
|
|
|
|
|
|
|
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;
|
|
doneCurrent();
|
|
|
|
PickedGeom result = PickedGeom();
|
|
|
|
result.position = pickedPosition;
|
|
result.shape = pickedShape;
|
|
|
|
return result;
|
|
}
|