Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Added Bézier handles to path masks, so the control points can be moved independently #17204

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
193 changes: 191 additions & 2 deletions src/develop/masks.h
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,24 @@ typedef enum dt_masks_source_pos_type_t
DT_MASKS_SOURCE_POS_ABSOLUTE = 2
} dt_masks_source_pos_type_t;

/* selected Bézier control point for path*/
typedef enum dt_masks_path_ctrl_t
{
DT_MASKS_PATH_CRTL_NONE = 0,
DT_MASKS_PATH_CTRL1 = 1,
DT_MASKS_PATH_CTRL2 = 2

} dt_masks_path_ctrl_t;

/* restrictions on moving Bézier control points */
typedef enum dt_masks_path_edit_mode_t
{
DT_MASKS_BEZIER_NONE = 0, // preserve angle & scale
DT_MASKS_BEZIER_SINGLE = 1, // no restriction
DT_MASKS_BEZIER_SYMMETRIC = 2, // force full symmetry
DT_MASKS_BEZIER_SING_SYMM = 3 // SINGLE && SYMMETRIC => force angle symmetry only
} dt_masks_path_edit_mode_t;

/** structure used to store 1 point for a circle */
typedef struct dt_masks_point_circle_t
{
Expand Down Expand Up @@ -345,6 +363,14 @@ typedef struct dt_masks_dynbuf_t
size_t size;
} dt_masks_dynbuf_t;

typedef struct dt_masks_intbuf_t
{
int *buffer;
char tag[128];
size_t pos;
size_t size;
} dt_masks_intbuf_t;


/** structure used to display a form */
typedef struct dt_masks_form_gui_t
Expand All @@ -367,6 +393,7 @@ typedef struct dt_masks_form_gui_t
int point_selected;
int point_edited;
int feather_selected;
dt_masks_path_ctrl_t bezier_ctrl; // For paths, this selects a Bézier control point.
int seg_selected;
int point_border_selected;
int source_pos_type;
Expand All @@ -378,9 +405,13 @@ typedef struct dt_masks_form_gui_t
gboolean gradient_toggling;
int point_dragging;
int feather_dragging;
int seg_dragging;
int seg_dragging;
int point_border_dragging;

dt_masks_path_edit_mode_t bezier_mode; // Bézier editing with shift or ctrl
float bezier_ctrl_angle; // angle between ctrl1 and ctrl2
float bezier_ctrl_scale; // length of ctrl2 relative to ctrl1

int group_edited;
int group_selected;

Expand Down Expand Up @@ -694,7 +725,11 @@ void dt_group_events_post_expose(cairo_t *cr,
dt_masks_form_t *form,
dt_masks_form_gui_t *gui);

/** code for dynamic handling of intermediate buffers */

/******************************************************
* code for dynamic handling of intermediate buffers
* buffer for floats
*/
static inline gboolean _dt_masks_dynbuf_growto(dt_masks_dynbuf_t *a,
const size_t newsize)
{
Expand Down Expand Up @@ -827,6 +862,15 @@ float dt_masks_dynbuf_get(dt_masks_dynbuf_t *a, const int offset)
return (a->buffer[a->pos + offset]);
}

static inline
float dt_masks_dynbuf_get_absolute(dt_masks_dynbuf_t *a, const int position)
{
assert(a != NULL);
assert(position >= 0);
assert((long)a->pos > position);
return (a->buffer[position]);
}

static inline
void dt_masks_dynbuf_set(dt_masks_dynbuf_t *a, const int offset, const float value)
{
Expand All @@ -837,6 +881,15 @@ void dt_masks_dynbuf_set(dt_masks_dynbuf_t *a, const int offset, const float val
a->buffer[a->pos + offset] = value;
}

static inline
void dt_masks_dynbuf_set_absolute(dt_masks_dynbuf_t *a, const int position, const float value)
{
assert(a != NULL);
assert(position >= 0);
assert((long)a->pos > position);
a->buffer[position] = value;
}

static inline
float *dt_masks_dynbuf_buffer(dt_masks_dynbuf_t *a)
{
Expand All @@ -851,6 +904,14 @@ size_t dt_masks_dynbuf_position(dt_masks_dynbuf_t *a)
return a->pos;
}

static inline
void dt_masks_dynbuf_reset_position(dt_masks_dynbuf_t *a, const size_t newpos)
{
assert(a != NULL);
assert(newpos <= a->pos);
a->pos = newpos;
}

static inline
void dt_masks_dynbuf_reset(dt_masks_dynbuf_t *a)
{
Expand Down Expand Up @@ -879,6 +940,134 @@ void dt_masks_dynbuf_free(dt_masks_dynbuf_t *a)
free(a);
}

// Dump buffer to file for debugging.
static inline
void dt_masks_dynbuf_debug_print(dt_masks_dynbuf_t *a, gboolean to_stdout)
{
if(a == NULL) return;
if (to_stdout) {
printf("'%s' buffer: ", a->tag);
for (size_t i = 0; i < a->pos; i += 2) {
printf("(%f %f), ", a->buffer[i], a->buffer[i+1]);
}
printf("\n");
}
else
{
FILE *f;
char filename[255] = { 0 };
sprintf(filename, "debug-%ld-%s", time(NULL), a->tag);
f = g_fopen(filename, "w");
for (size_t i = 0; i < a->pos; i += 2) {
fprintf(f, "%f %f\n", a->buffer[i], a->buffer[i+1]);
}
fclose(f);
}
}

/******************************************************
* code for dynamic handling of intermediate buffers
* buffer for ints
*/
static inline gboolean _dt_masks_intbuf_growto(dt_masks_intbuf_t *a,
const size_t newsize)
{
int *newbuf = dt_alloc_align_int(newsize);
if (!newbuf)
{
// not much we can do here except emit an error message
dt_print(DT_DEBUG_ALWAYS,
"critical: out of memory for intbuf '%s' with size request %zu!\n",
a->tag, newsize);
return FALSE;
}
if (a->buffer)
{
memcpy(newbuf, a->buffer, a->size * sizeof(int));
dt_print(DT_DEBUG_MASKS, "[masks intbuf '%s'] grows to size %lu (is %p, was %p)\n",
a->tag,
(unsigned long)a->size, newbuf, a->buffer);
dt_free_align(a->buffer);
}
a->size = newsize;
a->buffer = newbuf;
return TRUE;
}


static inline
dt_masks_intbuf_t *dt_masks_intbuf_init(const size_t size, const char *tag)
{
assert(size > 0);
dt_masks_intbuf_t *a = (dt_masks_intbuf_t *)calloc(1, sizeof(dt_masks_intbuf_t));

if(a != NULL)
{
g_strlcpy(a->tag, tag, sizeof(a->tag)); //only for debugging purposes
a->pos = 0;
if(_dt_masks_intbuf_growto(a, size))
dt_print(DT_DEBUG_MASKS, "[masks intbuf '%s'] with initial size %lu (is %p)\n",
a->tag,
(unsigned long)a->size, a->buffer);
if(a->buffer == NULL)
{
free(a);
a = NULL;
}
}
return a;
}


static inline
void dt_masks_intbuf_add2(dt_masks_intbuf_t *a, const float value1, const float value2)
{
assert(a != NULL);
assert(a->pos <= a->size);
if(__builtin_expect(a->pos + 2 >= a->size, 0))
{
if (a->size == 0 || !_dt_masks_intbuf_growto(a, 2 * (a->size+1)))
return;
}
a->buffer[a->pos++] = value1;
a->buffer[a->pos++] = value2;
}

static inline
size_t dt_masks_intbuf_position(dt_masks_intbuf_t *a)
{
assert(a != NULL);
return a->pos;
}

static inline
void dt_masks_intbuf_free(dt_masks_intbuf_t *a)
{
if(a == NULL) return;
dt_print(DT_DEBUG_MASKS, "[masks intbuf '%s'] freed (was %p)\n", a->tag,
a->buffer);
dt_free_align(a->buffer);
free(a);
}

// Dump buffer to file for debugging.
static inline
void dt_masks_intnbuf_debug_print(dt_masks_intbuf_t *a)
{
if(a == NULL) return;
FILE *f;
char filename[255] = { 0 };
sprintf(filename, "debug-%ld-%s", time(NULL), a->tag);
f = g_fopen(filename, "w");
for (size_t i = 0; i < a->pos; i += 2) {
fprintf(f, "%d %d\n", a->buffer[i], a->buffer[i+1]);
}
fclose(f);
}

/* End of dynamic buffer code
******************************************************/

static inline
int dt_masks_roundup(const int num, const int mult)
{
Expand Down
Loading