Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/editors/transform/transform_convert_gpencil.c')
-rw-r--r--source/blender/editors/transform/transform_convert_gpencil.c436
1 files changed, 409 insertions, 27 deletions
diff --git a/source/blender/editors/transform/transform_convert_gpencil.c b/source/blender/editors/transform/transform_convert_gpencil.c
index 84885dd8c49..0a742ec4470 100644
--- a/source/blender/editors/transform/transform_convert_gpencil.c
+++ b/source/blender/editors/transform/transform_convert_gpencil.c
@@ -31,7 +31,9 @@
#include "BKE_colortools.h"
#include "BKE_context.h"
+#include "BKE_curve.h"
#include "BKE_gpencil.h"
+#include "BKE_gpencil_curve.h"
#include "BKE_gpencil_geom.h"
#include "ED_gpencil.h"
@@ -63,33 +65,351 @@ static void createTransGPencil_center_get(bGPDstroke *gps, float r_center[3])
}
}
-void createTransGPencil(bContext *C, TransInfo *t)
+static short get_bezt_sel_triple_flag(BezTriple *bezt, const bool handles_visible)
{
- if (t->data_container_len == 0) {
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+#define SEL_ALL ((1 << 0) | (1 << 1) | (1 << 2))
+
+ short flag = 0;
+
+ if (handles_visible) {
+ flag = ((bezt->f1 & SELECT) ? SEL_F1 : 0) | ((bezt->f2 & SELECT) ? SEL_F2 : 0) |
+ ((bezt->f3 & SELECT) ? SEL_F3 : 0);
+ }
+ else {
+ if (bezt->f2 & SELECT) {
+ flag = SEL_ALL;
+ }
+ }
+
+ /* Special case for auto & aligned handles */
+ if (flag != SEL_ALL && flag & SEL_F2) {
+ if (ELEM(bezt->h1, HD_AUTO, HD_ALIGN) && ELEM(bezt->h2, HD_AUTO, HD_ALIGN)) {
+ flag = SEL_ALL;
+ }
+ }
+
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
+ return flag;
+}
+
+static void createTransGPencil_curves(bContext *C,
+ TransInfo *t,
+ Depsgraph *depsgraph,
+ ToolSettings *ts,
+ Object *obact,
+ bGPdata *gpd,
+ const int cfra_scene,
+ const bool is_multiedit,
+ const bool use_multiframe_falloff,
+ const bool is_prop_edit,
+ const bool is_prop_edit_connected,
+ const bool is_scale_thickness)
+{
+#define SEL_F1 (1 << 0)
+#define SEL_F2 (1 << 1)
+#define SEL_F3 (1 << 2)
+
+ View3D *v3d = t->view;
+ const bool handle_only_selected_visible = (v3d->overlay.handle_display == CURVE_HANDLE_SELECTED);
+ const bool handle_all_visible = (v3d->overlay.handle_display == CURVE_HANDLE_ALL);
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ tc->data_len = 0;
+
+ /* Number of selected curve points */
+ uint32_t tot_curve_points = 0, tot_sel_curve_points = 0, tot_points = 0, tot_sel_points = 0;
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Only editable and visible layers are considered. */
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+ for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* Check if stroke has an editcurve */
+ if (gps->editcurve == NULL) {
+ continue;
+ }
+
+ bGPDcurve *gpc = gps->editcurve;
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
+ BezTriple *bezt = &gpc_pt->bezt;
+ if (bezt->hide) {
+ continue;
+ }
+
+ const bool handles_visible = (handle_all_visible ||
+ (handle_only_selected_visible &&
+ (gpc_pt->flag & GP_CURVE_POINT_SELECT)));
+
+ const short sel_flag = get_bezt_sel_triple_flag(bezt, handles_visible);
+ if (sel_flag & (SEL_F1 | SEL_F2 | SEL_F3)) {
+ if (sel_flag & SEL_F1) {
+ tot_sel_points++;
+ }
+ if (sel_flag & SEL_F2) {
+ tot_sel_points++;
+ }
+ if (sel_flag & SEL_F3) {
+ tot_sel_points++;
+ }
+ tot_sel_curve_points++;
+ }
+
+ if (is_prop_edit) {
+ tot_points += 3;
+ tot_curve_points++;
+ }
+ }
+ }
+ }
+
+ /* If not multiedit out of loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+
+ if (((is_prop_edit && !is_prop_edit_connected) ? tot_curve_points : tot_sel_points) == 0) {
+ tc->data_len = 0;
return;
}
- Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
- bGPdata *gpd = ED_gpencil_data_get_active(C);
- ToolSettings *ts = CTX_data_tool_settings(C);
+ int data_len_pt = 0;
- bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
- bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) != 0;
+ if (is_prop_edit) {
+ tc->data_len = tot_points;
+ data_len_pt = tot_curve_points;
+ }
+ else {
+ tc->data_len = tot_sel_points;
+ data_len_pt = tot_sel_curve_points;
+ }
- Object *obact = CTX_data_active_object(C);
- TransData *td = NULL;
- float mtx[3][3], smtx[3][3];
+ if (tc->data_len == 0) {
+ return;
+ }
- const Scene *scene = CTX_data_scene(C);
- const int cfra_scene = CFRA;
+ transform_around_single_fallback_ex(t, data_len_pt);
- const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
- const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
- const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
- (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
+ tc->data = MEM_callocN(tc->data_len * sizeof(TransData), __func__);
+ TransData *td = tc->data;
- TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
+ const bool use_around_origins_for_handles_test = ((t->around == V3D_AROUND_LOCAL_ORIGINS) &&
+ transform_mode_use_local_origins(t));
+
+ LISTBASE_FOREACH (bGPDlayer *, gpl, &gpd->layers) {
+ /* Only editable and visible layers are considered. */
+ if (BKE_gpencil_layer_is_editable(gpl) && (gpl->actframe != NULL)) {
+ const int cfra = (gpl->flag & GP_LAYER_FRAMELOCK) ? gpl->actframe->framenum : cfra_scene;
+ bGPDframe *gpf = gpl->actframe;
+ bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
+ float diff_mat[4][4], mtx[3][3];
+ float smtx[3][3];
+
+ /* Init multiframe falloff options. */
+ int f_init = 0;
+ int f_end = 0;
+
+ if (use_multiframe_falloff) {
+ BKE_gpencil_frame_range_selected(gpl, &f_init, &f_end);
+ }
+
+ if ((gpf->framenum != cfra) && (!is_multiedit)) {
+ gpf = BKE_gpencil_frame_addcopy(gpl, cfra);
+ /* in some weird situations (framelock enabled) return NULL */
+ if (gpf == NULL) {
+ continue;
+ }
+ if (!is_multiedit) {
+ init_gpf = gpf;
+ }
+ }
+
+ /* Calculate difference matrix. */
+ BKE_gpencil_parent_matrix_get(depsgraph, obact, gpl, diff_mat);
+ copy_m3_m4(mtx, diff_mat);
+ pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
+
+ for (gpf = init_gpf; gpf; gpf = gpf->next) {
+ if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
+ /* If multi-frame and falloff, recalculate and save value. */
+ float falloff = 1.0f; /* by default no falloff */
+ if ((is_multiedit) && (use_multiframe_falloff)) {
+ /* Falloff depends on distance to active frame
+ * (relative to the overall frame range). */
+ falloff = BKE_gpencil_multiframe_falloff_calc(
+ gpf, gpl->actframe->framenum, f_init, f_end, ts->gp_sculpt.cur_falloff);
+ }
+
+ LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
+ /* skip strokes that are invalid for current view */
+ if (ED_gpencil_stroke_can_use(C, gps) == false) {
+ continue;
+ }
+ /* Check if the color is editable. */
+ if (ED_gpencil_stroke_color_use(obact, gpl, gps) == false) {
+ continue;
+ }
+ /* Check if stroke has an editcurve */
+ if (gps->editcurve == NULL) {
+ continue;
+ }
+ TransData *head, *tail;
+ head = tail = td;
+
+ gps->runtime.multi_frame_falloff = falloff;
+ bool need_handle_recalc = false;
+
+ bGPDcurve *gpc = gps->editcurve;
+ const bool is_cyclic = gps->flag & GP_STROKE_CYCLIC;
+ for (int i = 0; i < gpc->tot_curve_points; i++) {
+ bGPDcurve_point *gpc_pt = &gpc->curve_points[i];
+ BezTriple *bezt = &gpc_pt->bezt;
+ if (bezt->hide) {
+ continue;
+ }
+
+ TransDataCurveHandleFlags *hdata = NULL;
+ bool bezt_use = false;
+ const bool handles_visible = (handle_all_visible ||
+ (handle_only_selected_visible &&
+ (gpc_pt->flag & GP_CURVE_POINT_SELECT)));
+ const short sel_flag = get_bezt_sel_triple_flag(bezt, handles_visible);
+ /* Iterate over bezier triple */
+ for (int j = 0; j < 3; j++) {
+ bool is_ctrl_point = (j == 1);
+ bool sel = sel_flag & (1 << j);
+
+ if (is_prop_edit || sel) {
+ copy_v3_v3(td->iloc, bezt->vec[j]);
+ td->loc = bezt->vec[j];
+ bool rotate_around_ctrl = !handles_visible ||
+ (t->around == V3D_AROUND_LOCAL_ORIGINS) ||
+ (bezt->f2 & SELECT);
+ copy_v3_v3(td->center, bezt->vec[rotate_around_ctrl ? 1 : j]);
+
+ if (!handles_visible || is_ctrl_point) {
+ if (bezt->f2 & SELECT) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+ else if (handles_visible) {
+ if (BEZT_ISSEL_IDX(bezt, j)) {
+ td->flag = TD_SELECTED;
+ }
+ else {
+ td->flag = 0;
+ }
+ }
+
+ td->ext = NULL;
+ if (is_ctrl_point) {
+ if (t->mode != TFM_MIRROR) {
+ if (t->mode != TFM_GPENCIL_OPACITY) {
+ if (is_scale_thickness) {
+ td->val = &(gpc_pt->pressure);
+ td->ival = gpc_pt->pressure;
+ }
+ }
+ else {
+ td->val = &(gpc_pt->strength);
+ td->ival = gpc_pt->strength;
+ }
+ }
+ }
+ else {
+ td->val = NULL;
+ }
+
+ if (hdata == NULL) {
+ if (is_ctrl_point && ((sel_flag & SEL_F1 & SEL_F3) == 0)) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ else if (!is_ctrl_point) {
+ hdata = initTransDataCurveHandles(td, bezt);
+ }
+ }
+
+ td->extra = gps;
+ td->ob = obact;
+
+ copy_m3_m3(td->smtx, smtx);
+ copy_m3_m3(td->mtx, mtx);
+ copy_m3_m3(td->axismtx, mtx);
+
+ td++;
+ tail++;
+ }
+
+ bezt_use |= sel;
+ }
+
+ /* Update the handle types so transformation is possible */
+ if (bezt_use && !ELEM(t->mode, TFM_GPENCIL_OPACITY, TFM_GPENCIL_SHRINKFATTEN)) {
+ BKE_nurb_bezt_handle_test(
+ bezt, SELECT, handles_visible, use_around_origins_for_handles_test);
+ need_handle_recalc = true;
+ }
+ }
+ if (is_prop_edit && (head != tail)) {
+ calc_distanceCurveVerts(head, tail - 1, is_cyclic);
+ }
+
+ if (need_handle_recalc) {
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ }
+ }
+ }
+
+ /* If not multiedit out of loop. */
+ if (!is_multiedit) {
+ break;
+ }
+ }
+ }
+ }
+#undef SEL_F1
+#undef SEL_F2
+#undef SEL_F3
+}
+
+static void createTransGPencil_strokes(bContext *C,
+ TransInfo *t,
+ Depsgraph *depsgraph,
+ ToolSettings *ts,
+ Object *obact,
+ bGPdata *gpd,
+ const int cfra_scene,
+ const bool is_multiedit,
+ const bool use_multiframe_falloff,
+ const bool is_prop_edit,
+ const bool is_prop_edit_connected,
+ const bool is_scale_thickness)
+{
+ TransData *td = NULL;
+ float mtx[3][3], smtx[3][3];
+
+ TransDataContainer *tc = TRANS_DATA_CONTAINER_FIRST_SINGLE(t);
/* == Grease Pencil Strokes to Transform Data ==
* Grease Pencil stroke points can be a mixture of 2D (screen-space),
* or 3D coordinates. However, they're always saved as 3D points.
@@ -98,15 +418,6 @@ void createTransGPencil(bContext *C, TransInfo *t)
*/
tc->data_len = 0;
- if (gpd == NULL) {
- return;
- }
-
- /* initialize falloff curve */
- if (is_multiedit) {
- BKE_curvemapping_init(ts->gp_sculpt.cur_falloff);
- }
-
/* First Pass: Count the number of data-points required for the strokes,
* (and additional info about the configuration - e.g. 2D/3D?).
*/
@@ -368,6 +679,71 @@ void createTransGPencil(bContext *C, TransInfo *t)
}
}
+void createTransGPencil(bContext *C, TransInfo *t)
+{
+ if (t->data_container_len == 0) {
+ return;
+ }
+
+ Depsgraph *depsgraph = CTX_data_ensure_evaluated_depsgraph(C);
+ const Scene *scene = CTX_data_scene(C);
+ ToolSettings *ts = scene->toolsettings;
+ Object *obact = CTX_data_active_object(C);
+ bGPdata *gpd = obact->data;
+ BLI_assert(gpd != NULL);
+
+ const int cfra_scene = CFRA;
+
+ const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
+ const bool use_multiframe_falloff = (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_FRAME_FALLOFF) !=
+ 0;
+
+ const bool is_prop_edit = (t->flag & T_PROP_EDIT) != 0;
+ const bool is_prop_edit_connected = (t->flag & T_PROP_CONNECTED) != 0;
+ const bool is_scale_thickness = ((t->mode == TFM_GPENCIL_SHRINKFATTEN) ||
+ (ts->gp_sculpt.flag & GP_SCULPT_SETT_FLAG_SCALE_THICKNESS));
+
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
+
+ /* initialize falloff curve */
+ if (is_multiedit) {
+ BKE_curvemapping_init(ts->gp_sculpt.cur_falloff);
+ }
+
+ if (gpd == NULL) {
+ return;
+ }
+
+ if (is_curve_edit) {
+ createTransGPencil_curves(C,
+ t,
+ depsgraph,
+ ts,
+ obact,
+ gpd,
+ cfra_scene,
+ is_multiedit,
+ use_multiframe_falloff,
+ is_prop_edit,
+ is_prop_edit_connected,
+ is_scale_thickness);
+ }
+ else {
+ createTransGPencil_strokes(C,
+ t,
+ depsgraph,
+ ts,
+ obact,
+ gpd,
+ cfra_scene,
+ is_multiedit,
+ use_multiframe_falloff,
+ is_prop_edit,
+ is_prop_edit_connected,
+ is_scale_thickness);
+ }
+}
+
/* force recalculation of triangles during transformation */
void recalcData_gpencil_strokes(TransInfo *t)
{
@@ -375,13 +751,19 @@ void recalcData_gpencil_strokes(TransInfo *t)
GHash *strokes = BLI_ghash_ptr_new(__func__);
TransData *td = tc->data;
+ bGPdata *gpd = td->ob->data;
+ const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
for (int i = 0; i < tc->data_len; i++, td++) {
bGPDstroke *gps = td->extra;
if ((gps != NULL) && (!BLI_ghash_haskey(strokes, gps))) {
BLI_ghash_insert(strokes, gps, gps);
+ if (is_curve_edit && gps->editcurve != NULL) {
+ BKE_gpencil_editcurve_recalculate_handles(gps);
+ gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
+ }
/* Calc geometry data. */
- BKE_gpencil_stroke_geometry_update(gps);
+ BKE_gpencil_stroke_geometry_update(gpd, gps);
}
}
BLI_ghash_free(strokes, NULL, NULL);