GPv3: Initial sculpt mode

Adds an (empty) sculpt mode for Grease Pencil v3 objects.

The object `SCULPT_GPENCIL` mode is re-used for Grease Pencil object
types. A `SCULPT_GREASE_PENCIL` context mode has been added, which is
specific to grease pencil objects. This is necessary for polling tools
and keymaps.

Pull Request: https://projects.blender.org/blender/blender/pulls/119338
This commit is contained in:
Lukas Tönne
2024-04-11 09:39:48 +02:00
parent 88526ab5f4
commit 658a9ac3a9
23 changed files with 469 additions and 75 deletions

View File

@@ -4680,6 +4680,25 @@ def km_grease_pencil_edit_mode(params):
return keymap
def km_grease_pencil_sculpt_mode(params):
items = []
keymap = (
"Grease Pencil Sculpt Mode",
{"space_type": 'EMPTY', "region_type": 'WINDOW'},
{"items": items}
)
items.extend([
("brush.scale_size", {"type": 'LEFT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 0.9)]}),
("brush.scale_size", {"type": 'RIGHT_BRACKET', "value": 'PRESS', "repeat": True},
{"properties": [("scalar", 1.0 / 0.9)]}),
*_template_paint_radial_control("gpencil_sculpt_paint"),
])
return keymap
# ------------------------------------------------------------------------------
# Object/Pose Modes
@@ -8599,6 +8618,7 @@ def generate_keymaps(params=None):
km_animation_channels(params),
# Modes.
# Grease Pencil v2
km_grease_pencil(params), # TODO: Rename to km_annotate
km_grease_pencil_stroke_curve_edit_mode(params),
km_grease_pencil_stroke_edit_mode(params),
@@ -8631,6 +8651,7 @@ def generate_keymaps(params=None):
# Grease Pencil v3
km_grease_pencil_paint_mode(params),
km_grease_pencil_edit_mode(params),
km_grease_pencil_sculpt_mode(params),
# Object mode.
km_object_mode(params),
km_object_non_modal(params),

View File

@@ -70,7 +70,7 @@ class GreasePencilDisplayPanel:
def poll(cls, context):
ob = context.active_object
brush = context.tool_settings.gpencil_paint.brush
if ob and ob.type == 'GPENCIL' and brush:
if ob and ob.type in {'GPENCIL', 'GREASE_PENCIL'} and brush:
return True
return False

View File

@@ -84,6 +84,8 @@ class UnifiedPaintPanel:
return tool_settings.curves_sculpt
elif mode == 'PAINT_GREASE_PENCIL':
return tool_settings.gpencil_paint
elif mode == 'SCULPT_GREASE_PENCIL':
return tool_settings.gpencil_sculpt_paint
return None
@staticmethod
@@ -906,6 +908,11 @@ def brush_shared_settings(layout, context, brush, popover=False):
size = True
strength = True
# Grease Pencil #
if mode == 'SCULPT_GREASE_PENCIL':
size = True
strength = True
### Draw settings. ###
ups = context.scene.tool_settings.unified_paint_settings
@@ -1053,6 +1060,17 @@ def brush_settings_advanced(layout, context, brush, popover=False):
col.prop(brush, "use_original_plane", text="Plane")
layout.separator()
elif mode == 'SCULPT_GREASE_PENCIL':
tool = brush.gpencil_sculpt_tool
gp_settings = brush.gpencil_settings
if tool in {'SMOOTH', 'RANDOMIZE'}:
col = layout.column(heading="Affect", align=True)
col.prop(gp_settings, "use_edit_position", text="Position")
col.prop(gp_settings, "use_edit_strength", text="Strength")
col.prop(gp_settings, "use_edit_thickness", text="Thickness")
col.prop(gp_settings, "use_edit_uv", text="UV")
# 3D and 2D Texture Paint.
elif mode in {'PAINT_TEXTURE', 'PAINT_2D'}:
capabilities = brush.image_paint_capabilities

View File

@@ -2460,6 +2460,37 @@ class _defs_gpencil_sculpt:
)
class _defs_grease_pencil_sculpt:
@staticmethod
def poll_select_mask(context):
if context is None:
return True
ob = context.active_object
tool_settings = context.scene.tool_settings
return (
ob is not None and
ob.type in {'GPENCIL', 'GREASE_PENCIL'} and (
tool_settings.use_gpencil_select_mask_point or
tool_settings.use_gpencil_select_mask_stroke or
tool_settings.use_gpencil_select_mask_segment
)
)
@staticmethod
def generate_from_brushes(context):
return generate_from_enum_ex(
context,
idname_prefix="builtin_brush.",
icon_prefix="ops.gpencil.sculpt_",
type=bpy.types.Brush,
# Uses GPv2 tool settings
attr="gpencil_sculpt_tool",
tooldef_keywords=dict(
operator="grease_pencil.sculpt_paint",
),
)
class _defs_gpencil_weight:
@staticmethod
@@ -3159,6 +3190,16 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
None,
*_tools_annotate,
],
'SCULPT_GREASE_PENCIL': [
_defs_grease_pencil_sculpt.generate_from_brushes,
None,
*_tools_annotate,
lambda context: (
VIEW3D_PT_tools_active._tools_gpencil_select
if _defs_grease_pencil_sculpt.poll_select_mask(context)
else ()
),
],
'PAINT_TEXTURE': [
_defs_texture_paint.generate_from_brushes,
None,

View File

@@ -120,6 +120,14 @@ class VIEW3D_HT_tool_header(Header):
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'SCULPT_GREASE_PENCIL':
if is_valid_context:
brush = context.tool_settings.gpencil_sculpt_paint.brush
if brush:
tool = brush.gpencil_sculpt_tool
if tool in {'SMOOTH', 'RANDOMIZE'}:
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_brush_popover")
layout.popover("VIEW3D_PT_tools_grease_pencil_sculpt_appearance")
elif tool_mode == 'WEIGHT_GPENCIL':
if is_valid_context:
layout.popover("VIEW3D_PT_tools_grease_pencil_weight_appearance")
@@ -417,6 +425,59 @@ class _draw_tool_settings_context_mode:
return True
@staticmethod
def SCULPT_GREASE_PENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
return False
paint = context.tool_settings.gpencil_sculpt_paint
layout.template_ID_preview(paint, "brush", rows=3, cols=8, hide_buttons=True)
brush = paint.brush
if brush is None:
return False
tool_settings = context.tool_settings
capabilities = brush.sculpt_capabilities
ups = tool_settings.unified_paint_settings
size = "size"
size_owner = ups if ups.use_unified_size else brush
if size_owner.use_locked_size == 'SCENE':
size = "unprojected_radius"
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
size,
pressure_name="use_pressure_size",
unified_name="use_unified_size",
text="Radius",
slider=True,
header=True,
)
# strength, use_strength_pressure
pressure_name = "use_pressure_strength" if capabilities.has_strength_pressure else None
UnifiedPaintPanel.prop_unified(
layout,
context,
brush,
"strength",
pressure_name=pressure_name,
unified_name="use_unified_strength",
text="Strength",
header=True,
)
# direction
if not capabilities.has_direction:
layout.row().prop(brush, "direction", expand=True, text="")
return True
@staticmethod
def WEIGHT_GPENCIL(context, layout, tool):
if (tool is None) or (not tool.has_datablock):
@@ -1132,7 +1193,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_select_paint_mask")
elif mesh.use_paint_mask_vertex and mode_string in {'PAINT_WEIGHT', 'PAINT_VERTEX'}:
layout.menu("VIEW3D_MT_select_paint_mask_vertex")
elif mode_string not in {'SCULPT', 'SCULPT_CURVES', 'PAINT_GREASE_PENCIL'}:
elif mode_string not in {'SCULPT', 'SCULPT_CURVES', 'PAINT_GREASE_PENCIL', 'SCULPT_GREASE_PENCIL'}:
layout.menu("VIEW3D_MT_select_%s" % mode_string.lower())
if gp_edit:
@@ -1183,7 +1244,7 @@ class VIEW3D_MT_editor_menus(Menu):
layout.menu("VIEW3D_MT_edit_greasepencil_point")
elif obj:
if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES'}:
if mode_string not in {'PAINT_TEXTURE', 'SCULPT_CURVES', 'SCULPT_GREASE_PENCIL'}:
layout.menu("VIEW3D_MT_%s" % mode_string.lower())
if mode_string == 'SCULPT':
layout.menu("VIEW3D_MT_mask")

View File

@@ -141,8 +141,9 @@ enum eContextObjectMode {
CTX_MODE_VERTEX_GPENCIL_LEGACY,
CTX_MODE_SCULPT_CURVES,
CTX_MODE_PAINT_GREASE_PENCIL,
CTX_MODE_SCULPT_GREASE_PENCIL,
};
#define CTX_MODE_NUM (CTX_MODE_PAINT_GREASE_PENCIL + 1)
#define CTX_MODE_NUM (CTX_MODE_SCULPT_GREASE_PENCIL + 1)
/* Context */

View File

@@ -84,6 +84,7 @@ extern const uchar PAINT_CURSOR_VERTEX_PAINT[3];
extern const uchar PAINT_CURSOR_WEIGHT_PAINT[3];
extern const uchar PAINT_CURSOR_TEXTURE_PAINT[3];
extern const uchar PAINT_CURSOR_SCULPT_CURVES[3];
extern const uchar PAINT_CURSOR_SCULPT_GREASE_PENCIL[3];
enum class PaintMode : int8_t {
Sculpt = 0,
@@ -102,9 +103,11 @@ enum class PaintMode : int8_t {
WeightGPencil = 9,
/** Curves. */
SculptCurves = 10,
/** Grease Pencil. */
SculptGreasePencil = 11,
/** Keep last. */
Invalid = 11,
Invalid = 12,
};
#define PAINT_MODE_HAS_BRUSH(mode) !ELEM(mode, PaintMode::SculptUV)

View File

@@ -1191,7 +1191,12 @@ enum eContextObjectMode CTX_data_mode_enum_ex(const Object *obedit,
return CTX_MODE_EDIT_GPENCIL_LEGACY;
}
if (object_mode & OB_MODE_SCULPT_GPENCIL_LEGACY) {
return CTX_MODE_SCULPT_GPENCIL_LEGACY;
if (ob->type == OB_GPENCIL_LEGACY) {
return CTX_MODE_SCULPT_GPENCIL_LEGACY;
}
if (ob->type == OB_GREASE_PENCIL) {
return CTX_MODE_SCULPT_GREASE_PENCIL;
}
}
if (object_mode & OB_MODE_WEIGHT_GPENCIL_LEGACY) {
return CTX_MODE_WEIGHT_GPENCIL_LEGACY;
@@ -1248,6 +1253,7 @@ static const char *data_mode_strings[] = {
"greasepencil_vertex",
"curves_sculpt",
"grease_pencil_paint",
"grease_pencil_sculpt",
nullptr,
};
BLI_STATIC_ASSERT(ARRAY_SIZE(data_mode_strings) == CTX_MODE_NUM + 1,

View File

@@ -10,6 +10,7 @@
#include <cstring>
#include <optional>
#include "DNA_object_enums.h"
#include "MEM_guardedalloc.h"
#include "DNA_brush_types.h"
@@ -250,6 +251,7 @@ const uchar PAINT_CURSOR_VERTEX_PAINT[3] = {255, 255, 255};
const uchar PAINT_CURSOR_WEIGHT_PAINT[3] = {200, 200, 255};
const uchar PAINT_CURSOR_TEXTURE_PAINT[3] = {255, 255, 255};
const uchar PAINT_CURSOR_SCULPT_CURVES[3] = {255, 100, 100};
const uchar PAINT_CURSOR_SCULPT_GREASE_PENCIL[3] = {255, 100, 100};
static ePaintOverlayControlFlags overlay_flags = (ePaintOverlayControlFlags)0;
@@ -361,6 +363,9 @@ bool BKE_paint_ensure_from_paintmode(Scene *sce, PaintMode mode)
case PaintMode::SculptCurves:
paint_ptr = (Paint **)&ts->curves_sculpt;
break;
case PaintMode::SculptGreasePencil:
paint_ptr = (Paint **)&ts->gp_sculptpaint;
break;
case PaintMode::Invalid:
break;
}
@@ -398,6 +403,8 @@ Paint *BKE_paint_get_active_from_paintmode(Scene *sce, PaintMode mode)
return &ts->gp_weightpaint->paint;
case PaintMode::SculptCurves:
return &ts->curves_sculpt->paint;
case PaintMode::SculptGreasePencil:
return &ts->gp_sculptpaint->paint;
case PaintMode::Invalid:
return nullptr;
default:
@@ -432,6 +439,8 @@ const EnumPropertyItem *BKE_paint_get_tool_enum_from_paintmode(const PaintMode m
return rna_enum_brush_gpencil_weight_types_items;
case PaintMode::SculptCurves:
return rna_enum_brush_curves_sculpt_tool_items;
case PaintMode::SculptGreasePencil:
return rna_enum_brush_gpencil_sculpt_types_items;
case PaintMode::Invalid:
break;
}
@@ -462,6 +471,8 @@ const char *BKE_paint_get_tool_prop_id_from_paintmode(const PaintMode mode)
return "gpencil_weight_tool";
case PaintMode::SculptCurves:
return "curves_sculpt_tool";
case PaintMode::SculptGreasePencil:
return "gpencil_sculpt_tool";
case PaintMode::Invalid:
break;
}
@@ -485,6 +496,7 @@ const char *BKE_paint_get_tool_enum_translation_context_from_paintmode(const Pai
case PaintMode::SculptGPencil:
case PaintMode::WeightGPencil:
case PaintMode::SculptCurves:
case PaintMode::SculptGreasePencil:
case PaintMode::Invalid:
break;
}
@@ -596,7 +608,13 @@ PaintMode BKE_paintmode_get_active_from_context(const bContext *C)
case OB_MODE_SCULPT:
return PaintMode::Sculpt;
case OB_MODE_SCULPT_GPENCIL_LEGACY:
return PaintMode::SculptGPencil;
if (obact->type == OB_GPENCIL_LEGACY) {
return PaintMode::SculptGPencil;
}
if (obact->type == OB_GREASE_PENCIL) {
return PaintMode::SculptGreasePencil;
}
return PaintMode::Invalid;
case OB_MODE_WEIGHT_GPENCIL_LEGACY:
return PaintMode::WeightGPencil;
case OB_MODE_VERTEX_PAINT:
@@ -648,6 +666,8 @@ PaintMode BKE_paintmode_get_from_tool(const bToolRef *tref)
return PaintMode::SculptCurves;
case CTX_MODE_PAINT_GREASE_PENCIL:
return PaintMode::GPencil;
case CTX_MODE_SCULPT_GREASE_PENCIL:
return PaintMode::SculptGreasePencil;
}
}
else if (tref->space_type == SPACE_IMAGE) {
@@ -759,6 +779,8 @@ uint BKE_paint_get_brush_tool_offset_from_paintmode(const PaintMode mode)
return offsetof(Brush, gpencil_weight_tool);
case PaintMode::SculptCurves:
return offsetof(Brush, curves_sculpt_tool);
case PaintMode::SculptGreasePencil:
return offsetof(Brush, gpencil_sculpt_tool);
case PaintMode::Invalid:
break; /* We don't use these yet. */
}
@@ -1093,6 +1115,8 @@ eObjectMode BKE_paint_object_mode_from_paintmode(const PaintMode mode)
return OB_MODE_SCULPT_CURVES;
case PaintMode::GPencil:
return OB_MODE_PAINT_GREASE_PENCIL;
case PaintMode::SculptGreasePencil:
return OB_MODE_SCULPT_GPENCIL_LEGACY;
case PaintMode::Invalid:
default:
return OB_MODE_OBJECT;

View File

@@ -182,6 +182,7 @@ static void OVERLAY_cache_init(void *vedata)
OVERLAY_edit_lattice_cache_init(data);
break;
case CTX_MODE_PAINT_GREASE_PENCIL:
case CTX_MODE_SCULPT_GREASE_PENCIL:
case CTX_MODE_EDIT_GREASE_PENCIL:
OVERLAY_edit_grease_pencil_cache_init(data);
break;

View File

@@ -13,6 +13,7 @@
#include <cstdlib>
#include <cstring>
#include "DNA_object_enums.h"
#include "MEM_guardedalloc.h"
#include "BLI_ghash.h"
@@ -25,6 +26,7 @@
#include "BLT_translation.hh"
#include "DNA_gpencil_legacy_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_material_types.h"
#include "DNA_meshdata_types.h"
#include "DNA_object_types.h"
@@ -61,6 +63,7 @@
#include "UI_view2d.hh"
#include "ED_gpencil_legacy.hh"
#include "ED_image.hh"
#include "ED_object.hh"
#include "ED_outliner.hh"
#include "ED_screen.hh"
@@ -453,10 +456,25 @@ static bool gpencil_sculptmode_toggle_poll(bContext *C)
{
/* if using gpencil object, use this gpd */
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
if (ob == nullptr) {
return false;
}
if (ELEM(ob->type, OB_GPENCIL_LEGACY, OB_GREASE_PENCIL)) {
return ob->data != nullptr;
}
return ED_gpencil_data_get_active(C) != nullptr;
return false;
}
bool gpencil_sculpt_poll_view3d(bContext *C)
{
const Object *ob = CTX_data_active_object(C);
if (ob == nullptr || (ob->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) == 0) {
return false;
}
if (CTX_wm_region_view3d(C) == nullptr) {
return false;
}
return true;
}
static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
@@ -467,35 +485,49 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
const bool back = RNA_boolean_get(op->ptr, "back");
wmMsgBus *mbus = CTX_wm_message_bus(C);
bGPdata *gpd = ED_gpencil_data_get_active(C);
bool is_object = false;
short mode;
/* if using a gpencil object, use this datablock */
Object *ob = CTX_data_active_object(C);
if ((ob) && (ob->type == OB_GPENCIL_LEGACY)) {
gpd = static_cast<bGPdata *>(ob->data);
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
}
/* Just toggle sculptmode flag... */
gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
else {
/* try to back previous mode */
if ((ob->restore_mode) && (back == 1)) {
mode = ob->restore_mode;
}
else {
mode = OB_MODE_OBJECT;
}
}
is_object = true;
}
if ((ob) && (ob->type == OB_GREASE_PENCIL)) {
const bool is_mode_set = (ob->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) != 0;
if (is_mode_set) {
mode = OB_MODE_OBJECT;
}
else {
Scene *scene = CTX_data_scene(C);
BKE_paint_init(
bmain, scene, PaintMode::SculptGreasePencil, PAINT_CURSOR_SCULPT_GREASE_PENCIL);
Paint *paint = BKE_paint_get_active_from_paintmode(scene, PaintMode::SculptGreasePencil);
ED_paint_cursor_start(paint, gpencil_sculpt_poll_view3d);
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
is_object = true;
}
if (gpd == nullptr) {
return OPERATOR_CANCELLED;
}
/* Just toggle sculptmode flag... */
gpd->flag ^= GP_DATA_STROKE_SCULPTMODE;
/* set mode */
if (gpd->flag & GP_DATA_STROKE_SCULPTMODE) {
mode = OB_MODE_SCULPT_GPENCIL_LEGACY;
}
else {
mode = OB_MODE_OBJECT;
}
if (is_object) {
/* try to back previous mode */
if ((ob->restore_mode) && ((gpd->flag & GP_DATA_STROKE_SCULPTMODE) == 0) && (back == 1)) {
mode = ob->restore_mode;
}
ob->restore_mode = ob->mode;
ob->mode = mode;
}
@@ -511,9 +543,16 @@ static int gpencil_sculptmode_toggle_exec(bContext *C, wmOperator *op)
}
/* setup other modes */
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
if (ob->type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = ED_gpencil_data_get_active(C);
ED_gpencil_setup_modes(C, gpd, mode);
/* set cache as dirty */
DEG_id_tag_update(&gpd->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
if (ob->type == OB_GREASE_PENCIL) {
GreasePencil *grease_pencil = static_cast<GreasePencil *>(ob->data);
DEG_id_tag_update(&grease_pencil->id, ID_RECALC_TRANSFORM | ID_RECALC_GEOMETRY);
}
WM_event_add_notifier(C, NC_GPENCIL | ND_DATA | ND_GPENCIL_EDITMODE, nullptr);
WM_event_add_notifier(C, NC_SCENE | ND_MODE, nullptr);

View File

@@ -8,6 +8,7 @@
#include "BKE_context.hh"
#include "DNA_object_enums.h"
#include "DNA_scene_types.h"
#include "ED_grease_pencil.hh"
@@ -81,6 +82,22 @@ bool grease_pencil_painting_poll(bContext *C)
return true;
}
bool grease_pencil_sculpting_poll(bContext *C)
{
if (!active_grease_pencil_poll(C)) {
return false;
}
Object *object = CTX_data_active_object(C);
if ((object->mode & OB_MODE_SCULPT_GPENCIL_LEGACY) == 0) {
return false;
}
ToolSettings *ts = CTX_data_tool_settings(C);
if (!ts || !ts->gp_sculptpaint) {
return false;
}
return true;
}
static void keymap_grease_pencil_edit_mode(wmKeyConfig *keyconf)
{
wmKeyMap *keymap = WM_keymap_ensure(

View File

@@ -175,6 +175,7 @@ bool editable_grease_pencil_poll(bContext *C);
bool active_grease_pencil_layer_poll(bContext *C);
bool editable_grease_pencil_point_selection_poll(bContext *C);
bool grease_pencil_painting_poll(bContext *C);
bool grease_pencil_sculpting_poll(bContext *C);
struct DrawingInfo {
const bke::greasepencil::Drawing &drawing;

View File

@@ -9,6 +9,7 @@
* actual mode switching logic is per-object type.
*/
#include "DNA_object_enums.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
@@ -147,7 +148,9 @@ bool mode_compat_test(const Object *ob, eObjectMode mode)
}
break;
case OB_GREASE_PENCIL:
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_WEIGHT_PAINT)) {
if (mode & (OB_MODE_EDIT | OB_MODE_PAINT_GREASE_PENCIL | OB_MODE_WEIGHT_PAINT |
OB_MODE_SCULPT_GPENCIL_LEGACY))
{
return true;
}
break;

View File

@@ -11,6 +11,7 @@
#include "DNA_brush_types.h"
#include "DNA_grease_pencil_types.h"
#include "DNA_scene_types.h"
#include "ED_grease_pencil.hh"
#include "ED_image.hh"
#include "ED_object.hh"
@@ -30,41 +31,9 @@
namespace blender::ed::sculpt_paint {
/* -------------------------------------------------------------------- */
/** \name Brush Stroke Operator
/** \name Common Paint Operator Functions
* \{ */
static bool start_brush_operation(bContext &C,
wmOperator & /*op*/,
PaintStroke *paint_stroke,
const InputSample &start_sample)
{
// const BrushStrokeMode mode = static_cast<BrushStrokeMode>(RNA_enum_get(op.ptr, "mode"));
const Scene &scene = *CTX_data_scene(&C);
const GpPaint &gp_paint = *scene.toolsettings->gp_paint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_paint.paint);
GreasePencilStrokeOperation *operation = nullptr;
switch (brush.gpencil_tool) {
case GPAINT_TOOL_DRAW:
/* FIXME: Somehow store the unique_ptr in the PaintStroke. */
operation = greasepencil::new_paint_operation().release();
break;
case GPAINT_TOOL_ERASE:
operation = greasepencil::new_erase_operation().release();
break;
case GPAINT_TOOL_TINT:
operation = greasepencil::new_tint_operation().release();
break;
}
if (operation) {
paint_stroke_set_mode_data(paint_stroke, operation);
operation->on_stroke_begin(C, start_sample);
return true;
}
return false;
}
static bool stroke_get_location(bContext * /*C*/,
float out[3],
const float mouse[2],
@@ -76,19 +45,19 @@ static bool stroke_get_location(bContext * /*C*/,
return true;
}
static bool stroke_test_start(bContext *C, wmOperator *op, const float mouse[2])
static void stroke_start(bContext &C,
wmOperator &op,
const float2 &mouse,
GreasePencilStrokeOperation &operation)
{
PaintStroke *paint_stroke = static_cast<PaintStroke *>(op->customdata);
PaintStroke *paint_stroke = static_cast<PaintStroke *>(op.customdata);
InputSample start_sample;
start_sample.mouse_position = float2(mouse);
start_sample.pressure = 0.0f;
if (!start_brush_operation(*C, *op, paint_stroke, start_sample)) {
return false;
}
return true;
paint_stroke_set_mode_data(paint_stroke, &operation);
operation.on_stroke_begin(C, start_sample);
}
static void stroke_update_step(bContext *C,
@@ -121,6 +90,12 @@ static void stroke_done(const bContext *C, PaintStroke *stroke)
operation->~GreasePencilStrokeOperation();
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Brush Stroke Operator
* \{ */
static bool grease_pencil_brush_stroke_poll(bContext *C)
{
if (!ed::greasepencil::grease_pencil_painting_poll(C)) {
@@ -132,6 +107,37 @@ static bool grease_pencil_brush_stroke_poll(bContext *C)
return true;
}
static GreasePencilStrokeOperation *grease_pencil_brush_stroke_operation(bContext &C)
{
const Scene &scene = *CTX_data_scene(&C);
const GpPaint &gp_paint = *scene.toolsettings->gp_paint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_paint.paint);
switch (eBrushGPaintTool(brush.gpencil_tool)) {
case GPAINT_TOOL_DRAW:
/* FIXME: Somehow store the unique_ptr in the PaintStroke. */
return greasepencil::new_paint_operation().release();
case GPAINT_TOOL_ERASE:
return greasepencil::new_erase_operation().release();
case GPAINT_TOOL_FILL:
return nullptr;
case GPAINT_TOOL_TINT:
return greasepencil::new_tint_operation().release();
}
return nullptr;
}
static bool grease_pencil_brush_stroke_test_start(bContext *C,
wmOperator *op,
const float mouse[2])
{
GreasePencilStrokeOperation *operation = grease_pencil_brush_stroke_operation(*C);
if (operation) {
stroke_start(*C, *op, float2(mouse), *operation);
return true;
}
return false;
}
static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
@@ -168,7 +174,7 @@ static int grease_pencil_brush_stroke_invoke(bContext *C, wmOperator *op, const
op->customdata = paint_stroke_new(C,
op,
stroke_get_location,
stroke_test_start,
grease_pencil_brush_stroke_test_start,
stroke_update_step,
stroke_redraw,
stroke_done,
@@ -211,6 +217,140 @@ static void GREASE_PENCIL_OT_brush_stroke(wmOperatorType *ot)
/** \} */
/* -------------------------------------------------------------------- */
/** \name Sculpt Operator
* \{ */
static bool grease_pencil_sculpt_paint_poll(bContext *C)
{
if (!ed::greasepencil::grease_pencil_sculpting_poll(C)) {
return false;
}
if (!WM_toolsystem_active_tool_is_brush(C)) {
return false;
}
return true;
}
static GreasePencilStrokeOperation *grease_pencil_sculpt_paint_operation(bContext &C)
{
const Scene &scene = *CTX_data_scene(&C);
const GpSculptPaint &gp_sculptpaint = *scene.toolsettings->gp_sculptpaint;
const Brush &brush = *BKE_paint_brush_for_read(&gp_sculptpaint.paint);
switch (eBrushGPSculptTool(brush.gpencil_sculpt_tool)) {
case GPSCULPT_TOOL_SMOOTH:
return nullptr;
case GPSCULPT_TOOL_THICKNESS:
return nullptr;
case GPSCULPT_TOOL_STRENGTH:
return nullptr;
case GPSCULPT_TOOL_GRAB:
return nullptr;
case GPSCULPT_TOOL_PUSH:
return nullptr;
case GPSCULPT_TOOL_TWIST:
return nullptr;
case GPSCULPT_TOOL_PINCH:
return nullptr;
case GPSCULPT_TOOL_RANDOMIZE:
return nullptr;
case GPSCULPT_TOOL_CLONE:
return nullptr;
}
return nullptr;
}
static bool grease_pencil_sculpt_paint_test_start(bContext *C,
wmOperator *op,
const float mouse[2])
{
GreasePencilStrokeOperation *operation = grease_pencil_sculpt_paint_operation(*C);
if (operation) {
stroke_start(*C, *op, float2(mouse), *operation);
return true;
}
return false;
}
static int grease_pencil_sculpt_paint_invoke(bContext *C, wmOperator *op, const wmEvent *event)
{
const Scene *scene = CTX_data_scene(C);
const Object *object = CTX_data_active_object(C);
if (!object || object->type != OB_GREASE_PENCIL) {
return OPERATOR_CANCELLED;
}
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
if (!grease_pencil.has_active_layer()) {
BKE_report(op->reports, RPT_ERROR, "No active Grease Pencil layer");
return OPERATOR_CANCELLED;
}
const Paint *paint = BKE_paint_get_active_from_context(C);
const Brush *brush = BKE_paint_brush_for_read(paint);
if (brush == nullptr) {
return OPERATOR_CANCELLED;
}
bke::greasepencil::Layer &active_layer = *grease_pencil.get_active_layer();
if (!active_layer.is_editable()) {
BKE_report(op->reports, RPT_ERROR, "Active layer is locked or hidden");
return OPERATOR_CANCELLED;
}
/* Ensure a drawing at the current keyframe. */
if (!ed::greasepencil::ensure_active_keyframe(*scene, grease_pencil)) {
BKE_report(op->reports, RPT_ERROR, "No Grease Pencil frame to draw on");
return OPERATOR_CANCELLED;
}
op->customdata = paint_stroke_new(C,
op,
stroke_get_location,
grease_pencil_sculpt_paint_test_start,
stroke_update_step,
stroke_redraw,
stroke_done,
event->type);
const int return_value = op->type->modal(C, op, event);
if (return_value == OPERATOR_FINISHED) {
return OPERATOR_FINISHED;
}
WM_event_add_modal_handler(C, op);
return OPERATOR_RUNNING_MODAL;
}
static int grease_pencil_sculpt_paint_modal(bContext *C, wmOperator *op, const wmEvent *event)
{
return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
}
static void grease_pencil_sculpt_paint_cancel(bContext *C, wmOperator *op)
{
paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
}
static void GREASE_PENCIL_OT_sculpt_paint(wmOperatorType *ot)
{
ot->name = "Grease Pencil Draw";
ot->idname = "GREASE_PENCIL_OT_sculpt_paint";
ot->description = "Draw a new stroke in the active Grease Pencil object";
ot->poll = grease_pencil_sculpt_paint_poll;
ot->invoke = grease_pencil_sculpt_paint_invoke;
ot->modal = grease_pencil_sculpt_paint_modal;
ot->cancel = grease_pencil_sculpt_paint_cancel;
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
paint_stroke_operator_properties(ot);
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Toggle Draw Mode
* \{ */
@@ -306,6 +446,7 @@ void ED_operatortypes_grease_pencil_draw()
{
using namespace blender::ed::sculpt_paint;
WM_operatortype_append(GREASE_PENCIL_OT_brush_stroke);
WM_operatortype_append(GREASE_PENCIL_OT_sculpt_paint);
WM_operatortype_append(GREASE_PENCIL_OT_draw_mode_toggle);
}

View File

@@ -1220,6 +1220,7 @@ static bool paint_use_2d_cursor(PaintMode mode)
case PaintMode::SculptGPencil:
case PaintMode::WeightGPencil:
case PaintMode::SculptCurves:
case PaintMode::SculptGreasePencil:
case PaintMode::GPencil:
return true;
case PaintMode::Invalid:

View File

@@ -689,6 +689,9 @@ static int paintcurve_draw_exec(bContext *C, wmOperator * /*op*/)
case PaintMode::GPencil:
name = "GREASE_PENCIL_OT_brush_stroke";
break;
case PaintMode::SculptGreasePencil:
name = "GREASE_PENCIL_OT_sculpt_paint";
break;
default:
return OPERATOR_PASS_THROUGH;
}

View File

@@ -943,6 +943,7 @@ static const PaintMode brush_select_paint_modes[] = {
PaintMode::SculptGPencil,
PaintMode::WeightGPencil,
PaintMode::SculptCurves,
PaintMode::SculptGreasePencil,
};
static int brush_select_exec(bContext *C, wmOperator *op)

View File

@@ -1041,7 +1041,7 @@ bool paint_space_stroke_enabled(Brush *br, PaintMode mode)
return false;
}
if (mode == PaintMode::GPencil) {
if (ELEM(mode, PaintMode::GPencil, PaintMode::SculptGreasePencil)) {
/* No spacing needed for now. */
return false;
}

View File

@@ -409,6 +409,10 @@ static void view3d_main_region_init(wmWindowManager *wm, ARegion *region)
wm->defaultconf, "Grease Pencil Paint Mode", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
keymap = WM_keymap_ensure(
wm->defaultconf, "Grease Pencil Sculpt Mode", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
/* Edit-font key-map swallows almost all (because of text input). */
keymap = WM_keymap_ensure(wm->defaultconf, "Font", SPACE_EMPTY, RGN_TYPE_WINDOW);
WM_event_add_keymap_handler(&region->handlers, keymap);
@@ -1707,6 +1711,9 @@ void ED_view3d_buttons_region_layout_ex(const bContext *C,
case CTX_MODE_PAINT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".grease_pencil_paint");
break;
case CTX_MODE_SCULPT_GREASE_PENCIL:
ARRAY_SET_ITEMS(contexts, ".paint_common", ".grease_pencil_sculpt");
break;
case CTX_MODE_EDIT_POINT_CLOUD:
ARRAY_SET_ITEMS(contexts, ".point_cloud_edit");
break;

View File

@@ -46,6 +46,7 @@ const EnumPropertyItem rna_enum_context_mode_items[] = {
{CTX_MODE_VERTEX_GPENCIL_LEGACY, "VERTEX_GPENCIL", 0, "Grease Pencil Vertex Paint", ""},
{CTX_MODE_SCULPT_CURVES, "SCULPT_CURVES", 0, "Curves Sculpt", ""},
{CTX_MODE_PAINT_GREASE_PENCIL, "PAINT_GREASE_PENCIL", 0, "Grease Pencil Paint", ""},
{CTX_MODE_SCULPT_GREASE_PENCIL, "SCULPT_GREASE_PENCIL", 0, "Grease Pencil Sculpt", ""},
{0, nullptr, 0, nullptr, nullptr},
};

View File

@@ -156,6 +156,9 @@ wmKeyMap *WM_keymap_guess_from_context(const bContext *C)
case CTX_MODE_PAINT_GREASE_PENCIL:
km_id = "Grease Pencil Paint Mode";
break;
case CTX_MODE_SCULPT_GREASE_PENCIL:
km_id = "Grease Pencil Sculpt Mode";
break;
}
}
else if (sl->spacetype == SPACE_IMAGE) {

View File

@@ -720,6 +720,7 @@ static const char *toolsystem_default_tool(const bToolKey *tkey)
case CTX_MODE_PAINT_GREASE_PENCIL:
return "builtin_brush.Draw";
case CTX_MODE_SCULPT_GPENCIL_LEGACY:
case CTX_MODE_SCULPT_GREASE_PENCIL:
return "builtin_brush.Push";
case CTX_MODE_WEIGHT_GPENCIL_LEGACY:
return "builtin_brush.Weight";