static void pixelize (gfloat *input, gfloat *output, const GeglRectangle *roi, const GeglRectangle *extended_roi, const GeglRectangle *whole_region, GeglProperties *o) { gint start_x = block_index (roi->x, o->size_x) * o->size_x; gint start_y = block_index (roi->y, o->size_y) * o->size_y; gint x, y; gint off_shape_x, off_shape_y; gfloat color[4]; GeglRectangle rect_shape; rect_shape.width = ceilf (o->size_x * (gfloat)o->ratio_x); rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y); off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f); off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f); for (y = start_y; y < roi->y + roi->height; y += o->size_y) for (x = start_x; x < roi->x + roi->width; x += o->size_x) { GeglRectangle rect = {x, y, o->size_x, o->size_y}; GeglRectangle rect2; rect_shape.x = x + off_shape_x; rect_shape.y = y + off_shape_y; gegl_rectangle_intersect (&rect, whole_region, &rect); if (rect.width < 1 || rect.height < 1) continue; rect2.x = rect.x - extended_roi->x; rect2.y = rect.y - extended_roi->y; rect2.width = rect.width; rect2.height = rect.height; mean_rectangle (input, &rect2, extended_roi->width, color); gegl_rectangle_intersect (&rect, roi, &rect); rect2.x = rect.x - roi->x; rect2.y = rect.y - roi->y; rect2.width = rect.width; rect2.height = rect.height; rect_shape.x -= roi->x; rect_shape.y -= roi->y; set_rectangle (output, &rect2, &rect_shape, roi->width, color, o->norm); } }
static gboolean gimp_operation_normal_parent_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { #if 0 /* this code tries to be smart but is in fact just a too stupid * copy from gegl's normal mode. to fix it, it needs to take * mask and opacity into account */ const GeglRectangle *in_extent = NULL; const GeglRectangle *aux_extent = NULL; GObject *input; GObject *aux; /* get the raw values this does not increase the reference count */ input = gegl_operation_context_get_object (context, "input"); aux = gegl_operation_context_get_object (context, "aux"); /* pass the input/aux buffers directly through if they are not * overlapping */ if (input) in_extent = gegl_buffer_get_abyss (GEGL_BUFFER (input)); if (! input || (aux && ! gegl_rectangle_intersect (NULL, in_extent, result))) { gegl_operation_context_set_object (context, "output", aux); return TRUE; } if (aux) aux_extent = gegl_buffer_get_abyss (GEGL_BUFFER (aux)); if (! aux || (input && ! gegl_rectangle_intersect (NULL, aux_extent, result))) { gegl_operation_context_set_object (context, "output", input); return TRUE; } #endif /* chain up, which will create the needed buffers for our actual * process function */ return GEGL_OPERATION_CLASS (parent_class)->process (operation, context, output_prop, result, level); }
int main(int argc, char *argv[]) { GeglRectangle expected_infinite_plane = gegl_rectangle_infinite_plane (); GeglRectangle infinite_plane = { INFINITE_PLANE }; int result = SUCCESS; int i = 0; /* Make sure our representation of an infinite plane GeglRectangle * is correct */ if (! gegl_rectangle_equal (&infinite_plane, &expected_infinite_plane)) { result = FAILURE; g_printerr("This test case and GEGL does not represent an infinite plane\n" "GeglRectangle in the same way, update this test case. Aborting.\n"); goto abort; } for (i = 0; i < G_N_ELEMENTS (tests); i++) { GeglRectangle result_rect; gboolean return_value; /* gegl_rectangle_bounding_box() */ gegl_rectangle_bounding_box (&result_rect, &tests[i].rect1, &tests[i].rect2); if (! gegl_rectangle_equal (&result_rect, &tests[i].bounding_box_result)) { result = FAILURE; g_printerr("The gegl_rectangle_bounding_box() test #%d failed. Aborting.\n", i + 1); goto abort; } /* gegl_rectangle_intersect() */ return_value = gegl_rectangle_intersect (&result_rect, &tests[i].rect1, &tests[i].rect2); if (! gegl_rectangle_equal (&result_rect, &tests[i].intersect_result) || return_value != tests[i].intersect_return_value) { result = FAILURE; g_printerr("The gegl_rectangle_intersect() test #%d failed. Aborting.\n", i + 1); goto abort; } /* gegl_rectangle_contains() */ return_value = gegl_rectangle_contains (&tests[i].rect1, &tests[i].rect2); if (return_value != tests[i].contains_return_value) { result = FAILURE; g_printerr("The gegl_rectangle_contains() test #%d failed. Aborting.\n", i + 1); goto abort; } } abort: return result; }
/* Fast paths */ static gboolean operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_prop, const GeglRectangle *result, gint level) { GeglOperationClass *operation_class; gpointer input, aux; operation_class = GEGL_OPERATION_CLASS (gegl_chant_parent_class); /* get the raw values this does not increase the reference count */ input = gegl_operation_context_get_object (context, "input"); aux = gegl_operation_context_get_object (context, "aux"); /* pass the input/aux buffers directly through if they are alone*/ { const GeglRectangle *in_extent = NULL; const GeglRectangle *aux_extent = NULL; if (input) in_extent = gegl_buffer_get_abyss (input); if ((!input || (aux && !gegl_rectangle_intersect (NULL, in_extent, result)))) { gegl_operation_context_take_object (context, "output", g_object_ref (aux)); return TRUE; } if (aux) aux_extent = gegl_buffer_get_abyss (aux); if (!aux || (input && !gegl_rectangle_intersect (NULL, aux_extent, result))) { gegl_operation_context_take_object (context, "output", g_object_ref (input)); return TRUE; } } /* chain up, which will create the needed buffers for our actual * process function */ return operation_class->process (operation, context, output_prop, result, level); }
static void pixelize_noalloc (GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, const GeglRectangle *whole_region, GeglProperties *o) { gint start_x = block_index (roi->x, o->size_x) * o->size_x; gint start_y = block_index (roi->y, o->size_y) * o->size_y; gint x, y; gint off_shape_x, off_shape_y; GeglColor *color = gegl_color_new ("white"); GeglRectangle rect_shape; rect_shape.width = ceilf (o->size_x * (gfloat)o->ratio_x); rect_shape.height = ceilf (o->size_y * (gfloat)o->ratio_y); off_shape_x = floorf ((o->size_x - (gfloat)o->ratio_x * o->size_x) / 2.0f); off_shape_y = floorf ((o->size_y - (gfloat)o->ratio_y * o->size_y) / 2.0f); for (y = start_y; y < roi->y + roi->height; y += o->size_y) for (x = start_x; x < roi->x + roi->width; x += o->size_x) { GeglRectangle rect = {x, y, o->size_x, o->size_y}; gegl_rectangle_intersect (&rect, whole_region, &rect); if (rect.width < 1 || rect.height < 1) continue; mean_rectangle_noalloc (input, &rect, color); gegl_rectangle_intersect (&rect, roi, &rect); rect_shape.x = x + off_shape_x; rect_shape.y = y + off_shape_y; set_rectangle_noalloc (output, &rect, &rect_shape, color, o->norm); } g_object_unref (color); }
static gboolean photos_operation_svg_multiply_operation_process (GeglOperation *operation, GeglOperationContext *context, const gchar *output_pad, const GeglRectangle *roi, gint level) { GObject *aux; GObject *input; const GeglRectangle *aux_bbox = NULL; const GeglRectangle *in_bbox = NULL; gboolean ret_val = TRUE; aux = gegl_operation_context_get_object (context, "aux"); if (aux != NULL) aux_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (aux)); input = gegl_operation_context_get_object (context, "input"); if (input != NULL) in_bbox = gegl_buffer_get_abyss (GEGL_BUFFER (input)); if (aux == NULL || (input != NULL && !gegl_rectangle_intersect (NULL, aux_bbox, roi))) { gegl_operation_context_set_object (context, "output", input); goto out; } if (input == NULL || (aux != NULL && !gegl_rectangle_intersect (NULL, in_bbox, roi))) { gegl_operation_context_set_object (context, "output", aux); goto out; } ret_val = GEGL_OPERATION_CLASS (photos_operation_svg_multiply_parent_class)->process (operation, context, output_pad, roi, level); out: return ret_val; }
static void set_rectangle (gfloat *output, GeglRectangle *rect, GeglRectangle *rect_shape, gint rowstride, gfloat *color, GeglPixelizeNorm norm) { gint c, x, y; gfloat center_x, center_y; GeglRectangle rect2; gfloat shape_area = rect_shape->width * rect_shape->height; center_x = rect_shape->x + rect_shape->width / 2.0f; center_y = rect_shape->y + rect_shape->height / 2.0f; gegl_rectangle_intersect (&rect2, rect, rect_shape); switch (norm) { case (GEGL_PIXELIZE_NORM_INFINITY): for (y = rect2.y; y < rect2.y + rect2.height; y++) for (x = rect2.x; x < rect2.x + rect2.width; x++) for (c = 0; c < 4; c++) output [4 * (y * rowstride + x) + c] = color[c]; break; case (GEGL_PIXELIZE_NORM_EUCLIDEAN): for (y = rect->y; y < rect->y + rect->height; y++) for (x = rect->x; x < rect->x + rect->width; x++) if (SQR ((x - center_x) / (gfloat) rect_shape->width) + SQR ((y - center_y) / (gfloat) rect_shape->height) <= 1.0f) for (c = 0; c < 4; c++) output [4 * (y * rowstride + x) + c] = color[c]; break; case (GEGL_PIXELIZE_NORM_MANHATTAN): for (y = rect->y; y < rect->y + rect->height; y++) for (x = rect->x; x < rect->x + rect->width; x++) if (fabsf (center_x - x) * rect_shape->height + fabsf (center_y - y) * rect_shape->width < shape_area) for (c = 0; c < 4; c++) output [4 * (y * rowstride + x) + c] = color[c]; break; } }
static GeglRectangle gegl_crop_get_required_for_output (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *roi) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglRectangle result; result.x = o->x; result.y = o->y; result.width = o->width; result.height = o->height; gegl_rectangle_intersect (&result, &result, roi); return result; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { gint i, j; gfloat *buf1, *buf2, *buf3; if (gegl_operation_use_opencl (operation)) if (cl_process (operation, input, output, result)) return TRUE; buf1 = g_new (gfloat, SQR (CHUNK_SIZE + LAPLACE_RADIUS * 2) * 4); buf2 = g_new (gfloat, SQR (CHUNK_SIZE + LAPLACE_RADIUS * 2) * 4); buf3 = g_new (gfloat, SQR (CHUNK_SIZE) * 4); for (j = 0; (j-1) * CHUNK_SIZE < result->height; j++) for (i = 0; (i-1) * CHUNK_SIZE < result->width; i++) { GeglRectangle chunked_result; GeglRectangle compute; chunked_result = *GEGL_RECTANGLE (result->x + i * CHUNK_SIZE, result->y + j * CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); gegl_rectangle_intersect (&chunked_result, &chunked_result, result); if (chunked_result.width < 1 || chunked_result.height < 1) continue; compute = gegl_operation_get_required_for_output (operation, "input", &chunked_result); edge_laplace (input, &compute, output, &chunked_result, buf1, buf2, buf3); } g_free (buf1); g_free (buf2); g_free (buf3); return TRUE; }
static GeglRectangle gegl_crop_get_invalidated_by_change (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *input_region) { GeglProperties *o = GEGL_PROPERTIES (operation); GeglRectangle result; result.x = o->x; result.y = o->y; result.width = o->width; result.height = o->height; gegl_rectangle_intersect (&result, &result, input_region); return result; }
void gegl_buffer_cl_cache_invalidate (GeglBuffer *buffer, const GeglRectangle *roi) { GeglRectangle tmp; GList *elem; gpointer data; for (elem=cache_entries; elem; elem=elem->next) { CacheEntry *e = elem->data; if (e->valid && e->buffer == buffer && (!roi || gegl_rectangle_intersect (&tmp, roi, &e->roi))) { g_assert (e->used == 0); gegl_clReleaseMemObject (e->tex); e->valid = FALSE; } } g_mutex_lock (&cache_mutex); while (cache_entry_find_invalid (&data)) { CacheEntry *entry = data; memset(entry, 0x0, sizeof (CacheEntry)); g_slice_free (CacheEntry, data); cache_entries = g_list_remove (cache_entries, data); } g_mutex_unlock (&cache_mutex); #if 0 g_printf ("-- "); for (elem=cache_entry; elem; elem=elem->next) { CacheEntry *e = elem->data; g_printf ("%p %p {%d, %d, %d, %d} %d | ", e->tex, e->buffer, e->roi.x, e->roi.y, e->roi.width, e->roi.height, e->valid); } g_printf ("\n"); #endif }
static void retile_subs (GeglBufferIterator *iter, int x, int y) { GeglBufferIteratorPriv *priv = iter->priv; GeglRectangle real_roi; int index; int shift_x = priv->origin_tile.x; int shift_y = priv->origin_tile.y; int tile_x = gegl_tile_indice (x + shift_x, priv->origin_tile.width); int tile_y = gegl_tile_indice (y + shift_y, priv->origin_tile.height); /* Reset tile size */ real_roi.x = (tile_x * priv->origin_tile.width) - shift_x; real_roi.y = (tile_y * priv->origin_tile.height) - shift_y; real_roi.width = priv->origin_tile.width; real_roi.height = priv->origin_tile.height; /* Trim tile down to the iteration roi */ gegl_rectangle_intersect (&iter->roi[0], &real_roi, &priv->sub_iter[0].full_rect); priv->sub_iter[0].real_roi = iter->roi[0]; for (index = 1; index < priv->num_buffers; index++) { SubIterState *lead_sub = &priv->sub_iter[0]; SubIterState *sub = &priv->sub_iter[index]; int roi_offset_x = sub->full_rect.x - lead_sub->full_rect.x; int roi_offset_y = sub->full_rect.y - lead_sub->full_rect.y; iter->roi[index].x = iter->roi[0].x + roi_offset_x; iter->roi[index].y = iter->roi[0].y + roi_offset_y; iter->roi[index].width = iter->roi[0].width; iter->roi[index].height = iter->roi[0].height; sub->real_roi = iter->roi[index]; } }
static GeglRectangle get_required_for_output (GeglOperation *operation, const gchar *input_pad, const GeglRectangle *region) { GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation); GeglRectangle rect; GeglRectangle defined; defined = get_bounding_box (operation); gegl_rectangle_intersect (&rect, region, &defined); if (rect.width != 0 && rect.height != 0) { rect.x -= area->left; rect.y -= area->top; rect.width += area->left + area->right; rect.height += area->top + area->bottom; } return rect; }
static void set_rectangle_noalloc (GeglBuffer *output, GeglRectangle *rect, GeglRectangle *rect_shape, GeglColor *color, GeglPixelizeNorm norm) { if (norm == GEGL_PIXELIZE_NORM_INFINITY) { GeglRectangle rect2; gegl_rectangle_intersect (&rect2, rect, rect_shape); gegl_buffer_set_color (output, &rect2, color); } else { GeglBufferIterator *gi; gint c, x, y; gfloat col[4]; gfloat center_x, center_y; gfloat shape_area = rect_shape->width * rect_shape->height; center_x = rect_shape->x + rect_shape->width / 2.0f; center_y = rect_shape->y + rect_shape->height / 2.0f; gegl_color_get_pixel (color, babl_format ("RaGaBaA float"), col); gi = gegl_buffer_iterator_new (output, rect, 0, babl_format ("RaGaBaA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_CLAMP); while (gegl_buffer_iterator_next (gi)) { gfloat *data = (gfloat*) gi->data[0]; GeglRectangle roi = gi->roi[0]; switch (norm) { case (GEGL_PIXELIZE_NORM_EUCLIDEAN): for (y = 0; y < roi.height; y++) for (x = 0; x < roi.width; x++) if (SQR ((x + roi.x - center_x) / (gfloat) rect_shape->width) + SQR ((y + roi.y - center_y) / (gfloat) rect_shape->height) <= 1.0f) for (c = 0; c < 4; c++) data [4 * (y * roi.width + x) + c] = col[c]; break; case (GEGL_PIXELIZE_NORM_MANHATTAN): for (y = 0; y < roi.height; y++) for (x = 0; x < roi.width; x++) if (fabsf (x + roi.x - center_x) * rect_shape->height + fabsf (y + roi.y - center_y) * rect_shape->width < shape_area) for (c = 0; c < 4; c++) data [4 * (y * roi.width + x) + c] = col[c]; break; case (GEGL_PIXELIZE_NORM_INFINITY): break; } } } }
static int gimp_mypaint_surface_draw_dab (MyPaintSurface *base_surface, float x, float y, float radius, float color_r, float color_g, float color_b, float opaque, float hardness, float color_a, float aspect_ratio, float angle, float lock_alpha, float colorize) { GimpMybrushSurface *surface = (GimpMybrushSurface *)base_surface; GeglBufferIterator *iter; GeglRectangle dabRect; GimpComponentMask component_mask = surface->component_mask; const float one_over_radius2 = 1.0f / (radius * radius); const double angle_rad = angle / 360 * 2 * M_PI; const float cs = cos(angle_rad); const float sn = sin(angle_rad); float normal_mode; float segment1_slope; float segment2_slope; float r_aa_start; hardness = CLAMP (hardness, 0.0f, 1.0f); segment1_slope = -(1.0f / hardness - 1.0f); segment2_slope = -hardness / (1.0f - hardness); aspect_ratio = MAX (1.0f, aspect_ratio); r_aa_start = radius - 1.0f; r_aa_start = MAX (r_aa_start, 0); r_aa_start = (r_aa_start * r_aa_start) / aspect_ratio; normal_mode = opaque * (1.0f - colorize); colorize = opaque * colorize; /* FIXME: This should use the real matrix values to trim aspect_ratio dabs */ dabRect = calculate_dab_roi (x, y, radius); gegl_rectangle_intersect (&dabRect, &dabRect, gegl_buffer_get_extent (surface->buffer)); if (dabRect.width <= 0 || dabRect.height <= 0) return 0; gegl_rectangle_bounding_box (&surface->dirty, &surface->dirty, &dabRect); iter = gegl_buffer_iterator_new (surface->buffer, &dabRect, 0, babl_format ("R'G'B'A float"), GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); if (surface->paint_mask) { GeglRectangle mask_roi = dabRect; mask_roi.x -= surface->paint_mask_x; mask_roi.y -= surface->paint_mask_y; gegl_buffer_iterator_add (iter, surface->paint_mask, &mask_roi, 0, babl_format ("Y float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); } while (gegl_buffer_iterator_next (iter)) { float *pixel = (float *)iter->data[0]; float *mask; int iy, ix; if (surface->paint_mask) mask = iter->data[1]; else mask = NULL; for (iy = iter->roi[0].y; iy < iter->roi[0].y + iter->roi[0].height; iy++) { for (ix = iter->roi[0].x; ix < iter->roi[0].x + iter->roi[0].width; ix++) { float rr, base_alpha, alpha, dst_alpha, r, g, b, a; if (radius < 3.0f) rr = calculate_rr_antialiased (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2, r_aa_start); else rr = calculate_rr (ix, iy, x, y, aspect_ratio, sn, cs, one_over_radius2); base_alpha = calculate_alpha_for_rr (rr, hardness, segment1_slope, segment2_slope); alpha = base_alpha * normal_mode; if (mask) alpha *= *mask; dst_alpha = pixel[ALPHA]; /* a = alpha * color_a + dst_alpha * (1.0f - alpha); * which converts to: */ a = alpha * (color_a - dst_alpha) + dst_alpha; r = pixel[RED]; g = pixel[GREEN]; b = pixel[BLUE]; if (a > 0.0f) { /* By definition the ratio between each color[] and pixel[] component in a non-pre-multipled blend always sums to 1.0f. * Originaly this would have been "(color[n] * alpha * color_a + pixel[n] * dst_alpha * (1.0f - alpha)) / a", * instead we only calculate the cheaper term. */ float src_term = (alpha * color_a) / a; float dst_term = 1.0f - src_term; r = color_r * src_term + r * dst_term; g = color_g * src_term + g * dst_term; b = color_b * src_term + b * dst_term; } if (colorize > 0.0f && base_alpha > 0.0f) { alpha = base_alpha * colorize; a = alpha + dst_alpha - alpha * dst_alpha; if (a > 0.0f) { GimpHSL pixel_hsl, out_hsl; GimpRGB pixel_rgb = {color_r, color_g, color_b}; GimpRGB out_rgb = {r, g, b}; float src_term = alpha / a; float dst_term = 1.0f - src_term; gimp_rgb_to_hsl (&pixel_rgb, &pixel_hsl); gimp_rgb_to_hsl (&out_rgb, &out_hsl); out_hsl.h = pixel_hsl.h; out_hsl.s = pixel_hsl.s; gimp_hsl_to_rgb (&out_hsl, &out_rgb); r = (float)out_rgb.r * src_term + r * dst_term; g = (float)out_rgb.g * src_term + g * dst_term; b = (float)out_rgb.b * src_term + b * dst_term; } } if (component_mask != GIMP_COMPONENT_MASK_ALL) { if (component_mask & GIMP_COMPONENT_MASK_RED) pixel[RED] = r; if (component_mask & GIMP_COMPONENT_MASK_GREEN) pixel[GREEN] = g; if (component_mask & GIMP_COMPONENT_MASK_BLUE) pixel[BLUE] = b; if (component_mask & GIMP_COMPONENT_MASK_ALPHA) pixel[ALPHA] = a; } else { pixel[RED] = r; pixel[GREEN] = g; pixel[BLUE] = b; pixel[ALPHA] = a; } pixel += 4; if (mask) mask += 1; } } } return 1; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglOperationAreaFilter *area = GEGL_OPERATION_AREA_FILTER (operation); GeglProperties *o = GEGL_PROPERTIES (operation); GeglBuffer *dest, *dest_tmp; GeglRectangle working_region; GeglRectangle *whole_region; GeglBufferIterator *iter; whole_region = gegl_operation_source_get_bounding_box (operation, "input"); working_region.x = result->x - area->left; working_region.width = result->width + area->left + area->right; working_region.y = result->y - area->top; working_region.height = result->height + area->top + area->bottom; gegl_rectangle_intersect (&working_region, &working_region, whole_region); dest_tmp = gegl_buffer_new (&working_region, babl_format ("Y' float")); iter = gegl_buffer_iterator_new (dest_tmp, &working_region, 0, babl_format ("Y' float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, &working_region, 0, babl_format ("Y' float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint i; gfloat *data_out = iter->data[0]; gfloat *data_in = iter->data[1]; for (i = 0; i < iter->length; i++) { /* compute sigmoidal transfer */ gfloat val = *data_in; val = 1.0 / (1.0 + exp (-(SIGMOIDAL_BASE + (o->sharpness * SIGMOIDAL_RANGE)) * (val - 0.5))); val = val * o->brightness; *data_out = CLAMP (val, 0.0, 1.0); data_out +=1; data_in +=1; } } dest = grey_blur_buffer (dest_tmp, o->glow_radius, result); iter = gegl_buffer_iterator_new (output, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_WRITE, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, input, result, 0, babl_format ("RGBA float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); gegl_buffer_iterator_add (iter, dest, result, 0, babl_format ("Y' float"), GEGL_ACCESS_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (iter)) { gint i; gfloat *data_out = iter->data[0]; gfloat *data_in = iter->data[1]; gfloat *data_blur = iter->data[2]; for (i = 0; i < iter->length; i++) { gint c; for (c = 0; c < 3; c++) { gfloat tmp = (1.0 - data_in[c]) * (1.0 - *data_blur); data_out[c] = CLAMP (1.0 - tmp, 0.0, 1.0); } data_out[3] = data_in[3]; data_out += 4; data_in += 4; data_blur+= 1; } } g_object_unref (dest); g_object_unref (dest_tmp); return TRUE; }
static gboolean gimp_channel_combine_start (GimpChannel *mask, GimpChannelOps op, const GeglRectangle *rect, gboolean full_extent, gboolean full_value, GimpChannelCombineData *data) { GeglBuffer *buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); GeglRectangle extent; gboolean intersects; extent.x = 0; extent.y = 0; extent.width = gimp_item_get_width (GIMP_ITEM (mask)); extent.height = gimp_item_get_height (GIMP_ITEM (mask)); intersects = gegl_rectangle_intersect (&data->rect, rect, &extent); data->bounds_known = mask->bounds_known; data->empty = mask->empty; data->bounds.x = mask->x1; data->bounds.y = mask->y1; data->bounds.width = mask->x2 - mask->x1; data->bounds.height = mask->y2 - mask->y1; gegl_buffer_freeze_changed (buffer); /* Determine new boundary */ switch (op) { case GIMP_CHANNEL_OP_REPLACE: gimp_channel_combine_clear (mask, NULL); if (! intersects) { data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } data->bounds_known = FALSE; if (full_extent) { data->bounds_known = TRUE; data->empty = FALSE; data->bounds = data->rect; } break; case GIMP_CHANNEL_OP_ADD: if (! intersects) return FALSE; data->bounds_known = FALSE; if (full_extent && (mask->bounds_known || gegl_rectangle_equal (&data->rect, &extent))) { data->bounds_known = TRUE; data->empty = FALSE; if (mask->bounds_known && ! mask->empty) { gegl_rectangle_bounding_box (&data->bounds, &data->bounds, &data->rect); } else { data->bounds = data->rect; } } break; case GIMP_CHANNEL_OP_SUBTRACT: if (intersects && mask->bounds_known) { if (mask->empty) { intersects = FALSE; } else { intersects = gegl_rectangle_intersect (&data->rect, &data->rect, &data->bounds); } } if (! intersects) return FALSE; if (full_value && gegl_rectangle_contains (&data->rect, mask->bounds_known ? &data->bounds : &extent)) { gimp_channel_combine_clear (mask, NULL); data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } data->bounds_known = FALSE; gegl_buffer_set_abyss (buffer, &data->rect); break; case GIMP_CHANNEL_OP_INTERSECT: if (intersects && mask->bounds_known) { if (mask->empty) { intersects = FALSE; } else { intersects = gegl_rectangle_intersect (&data->rect, &data->rect, &data->bounds); } } if (! intersects) { gimp_channel_combine_clear (mask, NULL); data->bounds_known = TRUE; data->empty = TRUE; return FALSE; } if (full_value && mask->bounds_known && gegl_rectangle_contains (&data->rect, &data->bounds)) { return FALSE; } data->bounds_known = FALSE; gimp_channel_combine_clear_complement (mask, &data->rect); gegl_buffer_set_abyss (buffer, &data->rect); break; } return TRUE; }
static inline gboolean _gegl_buffer_cl_cache_flush2 (GeglTileHandlerCache *cache, const GeglRectangle *roi) { size_t size; GList *elem; GeglRectangle tmp; cl_int cl_err = 0; gpointer data; gboolean need_cl = FALSE; for (elem=cache_entries; elem; elem=elem->next) { CacheEntry *entry = elem->data; if (entry->valid && entry->tile_storage->cache == cache && (!roi || gegl_rectangle_intersect (&tmp, roi, &entry->roi))) { entry->valid = FALSE; entry->used ++; gegl_cl_color_babl (entry->buffer->soft_format, &size); data = g_malloc(entry->roi.width * entry->roi.height * size); cl_err = gegl_clEnqueueReadBuffer(gegl_cl_get_command_queue(), entry->tex, CL_TRUE, 0, entry->roi.width * entry->roi.height * size, data, 0, NULL, NULL); /* tile-ize */ gegl_buffer_set (entry->buffer, &entry->roi, 0, entry->buffer->soft_format, data, GEGL_AUTO_ROWSTRIDE); entry->used --; need_cl = TRUE; g_free(data); CL_CHECK; } } if (need_cl) { cl_err = gegl_clFinish (gegl_cl_get_command_queue ()); CL_CHECK; g_mutex_lock (&cache_mutex); while (cache_entry_find_invalid (&data)) { CacheEntry *entry = data; #if 1 GEGL_NOTE (GEGL_DEBUG_OPENCL, "Removing from cl-cache: %p %s {%d %d %d %d}", entry->buffer, babl_get_name(entry->buffer->soft_format), entry->roi.x, entry->roi.y, entry->roi.width, entry->roi.height); #endif gegl_clReleaseMemObject(entry->tex); memset (entry, 0x0, sizeof (CacheEntry)); g_slice_free (CacheEntry, data); cache_entries = g_list_remove (cache_entries, data); } g_mutex_unlock (&cache_mutex); } return TRUE; error: g_mutex_lock (&cache_mutex); while (cache_entry_find_invalid (&data)) { g_slice_free (CacheEntry, data); cache_entries = g_list_remove (cache_entries, data); } g_mutex_unlock (&cache_mutex); /* XXX : result is corrupted */ return FALSE; }
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; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *roi, gint level) { GeglRectangle src_rect; GeglRectangle *whole_region; GeglProperties *o = GEGL_PROPERTIES (operation); GeglOperationAreaFilter *op_area; op_area = GEGL_OPERATION_AREA_FILTER (operation); whole_region = gegl_operation_source_get_bounding_box (operation, "input"); if (gegl_operation_use_opencl (operation)) if (cl_process (operation, input, output, roi)) return TRUE; if (o->size_x * o->size_y < SQR (ALLOC_THRESHOLD_SIZE)) { gfloat background_color[4]; gfloat *input_buf = g_new (gfloat, (CHUNK_SIZE + o->size_x * 2) * (CHUNK_SIZE + o->size_y * 2) * 4); gfloat *output_buf = g_new (gfloat, SQR (CHUNK_SIZE) * 4); gint i, j; gegl_color_get_pixel (o->background, babl_format("RaGaBaA float"), background_color); for (j = 0; (j-1) * CHUNK_SIZE < roi->height; j++) for (i = 0; (i-1) * CHUNK_SIZE < roi->width; i++) { GeglRectangle chunked_result; GeglRectangle chunked_sizes; chunked_result = *GEGL_RECTANGLE (roi->x + i * CHUNK_SIZE, roi->y + j * CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); gegl_rectangle_intersect (&chunked_result, &chunked_result, roi); if (chunked_result.width < 1 || chunked_result.height < 1) continue; src_rect = chunked_result; src_rect.x -= op_area->left; src_rect.y -= op_area->top; src_rect.width += op_area->left + op_area->right; src_rect.height += op_area->top + op_area->bottom; gegl_buffer_get (input, &src_rect, 1.0, babl_format ("RaGaBaA float"), input_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); gegl_rectangle_copy (&chunked_sizes, &chunked_result); chunked_sizes.x = 0; chunked_sizes.y = 0; set_rectangle (output_buf, &chunked_sizes, &chunked_sizes, chunked_result.width, background_color, GEGL_PIXELIZE_NORM_INFINITY); pixelize (input_buf, output_buf, &chunked_result, &src_rect, whole_region, o); gegl_buffer_set (output, &chunked_result, 0, babl_format ("RaGaBaA float"), output_buf, GEGL_AUTO_ROWSTRIDE); } g_free (input_buf); g_free (output_buf); } else { gegl_buffer_set_color (output, roi, o->background); pixelize_noalloc (input, output, roi, whole_region, o); } return TRUE; }
static GObject * gegl_buffer_constructor (GType type, guint n_params, GObjectConstructParam *params) { GObject *object; GeglBuffer *buffer; GeglTileBackend *backend; GeglTileHandler *handler; GeglTileSource *source; object = G_OBJECT_CLASS (parent_class)->constructor (type, n_params, params); buffer = GEGL_BUFFER (object); handler = GEGL_TILE_HANDLER (object); source = handler->source; backend = gegl_buffer_backend (buffer); if (source) { if (GEGL_IS_TILE_STORAGE (source)) buffer->format = GEGL_TILE_STORAGE (source)->format; else if (GEGL_IS_BUFFER (source)) buffer->format = GEGL_BUFFER (source)->format; } else { if (buffer->backend) { backend = buffer->backend; buffer->format = gegl_tile_backend_get_format (backend); } else { gboolean use_ram = FALSE; const char *maybe_path = NULL; if (!buffer->format) { g_warning ("Buffer constructed without format, assuming RGBA float"); buffer->format = babl_format("RGBA float"); } /* make a new backend & storage */ if (buffer->path) maybe_path = buffer->path; else maybe_path = gegl_config ()->swap; if (maybe_path) use_ram = g_ascii_strcasecmp (maybe_path, "ram") == 0; else use_ram = TRUE; if (use_ram == TRUE) { backend = g_object_new (GEGL_TYPE_TILE_BACKEND_RAM, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, NULL); } else { if (buffer->path) { backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, "path", buffer->path, NULL); } else { gchar *path = get_next_swap_path(); backend = g_object_new (GEGL_TYPE_TILE_BACKEND_FILE, "tile-width", buffer->tile_width, "tile-height", buffer->tile_height, "format", buffer->format, "path", path, NULL); g_free (path); } } buffer->backend = backend; } source = GEGL_TILE_SOURCE (gegl_tile_storage_new (backend)); gegl_tile_handler_set_source ((GeglTileHandler*)(buffer), source); g_object_unref (source); g_object_unref (backend); } /* Connect to the changed signal of source, this is used by some backends * (e.g. File) to notify of outside changes to the buffer. */ if (GEGL_IS_TILE_STORAGE (source)) { g_signal_connect (source, "changed", G_CALLBACK (gegl_buffer_storage_changed), buffer); } g_assert (backend); if (buffer->extent.width == -1 || buffer->extent.height == -1) /* no specified extents, inheriting from source */ { if (GEGL_IS_BUFFER (source)) { buffer->extent.x = GEGL_BUFFER (source)->extent.x; buffer->extent.y = GEGL_BUFFER (source)->extent.y; buffer->extent.width = GEGL_BUFFER (source)->extent.width; buffer->extent.height = GEGL_BUFFER (source)->extent.height; } else if (GEGL_IS_TILE_STORAGE (source)) { buffer->extent.x = 0; buffer->extent.y = 0; buffer->extent.width = GEGL_TILE_STORAGE (source)->width; buffer->extent.height = GEGL_TILE_STORAGE (source)->height; } else { buffer->extent.x = 0; buffer->extent.y = 0; buffer->extent.width = 0; buffer->extent.height = 0; } } buffer->abyss_tracks_extent = FALSE; if (buffer->abyss.width == 0 && buffer->abyss.height == 0 && buffer->abyss.x == 0 && buffer->abyss.y == 0) /* 0 sized extent == inherit buffer extent */ { buffer->abyss.x = buffer->extent.x; buffer->abyss.y = buffer->extent.y; buffer->abyss.width = buffer->extent.width; buffer->abyss.height = buffer->extent.height; buffer->abyss_tracks_extent = TRUE; } else if (buffer->abyss.width == 0 && buffer->abyss.height == 0) { g_warning ("peculiar abyss dimensions: %i,%i %ix%i", buffer->abyss.x, buffer->abyss.y, buffer->abyss.width, buffer->abyss.height); } else if (buffer->abyss.width == -1 || buffer->abyss.height == -1) { buffer->abyss.x = GEGL_BUFFER (source)->abyss.x - buffer->shift_x; buffer->abyss.y = GEGL_BUFFER (source)->abyss.y - buffer->shift_y; buffer->abyss.width = GEGL_BUFFER (source)->abyss.width; buffer->abyss.height = GEGL_BUFFER (source)->abyss.height; } /* intersect our own abyss with parent's abyss if it exists */ if (GEGL_IS_BUFFER (source)) { GeglRectangle parent; GeglRectangle request; GeglRectangle self; parent.x = GEGL_BUFFER (source)->abyss.x - buffer->shift_x; parent.y = GEGL_BUFFER (source)->abyss.y - buffer->shift_y; parent.width = GEGL_BUFFER (source)->abyss.width; parent.height = GEGL_BUFFER (source)->abyss.height; request.x = buffer->abyss.x; request.y = buffer->abyss.y; request.width = buffer->abyss.width; request.height = buffer->abyss.height; gegl_rectangle_intersect (&self, &parent, &request); /* Don't have the abyss track the extent if the intersection is * not the entire extent. Otherwise, setting the extent identical * to itself could suddenly make the abyss bigger. */ if (buffer->abyss_tracks_extent && (buffer->extent.x != self.x || buffer->extent.y != self.y || buffer->extent.width != self.width || buffer->extent.height != self.height) ) { buffer->abyss_tracks_extent = FALSE; } buffer->abyss.x = self.x; buffer->abyss.y = self.y; buffer->abyss.width = self.width; buffer->abyss.height = self.height; } /* compute our own total shift <- this should probably happen * approximatly first */ if (GEGL_IS_BUFFER (source)) { GeglBuffer *source_buf; source_buf = GEGL_BUFFER (source); buffer->shift_x += source_buf->shift_x; buffer->shift_y += source_buf->shift_y; } else { } buffer->tile_storage = gegl_buffer_tile_storage (buffer); /* intialize the soft format to be equivalent to the actual * format */ buffer->soft_format = buffer->format; return object; }
static gboolean process (GeglOperation *operation, GeglBuffer *input, GeglBuffer *output, const GeglRectangle *result, gint level) { GeglChantO *o = GEGL_CHANT_PROPERTIES (operation); LensValues lens; GeglRectangle boundary; gint i, j; gfloat *src_buf, *dst_buf; gfloat background[4]; boundary = *gegl_operation_source_get_bounding_box (operation, "input"); lens = lens_setup_calc (o, boundary); src_buf = g_new0 (gfloat, SQR (MAX_WH) * 4); dst_buf = g_new0 (gfloat, SQR (CHUNK_SIZE) * 4); gegl_color_get_pixel (o->background, babl_format ("RGBA float"), background); for (j = 0; (j-1) * CHUNK_SIZE < result->height; j++) for (i = 0; (i-1) * CHUNK_SIZE < result->width; i++) { GeglRectangle chunked_result; GeglRectangle area; gint x, y; chunked_result = *GEGL_RECTANGLE (result->x + i * CHUNK_SIZE, result->y + j * CHUNK_SIZE, CHUNK_SIZE, CHUNK_SIZE); gegl_rectangle_intersect (&chunked_result, &chunked_result, result); if (chunked_result.width < 1 || chunked_result.height < 1) continue; area = get_required (&boundary, &chunked_result, operation); clamp_area (&area, lens.centre_x, lens.centre_y); gegl_buffer_get (input, &area, 1.0, babl_format ("RGBA float"), src_buf, GEGL_AUTO_ROWSTRIDE, GEGL_ABYSS_CLAMP); for (y = chunked_result.y; y < chunked_result.y + chunked_result.height; y++) for (x = chunked_result.x; x < chunked_result.x + chunked_result.width; x++) { lens_distort_func (src_buf, dst_buf, &area, &chunked_result, &boundary, &lens, x, y, input, background); } gegl_buffer_set (output, &chunked_result, 0, babl_format ("RGBA float"), dst_buf, GEGL_AUTO_ROWSTRIDE); } g_free (dst_buf); g_free (src_buf); return TRUE; }
void gegl_graph_prepare_request (GeglGraphTraversal *path, const GeglRectangle *request_roi, gint level) { GList *list_iter = NULL; static const GeglRectangle empty_rect = {0, 0, 0, 0}; g_return_if_fail (path->bfs_path); if (path->rects_dirty) { /* Zero all the needs rects so we can intersect with them below */ for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperationContext *context = g_hash_table_lookup (path->contexts, node); /* We only need to reset the need rect, result will always get overwritten */ gegl_operation_context_set_need_rect (context, &empty_rect); /* Reset cached status, because the rect we need may have changed */ context->cached = FALSE; } } path->rects_dirty = TRUE; { /* Prep the first node */ GeglNode *node = GEGL_NODE (path->bfs_path->data); GeglOperationContext *context = g_hash_table_lookup (path->contexts, node); GeglRectangle new_need; g_return_if_fail (context); gegl_rectangle_intersect (&new_need, &node->have_rect, request_roi); gegl_operation_context_set_need_rect (context, &new_need); gegl_operation_context_set_result_rect (context, &new_need); } /* Iterate over all the nodes and propagate the requested rectangle */ for (list_iter = path->bfs_path; list_iter; list_iter = list_iter->next) { GeglNode *node = GEGL_NODE (list_iter->data); GeglOperation *operation = node->operation; GeglOperationContext *context; GeglRectangle *request; GSList *input_pads; context = g_hash_table_lookup (path->contexts, node); g_return_if_fail (context); request = gegl_operation_context_get_need_rect (context); if (request->width == 0 || request->height == 0) { gegl_operation_context_set_result_rect (context, &empty_rect); continue; } if (node->cache) { gint i; for (i = level; i >=0 && !context->cached; i--) { if (gegl_region_rect_in (node->cache->valid_region[level], request) == GEGL_OVERLAP_RECTANGLE_IN) { /* This node is cached and the cache fulfills our need rect */ context->cached = TRUE; gegl_operation_context_set_result_rect (context, &empty_rect); } } if (context->cached) continue; } { /* Expand request if the operation has a minimum processing requirement */ GeglRectangle full_request = gegl_operation_get_cached_region (operation, request); gegl_operation_context_set_need_rect (context, &full_request); /* FIXME: We could trim this down based on the cache, instead of being all or nothing */ gegl_operation_context_set_result_rect (context, request); for (input_pads = node->input_pads; input_pads; input_pads = input_pads->next) { GeglPad *source_pad = gegl_pad_get_connected_to (input_pads->data); if (source_pad) { GeglNode *source_node = gegl_pad_get_node (source_pad); GeglOperationContext *source_context = g_hash_table_lookup (path->contexts, source_node); const gchar *pad_name = gegl_pad_get_name (input_pads->data); GeglRectangle rect, current_need, new_need; /* Combine this need rect with any existing request */ rect = gegl_operation_get_required_for_output (operation, pad_name, &full_request); current_need = *gegl_operation_context_get_need_rect (source_context); gegl_rectangle_bounding_box (&new_need, &rect, ¤t_need); /* Limit request to the nodes output */ gegl_rectangle_intersect (&new_need, &source_node->have_rect, &new_need); gegl_operation_context_set_need_rect (source_context, &new_need); } } } } }
static void gimp_channel_combine_clear (GimpChannel *mask, const GeglRectangle *rect) { GeglBuffer *buffer; GeglRectangle area; GeglRectangle update_area; if (mask->bounds_known && mask->empty) return; buffer = gimp_drawable_get_buffer (GIMP_DRAWABLE (mask)); if (rect) { if (rect->width <= 0 || rect->height <= 0) return; if (mask->bounds_known) { if (! gegl_rectangle_intersect (&area, GEGL_RECTANGLE (mask->x1, mask->y1, mask->x2 - mask->x1, mask->y2 - mask->y1), rect)) { return; } } else { area = *rect; } update_area = area; } else { if (mask->bounds_known) { area.x = mask->x1; area.y = mask->y1; area.width = mask->x2 - mask->x1; area.height = mask->y2 - mask->y1; } else { area.x = 0; area.y = 0; area.width = gimp_item_get_width (GIMP_ITEM (mask)); area.height = gimp_item_get_height (GIMP_ITEM (mask)); } update_area = area; gimp_gegl_rectangle_align_to_tile_grid (&area, &area, buffer); } gegl_buffer_clear (buffer, &area); gimp_drawable_update (GIMP_DRAWABLE (mask), update_area.x, update_area.y, update_area.width, update_area.height); }
static void stamp (GeglChantO *o, const GeglRectangle *result, gdouble x, gdouble y) { WarpPrivate *priv = (WarpPrivate*) o->chant_data; GeglBufferIterator *it; const Babl *format; gdouble influence; gdouble x_mean = 0.0; gdouble y_mean = 0.0; gint x_iter, y_iter; GeglRectangle area = {x - o->size / 2.0, y - o->size / 2.0, o->size, o->size}; /* first point of the stroke */ if (!priv->last_point_set) { priv->last_x = x; priv->last_y = y; priv->last_point_set = TRUE; return; } /* don't stamp if outside the roi treated */ if (!gegl_rectangle_intersect (NULL, result, &area)) return; format = babl_format_n (babl_type ("float"), 2); /* If needed, compute the mean deformation */ if (o->behavior == GEGL_WARP_BEHAVIOR_SMOOTH) { gint pixel_count = 0; it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READ, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (it)) { gint n_pixels = it->length; gfloat *coords = it->data[0]; while (n_pixels--) { x_mean += coords[0]; y_mean += coords[1]; coords += 2; } pixel_count += it->roi->width * it->roi->height; } x_mean /= pixel_count; y_mean /= pixel_count; } it = gegl_buffer_iterator_new (priv->buffer, &area, 0, format, GEGL_BUFFER_READWRITE, GEGL_ABYSS_NONE); while (gegl_buffer_iterator_next (it)) { /* iterate inside the stamp roi */ gint n_pixels = it->length; gfloat *coords = it->data[0]; x_iter = it->roi->x; /* initial x */ y_iter = it->roi->y; /* and y coordinates */ while (n_pixels--) { influence = 0.01 * o->strength * get_stamp_force (o, x_iter - x, y_iter - y); switch (o->behavior) { case GEGL_WARP_BEHAVIOR_MOVE: coords[0] += influence * (priv->last_x - x); coords[1] += influence * (priv->last_y - y); break; case GEGL_WARP_BEHAVIOR_GROW: coords[0] -= 2.0 * influence * (x_iter - x) / o->size; coords[1] -= 2.0 * influence * (y_iter - y) / o->size; break; case GEGL_WARP_BEHAVIOR_SHRINK: coords[0] += 2.0 * influence * (x_iter - x) / o->size; coords[1] += 2.0 * influence * (y_iter - y) / o->size; break; case GEGL_WARP_BEHAVIOR_SWIRL_CW: coords[0] += 3.0 * influence * (y_iter - y) / o->size; coords[1] -= 5.0 * influence * (x_iter - x) / o->size; break; case GEGL_WARP_BEHAVIOR_SWIRL_CCW: coords[0] -= 3.0 * influence * (y_iter - y) / o->size; coords[1] += 5.0 * influence * (x_iter - x) / o->size; break; case GEGL_WARP_BEHAVIOR_ERASE: coords[0] *= 1.0 - MIN (influence, 1.0); coords[1] *= 1.0 - MIN (influence, 1.0); break; case GEGL_WARP_BEHAVIOR_SMOOTH: coords[0] -= influence * (coords[0] - x_mean); coords[1] -= influence * (coords[1] - y_mean); break; } coords += 2; /* update x and y coordinates */ x_iter++; if (x_iter >= (it->roi->x + it->roi->width)) { x_iter = it->roi->x; y_iter++; } } } /* Memorize the stamp location for movement dependant behavior like move */ priv->last_x = x; priv->last_y = y; }