static void on_save_exr (GtkWidget *widget, Explorer* self) { #ifdef HAVE_EXR GtkWidget *dialog; GError *error = NULL; gchar *filename = NULL; #if (GTK_CHECK_VERSION(2, 4, 0)) dialog = gtk_file_chooser_dialog_new ("Save OpenEXR Image", GTK_WINDOW (glade_xml_get_widget (self->xml, "explorer_window")), GTK_FILE_CHOOSER_ACTION_SAVE, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_SAVE, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); if (file_location != NULL) gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), file_location); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); exr_save_image_file (HISTOGRAM_IMAGER (self->map), filename, &error); if (file_location) g_free (file_location); file_location = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); } #else dialog = gtk_file_selection_new ("Save OpenEXR Image"); gtk_file_selection_set_filename (GTK_FILE_SELECTION (dialog), "rendering.exr"); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { const gchar *filename; filename = g_strdup (gtk_file_selection_get_filename (GTK_FILE_SELECTION (dialog))); exr_save_image_file (HISTOGRAM_IMAGER (self->map), filename, &error); } #endif /* GTK_CHECK_VERSION */ gtk_widget_destroy (dialog); if (error) { GtkWidget *dialog, *label; gchar *text; dialog = glade_xml_get_widget (self->xml, "error dialog"); label = glade_xml_get_widget (self->xml, "error label"); text = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">Could not save \"%s\"</span>\n\n%s", filename, error->message); gtk_label_set_markup (GTK_LABEL (label), text); g_free (text); g_error_free (error); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_hide (dialog); } if (filename) g_free (filename); #endif /* HAVE_EXR */ }
static void on_load_from_image (GtkWidget *widget, Explorer* self) { GtkWidget *dialog, *image; GError *error = NULL; gchar *filename = NULL; #if (GTK_CHECK_VERSION(2, 4, 0)) dialog = gtk_file_chooser_dialog_new ("Open Image Parameters", GTK_WINDOW (glade_xml_get_widget (self->xml, "explorer_window")), GTK_FILE_CHOOSER_ACTION_OPEN, GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, GTK_STOCK_OPEN, GTK_RESPONSE_OK, NULL); gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK); image = gtk_image_new (); gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (dialog), image); g_signal_connect (G_OBJECT (dialog), "update-preview", G_CALLBACK (update_image_preview), image); if (file_location) gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), file_location); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); histogram_imager_load_image_file (HISTOGRAM_IMAGER (self->map), filename, &error); if (file_location) g_free (file_location); file_location = gtk_file_chooser_get_current_folder (GTK_FILE_CHOOSER (dialog)); } #else dialog = gtk_file_selection_new ("Open Image Parameters"); if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_OK) { filename = gtk_file_selection_get_filename (GTK_FILE_SELECTION (dialog)); histogram_imager_load_image_file (HISTOGRAM_IMAGER (self->map), filename, &error); } #endif gtk_widget_destroy (dialog); if (error) { GtkWidget *dialog, *label; gchar *text; dialog = glade_xml_get_widget (self->xml, "error dialog"); label = glade_xml_get_widget (self->xml, "error label"); text = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">Could not load \"%s\"</span>\n\n%s", filename, error->message); gtk_label_set_markup (GTK_LABEL (label), text); g_free (text); g_error_free (error); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_hide (dialog); } g_free (filename); }
static void animation_render_main (IterativeMap *map, Animation *animation, const gchar *filename, double quality) { const double frame_rate = 24; AnimationIter iter; ParameterHolderPair frame; guint frame_count = 0; gboolean continuation; double current_quality; AviWriter *avi = avi_writer_new(fopen(filename, "wb"), HISTOGRAM_IMAGER(map)->width, HISTOGRAM_IMAGER(map)->height, frame_rate); animation_iter_get_first(animation, &iter); frame.a = PARAMETER_HOLDER(de_jong_new()); frame.b = PARAMETER_HOLDER(de_jong_new()); while (animation_iter_read_frame(animation, &iter, &frame, frame_rate)) { continuation = FALSE; do { /* Calculate 0.5 seconds between quality updates. This is lower than the * batch image rendering default of 2.0 seconds, to better handle * lower-quality animations where the individual frames go quicker. */ iterative_map_calculate_motion_timed(map, 0.5, continuation, PARAMETER_INTERPOLATOR(parameter_holder_interpolate_linear), &frame); current_quality = histogram_imager_compute_quality(HISTOGRAM_IMAGER(map)); printf("\rFrame %d, %e iterations, %.04f quality", frame_count, map->iterations, current_quality); fflush(stdout); continuation = TRUE; } while (current_quality < quality); histogram_imager_update_image(HISTOGRAM_IMAGER(map)); avi_writer_append_frame(avi, HISTOGRAM_IMAGER(map)->image); /* Move to the next line for each frame. * Updates within a frame overwrite that line. */ printf("\n"); frame_count++; } avi_writer_close(avi); }
static void cmd_calc_status (RemoteServerConn* self, const char* command, const char* parameters) { if (self->server->verbose) printf("[%s:%d] iterations: %.5e density: %ld\n", self->gconn->hostname, self->gconn->port, self->map->iterations, HISTOGRAM_IMAGER(self->map)->peak_density); remote_server_send_response(self, FYRE_RESPONSE_PROGRESS, "iterations=%.20e density=%ld", self->map->iterations, HISTOGRAM_IMAGER(self->map)->peak_density); }
static void histogram_merge_callback (RemoteClient* self, RemoteResponse* response, gpointer user_data) { HistogramImager *dest = HISTOGRAM_IMAGER(user_data); double elapsed; self->pending_stream_requests--; if (self->pending_param_changes) { /* This data is for an old parameter set, ignore it. * FIXME: This doesn't distinguish between parameters that * actaully affect calculation and those that don't. */ return; } if (!response->data_length) return; histogram_imager_merge_stream(dest, response->data, response->data_length); /* Update our download speed */ self->byte_accumulator += response->data_length; elapsed = g_timer_elapsed(self->stream_speed_timer, NULL); if (elapsed > MINIMUM_SPEED_WINDOW) { g_timer_start(self->stream_speed_timer); self->bytes_per_sec = self->byte_accumulator / elapsed; self->byte_accumulator = 0; } }
static void histogram_imager_dispose (GObject *gobject) { HistogramImager *self = HISTOGRAM_IMAGER (gobject); if (self->histogram) { g_free (self->histogram); self->histogram = NULL; } if (self->image) { gdk_pixbuf_unref (self->image); self->image = NULL; } if (self->color_table.table) { g_free (self->color_table.table); self->color_table.table = NULL; } if (self->color_table.quality) { g_free (self->color_table.quality); self->color_table.quality = NULL; } if (self->oversample_tables.linearize) { g_free (self->oversample_tables.linearize); self->oversample_tables.linearize = NULL; } if (self->oversample_tables.nonlinearize) { g_free (self->oversample_tables.nonlinearize); self->oversample_tables.nonlinearize = NULL; } G_OBJECT_CLASS (parent_class)->dispose (gobject); }
static void cmd_get_histogram_stream (RemoteServerConn* self, const char* command, const char* parameters) { gsize size; if (!self->buffer) { /* Allocate it with an initial size of 128kB */ self->buffer_size = 128 * 1024; self->buffer = g_malloc(self->buffer_size); } size = histogram_imager_export_stream(HISTOGRAM_IMAGER(self->map), self->buffer, self->buffer_size); remote_server_send_binary(self, self->buffer, size); /* If we used more than half the buffer, double its size. * This ensures that if we do run out of room, we'll have plenty * of space to send the remainder of the buffer next time. */ if (size > (self->buffer_size / 2)) { g_free(self->buffer); self->buffer_size *= 2; self->buffer = g_malloc(self->buffer_size); } }
static int screensaver_idle_handler(gpointer user_data) { ScreenSaver *self = SCREENSAVER(user_data); iterative_map_calculate_motion(ITERATIVE_MAP(self->frame_renders[self->current_frame]), 100000, TRUE, PARAMETER_INTERPOLATOR(parameter_holder_interpolate_linear), &self->frame_parameters[self->current_frame]); if (GTK_WIDGET_DRAWABLE(self->view)) { histogram_view_set_imager(HISTOGRAM_VIEW(self->view), HISTOGRAM_IMAGER(self->frame_renders[self->current_frame])); histogram_view_update(HISTOGRAM_VIEW(self->view)); self->current_frame += self->direction; if (self->current_frame >= self->num_frames) { self->current_frame = self->num_frames-2; self->direction = -1; } if (self->current_frame < 0) { self->current_frame = 1; self->direction = 1; } } return 1; }
static gboolean on_record_change (gpointer user_data) { Explorer* self = EXPLORER(user_data); explorer_append_history(self, history_node_new(HISTOGRAM_IMAGER(self->map))); self->history_timer = 0; return FALSE; }
static gchar* explorer_strdup_elapsed (Explorer *self) { gulong elapsed = (gulong) histogram_imager_get_elapsed_time(HISTOGRAM_IMAGER(self->map)); return g_strdup_printf("%02ld:%02ld:%02ld", elapsed / (60*60), (elapsed / 60) % 60, elapsed % 60); }
static gchar* explorer_strdup_quality (Explorer *self) { gdouble q = histogram_imager_compute_quality(HISTOGRAM_IMAGER(self->map)); if (q > (G_MAXDOUBLE / 2)) return g_strdup("N/A"); else return g_strdup_printf("%.3f", q); }
static void on_go_forward (GtkWidget *widget, Explorer *self) { self->history_current_link = self->history_current_link->next; explorer_update_history_sensitivity(self); self->history_freeze = TRUE; history_node_apply(self->history_current_link->data, HISTOGRAM_IMAGER(self->map)); self->history_freeze = FALSE; }
static int animation_render_ui_idle_handler(gpointer user_data) { AnimationRenderUi *self = (AnimationRenderUi*) user_data; gdouble frame_completion, anim_completion; animation_render_ui_run_timed_calculation(self); /* Figure out how complete this frame is */ frame_completion = histogram_imager_compute_quality(HISTOGRAM_IMAGER(self->map)) / self->quality; if (frame_completion >= 1) { frame_completion = 1; /* Write out this frame */ histogram_imager_update_image(HISTOGRAM_IMAGER(self->map)); avi_writer_append_frame(self->avi, HISTOGRAM_IMAGER(self->map)->image); /* Show the completed frame in our GUI's preview area */ gtk_image_set_from_pixbuf(GTK_IMAGE(glade_xml_get_widget(self->xml, "preview")), HISTOGRAM_IMAGER(self->map)->image); gtk_widget_show(glade_xml_get_widget(self->xml, "preview_frame")); /* Move to the next frame */ if (animation_iter_read_frame(self->animation, &self->iter, &self->frame, self->frame_rate)) { /* We still have more to render, calculate how much we've done so far */ self->continuation = FALSE; self->elapsed_anim_time += 1/self->frame_rate; anim_completion = self->elapsed_anim_time / self->anim_length; } else { /* We're done, yay. Clean up. */ anim_completion = 1; animation_render_ui_stop(self); } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(glade_xml_get_widget(self->xml, "animation_progress")), anim_completion); } else { /* Continue this frame later */ self->continuation = TRUE; } gtk_progress_bar_set_fraction(GTK_PROGRESS_BAR(glade_xml_get_widget(self->xml, "frame_progress")), frame_completion); return 1; }
static void on_go_menu_item (GtkWidget *menu, gpointer user_data) { GList *link = user_data; HistoryNode *node = link->data; Explorer *self = node->explorer; self->history_current_link = link; explorer_update_history_sensitivity(self); self->history_freeze = TRUE; history_node_apply(self->history_current_link->data, HISTOGRAM_IMAGER(self->map)); self->history_freeze = FALSE; }
Explorer* explorer_new(IterativeMap *map, Animation *animation) { Explorer *self = EXPLORER(g_object_new(explorer_get_type(), NULL)); GtkWidget *editor, *window, *scroll; GtkRequisition win_req; self->animation = ANIMATION(g_object_ref(animation)); self->map = ITERATIVE_MAP(g_object_ref(map)); /* Create the parameter editor */ editor = parameter_editor_new(PARAMETER_HOLDER(map)); gtk_box_pack_start(GTK_BOX(glade_xml_get_widget(self->xml, "parameter_editor_box")), editor, FALSE, FALSE, 0); gtk_widget_show_all(editor); /* Create the view */ self->view = histogram_view_new(HISTOGRAM_IMAGER(map)); gtk_container_add(GTK_CONTAINER(glade_xml_get_widget(self->xml, "drawing_area_viewport")), self->view); gtk_widget_show_all(self->view); /* Set the initial render time */ on_render_time_changed(glade_xml_get_widget(self->xml, "render_time"), self); explorer_init_history(self); explorer_init_animation(self); explorer_init_tools(self); explorer_init_cluster(self); explorer_init_about(self); /* Start the iterative map rendering in the background, and get a callback every time a block * of calculations finish so we can update the GUI. */ iterative_map_start_calculation(self->map); g_signal_connect(G_OBJECT(self->map), "calculation-finished", G_CALLBACK(on_calculation_finished), self); /* Set the window's default size to include our default image size. * The cleanest way I know of to do this is to set the scrolled window's scrollbar policies * to 'never' and get the window's size requests, set them back to automatic, then set the * default size to that size request. */ window = glade_xml_get_widget(self->xml, "explorer_window"); scroll = glade_xml_get_widget(self->xml, "main_scrolledwindow"); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_NEVER, GTK_POLICY_NEVER); gtk_widget_size_request(window, &win_req); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_window_set_default_size(GTK_WINDOW(window), win_req.width, win_req.height); gtk_widget_show(window); return self; }
static void gui_init_simple (RemoteServerConn* self) { /* Simple GUI, just a window holding our histogram view */ GtkWidget* view; GtkWidget* window; view = histogram_view_new(HISTOGRAM_IMAGER(self->map)); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); fyre_set_icon_later(window); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); gtk_window_set_title(GTK_WINDOW(window), "Fyre Server"); gtk_container_add(GTK_CONTAINER(window), view); gtk_widget_show_all(window); connect_map_to_view(self->map, HISTOGRAM_VIEW(view)); self->gui = window; }
void explorer_update_gui(Explorer *self) { /* If the GUI needs updating, update it. This includes limiting the maximum * update rate, updating the iteration count display, and actually rendering * frames to the drawing area. */ /* If we have rendering changes we're trying to push through as quickly * as possible, don't bother with the status bar or with frame rate limiting. */ if (HISTOGRAM_IMAGER(self->map)->render_dirty_flag) { histogram_view_update(HISTOGRAM_VIEW(self->view)); return; } /* If we have an important status change to report, update both * the status bar and the view without frame rate limiting. */ if (self->status_dirty_flag) { explorer_update_status_bar(self); histogram_view_update(HISTOGRAM_VIEW(self->view)); return; } /* Update the status bar at a fixed rate. This will give the user * the impression that things are moving along steadily even when * we're actually updating the view very slowly later in the render. */ if (!limit_update_rate(self->status_update_rate_timer, 2.0 )) { explorer_update_status_bar(self); } /* Use our funky automatic frame rate adjuster to time normal view updates. * This will slow down updates nonlinearly as rendering progresses, * to give good interactive response while making batch rendering * still fairly efficient. */ if (!explorer_auto_limit_update_rate(self)) { histogram_view_update(HISTOGRAM_VIEW(self->view)); } }
ScreenSaver* screensaver_new(IterativeMap *map, Animation *animation) { ScreenSaver *self = SCREENSAVER(g_object_new(screensaver_get_type(), NULL)); int i; AnimationIter iter; gchar* common_parameters; self->animation = ANIMATION(g_object_ref(animation)); self->map = ITERATIVE_MAP(g_object_ref(map)); self->view = g_object_ref(histogram_view_new(HISTOGRAM_IMAGER(self->map))); /* Allocate and interpolate all frames */ self->framerate = 10; self->num_frames = animation_get_length(self->animation) * self->framerate; self->frame_renders = g_new0(IterativeMap*, self->num_frames); self->frame_parameters = g_new0(ParameterHolderPair, self->num_frames); self->current_frame = 0; common_parameters = parameter_holder_save_string(PARAMETER_HOLDER(map)); animation_iter_seek(animation, &iter, 0); for (i=0; i<self->num_frames; i++) { self->frame_renders[i] = ITERATIVE_MAP(de_jong_new()); parameter_holder_load_string(PARAMETER_HOLDER(self->frame_renders[i]), common_parameters); self->frame_parameters[i].a = PARAMETER_HOLDER(de_jong_new()); animation_iter_load(animation, &iter, self->frame_parameters[i].a); animation_iter_seek_relative(animation, &iter, 1/self->framerate); } for (i=0; i<self->num_frames-1; i++) self->frame_parameters[i].b = self->frame_parameters[i+1].a; self->frame_parameters[self->num_frames-1].b = self->frame_parameters[self->num_frames-1].a; g_free(common_parameters); self->direction = 1; screensaver_start(self); return self; }
static gboolean explorer_auto_limit_update_rate(Explorer *self) { /* Automatically determine a good maximum frame rate based on the current * elapsed time, and use limit_update_rate() to limit us to that. * Returns 1 if a frame should not be rendered. * * 'gamma' determines the nonlinearity. At gamma=1 we ramp down the period * linearly. (not the rate) The other parameters determine the speed and the * maximum/minimum rates. Voodoo below! */ const double initial_rate = 60; const double final_rate = 0.1; const double ramp_down_seconds = 120; const double gamma = 0.9; /* Convert the user-friendly constants above into constants in nonlinear period space */ double rate, elapsed; static gboolean init = FALSE; static double pow_initial_period, pow_period_scale, one_over_gamma; if (!init) { pow_initial_period = pow(1.0 / initial_rate, gamma); pow_period_scale = (pow(1.0 / final_rate, gamma) - pow_initial_period) / ramp_down_seconds; one_over_gamma = 1.0 / gamma; init = TRUE; } /* Now it's just a simple linear function followed by a nonlinear * transformation back to rate space. */ elapsed = histogram_imager_get_elapsed_time(HISTOGRAM_IMAGER(self->map)); if (elapsed > ramp_down_seconds) rate = final_rate; else rate = 1.0 / pow(pow_initial_period + pow_period_scale * elapsed, one_over_gamma); return limit_update_rate(self->auto_update_rate_timer, rate); }
static void cell_renderer_bifurcation_render(GtkCellRenderer *cell, GdkWindow *window, GtkWidget *widget, GdkRectangle *background_area, GdkRectangle *cell_area, GdkRectangle *expose_area, GtkCellRendererState flags) { CellRendererBifurcation *self = CELL_RENDERER_BIFURCATION(cell); BifurcationDiagram *bd = get_bifurcation_diagram(self); GtkStateType state; RedrawInfo *nr; if (!bd) return; /* Determine the correct state to render our text in, based on * the cell's selectedness and the widget's current state. * This was copied from GtkCellRendererText. */ if ((flags & GTK_CELL_RENDERER_SELECTED) == GTK_CELL_RENDERER_SELECTED) { if (GTK_WIDGET_HAS_FOCUS (widget)) state = GTK_STATE_SELECTED; else state = GTK_STATE_ACTIVE; } else { if (GTK_WIDGET_STATE (widget) == GTK_STATE_INSENSITIVE) state = GTK_STATE_INSENSITIVE; else state = GTK_STATE_NORMAL; } /* Set the bifurcation diagram renderer's parameters appropriately for this * cell renderer. It will automatically figure out what if anything it has * to change internally. We size it to fit this cell exactly, and set * the colors appropriately for our state and theme. */ g_object_set(bd, "width", cell_area->width, "height", cell_area->height, "fgcolor-gdk", >K_WIDGET(widget)->style->fg[state], "bgcolor-gdk", >K_WIDGET(widget)->style->base[state], NULL); /* Assume that 5*(cell area) is good enough) */ if(HISTOGRAM_IMAGER(bd)->total_points_plotted > 5 * cell_area->width * cell_area->height) { gdk_draw_pixbuf(window, GTK_WIDGET(widget)->style->fg_gc[state], HISTOGRAM_IMAGER(bd)->image, 0, 0, cell_area->x, cell_area->y, cell_area->width, cell_area->height, GDK_RGB_DITHER_NONE, 0, 0); return; } /* Render it a bit and update the image */ bifurcation_diagram_calculate(bd, 10000, 100); histogram_imager_update_image(HISTOGRAM_IMAGER(bd)); gdk_draw_pixbuf(window, GTK_WIDGET(widget)->style->fg_gc[state], HISTOGRAM_IMAGER(bd)->image, 0, 0, cell_area->x, cell_area->y, cell_area->width, cell_area->height, GDK_RGB_DITHER_NONE, 0, 0); nr = g_new (RedrawInfo, 1); nr->view = self->tree; nr->rect.x = cell_area->x; nr->rect.y = cell_area->y; nr->rect.width = cell_area->width; nr->rect.height = cell_area->height; g_timeout_add (20, (GSourceFunc) cell_queue_redraw, nr); }
static void histogram_imager_set_property (GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec) { HistogramImager *self = HISTOGRAM_IMAGER(object); GdkColor gdkc; switch (prop_id) { case PROP_WIDTH: update_uint_if_necessary (g_value_get_uint (value), &self->size_dirty_flag, &self->width); break; case PROP_HEIGHT: update_uint_if_necessary (g_value_get_uint (value), &self->size_dirty_flag, &self->height); break; case PROP_OVERSAMPLE: if (update_uint_if_necessary (g_value_get_uint (value), &self->size_dirty_flag, &self->oversample)) g_object_notify (object, "oversample-enabled"); break; case PROP_SIZE: histogram_imager_resize_from_string (self, g_value_get_string (value)); break; case PROP_EXPOSURE: update_double_if_necessary (g_value_get_double (value), &self->render_dirty_flag, &self->exposure, 0.00009); break; case PROP_GAMMA: update_double_if_necessary (g_value_get_double (value), &self->render_dirty_flag, &self->gamma, 0.00009); break; case PROP_OVERSAMPLE_GAMMA: update_double_if_necessary (g_value_get_double (value), &self->render_dirty_flag, &self->oversample_gamma, 0.00009); break; case PROP_FGCOLOR: /* Convert to a GdkColor and set the fgcolor-gdk property. This is necessary * so that notify signals attached to fgcolor-gdk are sent properly, and in * general makes it cleaner. */ gdk_color_parse (g_value_get_string (value), &gdkc); g_object_set (self, "fgcolor-gdk", &gdkc, NULL); break; case PROP_BGCOLOR: /* And the same goes for background... */ gdk_color_parse (g_value_get_string (value), &gdkc); g_object_set (self, "bgcolor-gdk", &gdkc, NULL); break; case PROP_FGCOLOR_GDK: update_color_if_necessary ((GdkColor*) g_value_get_boxed (value), &self->render_dirty_flag, &self->fgcolor); break; case PROP_BGCOLOR_GDK: update_color_if_necessary ((GdkColor*) g_value_get_boxed (value), &self->render_dirty_flag, &self->bgcolor); break; case PROP_FGALPHA: update_uint_if_necessary (g_value_get_uint (value), &self->render_dirty_flag, &self->fgalpha); break; case PROP_BGALPHA: update_uint_if_necessary (g_value_get_uint (value), &self->render_dirty_flag, &self->bgalpha); break; case PROP_CLAMPED: update_boolean_if_necessary (g_value_get_boolean (value), &self->render_dirty_flag, &self->clamped); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
static void on_go_menu_show (GtkWidget *menu, Explorer *self) { const int max_linear_items = 4; const int max_scaled_items = 10; int i, num_scaled_items; GList *current; gdouble t_total, t; GTimeVal *scaled_reference; HistoryNode* node; explorer_cleanup_go_items(self); /* If our queue is empty, add a new record immediately. This * will prevent us from getting an empty 'go' menu right after * startup- instead it will have a thumbnail of our defaults * or whatever image the user happened to load. This can't * go in our initialization above since that happens before * we've actually rendered anything. Putting it here is more * reliable than using a timer. */ if (self->history_queue->length < 1) explorer_append_history(self, history_node_new(HISTOGRAM_IMAGER(self->map))); /* The first few items are straight from the most recent list */ current = g_queue_peek_tail_link(self->history_queue); for (i=0; i<max_linear_items; i++) { if (!current) return; explorer_add_go_item(self, current); current = current->prev; } /* The rest of the list is spread evenly over time, from the end * of the above section back to the oldest history we have. */ if (!current) return; node = current->data; scaled_reference = &node->timestamp; t_total = timeval_subtract(scaled_reference, &((HistoryNode*)g_queue_peek_head(self->history_queue))->timestamp); num_scaled_items = MIN(self->history_queue->length - max_linear_items, max_scaled_items); if (num_scaled_items <= 0) return; for (i=0; i<num_scaled_items; i++) { /* For each item on the scaled_items list, find the * node at the proper position in time. */ while (1) { if (!current) return; node = current->data; t = timeval_subtract(scaled_reference, &node->timestamp); if (t > (i*t_total/num_scaled_items)) break; current = current->prev; } explorer_add_go_item(self, current); } }
int main(int argc, char ** argv) { IterativeMap* map; Animation* animation; gboolean animate = FALSE; gboolean have_gtk; gboolean verbose = FALSE; gboolean hidden = FALSE; enum {INTERACTIVE, RENDER, SCREENSAVER, REMOTE} mode = INTERACTIVE; const gchar *outputFile = NULL; const gchar *pidfile = NULL; int c, option_index=0; double quality = 1.0; #ifdef HAVE_GNET int port_number = FYRE_DEFAULT_PORT; #endif GError *error = NULL; math_init(); g_type_init(); have_gtk = gtk_init_check(&argc, &argv); #ifdef HAVE_GNET gnet_init(); # ifdef WIN32 gnet_ipv6_set_policy(GIPV6_POLICY_IPV4_ONLY); # endif #endif map = ITERATIVE_MAP(de_jong_new()); animation = animation_new(); while (1) { static struct option long_options[] = { {"help", 0, NULL, 'h'}, {"read", 1, NULL, 'i'}, {"animate", 1, NULL, 'n'}, {"output", 1, NULL, 'o'}, {"param", 1, NULL, 'p'}, {"size", 1, NULL, 's'}, {"oversample", 1, NULL, 'S'}, {"quality", 1, NULL, 'q'}, {"remote", 0, NULL, 'r'}, {"verbose", 0, NULL, 'v'}, {"port", 1, NULL, 'P'}, {"cluster", 1, NULL, 'c'}, {"auto-cluster", 0, NULL, 'C'}, {"screensaver", 0, NULL, 1000}, /* Undocumented, still experimental */ {"hidden", 0, NULL, 1001}, {"chdir", 1, NULL, 1002}, /* Undocumented, used by win32 file associations */ {"pidfile", 1, NULL, 1003}, {"version", 0, NULL, 1004}, {NULL}, }; c = getopt_long(argc, argv, "hi:n:o:p:s:S:q:rvP:c:C", long_options, &option_index); if (c == -1) break; switch (c) { case 'i': { histogram_imager_load_image_file(HISTOGRAM_IMAGER(map), optarg, &error); break; } case 'n': { GtkTreeIter iter; animation_load_file(animation, optarg); animate = TRUE; gtk_tree_model_get_iter_first(GTK_TREE_MODEL(animation->model), &iter); animation_keyframe_load(animation, &iter, PARAMETER_HOLDER(map)); break; } case 'o': mode = RENDER; outputFile = optarg; break; case 'p': parameter_holder_load_string(PARAMETER_HOLDER(map), optarg); break; case 's': parameter_holder_set(PARAMETER_HOLDER(map), "size" , optarg); break; case 'S': parameter_holder_set(PARAMETER_HOLDER(map), "oversample", optarg); break; case 'q': quality = atof(optarg); break; case 'v': verbose = TRUE; break; #ifdef HAVE_GNET case 'c': { ClusterModel *cluster = cluster_model_get(map, TRUE); cluster_model_add_nodes(cluster, optarg); } break; case 'C': { ClusterModel *cluster = cluster_model_get(map, TRUE); cluster_model_enable_discovery(cluster); } break; case 'r': mode = REMOTE; break; case 'P': port_number = atol(optarg); break; #else case 'c': case 'C': case 'P': fprintf(stderr, "This Fyre binary was compiled without gnet support.\n" "Cluster support is not available.\n"); break; case 'r': fprintf(stderr, "This Fyre binary was compiled without gnet support.\n" "Cluster support is not available.\n"); exit(1); break; #endif case 1000: /* --screensaver */ mode = SCREENSAVER; break; case 1001: /* --hidden */ hidden = TRUE; break; case 1002: /* --chdir */ chdir(optarg); break; case 1003: /* --pidfile */ pidfile = optarg; break; case 1004: /* --version */ printf("%s\n", VERSION); return 0; case 'h': default: usage(argv); return 1; } } if (optind + 1 < argc) { usage(argv); return 1; } if (optind != argc) { char *ext = strrchr (argv[optind], '.'); if (ext) { if (g_strcasecmp(ext, ".png") == 0) { histogram_imager_load_image_file(HISTOGRAM_IMAGER(map), argv[optind], &error); } else if (g_strcasecmp(ext, ".fa") == 0) { GtkTreeIter iter; animation_load_file(animation, argv[optind]); animate = TRUE; gtk_tree_model_get_iter_first(GTK_TREE_MODEL(animation->model), &iter); animation_keyframe_load(animation, &iter, PARAMETER_HOLDER(map)); } else { usage(argv); return 1; } } else { usage(argv); return 1; } } switch (mode) { case INTERACTIVE: { Explorer *explorer; if (!have_gtk) { fprintf(stderr, "GTK intiailization failed, can't start in interactive mode\n"); return 1; } explorer = explorer_new (map, animation); if (error) { GtkWidget *dialog, *label; gchar *text; dialog = glade_xml_get_widget (explorer->xml, "error dialog"); label = glade_xml_get_widget (explorer->xml, "error label"); text = g_strdup_printf ("<span weight=\"bold\" size=\"larger\">Error!</span>\n\n%s", error->message); gtk_label_set_markup (GTK_LABEL (label), text); g_free (text); g_error_free (error); gtk_dialog_run (GTK_DIALOG (dialog)); gtk_widget_hide (dialog); } gtk_main(); break; } case RENDER: { acquire_console(); if (error) { g_print ("Error: %s\n", error->message); g_error_free (error); } if (animate) animation_render_main (map, animation, outputFile, quality); else batch_image_render (map, outputFile, quality); break; } case REMOTE: { #ifdef HAVE_GNET if (verbose) { acquire_console(); } else { daemonize_to_pidfile(pidfile); } if (!hidden) discovery_server_new(FYRE_DEFAULT_SERVICE, port_number); remote_server_main_loop(port_number, have_gtk, verbose); #else fprintf(stderr, "This Fyre binary was compiled without gnet support.\n" "Remote control mode is not available.\n"); #endif break; } case SCREENSAVER: { ScreenSaver* screensaver; GtkWidget* window; if (!have_gtk) { fprintf(stderr, "GTK intiailization failed, can't start in screensaver mode\n"); return 1; } screensaver = screensaver_new(map, animation); window = gtk_window_new(GTK_WINDOW_TOPLEVEL); fyre_set_icon_later(window); gtk_window_set_resizable(GTK_WINDOW(window), FALSE); gtk_window_set_title(GTK_WINDOW(window), "Fyre Screensaver"); gtk_container_add(GTK_CONTAINER(window), screensaver->view); gtk_widget_show_all(window); gtk_main(); break; } } return 0; }
static void histogram_imager_get_property (GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) { HistogramImager *self = HISTOGRAM_IMAGER (object); switch (prop_id) { case PROP_WIDTH: g_value_set_uint (value, self->width); break; case PROP_HEIGHT: g_value_set_uint (value, self->height); break; case PROP_OVERSAMPLE: g_value_set_uint (value, self->oversample); break; case PROP_OVERSAMPLE_ENABLED: g_value_set_boolean (value, self->oversample > 1); break; case PROP_CLAMPED: g_value_set_boolean (value, self->clamped); break; case PROP_EXPOSURE: g_value_set_double (value, self->exposure); break; case PROP_GAMMA: g_value_set_double (value, self->gamma); break; case PROP_OVERSAMPLE_GAMMA: g_value_set_double (value, self->oversample_gamma); break; case PROP_FGALPHA: g_value_set_uint (value, self->fgalpha); break; case PROP_BGALPHA: g_value_set_uint (value, self->bgalpha); break; case PROP_SIZE: g_value_set_string_take_ownership (value, g_strdup_printf ("%dx%d", self->width, self->height)); break; case PROP_FGCOLOR: g_value_set_string_take_ownership (value, describe_color (&self->fgcolor)); break; case PROP_BGCOLOR: g_value_set_string_take_ownership (value, describe_color (&self->bgcolor)); break; case PROP_FGCOLOR_GDK: g_value_set_boxed (value, &self->fgcolor); break; case PROP_BGCOLOR_GDK: g_value_set_boxed (value, &self->bgcolor); break; default: G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); break; } }
HistogramImager* histogram_imager_new () { return HISTOGRAM_IMAGER (g_object_new (histogram_imager_get_type (), NULL)); }