GPencil: New operator to Normalize strokes

Sometimes is required to reset the thickness or the opacity of the strokes. Actually this was done using a modifier, but this operators solves this.

Reviewed By: mendio, filedescriptor

Maniphest Tasks: T87427

Differential Revision: https://developer.blender.org/D11453
This commit is contained in:
Antonio Vazquez 2021-06-02 16:41:13 +02:00
parent 21de669141
commit f944121700
Notes: blender-bot 2023-02-14 10:29:30 +01:00
Referenced by issue #87427, GPencil: New operator to normalize thickness and opacity
4 changed files with 184 additions and 0 deletions

View File

@ -5035,6 +5035,10 @@ class VIEW3D_MT_edit_gpencil_stroke(Menu):
layout.operator("gpencil.stroke_flip", text="Switch Direction")
layout.prop(settings, "use_scale_thickness", text="Scale Thickness")
layout.separator()
layout.operator("gpencil.stroke_normalize", text="Normalize Thickness").mode = 'THICKNESS'
layout.operator("gpencil.stroke_normalize", text="Normalize Opacity").mode = 'OPACITY'
layout.separator()
layout.operator("gpencil.reset_transform_fill", text="Reset Fill Transform")

View File

@ -5347,3 +5347,181 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Stroke Normalize Operator
* \{ */
typedef enum eGP_NormalizeMode {
GP_NORMALIZE_THICKNESS = 0,
GP_NORMALIZE_OPACITY,
} eGP_NormalizeMode;
static bool gpencil_stroke_normalize_poll(bContext *C)
{
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
return false;
}
bGPdata *gpd = (bGPdata *)ob->data;
if (gpd == NULL) {
return false;
}
bGPDlayer *gpl = BKE_gpencil_layer_active_get(gpd);
return ((gpl != NULL) && (ob->mode == OB_MODE_EDIT_GPENCIL));
}
static void gpencil_stroke_normalize_ui(bContext *C, wmOperator *op)
{
uiLayout *layout = op->layout;
uiLayout *row;
const eGP_NormalizeMode mode = RNA_enum_get(op->ptr, "mode");
uiLayoutSetPropSep(layout, true);
uiLayoutSetPropDecorate(layout, false);
row = uiLayoutRow(layout, true);
uiItemR(row, op->ptr, "mode", 0, NULL, ICON_NONE);
if (mode == GP_NORMALIZE_THICKNESS) {
row = uiLayoutRow(layout, true);
uiItemR(row, op->ptr, "value", 0, NULL, ICON_NONE);
}
else if (mode == GP_NORMALIZE_OPACITY) {
row = uiLayoutRow(layout, true);
uiItemR(row, op->ptr, "factor", 0, NULL, ICON_NONE);
}
}
static int gpencil_stroke_normalize_exec(bContext *C, wmOperator *op)
{
bGPdata *gpd = ED_gpencil_data_get_active(C);
/* Sanity checks. */
if (ELEM(NULL, gpd)) {
return OPERATOR_CANCELLED;
}
const eGP_NormalizeMode mode = RNA_enum_get(op->ptr, "mode");
const int value = RNA_int_get(op->ptr, "value");
const float factor = RNA_float_get(op->ptr, "factor");
/* Go through each editable + selected stroke. */
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
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;
}
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* Skip strokes that are invalid for current view. */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
bool selected = (is_curve_edit) ? gps->editcurve->flag |= GP_CURVE_SELECT :
(gps->flag & GP_STROKE_SELECT);
if (!selected) {
continue;
}
float stroke_thickness_inv = 1.0f / max_ii(gps->thickness, 1);
/* Fill opacity need to be managed before. */
if (mode == GP_NORMALIZE_OPACITY) {
gps->fill_opacity_fac = factor;
CLAMP(gps->fill_opacity_fac, 0.0f, 1.0f);
}
/* Loop all Polyline points. */
if (!is_curve_edit) {
for (int i = 0; i < gps->totpoints; i++) {
bGPDspoint *pt = &gps->points[i];
if (mode == GP_NORMALIZE_THICKNESS) {
pt->pressure = max_ff((float)value * stroke_thickness_inv, 0.0f);
}
else if (mode == GP_NORMALIZE_OPACITY) {
pt->strength = factor;
CLAMP(pt->strength, 0.0f, 1.0f);
}
}
}
else {
/* Loop all Bezier points. */
for (int i = 0; i < gps->editcurve->tot_curve_points; i++) {
bGPDcurve_point *gpc_pt = &gps->editcurve->curve_points[i];
if (mode == GP_NORMALIZE_THICKNESS) {
gpc_pt->pressure = max_ff((float)value * stroke_thickness_inv, 0.0f);
}
else if (mode == GP_NORMALIZE_OPACITY) {
gpc_pt->strength = factor;
CLAMP(gpc_pt->strength, 0.0f, 1.0f);
}
}
gps->flag |= GP_STROKE_NEEDS_CURVE_UPDATE;
BKE_gpencil_stroke_geometry_update(gpd, gps);
}
}
/* If not multiedit, exit loop. */
if (!is_multiedit) {
break;
}
}
}
}
CTX_DATA_END;
/* notifiers */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | NA_EDITED, NULL);
return OPERATOR_FINISHED;
}
void GPENCIL_OT_stroke_normalize(wmOperatorType *ot)
{
static const EnumPropertyItem prop_gpencil_normalize_modes[] = {
{GP_NORMALIZE_THICKNESS,
"THICKNESS",
0,
"Thickness",
"Normalizes the stroke thickness by making all points use the same thickness value"},
{GP_NORMALIZE_OPACITY,
"OPACITY",
0,
"Opacity",
"Normalizes the stroke opacity by making all points use the same opacity value"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Normalize Stroke";
ot->idname = "GPENCIL_OT_stroke_normalize";
ot->description = "Normalize stroke attributes";
/* api callbacks */
ot->exec = gpencil_stroke_normalize_exec;
ot->poll = gpencil_stroke_normalize_poll;
ot->ui = gpencil_stroke_normalize_ui;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* props */
ot->prop = RNA_def_enum(
ot->srna, "mode", prop_gpencil_normalize_modes, 0, "Mode", "Attribute to be normalized");
RNA_def_float(ot->srna, "factor", 1.0f, 0.0f, 1.0f, "Factor", "", 0.0f, 1.0f);
RNA_def_int(ot->srna, "value", 10, 0, 1000, "Value", "Value", 0, 1000);
}
/** \} */

View File

@ -488,6 +488,7 @@ void GPENCIL_OT_stroke_trim(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_merge_by_distance(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_merge_material(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_reset_vertex_color(struct wmOperatorType *ot);
void GPENCIL_OT_stroke_normalize(struct wmOperatorType *ot);
void GPENCIL_OT_material_to_vertex_color(struct wmOperatorType *ot);
void GPENCIL_OT_extract_palette_vertex(struct wmOperatorType *ot);

View File

@ -649,6 +649,7 @@ void ED_operatortypes_gpencil(void)
WM_operatortype_append(GPENCIL_OT_stroke_merge_by_distance);
WM_operatortype_append(GPENCIL_OT_stroke_merge_material);
WM_operatortype_append(GPENCIL_OT_stroke_reset_vertex_color);
WM_operatortype_append(GPENCIL_OT_stroke_normalize);
WM_operatortype_append(GPENCIL_OT_material_to_vertex_color);
WM_operatortype_append(GPENCIL_OT_extract_palette_vertex);