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()); }
// 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; }