Undefined symbols for architecture x86_64



  • Hi, I'm a newbie of QT and OpenGL, so please bare with me. I'm having an hard time with an example my professor gave in today's lecture.
    I'm using QT Creator 5.5.1 (Clang 6.1) on a OS X, Intel Iris Graphics 6100 1536 MB

    This is the .pro file:

    QT += core gui opengl

    greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

    TARGET = hello_world3D_interaction_todo
    TEMPLATE = app

    SOURCES += main.cpp
    glwidget.cpp
    glew.c
    ppm.cpp

    HEADERS +=
    glwidget.h
    cvec.h
    matrix4.h
    shader.h
    ppm.h

    FORMS += mainwindow.ui

    DISTFILES +=
    shaders/diffuse.fsh
    shaders/solid.fsh
    shaders/basic.vsh

    unix:
    INCLUDEPATH += /usr/local/include
    DEPENDPATH += /usr/local/include

    this is the main.cpp:

    #ifndef GLEW_STATIC
    #define GLEW_STATIC
    #include <GL/glew.h> // the library to load the appropriate OpenGL function
    #endif

    #include <iostream> // C++ I/O library

    #include <QApplication>
    #include <QtOpenGL/QGLFormat>
    #include "glwidget.h"

    int main(int argc, char *argv[])
    {
    // manages the Qt GUI application's control flow and main settings
    QApplication a(argc, argo);

    // specifies the display format of an OpenGL rendering context
    // it will be used to set the widget (window) appropriately
    
    
    QSurfaceFormat glFormat;
    glFormat.setVersion(3, 3);
    glFormat.setProfile(QSurfaceFormat::CoreProfile);
    QSurfaceFormat::setDefaultFormat(glFormat);
    glFormat.setSamples(4);
    // print the OpenGL version and subversion used
    std::cerr << "GL version: " << glFormat.majorVersion() << "." << glFormat.minorVersion() << " ";
    
    // create a GLWidget requesting our format
    // (inherits from QOpenGLWidget, a widget for rendering OpenGL graphics)
    GLWidget widget;
    widget.setFormat(glFormat);
    // show the widget - inside it calls initializeGL, then resizeGL and paintGL
    widget.show();
    
    // enters the main event loop
    return a.exec();
    

    }

    this is the glwidget.cpp

    #ifndef GLEW_STATIC
    #define GLEW_STATIC
    #include <GL/glew.h>
    #endif
    #ifndef SHADER_H
    #include <shader.h>
    #endif

    #include "glwidget.h"
    #include <QCoreApplication>
    #include <QkeyEvent>
    #include <QtGlobal> // if we want to use qwarning

    #include <iostream>
    #include <vector>
    #include <string>
    #include <stdexcept>

    #include "cvec.h"
    #include "matrix4.h"
    #include "ppm.h"

    // for string, vector, iostream, and other standard C++ stuff
    using namespace std;

    // G L O B A L S ///////////////////////////////////////////////////
    static const float g_frustMinFov = 60.0; // A minimal of 60 degree field of view
    static float g_frustFovY = g_frustMinFov; // FOV in y direction (updated by updateFrustFovY)
    static const float g_frustNear = -0.1; // near plane
    static const float g_frustFar = -50.0; // far plane

    //static int g_windowWidth = 512;
    //static int g_windowHeight = 512;
    static int g_windowWidth = 640;
    static int g_windowHeight = 480;

    // --------- Scene
    // define two lights positions in world space
    static const Cvec3 g_light1(2.0, 3.0, 14.0), g_light2(-2, -3.0, -5.0);
    static Matrix4 skyRbt = Matrix4::makeTranslation(Cvec3(0.0, 0.5, 5.0));
    static Matrix4 objRbt[2] = {Matrix4::makeTranslation(Cvec3(-1,0,0)), Matrix4::makeTranslation(Cvec3(1,0,0))};
    static Matrix4 eyeRbt;

    // update g_frustFovY from g_frustMinFov, g_windowWidth, and g_windowHeight
    static void updateFrustFovY() {
    if (g_windowWidth >= g_windowHeight)
    g_frustFovY = g_frustMinFov;
    else {
    const double RAD_PER_DEG = 0.5 * CS175_PI/180;
    g_frustFovY = atan2(sin(g_frustMinFov * RAD_PER_DEG) * g_windowHeight / g_windowWidth, cos(g_frustMinFov * RAD_PER_DEG)) / RAD_PER_DEG;
    }
    }

    // creates the projection matrix of the camera
    static Matrix4 makeProjectionMatrix() {
    return Matrix4::makeProjection(
    g_frustFovY, g_windowWidth / static_cast <double> (g_windowHeight),
    g_frustNear, g_frustFar);
    }

    ///////////////////////////////////////////////////////////////
    // GLWidget constructor
    GLWidget::GLWidget( QWidget* parent ) : QOpenGLWidget( parent )
    {
    // set the window title
    this->setWindowTitle("Hello world 3D (with interaction)");

    // the default polygon visualization is FILL
    polyMode = GL_FILL;
    
    // the default shader is solid
    activeShader = 0;
    
    // the default view is sky camera
    viewMode = 0;
    
    // the default object is sky camera
    objMode = 0;
    
    // the default mode for the auxiliary frame when the sky
    // camera is selected is the sky-sky frame
    mMode = 0;
    
    //qWarning("GLWidget constructor: exited");
    std::cout << "GLWidget constructor: exited" << endl;
    

    }

    // OpenGL initialization - called once at the beginning of the program
    // initialize shapes and specify OpenGL setting
    void GLWidget::initializeGL()
    {
    // Set this to true so GLEW knows to use a modern approach to retrieving
    // function pointers and extensions
    glewExperimental = true;
    // GLEW ininitialization - load the correct OpenGL functions
    GLenum err = glewInit(); // load the OpenGL extensions
    if ( err != GLEW_OK ) {
    // check for error
    std::cerr << "GLEW ERROR: " << glewGetErrorString(err);
    exit(1);
    }
    std::cout << "initializeGL: GLEW correctly initialized" << endl;

    // check if we can use sample buffers
    QSurfaceFormat format = QOpenGLWidget::format();
    if ( !format.samples() )
        std::cerr << "initializeGL: Could not enable sample buffers";
    
    // OpenGL state initialization
    glClearColor(128./255., 200./255., 255./255., 0.);
    glClearDepth(0.);
    glCullFace(GL_BACK);
    glEnable(GL_CULL_FACE);
    glEnable(GL_DEPTH_TEST);
    glDepthFunc(GL_GREATER);
    glReadBuffer(GL_BACK);
    //    glEnable(GL_FRAMEBUFFER_SRGB);
    // set the wireframe or fill polygon mode
    glPolygonMode(GL_FRONT_AND_BACK, polyMode);
    
    // debug
    std::cout << "initializeGL: GL initialized" << endl;
    
    // relative path to the vertex shader
    const GLchar * vShaderPath = "/Users/alessandromusi/Documents/workspace QT/hello_world3D_interaction_todo/shaders/basic.vsh";
    const GLchar * fShaderPath[2];
    // path to the (diffuse) fragment shader
    fShaderPath[0] = "/Users/alessandromusi/Documents/workspace QT/hello_world3D_interaction_todo/shaders/diffuse.fsh";
    // path to the (solid, no lights effects) fragment shader
    fShaderPath[1] = "/Users/alessandromusi/Documents/workspace QT/hello_world3D_interaction_todo/shaders/solid.fsh";
    // the program shader 0 uses the diffuse fragment shader
    ourShader[0] = new Shader( vShaderPath, fShaderPath[0] );
    // the program shader 1 uses the solid fragment shader
    ourShader[1] = new Shader( vShaderPath, fShaderPath[1] );
    
    // retrieve handles to uniform variables for the Shader program 0
    // (that using diffuse fragment shader)
    // vertex shader
    h_uProjMatrix[0] = glGetUniformLocation(ourShader[0]->programID, "uProjMatrix");
    h_uModelViewMatrix[0] = glGetUniformLocation(ourShader[0]->programID, "uModelViewMatrix");
    h_uNormalMatrix[0] = glGetUniformLocation(ourShader[0]->programID, "uNormalMatrix");
    // fragment shader
    h_uColor[0] = glGetUniformLocation(ourShader[0]->programID, "uColor");
    h_uLight1[0] = glGetUniformLocation(ourShader[0]->programID, "uLight");
    h_uLight2[0] = glGetUniformLocation(ourShader[0]->programID, "uLight2");
    
    // retrieve handles to uniform variables for the Shader program 1
    // (that using solid fragment shader)
    // vertex shader
    h_uProjMatrix[1] = glGetUniformLocation(ourShader[1]->programID, "uProjMatrix");
    h_uModelViewMatrix[1] = glGetUniformLocation(ourShader[1]->programID, "uModelViewMatrix");
    h_uNormalMatrix[1] = glGetUniformLocation(ourShader[1]->programID, "uNormalMatrix");
    // fragment shader
    h_uColor[1] = glGetUniformLocation(ourShader[1]->programID, "uColor");
    
    //    glBindFragDataLocation(h_fragColor, 0, "fragColor");
    
    // error checking
    const GLenum errCode = glGetError();
    if (errCode != GL_NO_ERROR) {
        cerr << "GL Error: " << errCode << endl;
    }
    
    // initialize the shape data
    initializeShape();
    

    }

    // drawing - called every time the screen should be updated
    void GLWidget::paintGL()
    {
    // clear color background color (light blue for the sky)
    // it is transparent
    glClearColor(128./255., 200./255., 255./255., 0.);
    // clear the buffer with the current clearing color
    glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );

    // set the wireframe or fill polygon mode
    glPolygonMode(GL_FRONT_AND_BACK, polyMode);
    
    // use program shader
    if ( !activeShader )
        // set the shader 0 as the active one
        ourShader[0]->Use();
    else
        // set the shader 1 as the active one
        ourShader[1]->Use();
    
    // build & send projection matrix to vertex shader
    const Matrix4 projMatrix = makeProjectionMatrix();
    GLfloat glmatrix[16];
    projMatrix.writeToColumnMajorMatrix(glmatrix);
    // send projection matrix
    glUniformMatrix4fv(h_uProjMatrix[activeShader], 1, false, glmatrix);
    
    // change teh view point according to the user selection
    //Matrix4 eyeRbt;
    if ( viewMode == 0 )
        // use the skyRbt as the eyeRbt
        eyeRbt = skyRbt;
    else if ( viewMode == 1 )
        // use the frame of cube 1 (red cube)
        eyeRbt = objRbt[0];
    //eyeRbt = objRbt[0]*Matrix4::makeYRotation(-90);
    else if ( viewMode == 2 )
        // use the frame of cube 2 (blue cube)
        eyeRbt = objRbt[1];
    //eyeRbt = objRbt[1]*Matrix4::makeYRotation(90);
    
    // invert the eye frame matrix E-1
    const Matrix4 invEyeRbt = inv(eyeRbt);
    
    if ( !activeShader ) {
        // g_light1 position in eye coordinates
        const Cvec3 eyeLight1 = Cvec3(invEyeRbt * Cvec4(g_light1, 1));
        // g_light2 position in eye coordinates
        const Cvec3 eyeLight2 = Cvec3(invEyeRbt * Cvec4(g_light2, 1));
        // assign the uniform for the light
        glUniform3f(h_uLight1[activeShader], eyeLight1[0], eyeLight1[1], eyeLight1[2]);
        glUniform3f(h_uLight2[activeShader], eyeLight2[0], eyeLight2[1], eyeLight2[2]);
    }
    
    //////// draw FLOOR /////////////
    // set the floor Rbt matrix to the identity
    const Matrix4 groundRbt = Matrix4();
    Matrix4 MVM = invEyeRbt * groundRbt;
    Matrix4 NMVM = normalMatrix(MVM);
    GLfloat glmatrix1[16];
    // send MVM
    MVM.writeToColumnMajorMatrix(glmatrix1);
    glUniformMatrix4fv(h_uModelViewMatrix[activeShader], 1, false, glmatrix1);
    // send NMVM
    NMVM.writeToColumnMajorMatrix(glmatrix1);
    glUniformMatrix4fv(h_uNormalMatrix[activeShader], 1, false, glmatrix1);
    // set the floor color to green
    glUniform3f(h_uColor[activeShader], 0.1f, 0.95f, 0.1f);
    
    // draw floor
    glBindVertexArray(floorVAOID);
    glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
    glBindVertexArray(0);
    /////////////////////////////////
    
    //////// draw a red CUBE ////////
    // set the Rbt matrix of the cube to the identity
    //    Matrix4 objRbt = Matrix4::makeTranslation(Cvec3(0,0,0));
    MVM = invEyeRbt * objRbt[0];   // model view matrix E-1*O
    NMVM = normalMatrix(MVM);
    // linearize to a vector and send MVM
    MVM.writeToColumnMajorMatrix(glmatrix);
    glUniformMatrix4fv(h_uModelViewMatrix[activeShader], 1, false, glmatrix);
    // linearize to a vector and send NMVM
    NMVM.writeToColumnMajorMatrix(glmatrix);
    glUniformMatrix4fv(h_uNormalMatrix[activeShader], 1, false, glmatrix);
    // set the color of the cube object to red
    Cvec3f objColor = Cvec3f(1, 0, 0);
    glUniform3f(h_uColor[activeShader], objColor[0], objColor[1], objColor[2]);
    // draw cube
    glBindVertexArray(cubeVAOID);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    
    /////////////////////////////////
    
    //////// draw a blue CUBE ///////
    // set the Rbt matrix of the cube with a translation on the positive x
    //    objRbt = Matrix4::makeTranslation(Cvec3(2,0,0));
    // prima ruota e poi trasla
    //objRbt = Matrix4::makeTranslation(Cvec3(2,0,-1)) * Matrix4::makeYRotation(22.0);
    // prima trasla e po ruota
    //objRbt =  Matrix4::makeYRotation(22.0) * Matrix4::makeTranslation(Cvec3(2,0,-1));
    // prima scala e poi trasla
    //objRbt = Matrix4::makeTranslation(Cvec3(2,0,-1)) * Matrix4::makeScale(Cvec3(2,0.5,0.5));
    // prima trasla e poi scala
    //objRbt = Matrix4::makeScale(Cvec3(2,0.5,0.5)) * Matrix4::makeTranslation(Cvec3(2,0,-1));
    MVM = invEyeRbt * objRbt[1];   // E-1*O
    NMVM = normalMatrix(MVM);
    // linearize to a vector and send MVM
    MVM.writeToColumnMajorMatrix(glmatrix);
    glUniformMatrix4fv(h_uModelViewMatrix[activeShader], 1, false, glmatrix);
    // linearize to a vector and send NMVM
    NMVM.writeToColumnMajorMatrix(glmatrix);
    glUniformMatrix4fv(h_uNormalMatrix[activeShader], 1, false, glmatrix);
    // set the color of the cube object to blue
    objColor = Cvec3f(0, 0, 1);
    glUniform3f(h_uColor[activeShader], objColor[0], objColor[1], objColor[2]);
    // draw cube
    glBindVertexArray(cubeVAOID);
    glDrawArrays(GL_TRIANGLES, 0, 36);
    glBindVertexArray(0);
    
    /////////////////////////////////
    
    // debug
    std::cout << "paintGL: painted" << endl;
    

    }

    // resizing - called every time the widget is resized
    // The new size is passed in width and height
    void GLWidget::resizeGL( int w, int h )
    {
    // set the viewport to window dimensions
    // specifies the affine transformation of x and y from
    // normalized device coordinates to window coordinates
    glViewport( 0, 0, w, qMax( h, 1 ) );

    updateFrustFovY();
    // debug
    std::cout << "resizeGL: window resized w = " << w << " h = " << h << endl;
    

    }

    // initialize the shape (triangle data)
    void GLWidget::initializeShape()
    {
    GLfloat floor_size = 10.0f;
    GLfloat floor_y = -0.5f;
    // Set up vertex data (and buffer(s)) and attribute pointers
    GLfloat floor[] = {
    floor_size, floor_y, -floor_size, 0.0f, 1.0f, 0.0f, // Top Right
    floor_size, floor_y, floor_size, 0.0f, 1.0f, 0.0f, // Bottom Right
    -floor_size, floor_y, floor_size, 0.0f, 1.0f, 0.0f, // Bottom Left
    -floor_size, floor_y, -floor_size, 0.0f, 1.0f, 0.0f // Top Left
    };
    GLuint floorIdx[] = { // Note that we start from 0!
    0, 2, 1, // First Triangle
    0, 3, 2 // Second Triangle
    };

    GLfloat cube_size = 0.5f;
    // cube vertices and normal (36 vertices - six faces, each made
    // up of two triangles)
    GLfloat cube[] = {
        // bottom face
        -cube_size, -cube_size, -cube_size, 0.0f, -1.0f,  0.0f,
        cube_size, -cube_size,  cube_size, 0.0f, -1.0f,  0.0f,
        -cube_size, -cube_size,  cube_size, 0.0f, -1.0f,  0.0f,
        -cube_size, -cube_size, -cube_size, 0.0f, -1.0f,  0.0f,
        cube_size, -cube_size, -cube_size, 0.0f, -1.0f,  0.0f,
        cube_size, -cube_size,  cube_size, 0.0f, -1.0f,  0.0f,
        // right face
        cube_size, -cube_size,  cube_size, 1.0f,  0.0f,  0.0f,
        cube_size,  cube_size, -cube_size, 1.0f,  0.0f,  0.0f,
        cube_size,  cube_size,  cube_size, 1.0f,  0.0f,  0.0f,
        cube_size, -cube_size,  cube_size, 1.0f,  0.0f,  0.0f,
        cube_size, -cube_size, -cube_size, 1.0f,  0.0f,  0.0f,
        cube_size,  cube_size, -cube_size, 1.0f,  0.0f,  0.0f,
        // back face
        cube_size, -cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        -cube_size, -cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        cube_size,  cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        -cube_size, -cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        -cube_size,  cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        cube_size,  cube_size, -cube_size, 0.0f,  0.0f, -1.0f,
        // left face
        -cube_size, -cube_size, -cube_size, -1.0f,  0.0f,  0.0f,
        -cube_size, -cube_size,  cube_size, -1.0f,  0.0f,  0.0f,
        -cube_size,  cube_size, -cube_size, -1.0f,  0.0f,  0.0f,
        -cube_size, -cube_size,  cube_size, -1.0f,  0.0f,  0.0f,
        -cube_size,  cube_size,  cube_size, -1.0f,  0.0f,  0.0f,
        -cube_size,  cube_size, -cube_size, -1.0f,  0.0f,  0.0f,
        // front face
        -cube_size, -cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        cube_size, -cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        cube_size,  cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        -cube_size, -cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        cube_size,  cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        -cube_size,  cube_size,  cube_size, 0.0f,  0.0f,  1.0f,
        // top face
        -cube_size,  cube_size,  cube_size, 0.0f, 1.0f,  0.0f,
        cube_size,  cube_size,  cube_size, 0.0f, 1.0f,  0.0f,
        cube_size,  cube_size, -cube_size, 0.0f, 1.0f,  0.0f,
        -cube_size,  cube_size,  cube_size, 0.0f, 1.0f,  0.0f,
        cube_size,  cube_size, -cube_size, 0.0f, 1.0f,  0.0f,
        -cube_size,  cube_size, -cube_size, 0.0f, 1.0f,  0.0f
    };
    
    /////////// FLOOR //////////
    // create the VAO
    glGenVertexArrays(1, &floorVAOID);
    // create the VBO and eBO
    glGenBuffers(1, &floorVBOID);
    glGenBuffers(1, &floorEBOID);
    // Bind the VAO first, then bind and set vertex
    // buffer(s) and attribute pointer(s)
    glBindVertexArray(floorVAOID);
    // bind and pass data to the VBO
    glBindBuffer(GL_ARRAY_BUFFER, floorVBOID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(floor), floor, GL_STATIC_DRAW);
    // bind and pass data to the EBO
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, floorEBOID);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(floorIdx), floorIdx, GL_STATIC_DRAW);
    // set the position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // set the normal attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    // Unbind VAO (it's always a good thing to unbind any buffer/array
    // to prevent strange bugs)
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    
    /////////// CUBE //////////
    // cube vertices
    glGenVertexArrays(1, &cubeVAOID);
    glGenBuffers(1, &cubeVBOID);
    glBindVertexArray(cubeVAOID);
    glBindBuffer(GL_ARRAY_BUFFER, cubeVBOID);
    glBufferData(GL_ARRAY_BUFFER, sizeof(cube), cube, GL_STATIC_DRAW);
    // set the position attribute
    glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (GLvoid*)0);
    glEnableVertexAttribArray(0);
    // set the normal attribute
    glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 6*sizeof(GLfloat), (GLvoid*)(3*sizeof(GLfloat)));
    glEnableVertexAttribArray(1);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    glBindVertexArray(0);
    

    }

    // initialize the shape (triangle data)
    void GLWidget::setRbtMatrix(Matrix4& m)
    {
    // set the object matrix (i.e., the matrix which express the
    // transformation to transfom the world frame into the object frame)
    if ( objMode == 0 )
    // apply the transformation to eye (camera) object
    //eyeRbt = m;
    skyRbt = m;
    else if ( objMode == 1 )
    // apply the transformation to cube 0
    objRbt[0] = m;
    else if ( objMode == 2 )
    // apply the transformation to cube 1
    objRbt[1] = m;

    // we always redraw if we changed the scene
    update();
    

    }

    // miscellaneous - overrides the behavior for the keyPressEvent
    // captures keyboard events
    void GLWidget::keyPressEvent( QKeyEvent* e )
    {
    // makes the application quit when the escape key is pressed
    switch ( e->key() ) {
    case Qt::Key_Escape:
    QCoreApplication::instance()->quit();
    std::cout << "ESC key pressed" << endl;
    break;
    case Qt::Key_H:
    cout << "\n ============== H E L P ==============\n\n"
    << "h\thelp menu\n"
    << "f\tToggle flat shading on/off\n"
    << "m\tToggle world-sky frame (sky view)\n"
    << "o\tCycle object to edit\n"
    << "s\tsave screenshot\n"
    << "v\tCycle view\n"
    << "w\tCycle fill/wireframe/point visualization\n"
    << "drag left mouse to rotate\n" << endl;
    break;
    case Qt::Key_F:
    // switch the fragment shader from solid to flat
    std::cout << "F key pressed" << endl;
    activeShader = (activeShader == 0) ? 1 : 0;
    break;
    case Qt::Key_M:
    // if the current object being modified is the sky camera (objMode==0),
    // and the eye is the sky camera (v), pressing ‘m’ should
    // switch between two frames for the auxiliary frame a
    // - World-sky frame: center at world’s origin and
    // axes aligned with sky camera
    // - Sky-sky frame: the sky camera’s frame
    mMode = (mMode == 0) ? 1 : 0;
    if (mMode == 0 )
    std::cout << "sky camera-sky camera mode" << endl;
    else
    std::cout << "world-sky camera mode" << endl;
    break;
    case Qt::Key_O:
    // cycles object to edit
    //std::cout << "O key pressed" << endl;
    objMode = (objMode+1)%3;
    if ( objMode == 0 )
    std::cout << "sky camera object selected" << endl;
    else if ( objMode == 1 )
    std::cout << "cube 1 object selected" << endl;
    else if ( objMode == 2 )
    std::cout << "cube 2 object selected" << endl;
    break;
    case Qt::Key_S:
    std::cout << "saving a screenshot of the scene";
    // force execution of GL commands in finite time
    glFlush();
    writePpmScreenshot(g_windowWidth, g_windowHeight, "out.ppm");
    break;
    case Qt::Key_V:
    //std::cout << "V key pressed (change the view)" << endl;
    viewMode = (viewMode+1)%3;
    if ( viewMode == 0 )
    std::cout << "view from the sky camera (default)" << endl;
    else if ( viewMode == 1 )
    std::cout << "view from cube 1 (red cube)" << endl;
    else if ( viewMode == 2 )
    std::cout << "view from cube 2 (blue cube)" << endl;
    break;
    case Qt::Key_W:
    // set a state variable and use it in paint
    //std::cerr << "W (wireframe) key pressed";
    if ( polyMode == GL_FILL ) {
    polyMode = GL_LINE;
    std::cout << "solid lines (wireframe)" << endl;
    }
    else if ( polyMode == GL_LINE ) {
    polyMode = GL_POINT;
    std::cout << "points" << endl;
    }
    else if ( polyMode == GL_POINT ) {
    polyMode = GL_FILL;
    std::cout << "fill (default)" << endl;
    }
    default:
    QOpenGLWidget::keyPressEvent( e );
    }
    update(); // see also repaint()
    }

    // simply records the position of the mouse when a button is initially pressed
    void GLWidget::mouseMoveEvent(QMouseEvent * event)
    {
    int dx = event->x() - lastPos.x();
    int dy = (g_windowHeight -1) - event->y() - lastPos.y(); // in Qt y=0 is at the top of the image
    //
    std::cout << "dx -> " << dx << " dy -> " << dy << endl;
    Matrix4 rbt;
    Matrix4 m;
    if ( objMode == 0 )
    rbt=skyRbt;
    else if ( objMode == 1 )
    rbt=objRbt[0];
    else if ( objMode == 2 )
    rbt=objRbt[1];
    if ( event->buttons() & Qt::LeftButton ) {
    // mouse left button down
    // rotate the object around x and y axis
    //da qui abbiamo usato la slide 25 moving with matrices
    Matrix4 Q= Matrix4::makeXRotation(-dy)*Matrix4::makeYRotation(dx);
    Matrix4 A=makeMixedFrame(rbt,eyeRbt);
    if(objMode==0){
    if(mMode==0)
    m=doQtoOwrtA(inv(Q),rbt,rbt);
    else{
    A=makeMixedFrame(Matrix4(),eyeRbt);//todo
    m=doQtoOwrtA(inv(Q),rbt,A);
    }
    }
    else
    m=doQtoOwrtA(Q,rbt,A);
    //Frame(rbt,eyeRbt);
    setRbtMatrix(m);
    std::cout << "left mouse button down" << endl;
    }
    else if ( event->buttons() & Qt::RightButton ) {
    // mouse right button down
    // translate the object left/right and up/down
    // TODO m matrix
    Matrix4 Q=Matrix4::makeTranslation(Cvec3(dx,dy,0)*0.01);
    Matrix4 A=makeMixedFrame(rbt,eyeRbt);
    if(objMode==0)
    if(mMode==0)
    m=doQtoOwrtA(inv(Q),rbt,rbt);
    else{
    A=makeMixedFrame(Matrix4(),eyeRbt);//todo
    m=doQtoOwrtA(inv(Q),rbt,A);
    }
    else
    m=doQtoOwrtA(Q,rbt,A);
    setRbtMatrix(m);
    std::cout << "right mouse button down" << endl;
    }
    else if ( event->buttons() & Qt::MidButton ) {
    // mouse middle button down or left and right button down
    // zoom in/out of the selected object
    Matrix4 Q=Matrix4::makeTranslation(Cvec3(0,0,-dy)*0.01);
    Matrix4 A=makeMixedFrame(rbt,eyeRbt);
    if(objMode==0)
    if(mMode==0)
    m=doQtoOwrtA(inv(Q),rbt,rbt);
    else{
    A=makeMixedFrame(Matrix4(),eyeRbt);//todo
    m=doQtoOwrtA(inv(Q),rbt,A);
    }
    else
    m=doQtoOwrtA(Q,rbt,A);
    setRbtMatrix(m);
    std::cout << "mid mouse button down" << endl;
    }
    // update the last position of the mouse
    lastPos = event->pos();
    lastPos.setY(g_windowHeight - lastPos.y() - 1);
    }

    // class destructor
    GLWidget::~GLWidget()
    {
    // Properly de-allocate all resources once they've outlived their purpose
    glDeleteVertexArrays(1, &floorVAOID);
    glDeleteVertexArrays(1, &cubeVAOID);

    glDeleteVertexArrays(1, &floorVBOID);
    glDeleteVertexArrays(1, &floorEBOID);
    glDeleteVertexArrays(1, &cubeVBOID);
    
    std::cout << "VBO and VAO released";
    

    }

    When I try to build i get this error:

    Undefined symbols for architecture x86_64:
    "GLWidget::mousePressEvent(QMouseEvent*)", referenced from:
    vtable for GLWidget in glwidget.o
    ld: symbol(s) not found for architecture x86_64
    clang: error: linker command failed with exit code 1 (use -v to see invocation)
    make: *** [hello_world3D_interaction_todo.app/Contents/MacOS/hello_world3D_interaction_todo] Error 1
    18:12:31: The process "/usr/bin/make" exited with code 2.
    Error while building/deploying project hello_world3D_interaction_todo (kit: Desktop Qt 5.5.1 clang 64bit)
    When executing step "Make"

    this is a screenshot of the compiler's option
    link text

    I have no clue what's the problem.


  • Lifetime Qt Champion

    Hi and welcome to devnet,

    The error is that you don't have any implementation of mousePressEvent. Did you declare that function in GLWidget ?



  • @SGaist
    Hi, thanks for the reply
    here's the declaration in the header link text
    and here's the implementation in the .cpp file link text

    There real problem is that I've seen this very code perfectly working on other Mac, so this shouldn't be a coding problem.



  • @ZakkWylde said:

    and here's the implementation in the .cpp file link text

    That image shows the implementation of mouseMoveEvent - not mousePressEvent.

    Your header is declaring both functions. Is your .cpp file implementing both? (Can't tell from the image)



  • @Paul-Colby Ok, I'm a total dumbass, the implementation of mousePressEvent was missing, I was probably confusing with mouseMoveEvent. I've added the implementation and it works just fine. Sorry for wasting your time.


  • Lifetime Qt Champion

    No worries, things like that can happen ;)

    Since you have it working now, please mark the thread as solved using the "Topic Tool" button so that other forum users may know a solution has been found :)


Log in to reply
 

Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.