#include //#include "gtk_includes.h" #include "gtk_win_main.hpp" //#include "my_gtk_gl_scene_widget.hpp" #include "boring_parts.hpp" #include // X11 specific // Macro to make things readable in main() function #define EXIT_IF_FAIL(val, expr) do { \ if ( ! (expr) ) { \ std::cerr << "Init error " << val << std::endl; \ exit(val); \ } \ } while(0) // For understanding the event sequences #define CALL_TRACE do { \ std::cout << "trace " <<__PRETTY_FUNCTION__ << std::endl; \ } while(0) int main(int argc, char* argv[]) { CALL_TRACE; // Initialize GTK Gtk::Main gtkKit(argc, argv); // gtk itself Gtk::GL::init(argc, argv); // gtkglextmm // Query and print OpenGL version int glVersionMajor, glVersionMinor; EXIT_IF_FAIL(1, Gdk::GL::query_version(glVersionMajor, glVersionMinor) ); std::cout << "OpenGL extension version - " << glVersionMajor << "." << glVersionMinor << std::endl; // Initialize OpenGL Gdk::GL::ConfigMode glMode = Gdk::GL::MODE_RGB | Gdk::GL::MODE_DEPTH | Gdk::GL::MODE_DOUBLE; Glib::RefPtr glconfig; EXIT_IF_FAIL(2, glconfig=Gdk::GL::Config::create(glMode) ); // Initialize the OpenGL scene widget (realization came later) MyGTKGLSceneWidget glScene(glconfig); // Instantiate the GTK app (and realize glScene) // Could exit() the program if problem with OpenGL or OpenCL GTKWinMain gtkwinmain(glScene); // Initialize OpenCL (only after the MyGTKGLSceneWidget realize) //EXIT_IF_FAIL(3, initLibs()==0 ); // See boring_parts.cc gtkKit.run(gtkwinmain); return 0; } /* MyGTKGLSceneWidget implementation I want to keep interesting code part in this file in natural reading order */ MyGTKGLSceneWidget::MyGTKGLSceneWidget(Glib::RefPtr &glconfig) { set_gl_capability(glconfig); Gdk::EventMask mask = Gdk::POINTER_MOTION_MASK | Gdk::BUTTON_MOTION_MASK | Gdk::BUTTON_PRESS_MASK | Gdk::BUTTON_RELEASE_MASK; set_events(mask); // The containing window should have those attributes too this->camera.rx = this->camera.ry = 0.0f; this->camera.tz = -3.0f; } MyGTKGLSceneWidget::~MyGTKGLSceneWidget() { } void MyGTKGLSceneWidget::on_size_request(Gtk::Requisition* requisition) { CALL_TRACE; // Technical stuff : GTK call this to ask the widget minimal size *requisition = Gtk::Requisition(); requisition->width = 320; requisition->height = 240; } void MyGTKGLSceneWidget::on_realize() { CALL_TRACE; // This one runs once at window creation time // It's time to setup GL things that don't change on each frame GLenum gl_res; Gtk::DrawingArea::on_realize(); Glib::RefPtr glwindow = get_gl_window(); // *** OpenGL BEGIN *** if (!glwindow->gl_begin(get_gl_context())) { std::cerr << "Oups : glwindow->gl_begin(get_gl_context())" << std::endl; return; } EXIT_IF_FAIL(3, Gdk::GL::query_gl_extension("GL_ARB_vertex_buffer_object") ); size_t mesh_width=64; size_t mesh_height=64; GLsizeiptr gl_vbo_data_size = mesh_width * mesh_height * sizeof(cl_float4); intptr_t gl_vbo=0; glGenBuffers(1, &gl_vbo); glBindBuffer(GL_ARRAY_BUFFER, gl_vbo); /* STREAM : The data store contents will be modified once and used at most a few times. STATIC : The data store contents will be modified once and used many times. DYNAMIC : The data store contents will be modified repeatedly and used many times. */ glBufferData(GL_ARRAY_BUFFER, gl_vbo_data_size, NULL, GL_DYNAMIC_DRAW); if ( gl_res=glGetError() ) { std::cerr << "glBufferData(). Unable to allocate " << gl_vbo_data_size << "bytes in VRAM"; std::cerr << gluErrorString(gl_res); } #ifdef HAS_OPENCL // static bool isOpenCLInitialized=false; // if (! isOpenCLInitialized) { // #ifdef X11 intptr_t gl_context = (intptr_t)glXGetCurrentContext(); intptr_t gl_display = (intptr_t)glXGetCurrentDisplay(); // std::cerr << "DEBUG : begin initOpenCL()" << std::endl; initOpenCL(gl_display, gl_context, gl_vbo); /* See boring_parts.cc */ // isOpenCLInitialized=true; // #else // #error initOpenCL works only for X11 systems for now // #endif // } #endif // Programmatically create rendering lists : opengl will able to replay that efficiently GLUquadricObj* qobj = gluNewQuadric(); gluQuadricDrawStyle(qobj, GLU_FILL); glNewList(1, GL_COMPILE); //gluSphere(qobj, 1.0, 20, 20); gluSphere(qobj, 1.0, 5, 5); glEndList(); // Setup scene envrionnement static GLfloat light_diffuse[] = {1.0, 0.0, 0.0, 1.0}; static GLfloat light_position[] = {1.0, 1.0, 1.0, 0.0}; glLightfv(GL_LIGHT0, GL_DIFFUSE, light_diffuse); glLightfv(GL_LIGHT0, GL_POSITION, light_position); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glEnable(GL_DEPTH_TEST); glClearColor(1.0, 1.0, 1.0, 1.0); glClearDepth(1.0); // Projection setup is done at on_configure_event // Camera setup (ie initial MODELVIEW matrix) is done at on_expose_event glwindow->gl_end(); // *** OpenGL END *** } bool MyGTKGLSceneWidget::on_configure_event(GdkEventConfigure* event) { CALL_TRACE ; // This one runs mainly when GTK GL Widget is resized // See boring_parts.cc. In short : gluPerspective(60.0, aspect, 0.1, 10.0); return updateGLProjectionMatrix(get_gl_context(), get_gl_window(), get_width(), get_height()); } bool MyGTKGLSceneWidget::on_expose_event(GdkEventExpose* event) { // CALL_TRACE ; // This one runs mainly when GTK GL Widget have to be redrawn Glib::RefPtr glwindow = get_gl_window(); // *** OpenGL BEGIN *** if (!glwindow->gl_begin(get_gl_context())) { std::cerr << "Oups : glwindow->gl_begin(get_gl_context())" << std::endl; return false; } //Camera position update glMatrixMode(GL_MODELVIEW); glLoadIdentity(); glTranslatef(0.0, 0.0, this->camera.tz); glRotatef(this->camera.rx, 1.0, 0.0, 0.0); glRotatef(this->camera.ry, 0.0, 1.0, 0.0); // Drawing all the stuff glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glCallList(1); glwindow->gl_end(); // *** OpenGL END *** glwindow->swap_buffers(); // Display the rendered image return true; } bool MyGTKGLSceneWidget::on_motion_notify_event (GdkEventMotion *event) { return do_mouse_logic(event->type, event->state, event->x, event->y); } bool MyGTKGLSceneWidget::on_button_press_event(GdkEventButton *event) { return do_mouse_logic(event->type, event->state | 1<<(7+event->button) , event->x, event->y); } bool MyGTKGLSceneWidget::on_button_release_event(GdkEventButton *event) { return do_mouse_logic(event->type, event->state, event->x, event->y); } #define ALL_KEYBOARD_MODIFIERS ( GDK_SHIFT_MASK | GDK_CONTROL_MASK \ | GDK_SUPER_MASK | GDK_HYPER_MASK | GDK_META_MASK ) #define MOUSE_CLIC(button, required_modifier_mask, allowed_extra_modifier_mask) if ( \ type == GDK_BUTTON_RELEASE \ && ( state & button ) == button \ && ( state & required_modifier_mask ) == required_modifier_mask \ && ( ( state & ALL_KEYBOARD_MODIFIERS ) & ~( required_modifier_mask | allowed_extra_modifier_mask ) ) == 0 \ ) #define MOUSE_DOUBLECLIC(state_mask) if ( \ type == GDK_BUTTON_RELEASE \ && ( state & state_mask ) == state_mask \ && prev_type == GDK_2BUTTON_PRESS \ ) #define MOUSE_DRAG_START(state_mask) if ( \ type == GDK_BUTTON_PRESS \ && ( state & state_mask ) == state_mask \ ) #define MOUSE_DRAGING(state_mask) if ( \ ( type == GDK_MOTION_NOTIFY ) \ && ( state & state_mask ) == state_mask \ ) #define MOUSE_DRAG_END(state_mask) if ( \ type == GDK_BUTTON_RELEASE \ && ( state & state_mask ) == state_mask \ ) bool MyGTKGLSceneWidget::do_mouse_logic(GdkEventType type, guint state, guint x, guint y) { /* * type : the type of the event. * Simple motion : GDK_MOTION_NOTIFY (3) * Simple clic : GDK_BUTTON_PRESS then GDK_BUTTON_RELEASE (4 then 7) * Double clic : GDK_BUTTON_PRESS, GDK_BUTTON_RELEASE, GDK_BUTTON_PRESS, GDK_2BUTTON_PRESS, GDK_BUTTON_RELEASE (4 7 4 5 7) * * stat : a bit-mask representing the state of the modifier keys and the pointer buttons. * GDK_BUTTON1_MASK, ... , GDK_BUTTON5_MASK (mouse buttons) * GDK_SHIFT_MASK, GDK_LOCK_MASK, GDK_CONTROL_MASK (keyboard standard modifier keys) * GDK_MOD1_MASK, ... (normally MOD1 it is the Alt key) * GDK_SUPER_MASK, GDK_HYPER_MASK, GDK_META_MASK (extra keybord modifier keys) */ // Static variables to hold previous mouse button event static GdkEventType prev_type = GDK_NOTHING; /*static guint prev_state=0; UNUSED FOR NOW */ static guint drag_x=0, drag_y=0; bool redraw=false; // Setting it to true will queue a redraw to the widget (invalidate) // std::cout << "event type " << type << " state " << state << " on (" << x << "," << y << ") " << std::endl; /* *** BEGIN event filtering *** */ MOUSE_DRAG_START(GDK_BUTTON2_MASK) { drag_x=x; drag_y=y; } MOUSE_DRAGING(GDK_BUTTON2_MASK) { float mouse_sensivity = 0.2f; gint dx = drag_x - x; // Delta movement (since last event) gint dy = drag_y - y; // Not unsigned ! // Yes dy for camera.rx, and -= operator // GTK mouse coords and Opengl are not on the same coords system this->camera.rx -= mouse_sensivity * dy; this->camera.ry -= mouse_sensivity * dx; drag_x = x; drag_y = y; redraw=true; } MOUSE_CLIC(GDK_BUTTON1_MASK, 0, 0) { //TODO } // Demo filters MOUSE_CLIC(GDK_BUTTON1_MASK, GDK_SHIFT_MASK, GDK_CONTROL_MASK) { std::cout << "Mouse 1 clic with shift or control-shift" << std::endl; } MOUSE_DOUBLECLIC(GDK_BUTTON3_MASK) { std::cout << "Mouse 1 double clic" << std::endl; } /* *** END event filtering *** */ // Previous button event retention for double-clic filtering switch(type) { case GDK_BUTTON_PRESS: case GDK_BUTTON_RELEASE: case GDK_2BUTTON_PRESS: prev_type=type; // prev_state=state; break; default: break; } if ( redraw ) queue_draw(); return true; }