Example #1
0
bool yoghurt::Screen::on_draw(const Cairo::RefPtr<Cairo::Context>& cr)
{
    // Just call On draw listener(if it is not NULL, ofcourse).
    return (on_draw_listener == NULL) ? true :
           on_draw_listener(cr, get_allocated_width(), get_allocated_height());
}
Example #2
0
// called when OpenGL context is ready and GTK widget is ready
bool Graph_disp::initiaize(const Cairo::RefPtr<Cairo::Context> & unused)
{
    // clear the screen
    glClearColor(bkg_color.r, bkg_color.g, bkg_color.b, 1.0f);
    glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
    display();

    // init glew
    if(glewInit() != GLEW_OK)
    {
        Gtk::MessageDialog error_dialog("Error loading Glew", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text("Aborting...");
        error_dialog.run();

        std::cerr<<"Error loading glew. Aborting"<<std::endl;
        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    // check for required OpenGL version
    if(!GLEW_VERSION_3_3)
    {
        Gtk::MessageDialog error_dialog("OpenGL version too low", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text("Version 3.3 required\nInstalled version is: " +
            std::string((const char *)glGetString(GL_VERSION)) + "\nAborting...");
        error_dialog.run();

        std::cerr<<"OpenGL version too low. Version 3.3 required"<<std::endl;
        std::cerr<<"Installed version is: "<<glGetString(GL_VERSION)<<std::endl;
        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    std::cerr<<"OpenGL version is: "<<glGetString(GL_VERSION)<<std::endl;

    // init GL state vars
    glEnable(GL_DEPTH_TEST);
    glDepthRangef(0.0f, 1.0f);
    glLineWidth(5.0f);

    glEnable(GL_POLYGON_SMOOTH);
    glHint(GL_POLYGON_SMOOTH_HINT, GL_DONT_CARE);
    glEnable(GL_LINE_SMOOTH);
    glHint(GL_LINE_SMOOTH_HINT, GL_DONT_CARE);
    glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
    glBlendColor(1.0f, 1.0f, 1.0f, 0.1f);
    glEnable(GL_BLEND);

    // build shader programs
    GLuint graph_vert = compile_shader(check_in_pwd("shaders/graph.vert"), GL_VERTEX_SHADER);
    GLuint line_vert = compile_shader(check_in_pwd("shaders/line.vert"), GL_VERTEX_SHADER);
    GLuint common_frag = compile_shader(check_in_pwd("shaders/common.frag"), GL_FRAGMENT_SHADER);
    GLuint tex_frag = compile_shader(check_in_pwd("shaders/tex.frag"), GL_FRAGMENT_SHADER);
    GLuint color_frag = compile_shader(check_in_pwd("shaders/color.frag"), GL_FRAGMENT_SHADER);
    GLuint flat_color_frag = compile_shader(check_in_pwd("shaders/flat_color.frag"), GL_FRAGMENT_SHADER);

    if(graph_vert == 0 || line_vert == 0 || tex_frag == 0 || color_frag == 0 || flat_color_frag == 0)
    {
        // error messages are displayed by the compile_shader function
        Gtk::MessageDialog error_dialog("Error compiling shaders", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text("See console output for details.\nAborting...");
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    // link shaders
    _prog_tex.prog = link_shader_prog(std::vector<GLuint> {graph_vert, tex_frag, common_frag});
    _prog_color.prog = link_shader_prog(std::vector<GLuint> {graph_vert, color_frag, common_frag});
    _prog_line.prog = link_shader_prog(std::vector<GLuint> {line_vert, flat_color_frag});

    if(_prog_tex.prog == 0 || _prog_color.prog == 0 || _prog_line.prog == 0)
    {
        // error messages are displayed by the link_shader_prog function
        Gtk::MessageDialog error_dialog("Error linking shaders", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text("See console output for details.\nAborting...");
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    check_error("build shaders");

    // free shader objects
    glDeleteShader(graph_vert);
    glDeleteShader(line_vert);
    glDeleteShader(common_frag);
    glDeleteShader(tex_frag);
    glDeleteShader(color_frag);
    glDeleteShader(flat_color_frag);

    // get uniform locations for each shader
    bool uniform_success = true;
    uniform_success &= _prog_tex.add_uniform("view_model_perspective");
    uniform_success &= _prog_tex.add_uniform("view_model");
    uniform_success &= _prog_tex.add_uniform("normal_transform");
    uniform_success &= _prog_tex.add_uniform("material.shininess");
    uniform_success &= _prog_tex.add_uniform("material.specular");
    uniform_success &= _prog_tex.add_uniform("ambient_color");
    uniform_success &= _prog_tex.add_uniform("cam_light.base.color");
    uniform_success &= _prog_tex.add_uniform("cam_light.base.strength");
    uniform_success &= _prog_tex.add_uniform("cam_light.pos_eye");
    uniform_success &= _prog_tex.add_uniform("cam_light.const_atten");
    uniform_success &= _prog_tex.add_uniform("cam_light.linear_atten");
    uniform_success &= _prog_tex.add_uniform("cam_light.quad_atten");
    uniform_success &= _prog_tex.add_uniform("dir_light.base.color");
    uniform_success &= _prog_tex.add_uniform("dir_light.base.strength");
    uniform_success &= _prog_tex.add_uniform("dir_light.dir");
    uniform_success &= _prog_tex.add_uniform("dir_light.half_vec");
    uniform_success &= _prog_tex.add_uniform("light_forward");
    check_error("_prog_tex GetUniformLocation");

    if(!uniform_success)
    {
        std::string missing_uniforms;

        for(auto const & uniform: _prog_tex.uniforms)
        {
            if(uniform.second == -1)
            {
                missing_uniforms += uniform.first + "\n";
            }
        }

        std::cerr<<"Error finding texture shader uniforms:\n"<<missing_uniforms<<std::endl;

        Gtk::MessageDialog error_dialog("Error finding texture shader uniforms", false,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text(missing_uniforms + "Aborting...");
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    uniform_success = true;
    uniform_success &= _prog_color.add_uniform("view_model_perspective");
    uniform_success &= _prog_color.add_uniform("view_model");
    uniform_success &= _prog_color.add_uniform("normal_transform");
    uniform_success &= _prog_color.add_uniform("material.shininess");
    uniform_success &= _prog_color.add_uniform("material.specular");
    uniform_success &= _prog_color.add_uniform("color");
    uniform_success &= _prog_color.add_uniform("ambient_color");
    uniform_success &= _prog_color.add_uniform("cam_light.base.color");
    uniform_success &= _prog_color.add_uniform("cam_light.base.strength");
    uniform_success &= _prog_color.add_uniform("cam_light.pos_eye");
    uniform_success &= _prog_color.add_uniform("cam_light.const_atten");
    uniform_success &= _prog_color.add_uniform("cam_light.linear_atten");
    uniform_success &= _prog_color.add_uniform("cam_light.quad_atten");
    uniform_success &= _prog_color.add_uniform("dir_light.base.color");
    uniform_success &= _prog_color.add_uniform("dir_light.base.strength");
    uniform_success &= _prog_color.add_uniform("dir_light.dir");
    uniform_success &= _prog_color.add_uniform("dir_light.half_vec");
    uniform_success &= _prog_color.add_uniform("light_forward");
    check_error("_prog_color GetUniformLocation");

    if(!uniform_success)
    {
        std::string missing_uniforms;

        for(auto const & uniform: _prog_color.uniforms)
        {
            if(uniform.second == -1)
            {
                missing_uniforms += uniform.first + "\n";
            }
        }

        std::cerr<<"Error finding color shader uniforms:\n"<<missing_uniforms<<std::endl;

        Gtk::MessageDialog error_dialog("Error finding color shader uniforms", false,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text(missing_uniforms + "Aborting...");
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    uniform_success = true;
    uniform_success &= _prog_line.add_uniform("perspective");
    uniform_success &= _prog_line.add_uniform("view_model");
    uniform_success &= _prog_line.add_uniform("color");
    check_error("_prog_line GetUniformLocation");

    if(!uniform_success)
    {
        std::string missing_uniforms;

        for(auto const & uniform: _prog_line.uniforms)
        {
            if(uniform.second == -1)
            {
                missing_uniforms += uniform.first + "\n";
            }
        }

        std::cerr<<"Error finding line shader uniforms:\n"<<missing_uniforms<<std::endl;

        Gtk::MessageDialog error_dialog("Error finding line shader uniforms", false,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text(missing_uniforms + "Aborting...");
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    // set up un-changing lighting values (in eye space)
    glm::vec3 cam_light_pos_eye(0.0f);
    glm::vec3 light_forward(0.0f, 0.0f, 1.0f);

    glUseProgram(_prog_tex.prog);
    glUniform3fv(_prog_tex.uniforms["cam_light.pos_eye"], 1, &cam_light_pos_eye[0]);
    glUniform3fv(_prog_tex.uniforms["light_forward"], 1, &light_forward[0]);
    check_error("_prog_tex uniforms static");

    glUseProgram(_prog_color.prog);
    glUniform3fv(_prog_color.uniforms["cam_light.pos_eye"], 1, &cam_light_pos_eye[0]);
    glUniform3fv(_prog_color.uniforms["light_forward"], 1, &light_forward[0]);
    check_error("_prog_color uniforms static");

    // create static geometry objects - cursor, axes
    try
    {
        _cursor.build(check_in_pwd("img/cursor.png"));
    }
    catch(Glib::Exception &e)
    {
        std::cerr<<"Error reading cursor image file:"<<std::endl<<e.what()<<std::endl;

        Gtk::MessageDialog error_dialog("Error reading cursor image_file", false,
            Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
        error_dialog.set_transient_for(*dynamic_cast<Gtk::Window *>(get_toplevel()));
        error_dialog.set_title("Fatal Error");
        error_dialog.set_secondary_text(e.what() + std::string("\nAborting..."));
        error_dialog.run();

        dynamic_cast<Gtk::Window *>(get_toplevel())->hide();
        return_code = EXIT_FAILURE;
        return true;
    }

    _axes.build();

    _draw_connection.disconnect();
    _draw_connection = signal_draw().connect(sigc::mem_fun(*this, &Graph_disp::draw));

    // explicitly setup the window size (since resize is automatically called before initialization
    Gtk::Allocation allocation(0, 0, get_allocated_width(), get_allocated_height());
    resize(allocation);

    _signal_initialized.emit();
    return draw(unused);
}
// main input processing
bool Graph_disp::input()
{
    // state vars
    static std::unordered_map<sf::Keyboard::Key, bool, std::hash<int>> key_lock;
    static sf::Vector2i old_mouse_pos = sf::Mouse::getPosition(glWindow);
    static sf::Clock cursor_delay;
    static sf::Clock zoom_delay;

    // the neat thing about having this in a timeout func is that we
    // don't need to calculate dt for movement controls.
    // it is always (almost) exactly 10ms

    // only process when the window is active and display is focused
    if(dynamic_cast<Gtk::Window *>(get_toplevel())->is_active())
    {
        sf::Vector2i new_mouse_pos = sf::Mouse::getPosition(glWindow);

        if(!has_focus() && new_mouse_pos.x >= 0 && new_mouse_pos.y >= 0 &&
            new_mouse_pos.x < get_allocated_width() && new_mouse_pos.y < get_allocated_height())
        {
            grab_focus();
        }

        if(has_focus())
        {
            // Camera controls

            float mov_scale = 0.1f;

            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LShift))
            {
                mov_scale *= 2.0f;
            }

            if(sf::Keyboard::isKeyPressed(sf::Keyboard::LAlt))
            {
                mov_scale *= 0.1f;
            }

            // orbiting rotational cam
            if(use_orbit_cam)
            {
                // reset
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::R) && !key_lock[sf::Keyboard::R])
                {
                    key_lock[sf::Keyboard::R] = true;
                    reset_cam();
                }
                else if(!sf::Keyboard::isKeyPressed(sf::Keyboard::R))
                    key_lock[sf::Keyboard::R] = false;

                // tilt up
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                    _orbit_cam.phi += (float)M_PI / 90.0f * mov_scale;
                    invalidate();
                }

                // tilt down
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                    _orbit_cam.phi -= (float)M_PI / 90.0f * mov_scale;
                    invalidate();
                }

                // rotate clockwise
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                    _orbit_cam.theta += (float)M_PI / 90.0f * mov_scale;
                    invalidate();
                }

                // rotate counter-clockwise
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                    _orbit_cam.theta -= (float)M_PI / 90.0f * mov_scale;
                    invalidate();
                }

                // move camera in
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
                {
                    _orbit_cam.r -= mov_scale;
                    invalidate();
                }

                // move camera out
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::E))
                {
                    _orbit_cam.r += mov_scale;
                    invalidate();
                }

                // rotate w/ mouse click & drag
                if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
                {
                    int d_x = new_mouse_pos.x - old_mouse_pos.x;
                    int d_y = new_mouse_pos.y - old_mouse_pos.y;

                    _orbit_cam.theta -= 0.005f * d_x;
                    _orbit_cam.phi -= 0.005f * d_y;

                    invalidate();
                }

                // wrap theta
                if(_orbit_cam.theta > (float)M_PI * 2.0f)
                    _orbit_cam.theta -= (float)M_PI * 2.0f;
                if(_orbit_cam.theta < 0.0f)
                    _orbit_cam.theta += (float)M_PI * 2.0f;

                // clamp phi
                if(_orbit_cam.phi > (float)M_PI)
                    _orbit_cam.phi = (float)M_PI;
                if(_orbit_cam.phi < 0.0f)
                    _orbit_cam.phi = 0.0f;
            }
            else // free camera
            {
                // reset
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::R) && !key_lock[sf::Keyboard::R])
                {
                    key_lock[sf::Keyboard::R] = true;
                    reset_cam();
                }
                else if(!sf::Keyboard::isKeyPressed(sf::Keyboard::R))
                    key_lock[sf::Keyboard::R] = false;

                // move forward
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::W))
                {
                    _cam.translate(mov_scale * _cam.forward());
                    invalidate();
                }

                // move backwards
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::S))
                {
                    _cam.translate(-mov_scale * _cam.forward());
                    invalidate();
                }

                // move left
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::A))
                {
                    _cam.translate(-mov_scale * _cam.right());
                    invalidate();
                }

                // move right
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::D))
                {
                    _cam.translate(mov_scale * _cam.right());
                    invalidate();
                }

                // move up
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Q))
                {
                    _cam.translate(mov_scale * glm::vec3(0.0f, 0.0f, 1.0f));
                    invalidate();
                }

                // move down
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::E))
                {
                    _cam.translate(-mov_scale * glm::vec3(0.0f, 0.0f, 1.0f));
                    invalidate();
                }

                // rotate view with mouse click & drag
                if(sf::Mouse::isButtonPressed(sf::Mouse::Left))
                {
                    int d_x = new_mouse_pos.x - old_mouse_pos.x;
                    int d_y = new_mouse_pos.y - old_mouse_pos.y;

                    _cam.rotate(0.001f * d_y, _cam.right());
                    _cam.rotate(0.001f * d_x, glm::vec3(0.0f, 0.0f, 1.0f));

                    invalidate();
                }
            }

            const int zoom_timeout = 200;

            // zoom in
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::Z) && zoom_delay.getElapsedTime().asMilliseconds() >= zoom_timeout)
            {
                _scale *= 2.0f;
                zoom_delay.restart();
                invalidate();
            }

            // zoom out
            if(sf::Keyboard::isKeyPressed(sf::Keyboard::X) && zoom_delay.getElapsedTime().asMilliseconds() >= zoom_timeout)
            {
                _scale *= 0.5f;
                zoom_delay.restart();
                invalidate();
            }

            // move cursor with arrow keys
            if(draw_cursor_flag && _active_graph)
            {
                const int cursor_timeout = 200;
                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Up) && cursor_delay.getElapsedTime().asMilliseconds() >= cursor_timeout)
                {
                    _active_graph->move_cursor(Graph::UP);
                    cursor_delay.restart();
                    invalidate();
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Down) && cursor_delay.getElapsedTime().asMilliseconds() >= cursor_timeout)
                {
                    _active_graph->move_cursor(Graph::DOWN);
                    cursor_delay.restart();
                    invalidate();
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Left) && cursor_delay.getElapsedTime().asMilliseconds() >= cursor_timeout)
                {
                    _active_graph->move_cursor(Graph::LEFT);
                    cursor_delay.restart();
                    invalidate();
                }

                if(sf::Keyboard::isKeyPressed(sf::Keyboard::Right) && cursor_delay.getElapsedTime().asMilliseconds() >= cursor_timeout)
                {
                    _active_graph->move_cursor(Graph::RIGHT);
                    cursor_delay.restart();
                    invalidate();
                }
            }
        }
        old_mouse_pos = new_mouse_pos;
    }
    return true;
}