GPv3: Transform operators

This adds the keybindings, menu, and functionally for the edit mode transform operators to grease pencil v3.

The transform operation include:
 * translate, rotate, scale, change opacity, change radius

Pull Request: https://projects.blender.org/blender/blender/pulls/111836
This commit is contained in:
casey bianco-davis 2023-10-21 15:12:47 +02:00 committed by Falk David
parent b4e6ef4279
commit e266b142f6
15 changed files with 458 additions and 125 deletions

View File

@ -4610,6 +4610,18 @@ def km_grease_pencil_edit(params):
{"properties": [("type", "ALL_FRAMES")]}),
# Keyframe Menu
op_menu("VIEW3D_MT_edit_greasepencil_animation", {"type": 'I', "value": 'PRESS'}),
# Transform Actions.
*_template_items_transform_actions(params, use_bend=True, use_mirror=True, use_tosphere=True, use_shear=True),
("transform.transform", {"type": 'S', "value": 'PRESS', "alt": True},
{"properties": [("mode", 'CURVE_SHRINKFATTEN')]}),
("transform.transform", {"type": 'F', "value": 'PRESS', "shift": True},
{"properties": [("mode", 'GPENCIL_OPACITY')]}),
# Proportional editing.
*_template_items_proportional_editing(
params, connected=True, toggle_data_path='tool_settings.use_proportional_edit'),
# Cyclical set
("grease_pencil.cyclical_set", {"type": 'F', "value": 'PRESS'}, {"properties": [("type", "CLOSE")]}),
("grease_pencil.cyclical_set", {"type": 'C', "value": 'PRESS',
@ -7265,6 +7277,16 @@ def km_3d_view_tool_shear(params):
]},
)
def km_3d_view_tool_bend(params):
return (
"3D View Tool: Bend",
{"space_type": 'VIEW_3D', "region_type": 'WINDOW'},
{"items": [
# No need for `tool_modifier` since this takes all input.
("transform.bend", params.tool_maybe_tweak_event,
{"properties": [("release_confirm", True)]}),
]},
)
def km_3d_view_tool_measure(params):
return (
@ -8567,6 +8589,7 @@ def generate_keymaps(params=None):
km_3d_view_tool_rotate(params),
km_3d_view_tool_scale(params),
km_3d_view_tool_shear(params),
km_3d_view_tool_bend(params),
km_3d_view_tool_measure(params),
km_3d_view_tool_interactive_add(params),
km_3d_view_tool_pose_breakdowner(params),

View File

@ -366,6 +366,16 @@ class _defs_transform:
draw_settings=draw_settings,
)
@ToolDef.from_fn
def bend():
return dict(
idname="builtin.bend",
label="Bend",
icon="ops.gpencil.edit_bend",
widget=None,
keymap="3D View Tool: Bend",
)
@ToolDef.from_fn
def transform():
def draw_settings(context, layout, tool):
@ -3012,6 +3022,18 @@ class VIEW3D_PT_tools_active(ToolSelectPanelHelper, Panel):
],
'EDIT_GREASE_PENCIL': [
*_tools_select,
_defs_view3d_generic.cursor,
None,
*_tools_transform,
None,
_defs_edit_curve.curve_radius,
_defs_transform.bend,
(
_defs_transform.shear,
_defs_edit_mesh.tosphere,
),
None,
*_tools_annotate,
],
'PARTICLE': [
*_tools_select,

View File

@ -1237,10 +1237,10 @@ class VIEW3D_MT_transform(VIEW3D_MT_transform_base, Menu):
if context.mode == 'EDIT_MESH':
layout.operator("transform.shrink_fatten", text="Shrink/Fatten").alt_navigation = alt_navigation
layout.operator("transform.skin_resize")
elif context.mode == 'EDIT_CURVE':
elif context.mode in ['EDIT_CURVE', 'EDIT_GREASE_PENCIL']:
layout.operator("transform.transform", text="Radius").mode = 'CURVE_SHRINKFATTEN'
if context.mode != 'EDIT_CURVES':
if context.mode != 'EDIT_CURVES' and context.mode != 'EDIT_GREASE_PENCIL':
layout.separator()
props = layout.operator("transform.translate", text="Move Texture Space")
props.texture_space = True
@ -5805,6 +5805,11 @@ class VIEW3D_MT_edit_greasepencil(Menu):
def draw(self, _context):
layout = self.layout
layout.menu("VIEW3D_MT_transform")
layout.menu("VIEW3D_MT_mirror")
layout.separator()
layout.menu("VIEW3D_MT_edit_greasepencil_delete")

View File

@ -53,6 +53,9 @@ GeometryDeformation get_evaluated_curves_deformation(const Depsgraph &depsgraph,
const Object &ob_orig);
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object *ob_eval,
const Object &ob_orig,
int drawing_index);
int layer_index);
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Depsgraph &depsgraph,
const Object &ob_orig,
int layer_index);
} // namespace blender::bke::crazyspace

View File

@ -740,4 +740,12 @@ GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Object
return deformation;
}
GeometryDeformation get_evaluated_grease_pencil_drawing_deformation(const Depsgraph &depsgraph,
const Object &ob_orig,
const int layer_index)
{
const Object *ob_eval = DEG_get_evaluated_object(&depsgraph, const_cast<Object *>(&ob_orig));
return get_evaluated_grease_pencil_drawing_deformation(ob_eval, ob_orig, layer_index);
}
} // namespace blender::bke::crazyspace

View File

@ -32,6 +32,7 @@ set(SRC
transform_convert_curves.cc
transform_convert_gpencil_legacy.cc
transform_convert_graph.cc
transform_convert_grease_pencil.cc
transform_convert_lattice.cc
transform_convert_mask.cc
transform_convert_mball.cc

View File

@ -426,11 +426,16 @@ void removeAspectRatio(TransInfo *t, float vec[2])
static void viewRedrawForce(const bContext *C, TransInfo *t)
{
if (t->options & CTX_GPENCIL_STROKES) {
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd) {
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
if (t->obedit_type == OB_GREASE_PENCIL) {
WM_event_add_notifier(C, NC_GEOM | ND_DATA, nullptr);
}
else if (t->obedit_type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = ED_gpencil_data_get_active(C);
if (gpd) {
DEG_id_tag_update(&gpd->id, ID_RECALC_GEOMETRY);
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
WM_event_add_notifier(C, NC_GPENCIL | NA_EDITED, nullptr);
}
else if (t->spacetype == SPACE_VIEW3D) {
if (t->options & CTX_PAINT_CURVE) {

View File

@ -718,23 +718,25 @@ static int countAndCleanTransDataContainer(TransInfo *t)
static void init_proportional_edit(TransInfo *t)
{
/* NOTE: Proportional editing is not usable in pose mode yet #32444. */
if (!ELEM(t->data_type,
&TransConvertType_Action,
&TransConvertType_Curve,
&TransConvertType_Curves,
&TransConvertType_Graph,
&TransConvertType_GPencil,
&TransConvertType_Lattice,
&TransConvertType_Mask,
&TransConvertType_MBall,
&TransConvertType_Mesh,
&TransConvertType_MeshEdge,
&TransConvertType_MeshSkin,
&TransConvertType_MeshUV,
&TransConvertType_MeshVertCData,
&TransConvertType_Node,
&TransConvertType_Object,
&TransConvertType_Particle))
/* NOTE: This `ELEM` uses more than 16 elements and so has been split. */
if (!(ELEM(t->data_type,
&TransConvertType_Action,
&TransConvertType_Curve,
&TransConvertType_Curves,
&TransConvertType_Graph,
&TransConvertType_GPencil,
&TransConvertType_GreasePencil,
&TransConvertType_Lattice,
&TransConvertType_Mask,
&TransConvertType_MBall,
&TransConvertType_Mesh,
&TransConvertType_MeshEdge,
&TransConvertType_MeshSkin,
&TransConvertType_MeshUV,
&TransConvertType_MeshVertCData,
&TransConvertType_Node,
&TransConvertType_Object) ||
ELEM(t->data_type, &TransConvertType_Particle)))
{
/* Disable proportional editing */
t->options |= CTX_NO_PET;
@ -797,6 +799,7 @@ static void init_TransDataContainers(TransInfo *t,
&TransConvertType_Curve,
&TransConvertType_Curves,
&TransConvertType_GPencil,
&TransConvertType_GreasePencil,
&TransConvertType_Lattice,
&TransConvertType_MBall,
&TransConvertType_Mesh,
@ -813,6 +816,7 @@ static void init_TransDataContainers(TransInfo *t,
const short object_type = obact ? obact->type : -1;
if ((object_mode & OB_MODE_EDIT) || (t->data_type == &TransConvertType_GPencil) ||
(t->data_type == &TransConvertType_GreasePencil) ||
((object_mode & OB_MODE_POSE) && (object_type == OB_ARMATURE)))
{
if (t->data_container) {
@ -860,6 +864,9 @@ static void init_TransDataContainers(TransInfo *t,
else if (t->data_type == &TransConvertType_GPencil) {
tc->use_local_mat = true;
}
else if (t->data_type == &TransConvertType_GreasePencil) {
tc->use_local_mat = true;
}
if (tc->use_local_mat) {
BLI_assert((t->flag & T_2D_EDIT) == 0);
@ -910,7 +917,13 @@ static TransConvertTypeInfo *convert_type_get(const TransInfo *t, Object **r_obj
return &TransConvertType_MeshEdge;
}
if (t->options & CTX_GPENCIL_STROKES) {
return &TransConvertType_GPencil;
if (t->obedit_type == OB_GREASE_PENCIL) {
return &TransConvertType_GreasePencil;
}
else if (t->obedit_type == OB_GPENCIL_LEGACY) {
return &TransConvertType_GPencil;
}
return nullptr;
}
if (t->spacetype == SPACE_IMAGE) {
if (t->options & CTX_MASK) {

View File

@ -11,6 +11,10 @@
#include "RE_engine.h"
#include "BKE_curves.hh"
#include "BLI_index_mask.hh"
struct BMEditMesh;
struct BMesh;
struct BezTriple;
@ -106,6 +110,19 @@ void transform_convert_clip_mirror_modifier_apply(TransDataContainer *tc);
*/
void animrecord_check_state(TransInfo *t, ID *id);
/* `transform_convert_curves.cc` */
/**
* Used for both curves and grease pencil objects.
*/
void curve_populate_trans_data_structs(TransDataContainer &tc,
blender::bke::CurvesGeometry &curves,
std::optional<blender::MutableSpan<float>> value_attribute,
const blender::IndexMask &selected_indices,
bool use_proportional_edit,
bool use_connected_only,
int trans_data_offset);
/* `transform_convert_action.cc` */
extern TransConvertTypeInfo TransConvertType_Action;
@ -131,7 +148,7 @@ extern TransConvertTypeInfo TransConvertType_Cursor3D;
extern TransConvertTypeInfo TransConvertType_Curve;
/* transform_convert_curves.cc */
/* `transform_convert_curves.cc` */
extern TransConvertTypeInfo TransConvertType_Curves;
@ -143,6 +160,10 @@ extern TransConvertTypeInfo TransConvertType_Graph;
extern TransConvertTypeInfo TransConvertType_GPencil;
/* `transform_convert_greasepencil.cc` */
extern TransConvertTypeInfo TransConvertType_GreasePencil;
/* `transform_convert_lattice.cc` */
extern TransConvertTypeInfo TransConvertType_Lattice;

View File

@ -6,6 +6,8 @@
* \ingroup edtransform
*/
#include <optional>
#include "BLI_array.hh"
#include "BLI_inplace_priority_queue.hh"
#include "BLI_math_matrix.h"
@ -95,82 +97,14 @@ static void createTransCurvesVerts(bContext * /*C*/, TransInfo *t)
Curves *curves_id = static_cast<Curves *>(tc.obedit->data);
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc.obedit->object_to_world);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
MutableSpan<float3> positions = curves.positions_for_write();
if (use_proportional_edit) {
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
".selection", ATTR_DOMAIN_POINT, true);
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
Vector<float> closest_distances;
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
const bool has_any_selected = ed::curves::has_anything_selected(selection, points);
if (!has_any_selected && use_connected_only) {
for (const int point_i : points) {
TransData &td = tc.data[point_i];
td.flag |= TD_SKIP;
}
continue;
}
closest_distances.reinitialize(points.size());
closest_distances.fill(std::numeric_limits<float>::max());
for (const int i : IndexRange(points.size())) {
const int point_i = points[i];
TransData &td = tc.data[point_i];
float3 *elem = &positions[point_i];
copy_v3_v3(td.iloc, *elem);
copy_v3_v3(td.center, td.iloc);
td.loc = *elem;
td.flag = 0;
if (selection[point_i]) {
closest_distances[i] = 0.0f;
td.flag = TD_SELECTED;
}
td.ext = nullptr;
copy_m3_m3(td.smtx, smtx);
copy_m3_m3(td.mtx, mtx);
}
if (use_connected_only) {
calculate_curve_point_distances_for_proportional_editing(
positions.slice(points), closest_distances.as_mutable_span());
for (const int i : IndexRange(points.size())) {
TransData &td = tc.data[points[i]];
td.dist = closest_distances[i];
}
}
}
});
}
else {
const IndexMask selected_indices = selection_per_object[i];
threading::parallel_for(selected_indices.index_range(), 1024, [&](const IndexRange range) {
for (const int selection_i : range) {
TransData *td = &tc.data[selection_i];
float3 *elem = &positions[selected_indices[selection_i]];
copy_v3_v3(td->iloc, *elem);
copy_v3_v3(td->center, td->iloc);
td->loc = *elem;
td->flag = TD_SELECTED;
td->ext = nullptr;
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
}
});
}
curve_populate_trans_data_structs(
tc,
curves,
{} /* Currently no transform for attributes other than position. */,
selection_per_object[i],
use_proportional_edit,
use_connected_only,
0 /* No data offset for curves. */);
}
}
@ -189,6 +123,106 @@ static void recalcData_curves(TransInfo *t)
} // namespace blender::ed::transform::curves
void curve_populate_trans_data_structs(TransDataContainer &tc,
blender::bke::CurvesGeometry &curves,
std::optional<blender::MutableSpan<float>> value_attribute,
const blender::IndexMask &selected_indices,
bool use_proportional_edit,
bool use_connected_only,
int trans_data_offset)
{
using namespace blender;
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc.obedit->object_to_world);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
MutableSpan<float3> positions = curves.positions_for_write();
if (use_proportional_edit) {
const OffsetIndices<int> points_by_curve = curves.points_by_curve();
const VArray<bool> selection = *curves.attributes().lookup_or_default<bool>(
".selection", ATTR_DOMAIN_POINT, true);
threading::parallel_for(curves.curves_range(), 512, [&](const IndexRange range) {
Vector<float> closest_distances;
for (const int curve_i : range) {
const IndexRange points = points_by_curve[curve_i];
const bool has_any_selected = ed::curves::has_anything_selected(selection, points);
if (!has_any_selected && use_connected_only) {
for (const int point_i : points) {
TransData &td = tc.data[point_i + trans_data_offset];
td.flag |= TD_SKIP;
}
continue;
}
closest_distances.reinitialize(points.size());
closest_distances.fill(std::numeric_limits<float>::max());
for (const int i : IndexRange(points.size())) {
const int point_i = points[i];
TransData &td = tc.data[point_i + trans_data_offset];
float3 *elem = &positions[point_i];
copy_v3_v3(td.iloc, *elem);
copy_v3_v3(td.center, td.iloc);
td.loc = *elem;
td.flag = 0;
if (selection[point_i]) {
closest_distances[i] = 0.0f;
td.flag = TD_SELECTED;
}
if (value_attribute) {
float *value = &((*value_attribute)[point_i]);
td.val = value;
td.ival = *value;
}
td.ext = nullptr;
copy_m3_m3(td.smtx, smtx);
copy_m3_m3(td.mtx, mtx);
}
if (use_connected_only) {
blender::ed::transform::curves::calculate_curve_point_distances_for_proportional_editing(
positions.slice(points), closest_distances.as_mutable_span());
for (const int i : IndexRange(points.size())) {
TransData &td = tc.data[points[i] + trans_data_offset];
td.dist = closest_distances[i];
}
}
}
});
}
else {
threading::parallel_for(selected_indices.index_range(), 1024, [&](const IndexRange range) {
for (const int selection_i : range) {
TransData *td = &tc.data[selection_i + trans_data_offset];
const int point_i = selected_indices[selection_i];
float3 *elem = &positions[point_i];
copy_v3_v3(td->iloc, *elem);
copy_v3_v3(td->center, td->iloc);
td->loc = *elem;
if (value_attribute) {
float *value = &((*value_attribute)[point_i]);
td->val = value;
td->ival = *value;
}
td->flag = TD_SELECTED;
td->ext = nullptr;
copy_m3_m3(td->smtx, smtx);
copy_m3_m3(td->mtx, mtx);
}
});
}
}
/** \} */
TransConvertTypeInfo TransConvertType_Curves = {

View File

@ -0,0 +1,145 @@
/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup edtransform
*/
#include "BLI_math_matrix.h"
#include "BKE_context.h"
#include "ED_curves.hh"
#include "ED_grease_pencil.hh"
#include "transform.hh"
#include "transform_convert.hh"
/* -------------------------------------------------------------------- */
/** \name Grease Pencil Transform Creation
* \{ */
namespace blender::ed::transform::greasepencil {
static void createTransGreasePencilVerts(bContext *C, TransInfo *t)
{
Scene *scene = CTX_data_scene(C);
MutableSpan<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
IndexMaskMemory memory;
Array<IndexMask> selection_per_layer_per_object(t->data_container_len);
const bool use_proportional_edit = (t->flag & T_PROP_EDIT_ALL) != 0;
const bool use_connected_only = (t->flag & T_PROP_CONNECTED) != 0;
int layer_offset = 0;
/* Count selected elements per layer per object and create TransData structs. */
for (const int i : trans_data_contrainers.index_range()) {
TransDataContainer &tc = trans_data_contrainers[i];
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int /*layer_index*/, blender::bke::greasepencil::Drawing &drawing) {
const bke::CurvesGeometry &curves = drawing.strokes();
if (use_proportional_edit) {
tc.data_len += curves.point_num;
}
else {
selection_per_layer_per_object[i + layer_offset] =
ed::curves::retrieve_selected_points(curves, memory);
tc.data_len += selection_per_layer_per_object[i + layer_offset].size();
}
layer_offset++;
});
if (tc.data_len > 0) {
tc.data = MEM_cnew_array<TransData>(tc.data_len, __func__);
}
}
/* Reuse the variable `layer_offset` */
layer_offset = 0;
/* Populate TransData structs. */
for (const int i : trans_data_contrainers.index_range()) {
TransDataContainer &tc = trans_data_contrainers[i];
if (tc.data_len == 0) {
continue;
}
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
float mtx[3][3], smtx[3][3];
copy_m3_m4(mtx, tc.obedit->object_to_world);
pseudoinverse_m3_m3(smtx, mtx, PSEUDOINVERSE_EPSILON);
int layer_points_offset = 0;
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int /*layer_index*/, blender::bke::greasepencil::Drawing &drawing) {
bke::CurvesGeometry &curves = drawing.strokes_for_write();
const IndexMask selected_indices = selection_per_layer_per_object[i + layer_offset];
std::optional<MutableSpan<float>> value_attribute;
if (t->mode == TFM_CURVE_SHRINKFATTEN) {
MutableSpan<float> radii = drawing.radii_for_write();
value_attribute = radii;
}
else if (t->mode == TFM_GPENCIL_OPACITY) {
MutableSpan<float> opacities = drawing.opacities_for_write();
value_attribute = opacities;
}
curve_populate_trans_data_structs(tc,
curves,
value_attribute,
selected_indices,
use_proportional_edit,
use_connected_only,
layer_points_offset);
if (use_proportional_edit) {
layer_points_offset += curves.points_num();
}
else {
layer_points_offset += selected_indices.size();
}
layer_offset++;
});
}
}
static void recalcData_grease_pencil(TransInfo *t)
{
bContext *C = t->context;
Scene *scene = CTX_data_scene(C);
const Span<TransDataContainer> trans_data_contrainers(t->data_container, t->data_container_len);
for (const TransDataContainer &tc : trans_data_contrainers) {
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(tc.obedit->data);
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int /*layer_index*/, bke::greasepencil::Drawing &drawing) {
bke::CurvesGeometry &curves = drawing.strokes_for_write();
curves.calculate_bezier_auto_handles();
curves.tag_positions_changed();
drawing.tag_positions_changed();
});
DEG_id_tag_update(&grease_pencil.id, ID_RECALC_GEOMETRY);
}
}
} // namespace blender::ed::transform::greasepencil
/** \} */
TransConvertTypeInfo TransConvertType_GreasePencil = {
/*flags*/ (T_EDIT | T_POINTS),
/*create_trans_data*/ blender::ed::transform::greasepencil::createTransGreasePencilVerts,
/*recalc_data*/ blender::ed::transform::greasepencil::recalcData_grease_pencil,
/*special_aftertrans_update*/ nullptr,
};

View File

@ -230,6 +230,11 @@ void initTransInfo(bContext *C, TransInfo *t, wmOperator *op, const wmEvent *eve
t->options |= CTX_GPENCIL_STROKES;
}
/* Grease Pencil editing context */
if (t->obedit_type == OB_GREASE_PENCIL && object_mode == OB_MODE_EDIT) {
t->options |= CTX_GPENCIL_STROKES;
}
/* Assign the space type, some exceptions for running in different mode */
if (area == nullptr) {
/* background mode */

View File

@ -10,6 +10,7 @@
* Used for 3D View
*/
#include "BLI_array_utils.h"
#include "BLI_function_ref.hh"
#include "BLI_math_geom.h"
#include "BLI_math_matrix.h"
@ -26,12 +27,12 @@
#include "BKE_editmesh.h"
#include "BKE_global.h"
#include "BKE_gpencil_legacy.h"
#include "BKE_grease_pencil.hh"
#include "BKE_layer.h"
#include "BKE_object.hh"
#include "BKE_paint.hh"
#include "BKE_pointcache.h"
#include "BKE_scene.h"
#include "BLI_array_utils.h"
#include "WM_api.hh"
#include "WM_message.hh"
@ -41,6 +42,7 @@
#include "ED_gizmo_library.hh"
#include "ED_gizmo_utils.hh"
#include "ED_gpencil_legacy.hh"
#include "ED_grease_pencil.hh"
#include "ED_object.hh"
#include "ED_particle.hh"
#include "ED_screen.hh"
@ -807,6 +809,35 @@ static int gizmo_3d_foreach_selected(const bContext *C,
}
FOREACH_EDIT_OBJECT_END();
}
else if (obedit->type == OB_GREASE_PENCIL) {
FOREACH_EDIT_OBJECT_BEGIN (ob_iter, use_mat_local) {
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_iter->data);
float4x4 mat_local;
if (use_mat_local) {
mat_local = float4x4(obedit->world_to_object) * float4x4(ob_iter->object_to_world);
}
grease_pencil.foreach_editable_drawing(
scene->r.cfra, [&](int layer_index, blender::bke::greasepencil::Drawing &drawing) {
const bke::CurvesGeometry &curves = drawing.strokes();
const bke::crazyspace::GeometryDeformation deformation =
bke::crazyspace::get_evaluated_grease_pencil_drawing_deformation(
*depsgraph, *ob, layer_index);
IndexMaskMemory memory;
const IndexMask selected_points = ed::curves::retrieve_selected_points(curves,
memory);
const Span<float3> positions = deformation.positions;
totsel += selected_points.size();
selected_points.foreach_index([&](const int point_i) {
run_coord_with_matrix(positions[point_i], use_mat_local, mat_local.ptr());
});
});
}
FOREACH_EDIT_OBJECT_END();
}
#undef FOREACH_EDIT_OBJECT_BEGIN
#undef FOREACH_EDIT_OBJECT_END

View File

@ -566,11 +566,17 @@ void ElementRotation_ex(const TransInfo *t,
/* Apply gpencil falloff. */
if (t->options & CTX_GPENCIL_STROKES) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
if (gps->runtime.multi_frame_falloff != 1.0f) {
float ident_mat[3][3];
unit_m3(ident_mat);
interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff);
if (t->obedit_type == OB_GPENCIL_LEGACY) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
if (gps->runtime.multi_frame_falloff != 1.0f) {
float ident_mat[3][3];
unit_m3(ident_mat);
interp_m3_m3m3(smat, ident_mat, smat, gps->runtime.multi_frame_falloff);
}
}
else if (t->obedit_type == OB_GREASE_PENCIL) {
/* pass */
}
}
@ -1030,21 +1036,26 @@ void ElementResize(const TransInfo *t,
* Operating on copies as a temporary solution.
*/
if (t->options & CTX_GPENCIL_STROKES) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
if (t->obedit_type == OB_GPENCIL_LEGACY) {
bGPDstroke *gps = (bGPDstroke *)td->extra;
mul_v3_fl(vec, td->factor * gps->runtime.multi_frame_falloff);
/* Scale stroke thickness. */
if (td->val) {
NumInput num_evil = t->num;
float values_final_evil[4];
copy_v4_v4(values_final_evil, t->values_final);
transform_snap_increment(t, values_final_evil);
applyNumInput(&num_evil, values_final_evil);
/* Scale stroke thickness. */
if (td->val) {
NumInput num_evil = t->num;
float values_final_evil[4];
copy_v4_v4(values_final_evil, t->values_final);
transform_snap_increment(t, values_final_evil);
applyNumInput(&num_evil, values_final_evil);
float ratio = values_final_evil[0];
float transformed_value = td->ival * fabs(ratio);
*td->val = max_ff(interpf(transformed_value, td->ival, gps->runtime.multi_frame_falloff),
0.001f);
float ratio = values_final_evil[0];
float transformed_value = td->ival * fabs(ratio);
*td->val = max_ff(interpf(transformed_value, td->ival, gps->runtime.multi_frame_falloff),
0.001f);
}
}
else if (t->obedit_type == OB_GREASE_PENCIL) {
mul_v3_fl(vec, td->factor);
}
}
else {

View File

@ -60,10 +60,16 @@ static void applyGPOpacity(TransInfo *t)
bool recalc = false;
FOREACH_TRANS_DATA_CONTAINER (t, tc) {
TransData *td = tc->data;
bGPdata *gpd = static_cast<bGPdata *>(td->ob->data);
const bool is_curve_edit = bool(GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd));
/* Only recalculate data when in curve edit mode. */
if (is_curve_edit) {
if (t->obedit_type == OB_GPENCIL_LEGACY) {
bGPdata *gpd = static_cast<bGPdata *>(td->ob->data);
const bool is_curve_edit = bool(GPENCIL_CURVE_EDIT_SESSIONS_ON(gpd));
/* Only recalculate data when in curve edit mode. */
if (is_curve_edit) {
recalc = true;
}
}
else if (t->obedit_type == OB_GREASE_PENCIL) {
recalc = true;
}