50#define FADING_MIN 0.0005f
51#define FADING_MAX 1.0f
53#define BORDER_MIN 0.00005f
54#define BORDER_MAX 0.5f
57 int num_points,
int *inside,
int *inside_border,
int *near_handle,
58 int *inside_source,
float *
dist)
75 const float pt[2] = {
x, y };
84 const float center_dx =
x - gpt->
source[0];
85 const float center_dy = y - gpt->
source[1];
86 *
dist = sqf(center_dx) + sqf(center_dy);
94 const float center_dx =
x - gpt->
points[0];
95 const float center_dy = y - gpt->
points[1];
96 *
dist = sqf(center_dx) + sqf(center_dy);
112 int *inside_border,
int *near_handle,
int *inside_source,
float *
dist,
void *user_data)
115 inside_border, near_handle, inside_source,
dist);
128 :
"plugins/darkroom/masks/circle/size");
130 :
"plugins/darkroom/masks/circle/border");
145 float **points,
int *points_count);
152 float radius_shape = 0.0f;
153 float radius_border = 0.0f;
155 radius_border += radius_shape;
163 if(!err && radius_shape != radius_border)
179 increment, flow, _(
"Fading: %3.2f%%"), 100.0f);
187 increment, flow, _(
"Size: %3.2f%%"), 2.f * 100.f);
194 increment, flow, _(
"Opacity: %3.2f%%"), 100.f);
279 if(amount > 1.0f && (circle->
border > 1.0f ))
285 if(node_hovered == -1 || node_hovered == 0)
344 double pressure,
int which,
int type, uint32_t
state,
451 circle->
center[0] = pts[0];
452 circle->
center[1] = pts[1];
478 const double min_step2 = min_step * min_step;
479 double last_x = points[coord_nb * 2 + 2], last_y = points[coord_nb * 2 + 3];
480 cairo_move_to(cr, last_x, last_y);
481 for(
int i = 2;
i < points_count;
i++)
483 const double x = points[
i * 2], y = points[
i * 2 + 1];
484 const double dx =
x - last_x, dy = y - last_y;
485 if((dx * dx + dy * dy) < min_step2)
continue;
486 cairo_line_to(cr,
x, y);
487 last_x =
x; last_y = y;
489 cairo_close_path(cr);
496 const size_t l = (size_t)(2.0f *
M_PI *
r);
504 *points_count = l + 1;
509 const float center_x =
center[0];
510 const float center_y =
center[1];
511 points[0] = center_x;
512 points[1] = center_y;
514 for(
int i = 1;
i < l + 1;
i++)
516 const float alpha = (
i - 1) * 2.0f *
M_PI / (
float)l;
517 points[
i * 2] = center_x +
r * cosf(alpha);
518 points[
i * 2 + 1] = center_y +
r * sinf(alpha);
524 float radius2,
float rotation,
float **points,
int *points_count,
530 const float wd =
geometry.raw_width;
531 const float ht =
geometry.raw_height;
542 float **points,
int *points_count)
547 const float wd =
geometry.raw_width;
548 const float ht =
geometry.raw_height;
624 int *points_count,
float **
border,
int *border_count,
629 if(!
IS_NULL_PTR(border_skips)) *border_skips = NULL;
630 if(!
IS_NULL_PTR(border_skip_count)) *border_skip_count = 0;
639 float y = circle->
center[1];
642 float xs = form->
source[0];
643 float ys = form->
source[1];
645 _circle_get_points_source(dev,
x, y, xs, ys, circle->
radius, circle->
radius, 0.0f, points, points_count, module));
679 const float outer_radius = circle->
radius + circle->
border;
681 float *
const restrict points =
714 const float outer_radius = circle->
radius + circle->
border;
716 float *
const restrict points =
736 float **buffer,
int *
width,
int *
height,
int *posx,
int *posy)
765 const float pos_x = *posx;
766 const float pos_y = *posy;
768 for(
int i = 0;
i < h;
i++)
770 float *
const restrict
p = points + 2 *
i * w;
771 const float y =
i + pos_y;
773 for(
int j = 0; j < w; j++)
808 float *
const restrict ptbuffer = *buffer;
810 const int mindim =
MIN(wi, hi);
811 const float centerx = circle->center[0] * wi;
812 const float centery = circle->center[1] * hi;
813 const float radius2 = circle->radius * mindim * circle->radius * mindim;
814 const float total2 = (circle->radius + circle->border) * mindim * (circle->radius + circle->border) * mindim;
815 const float border2 = total2 - radius2;
817 for(
int i = 0 ;
i < h*w;
i++)
820 const float l2 = sqf(points[2 *
i] - centerx) + sqf(points[2 *
i + 1] - centery);
822 const float ratio = (total2 -
l2) / border2;
824 const float f =
CLIP(ratio);
825 ptbuffer[
i] = sqf(
f);
846 double start2 = start1;
854 const float centerx = circle->
center[0] * wi;
855 const float centery = circle->
center[1] * hi;
856 const int min_dimention =
MIN(wi, hi);
857 const float total_radius = (circle->
radius + circle->
border) * min_dimention;
858 const float sqr_radius = circle->
radius * min_dimention * circle->
radius * min_dimention;
859 const float sqr_total = total_radius * total_radius;
860 const float sqr_border = sqr_total - sqr_radius;
866 const int px = roi->
x;
867 const int py = roi->
y;
870 const float grid_scale = 1.0f /
MAX(roi->
scale, 1e-6f);
871 const int grid = CLAMP((10.0f * grid_scale + 2.0f) / 3.0f, 1, 4);
872 const int grid_width = (
width + grid - 1) / grid + 1;
873 const int grid_height = (
height + grid - 1) / grid + 1;
890 for(
int n = 0;
n < circpts / 8;
n++)
892 const float phi = (2.0f *
M_PI *
n) / circpts;
893 const float x = total_radius * cosf(phi);
894 const float y = total_radius * sinf(phi);
895 const float cx = centerx;
896 const float cy = centery;
897 const int index_x = 2 *
n * 8;
898 const int index_y = 2 *
n * 8 + 1;
900 circ[index_x] = cx +
x;
901 circ[index_y] = cy + y;
902 circ[index_x + 2] = cx +
x;
903 circ[index_y + 2] = cy - y;
904 circ[index_x + 4] = cx -
x;
905 circ[index_y + 4] = cy + y;
906 circ[index_x + 6] = cx -
x;
907 circ[index_y + 6] = cy - y;
908 circ[index_x + 8] = cx + y;
909 circ[index_y + 8] = cy +
x;
910 circ[index_x + 10] = cx + y;
911 circ[index_y + 10] = cy -
x;
912 circ[index_x + 12] = cx - y;
913 circ[index_y + 12] = cy +
x;
914 circ[index_x + 14] = cx - y;
915 circ[index_y + 14] = cy -
x;
933 float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN;
934 for(
int n = 0;
n < circpts;
n++)
937 if(!(isnormal(circ[2 *
n]) && isnormal(circ[2 *
n + 1])))
continue;
939 xmin =
MIN(xmin, circ[2 *
n]);
940 xmax =
MAX(xmax, circ[2 *
n]);
941 ymin =
MIN(ymin, circ[2 *
n + 1]);
942 ymax =
MAX(ymax, circ[2 *
n + 1]);
946 printf(
"xmin %f, xmax %f, ymin %f, ymax %f\n", xmin, xmax, ymin, ymax);
947 printf(
"wi %d, hi %d, iscale %f\n", wi, hi,
iscale);
948 printf(
"w %d, h %d, px %d, py %d\n", w, h, px, py);
952 const int bbxm = CLAMP((
int)floorf(xmin /
iscale - px) / grid - 1, 0, grid_width - 1);
953 const int bbXM = CLAMP((
int)ceilf(xmax /
iscale - px) / grid + 2, 0, grid_width - 1);
954 const int bbym = CLAMP((
int)floorf(ymin /
iscale - py) / grid - 1, 0, grid_height - 1);
955 const int bbYM = CLAMP((
int)ceilf(ymax /
iscale - py) / grid + 2, 0, grid_height - 1);
956 const int bbw = bbXM - bbxm + 1;
957 const int bbh = bbYM - bbym + 1;
960 printf(
"bbxm %d, bbXM %d, bbym %d, bbYM %d\n", bbxm, bbXM, bbym, bbYM);
961 printf(
"gw %d, gh %d, bbw %d, bbh %d\n", gw,
gh, bbw, bbh);
974 if(bbw <= 1 || bbh <= 1)
978 = { .
x0 = bbxm, .y0 = bbym, .width = bbw, .height = bbh,
979 .step = grid, .px = px, .py = py, .iscale =
iscale };
980 float *
const restrict points
988 for(
int j = 0; j < bbh; j++)
989 for(
int i = 0;
i < bbw;
i++)
991 const size_t index = (size_t)j * bbw +
i;
993 const float l2 = sqf(points[2 * index] - centerx) + sqf(points[2 * index + 1] - centery);
995 const float ratio = (sqr_total -
l2) / sqr_border;
997 const float f = CLAMP(ratio, 0.0f, 1.0f);
998 points[2*index] =
f *
f;
1010 int endx = 0, endy = 0;
1043 snprintf(form->
name,
sizeof(form->
name), _(
"circle #%d"), (
int)nb);
1047 char *
const restrict msgbuf,
const size_t msgbuf_len)
1054 g_strlcat(msgbuf, _(
"<b>Set source</b>: Shift+Click"), msgbuf_len);
1057 g_strlcat(msgbuf, _(
"<b>Move source</b>: Drag"), msgbuf_len);
1059 g_strlcat(msgbuf, _(
"<b>Move</b>: Drag"), msgbuf_len);
Handle default and user-set shortcuts (accelerators)
static double dist(double x1, double y1, double x2, double y2)
typedef void((*dt_cache_allocate_t)(void *userdata, dt_cache_entry_t *entry))
static float _circle_set_interaction_value(dt_masks_form_t *form, dt_masks_interaction_t interaction, float value, dt_masks_increment_t increment, int flow, dt_masks_form_gui_t *gui, struct dt_iop_module_t *module)
static void _circle_sanitize_config(dt_masks_type_t type)
static void _circle_initial_source_pos(dt_develop_t *dev, const float iwd, const float iht, float *x, float *y)
static int _circle_events_mouse_scrolled(struct dt_iop_module_t *module, double x, double y, int up, const int flow, uint32_t state, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index, dt_masks_interaction_t interaction)
static void _circle_duplicate_points(dt_develop_t *dev, dt_masks_form_t *const base, dt_masks_form_t *const dest)
static int _find_closest_handle(dt_masks_form_t *mask_form, dt_masks_form_gui_t *mask_gui, int form_index)
static void _circle_init_new(dt_masks_form_t *form, dt_masks_form_gui_t *gui, dt_masks_node_circle_t *circle)
static int _circle_events_mouse_moved(struct dt_iop_module_t *module, double x, double y, double pressure, int which, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index)
static void _circle_events_post_expose(cairo_t *cr, float zoom_scale, dt_masks_form_gui_t *gui, int index, int num_points)
static void _circle_set_hint_message(const dt_masks_form_gui_t *const gui, const dt_masks_form_t *const form, char *const restrict msgbuf, const size_t msgbuf_len)
static float _circle_get_interaction_value(const dt_masks_form_t *form, dt_masks_interaction_t interaction)
static dt_masks_raster_result_t _circle_get_area(const dt_iop_module_t *const restrict module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const restrict piece, dt_masks_form_t *const restrict form, int *width, int *height, int *posx, int *posy)
static gboolean _circle_get_gravity_center(dt_develop_t *dev, const dt_masks_form_t *form, float center[2], float *area)
static float * _points_to_transform(dt_develop_t *dev, float x, float y, float radius, float wd, float ht, int *points_count)
static int _circle_get_points(dt_develop_t *dev, float x, float y, float radius, float radius2, float rotation, float **points, int *points_count)
static int _change_fading(dt_masks_form_t *form, dt_masks_form_gui_t *gui, struct dt_iop_module_t *module, int index, const float amount, const dt_masks_increment_t increment, const int flow)
static int _init_opacity(dt_masks_form_t *form, const float amount, const dt_masks_increment_t increment, const int flow)
static void _circle_distance_cb(float pointer_x, float pointer_y, float cursor_radius, dt_masks_form_gui_t *mask_gui, int form_index, int node_count, int *inside, int *inside_border, int *near_handle, int *inside_source, float *dist, void *user_data)
Circle-specific inside/border hit testing adapter.
static int _change_size(dt_masks_form_t *form, dt_masks_form_gui_t *gui, struct dt_iop_module_t *module, int index, const float amount, const dt_masks_increment_t increment, const int flow)
static void _circle_get_distance(float x, float y, float as, dt_masks_form_gui_t *gui, int index, int num_points, int *inside, int *inside_border, int *near_handle, int *inside_source, float *dist)
static int _circle_events_button_released(struct dt_iop_module_t *module, double x, double y, int which, uint32_t state, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index)
static void _circle_get_creation_values(const dt_masks_form_t *form, float *radius, float *border)
static int _init_size(dt_masks_form_t *form, const float amount, const dt_masks_increment_t increment, const int flow)
static void _circle_set_form_name(struct dt_masks_form_t *const form, const size_t nb)
const dt_masks_functions_t dt_masks_functions_circle
static dt_masks_raster_result_t _circle_get_mask_roi(const dt_iop_module_t *const restrict module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const restrict piece, dt_masks_form_t *const form, const dt_iop_roi_t *const roi, float *const restrict buffer, dt_iop_roi_t *touched)
static int _circle_get_creation_preview(dt_masks_form_t *form, dt_masks_form_gui_t *gui, dt_masks_preview_buffers_t *preview)
static dt_masks_raster_result_t _circle_get_points_border(dt_develop_t *dev, struct dt_masks_form_t *form, float **points, int *points_count, float **border, int *border_count, dt_masks_skip_range_t **border_skips, int *border_skip_count, int source, const dt_iop_module_t *module)
static int _init_fading(dt_masks_form_t *form, const float amount, const dt_masks_increment_t increment, const int flow)
static void _circle_draw_shape(dt_develop_t *dev, cairo_t *cr, const float *points, const int points_count, const int coord_nb, const gboolean border, const gboolean source, const dt_masks_skip_range_t *skips, const int skip_count)
static int _circle_get_points_source(dt_develop_t *dev, float x, float y, float xs, float ys, float radius, float radius2, float rotation, float **points, int *points_count, const dt_iop_module_t *module)
static int _circle_events_key_pressed(struct dt_iop_module_t *module, GdkEventKey *event, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index)
static dt_masks_raster_result_t _circle_get_source_area(dt_iop_module_t *module, dt_dev_pixelpipe_t *pipe, dt_dev_pixelpipe_iop_t *piece, dt_masks_form_t *form, int *width, int *height, int *posx, int *posy)
static int _circle_events_button_pressed(struct dt_iop_module_t *module, double x, double y, double pressure, int which, int type, uint32_t state, dt_masks_form_t *form, int parentid, dt_masks_form_gui_t *gui, int index)
static dt_masks_raster_result_t _circle_get_mask(const dt_iop_module_t *const restrict module, dt_dev_pixelpipe_t *pipe, const dt_dev_pixelpipe_iop_t *const restrict piece, dt_masks_form_t *const restrict form, float **buffer, int *width, int *height, int *posx, int *posy)
float dt_conf_get_float(const char *name)
Float for name, clamped to its declared bounds.
float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
int dt_get_num_openmp_threads(void)
Number of OpenMP threads the application decided to use.
dt_dev_image_geometry_t dt_dev_geometry_snapshot(const dt_develop_t *dev)
int dt_dev_coordinates_raw_abs_to_image_abs(dt_develop_t *dev, float *points, size_t points_count)
void dt_dev_coordinates_raw_norm_to_raw_abs(dt_develop_t *dev, float *points, size_t num_points)
int dt_dev_distort_transform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
int dt_dev_distort_backtransform_plus(const dt_dev_pixelpipe_t *pipe, const double iop_order, const int transf_direction, float *points, size_t points_count)
@ DT_DEV_TRANSFORM_DIR_BACK_INCL
GtkWidget * geometry
its size, under the preview
GtkWidget * preview
what the selected row actually captures
GHashTable * selected
set of checked row labels, mirrored to conf on every change
static double dt_draw_min_emit_step(cairo_t *cr)
Stroke a line with style.
static void dt_draw_shape_lines(struct dt_develop_t *dev, const dt_draw_dash_type_t dash_type, const gboolean source, cairo_t *cr, const int nb, const gboolean selected, const float zoom_scale, const float *points, const int points_count, const shape_draw_function_t *draw_shape_func, const cairo_line_cap_t line_cap, const struct dt_masks_skip_range_t *skips, const int skip_count)
Draw the lines of a mask shape.
_lib_location_type_t type
int32_t dt_get_debug_flags(void)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
void dt_masks_points_bounding_box(const float *const points, const int num_points, int *width, int *height, int *posx, int *posy)
void dt_masks_sample_grid_interpolate(const float *const points, const dt_masks_sample_grid_t *const grid, float *const buffer, const int buf_width, const int buf_height, int *const endx, int *const endy)
float * dt_masks_sample_grid_backtransform(struct dt_dev_pixelpipe_t *pipe, const double iop_order, const dt_masks_sample_grid_t *const grid, const char *const shape, const char *const form_name)
static dt_masks_raster_result_t dt_masks_raster_from_status(const int status)
dt_masks_raster_result_t
What a rasterisation attempt produced.
void dt_masks_duplicate_points(const dt_masks_form_t *base, dt_masks_form_t *dest, size_t node_size)
Duplicate a points list for a mask using a fixed node size.
int dt_masks_form_change_opacity(dt_develop_t *dev, dt_masks_form_t *form, int parentid, int up, const int flow)
static gboolean dt_masks_form_is_clone(const dt_masks_form_t *form)
static int dt_masks_roundup(int num, int mult)
static gboolean dt_masks_form_uses_spot_defaults(const dt_masks_form_t *form)
static void dt_masks_reset_source(dt_masks_form_t *form)
The per-shape function table, private to the masks implementation.
int dt_masks_point_in_form_exact(const float *pts, int num_pts, const float *points, int points_start, int points_count, const dt_masks_skip_range_t *skips, int skip_count)
Ray-cast point-in-polygon over a form point stream, honouring skip ranges.
int dt_masks_points_shift_to_source(struct dt_develop_t *dev, const struct dt_iop_module_t *module, float **points, int *points_count, const float xs, const float ys, const int first_shifted)
int dt_masks_preview_add_clone_source(struct dt_masks_form_gui_t *gui, struct dt_masks_preview_buffers_t *preview)
void dt_masks_draw_source(cairo_t *cr, dt_masks_form_gui_t *mask_gui, const int form_index, const int node_count, const float zoom_scale, struct dt_masks_gui_center_point_t *center_point, const shape_draw_function_t *draw_shape_func)
Draw the source for a correction mask.
dt_masks_form_t * dt_masks_get_visible_form(const dt_develop_t *dev)
Return the currently visible form used by the masks GUI.
float dt_masks_apply_increment(float current, float amount, dt_masks_increment_t increment, int flow)
Apply a scroll increment to a scalar value.
void dt_masks_set_source_pos_initial_value(dt_masks_form_gui_t *mask_gui, dt_masks_form_t *mask_form)
Initialize the clone source position based on current GUI state.
int dt_masks_find_closest_handle_common(dt_masks_form_t *mask_form, dt_masks_form_gui_t *mask_gui, int form_index, int node_count_override, dt_masks_border_handle_fn border_handle_cb, dt_masks_curve_handle_fn curve_handle_cb, dt_masks_node_position_fn node_position_cb, dt_masks_distance_fn distance_cb, dt_masks_post_select_fn post_select_cb, void *user_data)
Centralized hit-testing for node/handle/segment selection across shapes.
void dt_masks_set_source_pos_initial_state(dt_masks_form_gui_t *mask_gui, const uint32_t key_state)
Decide initial source positioning mode for clone masks.
void dt_masks_gui_form_create(dt_masks_form_t *mask_form, dt_masks_form_gui_t *mask_gui, int form_index, dt_iop_module_t *module)
float dt_masks_get_set_conf_value_with_toast(dt_masks_form_t *mask_form, const char *feature, float amount, float value_min, float value_max, dt_masks_increment_t increment, int flow, const char *toast_fmt, float toast_scale)
Update a mask configuration value and emit a toast message.
void dt_masks_gui_form_save_creation(dt_develop_t *develop, dt_iop_module_t *module, dt_masks_form_t *mask_form, dt_masks_form_gui_t *mask_gui)
Save the form creation right after a shape has been finished drawing.
The interactive half of the masks subsystem: the editing state (dt_masks_form_gui_t),...
static void dt_masks_draw_source_preview(cairo_t *cr, const float zoom_scale, dt_masks_form_gui_t *gui, const float initial_xpos, const float initial_ypos, const float xpos, const float ypos, const int adding)
static void dt_masks_gui_cursor_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
static void dt_masks_draw_preview_shape(struct dt_develop_t *dev, cairo_t *cr, const float zoom_scale, const int num_points, float *points, const int points_count, float *border, const int border_count, const shape_draw_function_t *draw_shape, const cairo_line_cap_t shape_cap, const cairo_line_cap_t border_cap, const gboolean save_restore, const gboolean source)
static void dt_masks_preview_buffers_cleanup(dt_masks_preview_buffers_t *buffers)
static gboolean dt_masks_gui_points_reach(const dt_masks_form_gui_points_t *gp, const float x, const float y, const float reach)
static void dt_masks_gui_delta_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
static void dt_masks_touched_set(dt_iop_roi_t *touched, int x0, int y0, int x1, int y1, const int width, const int height)
static void dt_masks_touched_none(dt_iop_roi_t *touched)
@ DT_MASKS_INTERACTION_OPACITY
@ DT_MASKS_INTERACTION_SIZE
@ DT_MASKS_INTERACTION_FADING
@ DT_MASKS_INCREMENT_SCALE
@ DT_MASKS_INCREMENT_OFFSET
#define CLAMPF(a, mn, mx)
static float gh(const float f)
#define __OMP_SIMD__(...)
#define __OMP_PARALLEL_FOR__(...)
#define __OMP_PARALLEL_FOR_SIMD__(...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
static const dt_aligned_pixel_simd_t value
const float uint32_t state[4]
Objective facts about the image a dev is working on.
struct dt_develop_t * dev
Region of interest passed through the pixelpipe.
int(* get_points)(struct dt_develop_t *dev, float x, float y, float radius_a, float radius_b, float rotation, float **points, int *points_count)
shape_draw_function_t draw_shape
struct dt_masks_gui_center_point_t::@27 main
One cut in a shape's border outline: while walking the border buffer forward, on reaching index jump_...
static double dt_get_wtime(void)