45#define HARDNESS_MIN 0.0005f
46#define HARDNESS_MAX 1.0f
48#define BORDER_MIN 0.00005f
49#define BORDER_MAX 0.5f
52 int num_points,
int *inside,
int *inside_border,
int *near,
53 int *inside_source,
float *
dist)
66 const float pt[2] = {
x, y };
75 const float center_dx =
x - gpt->
source[0];
76 const float center_dy = y - gpt->
source[1];
77 *
dist = sqf(center_dx) + sqf(center_dy);
85 const float center_dx =
x - gpt->
points[0];
86 const float center_dy = y - gpt->
points[1];
87 *
dist = sqf(center_dx) + sqf(center_dy);
103 int *inside_border,
int *near,
int *inside_source,
float *
dist,
void *user_data)
106 inside_border, near, inside_source,
dist);
119 :
"plugins/darkroom/masks/circle/size");
121 :
"plugins/darkroom/masks/circle/border");
136 float **points,
int *points_count);
143 float radius_shape = 0.0f;
144 float radius_border = 0.0f;
146 radius_border += radius_shape;
154 if(!err && radius_shape != radius_border)
160 float source_pos[2] = { 0.0f, 0.0f };
162 &source_pos[0], &source_pos[1],
FALSE);
163 const float center_source[2] = { source_pos[0] - gui->
pos[0], source_pos[1] - gui->
pos[1] };
185 increment, flow, _(
"Hardness: %3.2f%%"), 100.0f);
193 increment, flow, _(
"Size: %3.2f%%"), 2.f * 100.f);
200 increment, flow, _(
"Opacity: %3.2f%%"), 100.f);
282 if(amount > 1.0f && (circle->
border > 1.0f ))
288 if(node_hovered == -1 || node_hovered == 0)
334 double pressure,
int which,
int type, uint32_t
state,
441 circle->
center[0] = pts[0];
442 circle->
center[1] = pts[1];
458static void _circle_draw_shape(cairo_t *cr,
const float *points,
const int points_count,
const int coord_nb,
const gboolean
border,
const gboolean source)
460 cairo_move_to(cr, points[coord_nb * 2 + 2], points[coord_nb * 2 + 3]);
461 for(
int i = 2;
i < points_count;
i++)
462 cairo_line_to(cr, points[
i * 2], points[
i * 2 + 1]);
463 cairo_close_path(cr);
470 const size_t l = (size_t)(2.0f *
M_PI *
r);
478 *points_count = l + 1;
483 const float center_x =
center[0];
484 const float center_y =
center[1];
485 points[0] = center_x;
486 points[1] = center_y;
488 for(
int i = 1;
i < l + 1;
i++)
490 const float alpha = (
i - 1) * 2.0f *
M_PI / (
float)l;
491 points[
i * 2] = center_x +
r * cosf(alpha);
492 points[
i * 2 + 1] = center_y +
r * sinf(alpha);
498 float radius2,
float rotation,
float **points,
int *points_count,
514 *points, *points_count))
519 float pts[2] = { xs, ys };
526 const float dx = pts[0] - (*points)[0];
527 const float dy = pts[1] - (*points)[1];
529 for(
int i = 0;
i < *points_count;
i++)
531 (*points)[
i * 2] += dx;
532 (*points)[
i * 2 + 1] += dy;
539 *points, *points_count))
553 float **points,
int *points_count)
634 float xmin = FLT_MAX, xmax = FLT_MIN, ymin = FLT_MAX, ymax = FLT_MIN;
635 for(
int i = 1;
i < num_points;
i++)
637 xmin = fminf(points[
i * 2], xmin);
638 xmax = fmaxf(points[
i * 2], xmax);
639 ymin = fminf(points[
i * 2 + 1], ymin);
640 ymax = fmaxf(points[
i * 2 + 1], ymax);
645 *
width = (xmax - xmin);
650 int *points_count,
float **
border,
int *border_count,
int source,
657 float y = circle->
center[1];
660 float xs = form->
source[0];
661 float ys = form->
source[1];
662 return _circle_get_points_source(dev,
x, y, xs, ys, circle->
radius, circle->
radius, 0.0f, points, points_count, module);
689 const float outer_radius = circle->
radius + circle->
border;
691 float *
const restrict points =
720 const float outer_radius = circle->
radius + circle->
border;
722 float *
const restrict points =
742 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);
840 float *
const restrict buffer)
845 double start2 = start1;
853 const float centerx = circle->
center[0] * wi;
854 const float centery = circle->
center[1] * hi;
855 const int min_dimention =
MIN(wi, hi);
856 const float total_radius = (circle->
radius + circle->
border) * min_dimention;
857 const float sqr_radius = circle->
radius * min_dimention * circle->
radius * min_dimention;
858 const float sqr_total = total_radius * total_radius;
859 const float sqr_border = sqr_total - sqr_radius;
865 const int px = roi->
x;
866 const int py = roi->
y;
869 const float grid_scale = 1.0f /
MAX(roi->
scale, 1e-6f);
870 const int grid = CLAMP((10.0f * grid_scale + 2.0f) / 3.0f, 1, 4);
871 const int grid_width = (
width + grid - 1) / grid + 1;
872 const int grid_height = (
height + grid - 1) / grid + 1;
889 for(
int n = 0;
n < circpts / 8;
n++)
891 const float phi = (2.0f *
M_PI *
n) / circpts;
892 const float x = total_radius * cosf(phi);
893 const float y = total_radius * sinf(phi);
894 const float cx = centerx;
895 const float cy = centery;
896 const int index_x = 2 *
n * 8;
897 const int index_y = 2 *
n * 8 + 1;
899 circ[index_x] = cx +
x;
900 circ[index_y] = cy + y;
901 circ[index_x + 2] = cx +
x;
902 circ[index_y + 2] = cy - y;
903 circ[index_x + 4] = cx -
x;
904 circ[index_y + 4] = cy + y;
905 circ[index_x + 6] = cx -
x;
906 circ[index_y + 6] = cy - y;
907 circ[index_x + 8] = cx + y;
908 circ[index_y + 8] = cy +
x;
909 circ[index_x + 10] = cx + y;
910 circ[index_y + 10] = cy -
x;
911 circ[index_x + 12] = cx - y;
912 circ[index_y + 12] = cy +
x;
913 circ[index_x + 14] = cx - y;
914 circ[index_y + 14] = cy -
x;
932 float xmin = FLT_MAX, ymin = FLT_MAX, xmax = FLT_MIN, ymax = FLT_MIN;
933 for(
int n = 0;
n < circpts;
n++)
936 if(!(isnormal(circ[2 *
n]) && isnormal(circ[2 *
n + 1])))
continue;
938 xmin =
MIN(xmin, circ[2 *
n]);
939 xmax =
MAX(xmax, circ[2 *
n]);
940 ymin =
MIN(ymin, circ[2 *
n + 1]);
941 ymax =
MAX(ymax, circ[2 *
n + 1]);
945 printf(
"xmin %f, xmax %f, ymin %f, ymax %f\n", xmin, xmax, ymin, ymax);
946 printf(
"wi %d, hi %d, iscale %f\n", wi, hi,
iscale);
947 printf(
"w %d, h %d, px %d, py %d\n", w, h, px, py);
951 const int bbxm = CLAMP((
int)floorf(xmin /
iscale - px) / grid - 1, 0, grid_width - 1);
952 const int bbXM = CLAMP((
int)ceilf(xmax /
iscale - px) / grid + 2, 0, grid_width - 1);
953 const int bbym = CLAMP((
int)floorf(ymin /
iscale - py) / grid - 1, 0, grid_height - 1);
954 const int bbYM = CLAMP((
int)ceilf(ymax /
iscale - py) / grid + 2, 0, grid_height - 1);
955 const int bbw = bbXM - bbxm + 1;
956 const int bbh = bbYM - bbym + 1;
959 printf(
"bbxm %d, bbXM %d, bbym %d, bbYM %d\n", bbxm, bbXM, bbym, bbYM);
960 printf(
"gw %d, gh %d, bbw %d, bbh %d\n", gw,
gh, bbw, bbh);
973 if(bbw <= 1 || bbh <= 1)
981 for(
int j = bbym; j <= bbYM; j++)
982 for(
int i = bbxm;
i <= bbXM;
i++)
984 const size_t index = (size_t)(j - bbym) * bbw +
i - bbxm;
985 points[index * 2] = (grid *
i + px) *
iscale;
986 points[index * 2 + 1] = (grid * j + py) *
iscale;
1013 for(
int j = 0; j < bbh; j++)
1014 for(
int i = 0;
i < bbw;
i++)
1016 const size_t index = (size_t)j * bbw +
i;
1018 const float l2 = sqf(points[2 * index] - centerx) + sqf(points[2 * index + 1] - centery);
1020 const float ratio = (sqr_total -
l2) / sqr_border;
1022 const float f = CLAMP(ratio, 0.0f, 1.0f);
1023 points[2*index] =
f *
f;
1035 const int endx =
MIN(
width, bbXM * grid);
1036 const int endy =
MIN(
height, bbYM * grid);
1037 const float inv_grid2 = 1.0f / (grid * grid);
1039 for(
int i = 0;
i < grid;
i++)
1041 w0[
i] = (float)(grid -
i);
1045 for(
int j = bbym * grid; j < endy; j++)
1047 const int jj = j % grid;
1048 const int mj = j / grid - bbym;
1049 const float wj0 = w0[jj];
1050 const float wj1 =
w1[jj];
1051 const size_t row_base = (size_t)mj * bbw;
1052 float *
const row = buffer + (size_t)j *
width;
1055 for(
int i = bbxm * grid;
i < endx;
i++)
1057 const size_t mindex = row_base + mi;
1058 const float wii0 = w0[ii];
1059 const float wii1 =
w1[ii];
1060 row[
i] = (points[mindex * 2] * wii0 * wj0
1061 + points[(mindex + 1) * 2] * wii1 * wj0
1062 + points[(mindex + bbw) * 2] * wii0 * wj1
1063 + points[(mindex + bbw + 1) * 2] * wii1 * wj1) * inv_grid2;
1101 snprintf(form->
name,
sizeof(form->
name), _(
"circle #%d"), (
int)nb);
1105 const int opacity,
char *
const restrict msgbuf,
const size_t msgbuf_len)
1108 g_snprintf(msgbuf, msgbuf_len,
1109 _(
"<b>Size</b>: scroll, <b>Hardness</b>: shift+scroll\n"
1110 "<b>Opacity</b>: ctrl+scroll (%d%%)"), opacity);
static double dist(double x1, double y1, double x2, double y2)
static void error(char *msg)
static const dt_aligned_pixel_simd_t const dt_adaptation_t const float p
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_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, int *inside_source, float *dist)
static void _circle_sanitize_config(dt_masks_type_t type)
static float * _points_to_transform(float x, float y, float radius, float wd, float ht, int *points_count)
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 int _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)
static void _circle_init_new(dt_masks_form_t *form, dt_masks_form_gui_t *gui, dt_masks_node_circle_t *circle)
static int _init_hardness(dt_masks_form_t *form, const float amount, const dt_masks_increment_t increment, const int flow)
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 float _circle_get_interaction_value(const dt_masks_form_t *form, dt_masks_interaction_t interaction)
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 _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, 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 int _circle_get_points_border(dt_develop_t *dev, struct dt_masks_form_t *form, float **points, int *points_count, float **border, int *border_count, int source, const dt_iop_module_t *module)
static int _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 _change_hardness(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 _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 int _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)
static gboolean _circle_get_gravity_center(const dt_masks_form_t *form, float center[2], float *area)
static void _circle_initial_source_pos(const float iwd, const float iht, float *x, float *y)
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 int _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 int _circle_get_creation_preview(dt_masks_form_t *form, dt_masks_form_gui_t *gui, dt_masks_preview_buffers_t *preview)
static void _circle_draw_shape(cairo_t *cr, const float *points, const int points_count, const int coord_nb, const gboolean border, const gboolean source)
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 void _bounding_box(const float *const points, int num_points, 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 void _circle_set_hint_message(const dt_masks_form_gui_t *const gui, const dt_masks_form_t *const form, const int opacity, char *const restrict msgbuf, const size_t msgbuf_len)
const dt_aligned_pixel_t f
float dt_conf_get_float(const char *name)
float dt_conf_get_and_sanitize_float(const char *name, float min, float max)
void dt_print(dt_debug_thread_t thread, const char *msg,...)
#define __OMP_SIMD__(...)
#define dt_pixelpipe_cache_alloc_align_float_cache(pixels, id)
#define dt_pixelpipe_cache_free_align(mem)
#define __OMP_PARALLEL_FOR__(...)
static const dt_aligned_pixel_simd_t value
static double dt_get_wtime(void)
#define __OMP_PARALLEL_FOR_SIMD__(...)
static gboolean dt_modifier_is(const GdkModifierType state, const GdkModifierType desired_modifier_mask)
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
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_EXCL
@ DT_DEV_TRANSFORM_DIR_BACK_INCL
@ DT_DEV_TRANSFORM_DIR_FORW_INCL
static void dt_draw_shape_lines(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)
Draw the lines of a mask shape.
void dt_masks_calculate_source_pos_origin(dt_masks_form_gui_t *gui, const float initial_xpos, const float initial_ypos, const float xpos, const float ypos, float *px, float *py, const int adding)
Compute preview-space source position for drawing the clone indicator.
void dt_masks_gui_form_create(dt_masks_form_t *form, dt_masks_form_gui_t *gui, int index, struct dt_iop_module_t *module)
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)
int dt_masks_form_change_opacity(dt_masks_form_t *form, int parentid, int up, const int flow)
int dt_masks_point_in_form_exact(const float *pts, int num_pts, const float *points, int points_start, int points_count)
Check whether any 2D point in pts[] lies inside the form points[].
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.
void dt_masks_gui_form_save_creation(dt_develop_t *dev, struct dt_iop_module_t *module, dt_masks_form_t *form, dt_masks_form_gui_t *gui)
Save the form creation right after a shape has been finished drawing.
void dt_masks_draw_source(cairo_t *cr, dt_masks_form_gui_t *gui, const int index, const int nb, 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_INTERACTION_HARDNESS
@ DT_MASKS_INTERACTION_SIZE
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_preview_buffers_cleanup(dt_masks_preview_buffers_t *buffers)
float dt_masks_apply_increment(float current, float amount, dt_masks_increment_t increment, int flow)
Apply a scroll increment to a scalar value.
static gboolean dt_masks_form_is_clone(const dt_masks_form_t *form)
float dt_masks_get_set_conf_value_with_toast(dt_masks_form_t *form, const char *feature, float amount, float v_min, float v_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.
@ DT_MASKS_INCREMENT_SCALE
@ DT_MASKS_INCREMENT_OFFSET
void dt_masks_set_source_pos_initial_value(dt_masks_form_gui_t *gui, dt_masks_form_t *form)
Initialize the clone source position based on current GUI state.
static int dt_masks_roundup(int num, int mult)
static void dt_masks_draw_preview_shape(cairo_t *cr, const float zoom_scale, const int num_points, float *points, const int points_count, float *border, const int border_count, void(*const *draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source), const cairo_line_cap_t shape_cap, const cairo_line_cap_t border_cap, const gboolean save_restore, const gboolean source)
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)
Shared selection logic for node/handle/segment hit testing.
dt_masks_form_t * dt_masks_get_visible_form(const struct dt_develop_t *dev)
static void dt_masks_gui_delta_to_raw_norm(dt_develop_t *dev, const dt_masks_form_gui_t *gui, float point[2])
void dt_masks_set_source_pos_initial_state(dt_masks_form_gui_t *gui, const uint32_t state)
Decide initial source positioning mode for clone masks.
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)
#define CLAMPF(a, mn, mx)
static float gh(const float f)
const float uint32_t state[4]
int32_t num_openmp_threads
struct dt_develop_t * develop
struct dt_dev_pixelpipe_t * virtual_pipe
struct dt_develop_t::@17 roi
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)
void(* draw_shape)(cairo_t *cr, const float *points, const int points_count, const int nb, const gboolean border, const gboolean source)
struct dt_masks_gui_center_point_t::@34 main