Commit: d5bebb33b23d8630e43f369e25ea779d05275b02 Author: Antonioya Date: Sat Jun 29 16:24:59 2019 +0200 Branches: greasepencil-object https://developer.blender.org/rBd5bebb33b23d8630e43f369e25ea779d05275b02
GPencil: New Close Stroke operator This operator allows to close a stoke generating geometry for the closing gap. This is totally different of Cyclic, because this was only a visual closing, but as there wasn't new geometry, you could sculpt or edit and need manual subdivide. =================================================================== M source/blender/blenkernel/BKE_gpencil.h M source/blender/blenkernel/intern/gpencil.c M source/blender/editors/gpencil/gpencil_edit.c M source/blender/editors/gpencil/gpencil_intern.h M source/blender/editors/gpencil/gpencil_ops.c =================================================================== diff --git a/source/blender/blenkernel/BKE_gpencil.h b/source/blender/blenkernel/BKE_gpencil.h index 6e8efd1b194..742546680a4 100644 --- a/source/blender/blenkernel/BKE_gpencil.h +++ b/source/blender/blenkernel/BKE_gpencil.h @@ -291,6 +291,7 @@ bool BKE_gpencil_smooth_stroke(struct bGPDstroke *gps, int i, float inf); bool BKE_gpencil_smooth_stroke_strength(struct bGPDstroke *gps, int point_index, float influence); bool BKE_gpencil_smooth_stroke_thickness(struct bGPDstroke *gps, int point_index, float influence); bool BKE_gpencil_smooth_stroke_uv(struct bGPDstroke *gps, int point_index, float influence); +bool BKE_gpencil_close_stroke(struct bGPDstroke *gps); void BKE_gpencil_get_range_selected(struct bGPDlayer *gpl, int *r_initframe, int *r_endframe); float BKE_gpencil_multiframe_falloff_calc( diff --git a/source/blender/blenkernel/intern/gpencil.c b/source/blender/blenkernel/intern/gpencil.c index 842fa85bf76..e1204883a2d 100644 --- a/source/blender/blenkernel/intern/gpencil.c +++ b/source/blender/blenkernel/intern/gpencil.c @@ -1958,3 +1958,83 @@ bool BKE_gpencil_trim_stroke(bGPDstroke *gps) } return intersect; } + +/** + * Close stroke + * \param gps: Stroke to close + */ +bool BKE_gpencil_close_stroke(bGPDstroke *gps) +{ + bGPDspoint *pt1 = NULL; + bGPDspoint *pt2 = NULL; + + /* Only can close a stroke with 3 points or more. */ + if (gps->totpoints < 3) { + return false; + } + + /* Calc average distance between points to get same level of sampling. */ + float dist_tot = 0.0f; + for (int i = 0; i < gps->totpoints - 1; i++) { + pt1 = &gps->points[i]; + pt2 = &gps->points[i + 1]; + dist_tot += len_v3v3(&pt1->x, &pt2->x); + } + /* Calc the average distance. */ + float dist_avg = dist_tot / (gps->totpoints - 1); + + /* Calc distance between last and first point. */ + pt1 = &gps->points[gps->totpoints - 1]; + pt2 = &gps->points[0]; + float dist_close = len_v3v3(&pt1->x, &pt2->x); + + /* Calc number of points required using the average distance. */ + int tot_newpoints = MAX2(dist_close / dist_avg, 1); + + /* Resize stroke array. */ + int old_tot = gps->totpoints; + gps->totpoints += tot_newpoints; + gps->points = MEM_recallocN(gps->points, sizeof(*gps->points) * gps->totpoints); + if (gps->dvert != NULL) { + gps->dvert = MEM_recallocN(gps->dvert, sizeof(*gps->dvert) * gps->totpoints); + } + + /* Generate new points */ + pt1 = &gps->points[old_tot - 1]; + pt2 = &gps->points[0]; + bGPDspoint *pt = &gps->points[old_tot]; + for (int i = 1; i < tot_newpoints + 1; i++, pt++) { + float step = ((float)i / (float)tot_newpoints); + /* Clamp last point to be near, but not on top of first point. */ + CLAMP(step, 0.0f, 0.99f); + + /* Average point. */ + interp_v3_v3v3(&pt->x, &pt1->x, &pt2->x, step); + pt->pressure = interpf(pt1->pressure, pt2->pressure, step); + pt->strength = interpf(pt1->strength, pt2->strength, step); + pt->flag = 0; + + /* Set weights. */ + if (gps->dvert != NULL) { + MDeformVert *dvert1 = &gps->dvert[old_tot - 1]; + MDeformWeight *dw1 = defvert_verify_index(dvert1, 0); + float weight_1 = dw1 ? dw1->weight : 0.0f; + + MDeformVert *dvert2 = &gps->dvert[0]; + MDeformWeight *dw2 = defvert_verify_index(dvert2, 0); + float weight_2 = dw2 ? dw2->weight : 0.0f; + + MDeformVert *dvert_final = &gps->dvert[old_tot + i - 1]; + dvert_final->totweight = 0; + MDeformWeight *dw = defvert_verify_index(dvert_final, 0); + if (dvert_final->dw) { + dw->weight = interpf(weight_2, weight_1, step); + } + } + } + + /* Enable cyclic flag. */ + gps->flag |= GP_STROKE_CYCLIC; + + return true; +} diff --git a/source/blender/editors/gpencil/gpencil_edit.c b/source/blender/editors/gpencil/gpencil_edit.c index f07b22a7b96..2f68369db9e 100644 --- a/source/blender/editors/gpencil/gpencil_edit.c +++ b/source/blender/editors/gpencil/gpencil_edit.c @@ -4588,3 +4588,68 @@ bool ED_object_gpencil_exit(struct Main *bmain, Object *ob) } return ok; } + +/* Add geometry to stroke for closing the path */ +static int gpencil_close_exec(bContext *C, wmOperator *op) +{ + Object *obact = CTX_data_active_object(C); + bGPdata *gpd = (bGPdata *)obact->data; + const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd); + bGPDstroke *gps = NULL; + + if (gpd == NULL) { + BKE_report(op->reports, RPT_ERROR, "No Grease Pencil data"); + return OPERATOR_CANCELLED; + } + + CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) { + 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))) { + if (gpf == NULL) { + continue; + } + + for (gps = gpf->strokes.first; gps; gps = gps->next) { + /* skip strokes that are invalid for current view */ + if (ED_gpencil_stroke_can_use(C, gps) == false) { + continue; + } + + if (gps->flag & GP_STROKE_SELECT) { + /* generate geometry */ + BKE_gpencil_close_stroke(gps); + } + } + /* if not multiedit, exit loop*/ + if (!is_multiedit) { + break; + } + } + } + } + CTX_DATA_END; + + /* updates */ + DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY | ID_RECALC_COPY_ON_WRITE); + DEG_id_tag_update(&obact->id, ID_RECALC_COPY_ON_WRITE); + WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL); + + return OPERATOR_FINISHED; +} + +void GPENCIL_OT_stroke_close(wmOperatorType *ot) +{ + /* identifiers */ + ot->name = "Stroke Close"; + ot->description = "Add geometry to close stroke"; + ot->idname = "GPENCIL_OT_stroke_close"; + + /* callbacks */ + ot->exec = gpencil_close_exec; + ot->poll = gp_active_layer_poll; + + /* flag */ + ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; +} diff --git a/source/blender/editors/gpencil/gpencil_intern.h b/source/blender/editors/gpencil/gpencil_intern.h index a9acd8057c1..3778ea1023f 100644 --- a/source/blender/editors/gpencil/gpencil_intern.h +++ b/source/blender/editors/gpencil/gpencil_intern.h @@ -489,6 +489,7 @@ void GPENCIL_OT_stroke_smooth(struct wmOperatorType *ot); void GPENCIL_OT_stroke_merge(struct wmOperatorType *ot); void GPENCIL_OT_stroke_cutter(struct wmOperatorType *ot); void GPENCIL_OT_stroke_trim(struct wmOperatorType *ot); +void GPENCIL_OT_stroke_close(struct wmOperatorType *ot); void GPENCIL_OT_brush_presets_create(struct wmOperatorType *ot); diff --git a/source/blender/editors/gpencil/gpencil_ops.c b/source/blender/editors/gpencil/gpencil_ops.c index db4c601709c..b1edcf5499b 100644 --- a/source/blender/editors/gpencil/gpencil_ops.c +++ b/source/blender/editors/gpencil/gpencil_ops.c @@ -309,6 +309,7 @@ void ED_operatortypes_gpencil(void) WM_operatortype_append(GPENCIL_OT_stroke_merge); WM_operatortype_append(GPENCIL_OT_stroke_cutter); WM_operatortype_append(GPENCIL_OT_stroke_trim); + WM_operatortype_append(GPENCIL_OT_stroke_close); WM_operatortype_append(GPENCIL_OT_brush_presets_create); _______________________________________________ Bf-blender-cvs mailing list Bf-blender-cvs@blender.org https://lists.blender.org/mailman/listinfo/bf-blender-cvs