static void on_cam_renderer_param_widget_changed (GtkuParamWidget *pw, const char *param, void *user_data) { cam_renderer_t *cr = (cam_renderer_t*) user_data; // delete the old texture object if it exists. make sure that we've // selected the correct OpenGL context if (cr->texture) { if (cr->render_place == RENDER_IN_WIDGET) { gtku_gl_drawing_area_set_context (cr->gl_area); } else { gtku_gl_drawing_area_set_context (cr->renderer->viewer->gl_area); } glutil_texture_free (cr->texture); cr->texture = NULL; } cr->render_place = gtku_param_widget_get_enum (pw, PARAM_RENDER_IN); if (cr->render_place == RENDER_IN_WIDGET) { gtk_widget_show (GTK_WIDGET (cr->gl_area)); } else { gtk_widget_hide (GTK_WIDGET (cr->gl_area)); } cr->is_uploaded = 0; viewer_request_redraw (cr->renderer->viewer); }
static gboolean on_scroll_notify (GtkWidget *widget, GdkEventScroll *event, void *user_data) { Viewer *self = (Viewer*) user_data; gtku_gl_drawing_area_set_context (self->gl_area); double ray_start[3]; double ray_dir[3]; _window_coord_to_ray (event->x, widget->allocation.height - event->y, ray_start, ray_dir); // give picking handler first dibs int consumed = 0; if (self->picking_handler && !self->picking_handler->picking) self->picking_handler = NULL; if (self->picking_handler && self->picking_handler->enabled && self->picking_handler->mouse_scroll) { consumed = self->picking_handler->mouse_scroll(self, self->picking_handler, ray_start, ray_dir, event); update_status_bar(self); } // try all the other handlers in order of priority for (unsigned int eidx = 0; !consumed && eidx < g_ptr_array_size(self->event_handlers); eidx++) { EventHandler *handler = g_ptr_array_index(self->event_handlers, eidx); if (handler != self->picking_handler && handler->enabled && handler->mouse_scroll) if (handler->mouse_scroll(self, handler, ray_start, ray_dir, event)) break; } return TRUE; }
static gboolean on_motion_notify (GtkWidget *widget, GdkEventMotion *event, void *user_data) { Viewer *self = (Viewer*) user_data; gtku_gl_drawing_area_set_context (self->gl_area); double ray_start[3]; double ray_dir[3]; _window_coord_to_ray (event->x, widget->allocation.height - event->y, ray_start, ray_dir); // is anyone hovering? if (self->picking_handler == NULL || !self->picking_handler->picking) { // find a new hover? double best_distance = HUGE; EventHandler *best_handler = NULL; for (unsigned int eidx = 0; eidx < g_ptr_array_size(self->event_handlers); eidx++) { EventHandler *handler = g_ptr_array_index(self->event_handlers, eidx); handler->hovering = 0; if (handler->enabled && handler->hover_query) { double this_distance = handler->hover_query(self, handler, ray_start, ray_dir); if (this_distance < best_distance && this_distance >= 0) { best_distance = this_distance; best_handler = handler; } } } // notify the new handler if (best_handler) best_handler->hovering = 1; viewer_request_redraw(self); } // give picking handler first dibs int consumed = 0; if (self->picking_handler && !self->picking_handler->picking) self->picking_handler = NULL; if (self->picking_handler && self->picking_handler->enabled && self->picking_handler->mouse_motion) { consumed = self->picking_handler->mouse_motion(self, self->picking_handler, ray_start, ray_dir, event); update_status_bar(self); } // try all the other handlers in order of priority for (unsigned int eidx = 0; !consumed && eidx < g_ptr_array_size(self->event_handlers); eidx++) { EventHandler *handler = g_ptr_array_index(self->event_handlers, eidx); if (handler != self->picking_handler && handler->enabled && handler->mouse_motion) if (handler->mouse_motion(self, handler, ray_start, ray_dir, event)) break; } return TRUE; }
static void gtku_gl_drawing_area_size_allocate (GtkWidget * widget, GtkAllocation * allocation) { GtkuGLDrawingArea * self = GTKU_GL_DRAWING_AREA (widget); /* chain up */ GTK_WIDGET_CLASS (gtku_gl_drawing_area_parent_class)->size_allocate (widget, allocation); /* Resize the OpenGL area to match the allocation size. */ if (gtku_gl_drawing_area_set_context (self) == 0) glViewport (0, 0, allocation->width, allocation->height); }
static gboolean on_gl_area_expose (GtkWidget * widget, GdkEventExpose * event, void* user_data) { cam_renderer_t *cr = (cam_renderer_t*) user_data; gtku_gl_drawing_area_set_context (cr->gl_area); glClearColor (0.0, 0.0, 0.0, 1.0); glClear (GL_COLOR_BUFFER_BIT); glMatrixMode (GL_PROJECTION); glLoadIdentity (); glOrtho (0, 1, 1, 0, -1, 1); glMatrixMode (GL_MODELVIEW); cam_renderer_draw (cr); gtku_gl_drawing_area_swap_buffers (cr->gl_area); return TRUE; }
/* Called when the pipe has data on it, as written by the vblank-monitoring * thread. */ static gboolean swap_func (GIOChannel * source, GIOCondition cond, gpointer data) { GtkWidget * widget = GTK_WIDGET (data); GtkuGLDrawingArea * self = GTKU_GL_DRAWING_AREA (data); GtkuGLDrawingAreaPrivate * priv = GTKU_GL_DRAWING_AREA_GET_PRIVATE (self); if (priv->swap_requested) { if (gtku_gl_drawing_area_set_context (self) == 0) glXSwapBuffers (priv->dpy, GDK_WINDOW_XID (widget->window)); priv->swap_requested = 0; } /* Clear out the pipe of vblank events */ char buf[32]; while (1) { int num = read (priv->pipe[0], buf, sizeof (buf)); if (num <= 0) break; } return TRUE; }
static void start_recording (Viewer *self) { if (self->is_recording) { err ("viewer: already recording!!\n"); return; } #ifndef USE_ZMOV assert (self->fb_area == NULL); #endif assert (self->movie_buffer == NULL); int window_width = GTK_WIDGET (self->gl_area)->allocation.width; int window_height = GTK_WIDGET (self->gl_area)->allocation.height; self->movie_width = window_width - (window_width % 4); self->movie_height = window_height; self->movie_stride = self->movie_width * 3; self->movie_buffer = (uint8_t*) malloc (self->movie_stride * self->movie_height); self->movie_desired_fps = 1000.0 / gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->fps_spin)); self->movie_actual_fps = self->movie_desired_fps; self->movie_frame_last_utime = 0; /* int wwidth, wheight; gtk_window_get_size(GTK_WINDOW(self->window), &wwidth, &wheight); printf("%5d, %5d\n", self->movie_width, self->movie_height); gtk_widget_set_size_request(GTK_WIDGET(self->gl_area), self->movie_width, self->movie_height); gtk_window_set_default_size(GTK_WINDOW(self->window), wwidth, wheight); gtk_widget_set_size_request(GTK_WIDGET(self->gl_area), self->movie_width, self->movie_height); gtk_window_set_resizable(GTK_WINDOW(self->window), FALSE); */ #ifdef USE_ZMOV self->movie_path = get_unique_filename(NULL, "viewer", 1, "ppms.gz"); self->movie_gzf = gzopen(self->movie_path, "w"); gzsetparams(self->movie_gzf, Z_BEST_SPEED, Z_DEFAULT_STRATEGY); if (self->movie_gzf == NULL) goto abort_recording; viewer_set_status_bar_message (self, "Recording to: %s", self->movie_path); #else self->fb_area = fb_gl_drawing_area_new (FALSE, mov_width, mov_height, GL_BGR); if (!self->fb_area) { err ("Couldn't create FramebufferObject offscreen plugin\n"); gtk_toggle_tool_button_set_active ( GTK_TOGGLE_TOOL_BUTTON (self->record_button), FALSE); free (self->mov_bgr_buf); return; } assert(self->ezavi == NULL); ezavi_params_t avi_params = { .path = NULL, .file_prefix = "viewer", .date_in_file = 1, .codec = "raw", .width = mov_width, .height = mov_height, .src_stride = mov_width * 3, .frame_rate = 30, .split_point = 4000000000UL }; self->ezavi = ezavi_new (&avi_params); if (!self->ezavi) { err ("Couldn't create AVI file\n"); goto abort_recording; } g_signal_connect (G_OBJECT(self->fb_area), "buffer-ready", G_CALLBACK (on_fb_ready), self->ezavi); viewer_set_status_bar_message (self, "Recording to: %s", ezavi_get_filename (self->ezavi)); #endif self->render_timer_id = g_timeout_add (1000 / gtk_spin_button_get_value (GTK_SPIN_BUTTON (self->fps_spin)), (GSourceFunc) on_render_timer, self); self->is_recording = 1; return; abort_recording: #ifndef USE_ZMOV g_object_unref (self->fb_area); #endif gtk_toggle_tool_button_set_active ( GTK_TOGGLE_TOOL_BUTTON (self->record_button), FALSE); free (self->mov_bgr_buf); } static void stop_recording (Viewer *self) { #ifndef USE_ZMOV if (!self->fb_area) return; #endif free(self->movie_buffer); self->movie_buffer = NULL; dbg ("\nRecording stopped\n"); viewer_set_status_bar_message (self, "Recording stopped"); #ifdef USE_ZMOV gzclose(self->movie_gzf); self->movie_gzf = NULL; free(self->movie_path); self->movie_draw_pending = 0; #else fb_gl_drawing_area_flush (self->fb_area); ezavi_finish (self->ezavi); ezavi_destroy (self->ezavi); self->ezavi = NULL; g_object_unref (self->fb_area); self->fb_area = NULL; #endif g_source_remove (self->render_timer_id); self->is_recording = 0; gtk_toggle_tool_button_set_active (GTK_TOGGLE_TOOL_BUTTON (self->record_button), FALSE); // gtk_window_set_resizable(GTK_WINDOW(self->window), TRUE); } static void update_status_bar(Viewer *viewer) { char buf[1024]; if (viewer->picking_handler && !viewer->picking_handler->picking) viewer->picking_handler = NULL; int vp[4] = {0,0,0,0}; if (viewer->gl_area && gtku_gl_drawing_area_set_context (viewer->gl_area) == 0) { glGetIntegerv(GL_VIEWPORT, vp); } int width = vp[2], height = vp[3]; if (viewer->picking_handler) snprintf(buf, sizeof (buf), "%s%d x %d [%s] %s", (viewer->simulation_flag?"[SIM ENABLED] ":""), width, height, viewer->picking_handler->name, viewer->status_bar_message); else snprintf(buf, sizeof (buf), "%s%d x %d [Idle] %s", (viewer->simulation_flag?"[SIM ENABLED] ":""), width, height, viewer->status_bar_message); gtk_statusbar_push(GTK_STATUSBAR(viewer->status_bar), gtk_statusbar_get_context_id( GTK_STATUSBAR(viewer->status_bar),"info"), buf); }
static gboolean on_gl_expose (GtkWidget *widget, GdkEventExpose *event, void *user_data) { Viewer * self = (Viewer *) user_data; // if not enough time has elapsed since our last redraw, we // schedule a redraw in the future (if one isn't already pending). int64_t now = timestamp_now(); double dt = (now - self->last_draw_utime) / 1000000.0; if (dt < (1.0/MAX_REDRAW_HZ)) { if (!self->redraw_timer_pending) { int delay_ms = (now - self->last_draw_utime)/1000 + 1; g_timeout_add(delay_ms, on_redraw_timer, self); self->redraw_timer_pending = 1; } return TRUE; } self->last_draw_utime = now; // If we're making a movie, don't draw any faster than the // requested movie FPS rate. if (self->movie_gzf && !self->movie_draw_pending) return TRUE; // set this to 1 in order to cause viewer to exit cleanly after a // few hundred frames: useful for generating gprof output. g_draws++; if (0) { int thresh = 300; // for profiling PROFILE if (g_draws%50 == 0) printf("draws: %5i / %i\n", g_draws, thresh); if (g_draws == thresh) { printf("Profiling is enabled: exiting now\n"); exit(0); } } // we're going to actually draw. gtku_gl_drawing_area_set_context (self->gl_area); render_scene (self); gtku_gl_drawing_area_swap_buffers (self->gl_area); // write a movie frame? if (self->movie_draw_pending) { assert(self->movie_gzf); glReadPixels (0, 0, self->movie_width, self->movie_height, GL_RGB, GL_UNSIGNED_BYTE, self->movie_buffer); gzprintf(self->movie_gzf, "P6 %d %d %d\n", self->movie_width, self->movie_height, 255); for (int h = self->movie_height - 1; h >= 0; h--) { int offset = self->movie_stride * h; gzwrite(self->movie_gzf, &self->movie_buffer[offset], self->movie_stride); } self->movie_draw_pending = 0; int64_t now = timestamp_now(); double dt; if (self->movie_frame_last_utime == 0) dt = 1.0 / self->movie_desired_fps; else dt = (now - self->movie_frame_last_utime)/1000000.0; double fps = 1.0 / dt; self->movie_frame_last_utime = now; double alpha = 0.8; // higher = lower-pass self->movie_actual_fps = alpha * self->movie_actual_fps + (1 - alpha) * fps; self->movie_frames++; printf("%20s %6d (%5.2f fps)\r", self->movie_path, self->movie_frames, self->movie_actual_fps); fflush(NULL); } return TRUE; }