GPencil: Add Vertex Paint operators to Paint menu

These operators existed since 2.83, but the menu was hidden by error.

Also the operators have been cleanup and make multiframe compatible.

Reviewed By: mendio

Differential Revision: https://developer.blender.org/D9671
This commit is contained in:
Antonio Vazquez 2020-12-03 16:46:16 +01:00
parent 570a16da18
commit 986955a2d5
3 changed files with 436 additions and 334 deletions

View File

@ -1828,7 +1828,13 @@ class VIEW3D_MT_paint_gpencil(Menu):
def draw(self, context):
layout = self.layout
layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors")
layout.operator("gpencil.stroke_reset_vertex_color")
layout.separator()
layout.operator("gpencil.vertex_color_invert", text="Invert")
layout.operator("gpencil.vertex_color_levels", text="Levels")
layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value")
layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast")
class VIEW3D_MT_select_gpencil(Menu):
@ -5044,22 +5050,6 @@ class VIEW3D_MT_weight_gpencil(Menu):
layout.menu("VIEW3D_MT_gpencil_autoweights")
class VIEW3D_MT_vertex_gpencil(Menu):
bl_label = "Paint"
def draw(self, _context):
layout = self.layout
layout.operator("gpencil.vertex_color_set", text="Set Vertex Colors")
layout.separator()
layout.operator("gpencil.vertex_color_invert", text="Invert")
layout.operator("gpencil.vertex_color_levels", text="Levels")
layout.operator("gpencil.vertex_color_hsv", text="Hue Saturation Value")
layout.operator("gpencil.vertex_color_brightness_contrast", text="Bright/Contrast")
layout.separator()
layout.menu("VIEW3D_MT_join_palette")
class VIEW3D_MT_gpencil_animation(Menu):
bl_label = "Animation"
@ -7606,7 +7596,6 @@ classes = (
VIEW3D_MT_edit_gpencil_delete,
VIEW3D_MT_edit_gpencil_showhide,
VIEW3D_MT_weight_gpencil,
VIEW3D_MT_vertex_gpencil,
VIEW3D_MT_gpencil_animation,
VIEW3D_MT_gpencil_simplify,
VIEW3D_MT_gpencil_copy_layer,

View File

@ -5206,158 +5206,3 @@ void GPENCIL_OT_stroke_merge_by_distance(wmOperatorType *ot)
RNA_def_property_flag(prop, PROP_SKIP_SAVE);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Reset Stroke Vertex Color Operator
* \{ */
static void gpencil_reset_vertex(bGPDstroke *gps, eGp_Vertex_Mode mode)
{
if (mode != GPPAINT_MODE_STROKE) {
zero_v4(gps->vert_color_fill);
}
if (mode != GPPAINT_MODE_FILL) {
bGPDspoint *pt;
for (int i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
zero_v4(pt->vert_color);
}
}
}
static int gpencil_stroke_reset_vertex_color_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)obact->data;
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
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;
}
eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
/* First need to check if there are something selected. If not, apply to all strokes. */
bool all_strokes = true;
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 (is_curve_edit) {
if (gps->editcurve == NULL) {
continue;
}
bGPDcurve *gpc = gps->editcurve;
if (gpc->flag & GP_CURVE_SELECT) {
all_strokes = false;
break;
}
}
else {
if (gps->flag & GP_STROKE_SELECT) {
all_strokes = false;
break;
}
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
CTX_DATA_END;
/* Reset Vertex colors. */
bool changed = false;
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 (is_curve_edit) {
if (gps->editcurve == NULL) {
continue;
}
bGPDcurve *gpc = gps->editcurve;
if ((all_strokes) || (gpc->flag & GP_CURVE_SELECT)) {
gpencil_reset_vertex(gps, mode);
}
}
else {
if ((all_strokes) || (gps->flag & GP_STROKE_SELECT)) {
gpencil_reset_vertex(gps, mode);
}
}
changed = true;
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
CTX_DATA_END;
if (changed) {
/* 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_reset_vertex_color(wmOperatorType *ot)
{
static EnumPropertyItem mode_types_items[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"},
{GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Reset Vertex Color";
ot->idname = "GPENCIL_OT_stroke_reset_vertex_color";
ot->description = "Reset vertex color for all or selected strokes";
/* callbacks */
ot->exec = gpencil_stroke_reset_vertex_color_exec;
ot->poll = gpencil_stroke_edit_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
ot->prop = RNA_def_enum(ot->srna, "mode", mode_types_items, GPPAINT_MODE_BOTH, "Mode", "");
}
/** \} */

View File

@ -60,23 +60,69 @@
#include "gpencil_intern.h"
enum {
GP_PAINT_VERTEX_STROKE = 0,
GP_PAINT_VERTEX_FILL = 1,
GP_PAINT_VERTEX_BOTH = 2,
};
static const EnumPropertyItem gpencil_modesEnumPropertyItem_mode[] = {
{GP_PAINT_VERTEX_STROKE, "STROKE", 0, "Stroke", ""},
{GP_PAINT_VERTEX_FILL, "FILL", 0, "Fill", ""},
{GP_PAINT_VERTEX_BOTH, "BOTH", 0, "Both", ""},
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", ""},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", ""},
{GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", ""},
{0, NULL, 0, NULL, NULL},
};
/* Helper: Check if any stroke is selected. */
static bool is_any_stroke_selected(bContext *C, const bool is_multiedit, const bool is_curve_edit)
{
bool is_selected = false;
/* If not enabled any mask mode, the strokes are considered as not selected. */
ToolSettings *ts = CTX_data_tool_settings(C);
if (!GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex)) {
return false;
}
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;
}
if (is_curve_edit) {
if (gps->editcurve == NULL) {
continue;
}
bGPDcurve *gpc = gps->editcurve;
if (gpc->flag & GP_CURVE_SELECT) {
is_selected = true;
break;
}
}
else {
if (gps->flag & GP_STROKE_SELECT) {
is_selected = true;
break;
}
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
CTX_DATA_END;
return is_selected;
}
/* Poll callback for stroke vertex paint operator. */
static bool gpencil_vertexpaint_mode_poll(bContext *C)
{
ToolSettings *ts = CTX_data_tool_settings(C);
Object *ob = CTX_data_active_object(C);
if ((ob == NULL) || (ob->type != OB_GPENCIL)) {
return false;
@ -84,10 +130,6 @@ static bool gpencil_vertexpaint_mode_poll(bContext *C)
bGPdata *gpd = (bGPdata *)ob->data;
if (GPENCIL_VERTEX_MODE(gpd)) {
if (!(GPENCIL_ANY_VERTEX_MASK(ts->gpencil_selectmode_vertex))) {
return false;
}
/* Any data to use. */
if (gpd->layers.first) {
return true;
@ -101,10 +143,9 @@ static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator
{
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
bool changed = false;
int i;
bGPDspoint *pt;
const int mode = RNA_enum_get(op->ptr, "mode");
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
const bool any_selected = is_any_stroke_selected(C, is_multiedit, false);
float gain, offset;
{
@ -130,34 +171,56 @@ static int gpencil_vertexpaint_brightness_contrast_exec(bContext *C, wmOperator
}
/* Loop all selected strokes. */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
/* Fill color. */
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
if (mode != GP_PAINT_VERTEX_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset;
bool changed = false;
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;
}
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
/* Fill color. */
if (mode != GPPAINT_MODE_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
changed = true;
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = gain * gps->vert_color_fill[i2] + offset;
}
}
}
/* Stroke points. */
if (mode != GPPAINT_MODE_FILL) {
changed = true;
int i;
bGPDspoint *pt;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) &&
(pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = gain * pt->vert_color[i2] + offset;
}
}
}
}
}
}
}
/* Stroke points. */
if (mode != GP_PAINT_VERTEX_FILL) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = gain * pt->vert_color[i2] + offset;
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
CTX_DATA_END;
/* notifiers */
if (changed) {
@ -185,7 +248,8 @@ void GPENCIL_OT_vertex_color_brightness_contrast(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* params */
ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
ot->prop = RNA_def_enum(
ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", "");
const float min = -100, max = +100;
prop = RNA_def_float(ot->srna, "brightness", 0.0f, min, max, "Brightness", "", min, max);
prop = RNA_def_float(ot->srna, "contrast", 0.0f, min, max, "Contrast", "", min, max);
@ -197,64 +261,88 @@ static int gpencil_vertexpaint_hsv_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
bool changed = false;
int i;
bGPDspoint *pt;
float hsv[3];
const int mode = RNA_enum_get(op->ptr, "mode");
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
const bool any_selected = is_any_stroke_selected(C, is_multiedit, false);
float hue = RNA_float_get(op->ptr, "h");
float sat = RNA_float_get(op->ptr, "s");
float val = RNA_float_get(op->ptr, "v");
/* Loop all selected strokes. */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Fill color. */
if (mode != GP_PAINT_VERTEX_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
rgb_to_hsv_v(gps->vert_color_fill, hsv);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) {
hsv[0] -= 1.0f;
}
else if (hsv[0] < 0.0f) {
hsv[0] += 1.0f;
}
hsv[1] *= sat;
hsv[2] *= val;
hsv_to_rgb_v(hsv, gps->vert_color_fill);
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
if (gpf == NULL) {
continue;
}
}
/* Stroke points. */
if (mode != GP_PAINT_VERTEX_FILL) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
rgb_to_hsv_v(pt->vert_color, hsv);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) {
hsv[0] -= 1.0f;
}
else if (hsv[0] < 0.0f) {
hsv[0] += 1.0f;
}
hsv[1] *= sat;
hsv[2] *= val;
hsv_to_rgb_v(hsv, pt->vert_color);
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
float hsv[3];
/* Fill color. */
if (mode != GPPAINT_MODE_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
changed = true;
rgb_to_hsv_v(gps->vert_color_fill, hsv);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) {
hsv[0] -= 1.0f;
}
else if (hsv[0] < 0.0f) {
hsv[0] += 1.0f;
}
hsv[1] *= sat;
hsv[2] *= val;
hsv_to_rgb_v(hsv, gps->vert_color_fill);
}
}
/* Stroke points. */
if (mode != GPPAINT_MODE_FILL) {
changed = true;
int i;
bGPDspoint *pt;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) &&
(pt->vert_color[3] > 0.0f)) {
rgb_to_hsv_v(pt->vert_color, hsv);
hsv[0] += (hue - 0.5f);
if (hsv[0] > 1.0f) {
hsv[0] -= 1.0f;
}
else if (hsv[0] < 0.0f) {
hsv[0] += 1.0f;
}
hsv[1] *= sat;
hsv[2] *= val;
hsv_to_rgb_v(hsv, pt->vert_color);
}
}
}
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
CTX_DATA_END;
/* notifiers */
if (changed) {
@ -280,7 +368,8 @@ void GPENCIL_OT_vertex_color_hsv(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* params */
ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
ot->prop = RNA_def_enum(
ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", "");
RNA_def_float(ot->srna, "h", 0.5f, 0.0f, 1.0f, "Hue", "", 0.0f, 1.0f);
RNA_def_float(ot->srna, "s", 1.0f, 0.0f, 2.0f, "Saturation", "", 0.0f, 2.0f);
RNA_def_float(ot->srna, "v", 1.0f, 0.0f, 2.0f, "Value", "", 0.0f, 2.0f);
@ -291,41 +380,62 @@ static int gpencil_vertexpaint_invert_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
const bool any_selected = is_any_stroke_selected(C, is_multiedit, false);
bool changed = false;
int i;
bGPDspoint *pt;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
const int mode = RNA_enum_get(op->ptr, "mode");
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
if (gpf == NULL) {
continue;
}
/* Loop all selected strokes. */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
/* Fill color. */
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
if (mode != GP_PAINT_VERTEX_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2];
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
/* Fill color. */
if (mode != GPPAINT_MODE_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
changed = true;
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = 1.0f - gps->vert_color_fill[i2];
}
}
}
/* Stroke points. */
if (mode != GPPAINT_MODE_FILL) {
changed = true;
int i;
bGPDspoint *pt;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) &&
(pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = 1.0f - pt->vert_color[i2];
}
}
}
}
}
}
}
/* Stroke points. */
if (mode != GP_PAINT_VERTEX_FILL) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = 1.0f - pt->vert_color[i2];
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
CTX_DATA_END;
/* notifiers */
if (changed) {
@ -351,7 +461,8 @@ void GPENCIL_OT_vertex_color_invert(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* params */
ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
ot->prop = RNA_def_enum(
ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", "");
}
static int gpencil_vertexpaint_levels_exec(bContext *C, wmOperator *op)
@ -359,41 +470,63 @@ static int gpencil_vertexpaint_levels_exec(bContext *C, wmOperator *op)
Object *ob = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)ob->data;
bool changed = false;
bGPDspoint *pt;
const int mode = RNA_enum_get(op->ptr, "mode");
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
const bool any_selected = is_any_stroke_selected(C, is_multiedit, false);
float gain = RNA_float_get(op->ptr, "gain");
float offset = RNA_float_get(op->ptr, "offset");
/* Loop all selected strokes. */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Fill color. */
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
if (mode != GP_PAINT_VERTEX_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset);
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;
}
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
/* Fill color. */
if (mode != GPPAINT_MODE_STROKE) {
if (gps->vert_color_fill[3] > 0.0f) {
changed = true;
for (int i2 = 0; i2 < 3; i2++) {
gps->vert_color_fill[i2] = gain * (gps->vert_color_fill[i2] + offset);
}
}
}
/* Stroke points. */
if (mode != GPPAINT_MODE_FILL) {
changed = true;
int i;
bGPDspoint *pt;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) &&
(pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset);
}
}
}
}
}
}
}
}
/* Stroke points. */
if (mode != GP_PAINT_VERTEX_FILL) {
int i;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((pt->flag & GP_SPOINT_SELECT) && (pt->vert_color[3] > 0.0f)) {
for (int i2 = 0; i2 < 3; i2++) {
pt->vert_color[i2] = gain * (pt->vert_color[i2] + offset);
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
CTX_DATA_END;
/* notifiers */
if (changed) {
@ -420,7 +553,8 @@ void GPENCIL_OT_vertex_color_levels(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* params */
ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
ot->prop = RNA_def_enum(
ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", "");
RNA_def_float(
ot->srna, "offset", 0.0f, -1.0f, 1.0f, "Offset", "Value to add to colors", -1.0f, 1.0f);
@ -436,36 +570,58 @@ static int gpencil_vertexpaint_set_exec(bContext *C, wmOperator *op)
Paint *paint = &ts->gp_vertexpaint->paint;
Brush *brush = paint->brush;
bool changed = false;
int i;
bGPDspoint *pt;
const int mode = RNA_enum_get(op->ptr, "mode");
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
const bool any_selected = is_any_stroke_selected(C, is_multiedit, false);
float factor = RNA_float_get(op->ptr, "factor");
/* Loop all selected strokes. */
GP_EDITABLE_STROKES_BEGIN (gpstroke_iter, C, gpl, gps) {
bool changed = false;
CTX_DATA_BEGIN (C, bGPDlayer *, gpl, editable_gpencil_layers) {
bGPDframe *init_gpf = (is_multiedit) ? gpl->frames.first : gpl->actframe;
/* Fill color. */
if (gps->flag & GP_STROKE_SELECT) {
changed = true;
if (mode != GP_PAINT_VERTEX_STROKE) {
copy_v3_v3(gps->vert_color_fill, brush->rgb);
gps->vert_color_fill[3] = factor;
}
}
for (bGPDframe *gpf = init_gpf; gpf; gpf = gpf->next) {
if ((gpf == gpl->actframe) || ((gpf->flag & GP_FRAME_SELECT) && (is_multiedit))) {
if (gpf == NULL) {
continue;
}
/* Stroke points. */
if (mode != GP_PAINT_VERTEX_FILL) {
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if (pt->flag & GP_SPOINT_SELECT) {
copy_v3_v3(pt->vert_color, brush->rgb);
pt->vert_color[3] = factor;
LISTBASE_FOREACH (bGPDstroke *, gps, &gpf->strokes) {
/* skip strokes that are invalid for current view */
if (ED_gpencil_stroke_can_use(C, gps) == false) {
continue;
}
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
/* Fill color. */
if (mode != GPPAINT_MODE_STROKE) {
changed = true;
copy_v3_v3(gps->vert_color_fill, brush->rgb);
gps->vert_color_fill[3] = factor;
}
/* Stroke points. */
if (mode != GPPAINT_MODE_FILL) {
changed = true;
int i;
bGPDspoint *pt;
for (i = 0, pt = gps->points; i < gps->totpoints; i++, pt++) {
if ((!any_selected) || (pt->flag & GP_SPOINT_SELECT)) {
copy_v3_v3(pt->vert_color, brush->rgb);
pt->vert_color[3] = factor;
}
}
}
}
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
GP_EDITABLE_STROKES_END(gpstroke_iter);
CTX_DATA_END;
/* notifiers */
if (changed) {
@ -492,7 +648,8 @@ void GPENCIL_OT_vertex_color_set(wmOperatorType *ot)
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* params */
ot->prop = RNA_def_enum(ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, 0, "Mode", "");
ot->prop = RNA_def_enum(
ot->srna, "mode", gpencil_modesEnumPropertyItem_mode, GPPAINT_MODE_BOTH, "Mode", "");
RNA_def_float(ot->srna, "factor", 1.0f, 0.001f, 1.0f, "Factor", "Mix Factor", 0.001f, 1.0f);
}
@ -900,3 +1057,114 @@ void GPENCIL_OT_extract_palette_vertex(wmOperatorType *ot)
ot->srna, "selected", false, "Only Selected", "Convert only selected strokes");
RNA_def_int(ot->srna, "threshold", 1, 1, 4, "Threshold", "", 1, 4);
}
/* -------------------------------------------------------------------- */
/** \name Reset Stroke Vertex Color Operator
* \{ */
static void gpencil_reset_vertex(bGPDstroke *gps, eGp_Vertex_Mode mode)
{
if (mode != GPPAINT_MODE_STROKE) {
zero_v4(gps->vert_color_fill);
}
if (mode != GPPAINT_MODE_FILL) {
bGPDspoint *pt;
for (int i = 0; i < gps->totpoints; i++) {
pt = &gps->points[i];
zero_v4(pt->vert_color);
}
}
}
static int gpencil_stroke_reset_vertex_color_exec(bContext *C, wmOperator *op)
{
Object *obact = CTX_data_active_object(C);
bGPdata *gpd = (bGPdata *)obact->data;
const bool is_curve_edit = (bool)GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd);
const bool is_multiedit = (bool)GPENCIL_MULTIEDIT_SESSIONS_ON(gpd);
const eGp_Vertex_Mode mode = RNA_enum_get(op->ptr, "mode");
/* First need to check if there are something selected. If not, apply to all strokes. */
const bool any_selected = is_any_stroke_selected(C, is_multiedit, is_curve_edit);
/* Reset Vertex colors. */
bool changed = false;
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;
}
if (is_curve_edit) {
if (gps->editcurve == NULL) {
continue;
}
bGPDcurve *gpc = gps->editcurve;
if ((!any_selected) || (gpc->flag & GP_CURVE_SELECT)) {
gpencil_reset_vertex(gps, mode);
}
}
else {
if ((!any_selected) || (gps->flag & GP_STROKE_SELECT)) {
gpencil_reset_vertex(gps, mode);
}
}
changed = true;
}
/* if not multiedit, exit loop*/
if (!is_multiedit) {
break;
}
}
}
}
CTX_DATA_END;
if (changed) {
/* 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_reset_vertex_color(wmOperatorType *ot)
{
static EnumPropertyItem mode_types_items[] = {
{GPPAINT_MODE_STROKE, "STROKE", 0, "Stroke", "Reset Vertex Color to Stroke only"},
{GPPAINT_MODE_FILL, "FILL", 0, "Fill", "Reset Vertex Color to Fill only"},
{GPPAINT_MODE_BOTH, "BOTH", 0, "Stroke and Fill", "Reset Vertex Color to Stroke and Fill"},
{0, NULL, 0, NULL, NULL},
};
/* identifiers */
ot->name = "Reset Vertex Color";
ot->idname = "GPENCIL_OT_stroke_reset_vertex_color";
ot->description = "Reset vertex color for all or selected strokes";
/* callbacks */
ot->exec = gpencil_stroke_reset_vertex_color_exec;
ot->poll = gpencil_vertexpaint_mode_poll;
/* flags */
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
/* properties */
ot->prop = RNA_def_enum(ot->srna, "mode", mode_types_items, GPPAINT_MODE_BOTH, "Mode", "");
}
/** \} */