/* expand invalidated regions to be align with coordinates divisible by 8 in both * directions. This improves improves the performance of GeglProcessor when it * iterates the resulting dirtied rectangles in the GeglRegion. */ static GeglRectangle gegl_rectangle_expand (const GeglRectangle *rectangle) { gint align = 8; GeglRectangle expanded = *rectangle; gint xdiff; gint ydiff; if (gegl_rectangle_is_infinite_plane (rectangle)) return *rectangle; xdiff = expanded.x % align; if (xdiff < 0) xdiff = align + xdiff; expanded.width += xdiff; expanded.x -= xdiff; xdiff = align -(expanded.width % align); expanded.width += xdiff; ydiff = expanded.y % align; if (ydiff < 0) ydiff = align + ydiff; expanded.height += ydiff; expanded.y -= ydiff; ydiff = align -(expanded.height % align); expanded.height += ydiff; return expanded; }
static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input"); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (in_rect && gegl_rectangle_is_infinite_plane (in_rect)) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
/* Pass-through when trying to perform IIR on an infinite plane */ static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; GeglProperties *o = GEGL_PROPERTIES (operation); GeglGblur1dFilter filter = filter_disambiguation (o->filter, o->std_dev); operation_class = GEGL_OPERATION_CLASS (gegl_op_parent_class); if (filter == GEGL_GBLUR_1D_IIR) { const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input"); if (in_rect && gegl_rectangle_is_infinite_plane (in_rect)) { gpointer in = gegl_operation_context_get_object (context, "input"); gegl_operation_context_take_object (context, "output", g_object_ref (G_OBJECT (in))); return TRUE; } } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, gegl_operation_context_get_level (context)); }
static GeglRectangle get_bounding_box (GeglOperation *operation) { GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation); GeglRectangle result = { 0, }; GeglRectangle *in_rect; in_rect = gegl_operation_source_get_bounding_box (operation,"input"); if (!in_rect) return result; if (gegl_rectangle_is_infinite_plane (in_rect)) return *in_rect; result = *in_rect; if (result.width != 0 && result.height != 0) { result.x-= area->left; result.y-= area->top; result.width += area->left + area->right; result.height += area->top + area->bottom; } return result; }
static GeglRectangle get_required_for_output (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *roi) { GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input"); if (gegl_rectangle_is_infinite_plane (&result)) return *roi; return result; }
static GeglRectangle get_cached_region (GeglOperation *operation, const GeglRectangle *roi) { GeglRectangle result = *gegl_operation_source_get_bounding_box (operation, "input"); if (gegl_rectangle_is_infinite_plane (&result)) return *roi; return result; }
static GeglRectangle gegl_gblur_1d_get_required_for_output (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *output_roi) { GeglRectangle required_for_output = { 0, }; GeglProperties *o = GEGL_PROPERTIES (operation); GeglGblur1dFilter filter = filter_disambiguation (o->filter, o->std_dev); if (filter == GEGL_GBLUR_1D_IIR) { const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, input_pad); if (in_rect) { if (!gegl_rectangle_is_infinite_plane (in_rect)) { required_for_output = *output_roi; if (o->orientation == GEGL_ORIENTATION_HORIZONTAL) { required_for_output.x = in_rect->x; required_for_output.width = in_rect->width; } else { required_for_output.y = in_rect->y; required_for_output.height = in_rect->height; } if (!o->clip_extent) required_for_output = gegl_gblur_1d_enlarge_extent (o, &required_for_output); } /* pass-through case */ else return *output_roi; } } else { required_for_output = gegl_gblur_1d_enlarge_extent (o, output_roi); } return required_for_output; }
static GeglRectangle gegl_gblur_1d_get_bounding_box (GeglOperation *operation) { GeglProperties *o = GEGL_PROPERTIES (operation); const GeglRectangle *in_rect = gegl_operation_source_get_bounding_box (operation, "input"); if (! in_rect) return *GEGL_RECTANGLE (0, 0, 0, 0); if (gegl_rectangle_is_infinite_plane (in_rect)) return *in_rect; if (o->clip_extent) { return *in_rect; } else { /* We use the FIR convolution length for both the FIR and the IIR case */ return gegl_gblur_1d_enlarge_extent (o, in_rect); } }
static GeglRectangle gegl_gblur_1d_get_cached_region (GeglOperation *operation, const GeglRectangle *output_roi) { GeglRectangle cached_region; GeglProperties *o = GEGL_PROPERTIES (operation); GeglGblur1dFilter filter = filter_disambiguation (o->filter, o->std_dev); cached_region = *output_roi; if (filter == GEGL_GBLUR_1D_IIR) { const GeglRectangle in_rect = gegl_gblur_1d_get_bounding_box (operation); if (! gegl_rectangle_is_empty (&in_rect) && ! gegl_rectangle_is_infinite_plane (&in_rect)) { GeglProperties *o = GEGL_PROPERTIES (operation); cached_region = *output_roi; if (o->orientation == GEGL_ORIENTATION_HORIZONTAL) { cached_region.x = in_rect.x; cached_region.width = in_rect.width; } else { cached_region.y = in_rect.y; cached_region.height = in_rect.height; } } } return cached_region; }
GeglBuffer * gegl_operation_context_dup_input_maybe_copy (GeglOperationContext *context, const gchar *padname, const GeglRectangle *roi) { GeglBuffer *input; GeglBuffer *output; GeglBuffer *result; GeglRectangle required; GeglRectangle temp; gint shift_x; gint shift_y; gint tile_width; gint tile_height; input = GEGL_BUFFER (gegl_operation_context_get_object (context, padname)); if (! input) return NULL; /* return input directly when processing a level greater than 0, since * gegl_buffer_copy() only copies level-0 tiles */ if (context->level > 0) return g_object_ref (input); output = GEGL_BUFFER (gegl_operation_context_get_object (context, "output")); /* return input directly when processing in-place, otherwise, the copied * input buffer will occupy space in the cache after the original is modified */ if (input == output) return g_object_ref (input); /* get required region to copy */ required = gegl_operation_get_required_for_output (context->operation, padname, roi); /* return input directly if the required rectangle is infinite, so that we * don't attempt to copy an infinite region */ if (gegl_rectangle_is_infinite_plane (&required)) return g_object_ref (input); /* align required region to the tile grid */ shift_x = input->shift_x; shift_y = input->shift_y; tile_width = input->tile_width; tile_height = input->tile_height; temp.x = (gint) floor ((gdouble) (required.x + shift_x) / tile_width) * tile_width; temp.y = (gint) floor ((gdouble) (required.y + shift_y) / tile_height) * tile_height; temp.width = (gint) ceil ((gdouble) (required.x + required.width + shift_x) / tile_width) * tile_width - temp.x; temp.height = (gint) ceil ((gdouble) (required.y + required.height + shift_y) / tile_height) * tile_height - temp.y; temp.x -= shift_x; temp.y -= shift_y; required = temp; /* intersect required region with input abyss */ gegl_rectangle_intersect (&required, &required, &input->abyss); /* create new buffer with similar characteristics to the input buffer */ result = g_object_new (GEGL_TYPE_BUFFER, "format", input->soft_format, "x", input->extent.x, "y", input->extent.y, "width", input->extent.width, "height", input->extent.height, "abyss-x", input->abyss.x, "abyss-y", input->abyss.y, "abyss-width", input->abyss.width, "abyss-height", input->abyss.height, "shift-x", shift_x, "shift-y", shift_y, "tile-width", tile_width, "tile-height", tile_height, NULL); /* if the tile size doesn't match, bail */ if (result->tile_width != tile_width || result->tile_height != tile_height) { g_object_unref (result); return g_object_ref (input); } /* copy required region from input to result -- tiles will generally be COWed */ gegl_buffer_copy (input, &required, GEGL_ABYSS_NONE, result, &required); return result; }
gint layer_node_selected (gpointer host, GeglEditor* editor, gint node_id) { GeglEditorLayer* self = (GeglEditorLayer*)host; GeglNode* node = NULL; GSList* pair = self->pairs; for(;pair != NULL; pair = pair->next) { node_id_pair* data = pair->data; if(data->id == node_id) { node = data->node; break; } } g_assert(node != NULL); GeglNode** nodes; const gchar** pads; gint num = gegl_node_get_consumers(node, "output", &nodes, &pads); int i; g_print("%s: %d consumer(s)\n", gegl_node_get_operation(node), num); for(i = 0; i < num; i++) { g_print("Connection: (%s to %s)\n", gegl_node_get_operation(node), gegl_node_get_operation(nodes[0]), pads[0]); } g_print("Input from: %s\n", gegl_node_get_operation(gegl_node_get_producer(node, "input", NULL))); // g_print("selected: %s\n", gegl_node_get_operation(node)); guint n_props; GParamSpec** properties = gegl_operation_list_properties(gegl_node_get_operation(node), &n_props); //TODO: only create enough columns for the properties which will actually be included (i.e. ignoring GeglBuffer props) GtkTable *prop_table = GTK_TABLE(gtk_table_new(2, n_props, FALSE)); int d; for(d = 0, i = 0; i < n_props; i++, d++) { GParamSpec* prop = properties[i]; GType type = prop->value_type; const gchar* name = prop->name; GtkWidget* name_label = gtk_label_new(name); gtk_misc_set_alignment(GTK_MISC(name_label), 0, 0.5); GtkWidget* value_entry = gtk_entry_new(); gchar buf[256] = "*"; //can probably be smaller; In fact, can probably do this without sprintf and a buffer. TODO: look at g_string gint i_value; gdouble d_value; gchar* str_value; gboolean skip = FALSE; switch(type) { case G_TYPE_INT: gegl_node_get(node, name, &i_value, NULL); sprintf(buf, "%d", i_value); break; case G_TYPE_DOUBLE: gegl_node_get(node, name, &d_value, NULL); sprintf(buf, "%.3f", d_value); break; case G_TYPE_STRING: gegl_node_get(node, name, &str_value, NULL); sprintf(buf, "%s", str_value); break; } if(type == GEGL_TYPE_BUFFER) { skip = TRUE; d--; } else if( type == GEGL_TYPE_COLOR) { skip = TRUE; GtkWidget *color_button = gtk_button_new_with_label("Select"); select_color_info* info = malloc(sizeof(select_color_info)); info->node = node; info->property = name; info->layer = self; g_signal_connect(color_button, "clicked", (GCallback)select_color, info); gtk_table_attach(prop_table, name_label, 0, 1, d, d+1, GTK_FILL, GTK_FILL, 1, 1); gtk_table_attach(prop_table, color_button, 1, 2, d, d+1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 1, 1); } if(!skip) { gtk_entry_set_text(GTK_ENTRY(value_entry), buf); gtk_entry_set_width_chars(GTK_ENTRY(value_entry), 2); struct text_prop_data *data = malloc(sizeof(struct text_prop_data)); //TODO store this in a list and free it when the node is deselected data->node = node; data->property = name; data->prop_type = type; data->layer = self; g_signal_connect(value_entry, "activate", G_CALLBACK(text_property_changed), data); gtk_table_attach(prop_table, name_label, 0, 1, d, d+1, GTK_FILL, GTK_FILL, 1, 1); gtk_table_attach(prop_table, value_entry, 1, 2, d, d+1, GTK_EXPAND | GTK_FILL | GTK_SHRINK, GTK_FILL, 1, 1); } } // gegl_node_process(node); GeglGtkView *gtk_view = gegl_gtk_view_new_for_node(node); GeglRectangle rect = gegl_node_get_bounding_box(node); if(gegl_rectangle_is_infinite_plane(&rect)) { gegl_gtk_view_set_autoscale_policy(gtk_view, GEGL_GTK_VIEW_AUTOSCALE_DISABLED); gegl_gtk_view_set_scale(gtk_view, 1.0); g_print("Disable autoscale: scale=%f, x=%f, y=%f\n", gegl_gtk_view_get_scale(gtk_view), gegl_gtk_view_get_x(gtk_view), gegl_gtk_view_get_y(gtk_view)); } gtk_widget_show(GTK_WIDGET(gtk_view)); //TODO: draw checkerboard under preview to indicate transparency gtk_box_pack_start(GTK_BOX(self->prop_box), GTK_WIDGET(prop_table), FALSE, TRUE, 0); gtk_box_pack_start(GTK_BOX(self->prop_box), GTK_WIDGET(gtk_view), TRUE, TRUE, 10); GtkWidget* label = gtk_label_new("Click the image\nto open in a\nnew window"); gtk_label_set_justify(GTK_LABEL(label), GTK_JUSTIFY_CENTER); gtk_box_pack_start(GTK_BOX(self->prop_box), label, FALSE, TRUE, 10); gtk_widget_show_all(self->prop_box); }