Initial Grease Pencil 3.0 stage #106848
|
@ -3812,16 +3812,22 @@ def km_grease_pencil_stroke_paint_draw_brush(params):
|
|||
|
||||
items.extend([
|
||||
# Draw
|
||||
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
|
||||
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
|
||||
# Draw - straight lines
|
||||
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
|
||||
{"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
|
||||
# Erase
|
||||
("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
|
||||
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
{"properties": [("mode", 'NORMAL')]}),
|
||||
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
|
||||
{"properties": [("mode", 'INVERT')]}),
|
||||
("grease_pencil.brush_stroke", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
||||
{"properties": [("mode", 'SMOOTH')]}),
|
||||
# ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS'},
|
||||
# {"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
|
||||
# ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "shift": True},
|
||||
# {"properties": [("mode", 'DRAW'), ("wait_for_input", False)]}),
|
||||
# # Draw - straight lines
|
||||
# ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "alt": True},
|
||||
# {"properties": [("mode", 'DRAW_STRAIGHT'), ("wait_for_input", False)]}),
|
||||
# # Erase
|
||||
# ("gpencil.draw", {"type": 'LEFTMOUSE', "value": 'PRESS', "ctrl": True},
|
||||
# {"properties": [("mode", 'ERASER'), ("wait_for_input", False)]}),
|
||||
# Constrain Guides Speedlines
|
||||
# Freehand
|
||||
("gpencil.draw", {"type": 'O', "value": 'PRESS'}, None),
|
||||
|
|
|
@ -1941,6 +1941,15 @@ class _defs_gpencil_paint:
|
|||
),
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def draw():
|
||||
return dict(
|
||||
idname="builtin_brush.draw",
|
||||
label="Draw",
|
||||
icon="brush.gpencil_draw.draw",
|
||||
data_block='DRAW',
|
||||
)
|
||||
|
||||
@ToolDef.from_fn
|
||||
def cutter():
|
||||
def draw_settings(_context, layout, tool):
|
||||
|
@ -3121,7 +3130,7 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
|
|||
'PAINT_GPENCIL': [
|
||||
_defs_view3d_generic.cursor,
|
||||
None,
|
||||
_defs_gpencil_paint.generate_from_brushes,
|
||||
_defs_gpencil_paint.draw,
|
||||
_defs_gpencil_paint.cutter,
|
||||
None,
|
||||
_defs_gpencil_paint.eyedropper,
|
||||
|
|
|
@ -138,7 +138,12 @@ static bool gpencil_stroke_weightmode_poll_with_tool(bContext *C, const char gpe
|
|||
/* Poll callback for stroke painting (draw brush) */
|
||||
static bool gpencil_stroke_paintmode_draw_poll(bContext *C)
|
||||
{
|
||||
return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW);
|
||||
Object *object = CTX_data_active_object(C);
|
||||
if (object == NULL || object->type != OB_GREASE_PENCIL) {
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
// return gpencil_stroke_paintmode_poll_with_tool(C, GPAINT_TOOL_DRAW);
|
||||
}
|
||||
|
||||
/* Poll callback for stroke painting (erase brush) */
|
||||
|
|
|
@ -42,6 +42,7 @@ set(SRC
|
|||
curves_sculpt_smooth.cc
|
||||
curves_sculpt_snake_hook.cc
|
||||
grease_pencil_draw_ops.cc
|
||||
grease_pencil_paint.cc
|
||||
paint_canvas.cc
|
||||
paint_cursor.cc
|
||||
paint_curve.c
|
||||
|
@ -88,6 +89,7 @@ set(SRC
|
|||
|
||||
curves_sculpt_intern.h
|
||||
curves_sculpt_intern.hh
|
||||
grease_pencil_intern.hh
|
||||
paint_intern.h
|
||||
sculpt_intern.hh
|
||||
)
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
|
||||
#include "ED_grease_pencil_draw.h"
|
||||
#include "ED_object.h"
|
||||
#include "ED_screen.h"
|
||||
|
||||
#include "RNA_access.h"
|
||||
#include "RNA_define.h"
|
||||
|
@ -20,10 +21,151 @@
|
|||
#include "WM_message.h"
|
||||
#include "WM_toolsystem.h"
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
#include "paint_intern.h"
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Brush Stroke Operator
|
||||
* \{ */
|
||||
|
||||
static bool start_brush_operation(bContext &C,
|
||||
wmOperator &op,
|
||||
PaintStroke *paint_stroke,
|
||||
const StrokeExtension &stroke_start)
|
||||
{
|
||||
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 = gpencil::new_paint_operation().release();
|
||||
break;
|
||||
default:
|
||||
BLI_assert_unreachable();
|
||||
|
||||
}
|
||||
|
||||
if (operation) {
|
||||
paint_stroke_set_mode_data(paint_stroke, operation);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool stroke_get_location(bContext * /*C*/,
|
||||
float out[3],
|
||||
const float mouse[2],
|
||||
bool /*force_original*/)
|
||||
{
|
||||
out[0] = mouse[0];
|
||||
out[1] = mouse[1];
|
||||
out[2] = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
static bool stroke_test_start(bContext *C, struct wmOperator *op, const float mouse[2])
|
||||
{
|
||||
PaintStroke *paint_stroke = static_cast<PaintStroke *>(op->customdata);
|
||||
|
||||
StrokeExtension stroke_extension;
|
||||
stroke_extension.mouse_position = float2(mouse);
|
||||
stroke_extension.pressure = 0.0f;
|
||||
stroke_extension.is_first = true;
|
||||
|
||||
if (!start_brush_operation(*C, *op, paint_stroke, stroke_extension)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static void stroke_update_step(bContext *C,
|
||||
wmOperator *op,
|
||||
PaintStroke *stroke,
|
||||
PointerRNA *stroke_element)
|
||||
{
|
||||
GreasePencilStrokeOperation *operation = static_cast<GreasePencilStrokeOperation *>(
|
||||
paint_stroke_mode_data(stroke));
|
||||
|
||||
StrokeExtension stroke_extension;
|
||||
RNA_float_get_array(stroke_element, "mouse", stroke_extension.mouse_position);
|
||||
stroke_extension.pressure = RNA_float_get(stroke_element, "pressure");
|
||||
stroke_extension.is_first = false;
|
||||
|
||||
if (operation) {
|
||||
operation->on_stroke_extended(*C, stroke_extension);
|
||||
}
|
||||
}
|
||||
|
||||
static void stroke_redraw(const bContext *C, PaintStroke * /*stroke*/, bool /*final*/)
|
||||
{
|
||||
ED_region_tag_redraw(CTX_wm_region(C));
|
||||
}
|
||||
|
||||
static void stroke_done(const bContext *C, PaintStroke *stroke)
|
||||
{
|
||||
GreasePencilStrokeOperation *operation = static_cast<GreasePencilStrokeOperation *>(
|
||||
paint_stroke_mode_data(stroke));
|
||||
operation->on_stroke_done(*C);
|
||||
}
|
||||
|
||||
static int grease_pencil_stroke_invoke(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
op->customdata = static_cast<void *>(paint_stroke_new(C,
|
||||
op,
|
||||
stroke_get_location,
|
||||
stroke_test_start,
|
||||
stroke_update_step,
|
||||
stroke_redraw,
|
||||
stroke_done,
|
||||
event->type));
|
||||
|
||||
int return_value = op->type->modal(C, op, event);
|
||||
filedescriptor marked this conversation as resolved
Sergey Sharybin
commented
`const int`
|
||||
if (return_value == OPERATOR_FINISHED) {
|
||||
return OPERATOR_FINISHED;
|
||||
}
|
||||
|
||||
WM_event_add_modal_handler(C, op);
|
||||
return OPERATOR_RUNNING_MODAL;
|
||||
}
|
||||
|
||||
static int grease_pencil_stroke_modal(bContext *C, wmOperator *op, const wmEvent *event)
|
||||
{
|
||||
return paint_stroke_modal(C, op, event, reinterpret_cast<PaintStroke **>(&op->customdata));
|
||||
}
|
||||
|
||||
static void grease_pencil_stroke_cancel(bContext *C, wmOperator *op)
|
||||
{
|
||||
paint_stroke_cancel(C, op, static_cast<PaintStroke *>(op->customdata));
|
||||
}
|
||||
|
||||
static void GREASE_PENCIL_OT_brush_stroke(struct wmOperatorType *ot)
|
||||
{
|
||||
ot->name = "Stroke Curves Sculpt";
|
||||
ot->idname = "GREASE_PENCIL_OT_brush_stroke";
|
||||
ot->description = "Sculpt curves using a brush";
|
||||
|
||||
ot->invoke = grease_pencil_stroke_invoke;
|
||||
ot->modal = grease_pencil_stroke_modal;
|
||||
ot->cancel = grease_pencil_stroke_cancel;
|
||||
|
||||
ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO;
|
||||
|
||||
paint_stroke_operator_properties(ot);
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Toggle Draw Mode
|
||||
|
@ -121,6 +263,7 @@ static void GREASE_PENCIL_OT_draw_mode_toggle(wmOperatorType *ot)
|
|||
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_draw_mode_toggle);
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "paint_intern.h"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint {
|
||||
|
||||
struct StrokeExtension {
|
||||
bool is_first;
|
||||
float2 mouse_position;
|
||||
float pressure;
|
||||
};
|
||||
|
||||
class GreasePencilStrokeOperation {
|
||||
public:
|
||||
virtual ~GreasePencilStrokeOperation() = default;
|
||||
virtual void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) = 0;
|
||||
virtual void on_stroke_done(const bContext &C) = 0;
|
||||
};
|
||||
|
||||
namespace gpencil {
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_paint_operation();
|
||||
|
||||
} // namespace gpencil
|
||||
|
||||
} // namespace blender::ed::sculpt_paint
|
|
@ -0,0 +1,49 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
* Copyright 2023 Blender Foundation. */
|
||||
|
||||
#include "grease_pencil_intern.hh"
|
||||
|
||||
namespace blender::ed::sculpt_paint::gpencil {
|
||||
|
||||
class PaintOperation : public GreasePencilStrokeOperation {
|
||||
|
||||
public:
|
||||
~PaintOperation() override {}
|
||||
|
||||
void on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension) override;
|
||||
void on_stroke_done(const bContext &C) override;
|
||||
};
|
||||
|
||||
/**
|
||||
* Utility class that actually executes the update when the stroke is updated. That's useful
|
||||
* because it avoids passing a very large number of parameters between functions.
|
||||
*/
|
||||
struct PaintOperationExecutor {
|
||||
|
||||
PaintOperationExecutor(const bContext &C) {}
|
||||
|
||||
void execute(PaintOperation &self, const bContext &C, const StrokeExtension &stroke_extension)
|
||||
{
|
||||
std::cout << "pos: (" << stroke_extension.mouse_position.x << ", "
|
||||
<< stroke_extension.mouse_position.x << "), pressure: " << stroke_extension.pressure
|
||||
<< std::endl;
|
||||
}
|
||||
};
|
||||
|
||||
void PaintOperation::on_stroke_extended(const bContext &C, const StrokeExtension &stroke_extension)
|
||||
{
|
||||
PaintOperationExecutor executor{C};
|
||||
executor.execute(*this, C, stroke_extension);
|
||||
}
|
||||
|
||||
void PaintOperation::on_stroke_done(const bContext &C)
|
||||
{
|
||||
std::cout << "Done!" << std::endl;
|
||||
}
|
||||
|
||||
std::unique_ptr<GreasePencilStrokeOperation> new_paint_operation()
|
||||
{
|
||||
return std::make_unique<PaintOperation>();
|
||||
}
|
||||
Hans Goudey
commented
It seems a bit weird to modifier the evaluated object here. Is that purposeful? Or am I missing something? It seems a bit weird to modifier the evaluated object here. Is that purposeful? Or am I missing something?
Falk David
commented
Yes, this is done on purpose so that the extra copy from orig to eval for rendering is not needed every update. Once drawing is done, the stroke is copied from the eval buffer to orig. Yes, this is done on purpose so that the extra copy from orig to eval for rendering is not needed every update. Once drawing is done, the stroke is copied from the eval buffer to orig.
Hans Goudey
commented
Okay, makes sense. This definitely deserves a comment, since typically changing the evaluated data isn't a good idea. Okay, makes sense. This definitely deserves a comment, since typically changing the evaluated data isn't a good idea.
|
||||
|
||||
} // namespace blender::ed::sculpt_paint::gpencil
|
Loading…
Reference in New Issue
I am not really sure what the goal is here. If the goal is to somehow ensure all cases are handled it is much better to not use
default
and let compiler tell you where cases are missing at the compile time.