GPv3: Separate operator #116715

Merged
Falk David merged 42 commits from mendio/blender:GPv3_OP_Separate into main 2024-02-06 12:06:58 +01:00

This PR adds the Separate operator from GPv2.

Changes:
In GPv2 there were three modes: Selected Point, Selected Strokes and Active Layer. For better consistency with meshes Separate Operator, there are now three modes:

  • Selected (point or strokes is determined by mode selection)
  • By Layers (not only the active one)
  • By Materials (new)

Also Multiframe selection is now supported.

This PR adds the Separate operator from GPv2. Changes: In GPv2 there were three modes: Selected Point, Selected Strokes and Active Layer. For better consistency with meshes Separate Operator, there are now three modes: - Selected (point or strokes is determined by mode selection) - By Layers (not only the active one) - By Materials (new) Also Multiframe selection is now supported.
Matias Mendiola added the
Module
Grease Pencil
label 2024-01-02 16:34:08 +01:00
Falk David was assigned by Matias Mendiola 2024-01-02 16:34:08 +01:00
Hans Goudey was assigned by Matias Mendiola 2024-01-02 16:34:08 +01:00
Matias Mendiola added 13 commits 2024-01-02 16:34:23 +01:00
Matias Mendiola requested review from Falk David 2024-01-02 16:37:20 +01:00
Matias Mendiola requested review from Hans Goudey 2024-01-02 16:37:30 +01:00
Matias Mendiola self-assigned this 2024-01-02 16:37:38 +01:00
Falk David was unassigned by Matias Mendiola 2024-01-02 16:37:56 +01:00
Hans Goudey was unassigned by Matias Mendiola 2024-01-02 16:37:57 +01:00
Matias Mendiola added 1 commit 2024-01-02 16:41:55 +01:00
Antonio Vazquez added this to the Grease Pencil project 2024-01-02 17:47:08 +01:00
Matias Mendiola added 1 commit 2024-01-03 23:39:36 +01:00
Hans Goudey requested changes 2024-01-05 19:53:59 +01:00
@ -28,8 +29,11 @@
#include "DEG_depsgraph.hh"
#include "DNA_material_types.h"
Member

This include is already here, just a few lines above

This include is already here, just a few lines above
mendio marked this conversation as resolved
@ -37,6 +41,7 @@
#include "UI_resources.hh"
namespace blender::ed::greasepencil {
static void remove_unused_materials(Object *object_src, Main *bmain);
Member

Doesn't look like this prototype is necessary

Doesn't look like this prototype is necessary
mendio marked this conversation as resolved
@ -1643,0 +1653,4 @@
/* Selected Points/Strokes */
SELECTED = 0,
/* By Material */
MATERIAL,
Member

Add = 1, = 2. I've seen people do cleanups to give these explicit values before, since they can be stored in blend files.

Add `= 1`, `= 2`. I've seen people do cleanups to give these explicit values before, since they can be stored in blend files.
mendio marked this conversation as resolved
@ -1643,0 +1699,4 @@
}
static bke::greasepencil::Layer &get_layer_dst(const int layer_index,
GreasePencil &grease_pencil_src,
Member

const GreasePencil &grease_pencil_src

`const GreasePencil &grease_pencil_src`
mendio marked this conversation as resolved
@ -1643,0 +1719,4 @@
const bke::AttributeAccessor src_attributes = grease_pencil_src.attributes();
bke::MutableAttributeAccessor dst_attributes = grease_pencil_dst.attributes_for_write();
bke::gather_attributes(src_attributes,
Member

Most of the variables above can be passed directly to gather_attributes like this:

  bke::gather_attributes(grease_pencil_src.attributes(),
                         bke::AttrDomain::Layer,
                         {},
                         {".layers"},
                         {layer_index},
                         grease_pencil_dst.attributes_for_write());
Most of the variables above can be passed directly to `gather_attributes` like this: ```cpp bke::gather_attributes(grease_pencil_src.attributes(), bke::AttrDomain::Layer, {}, {".layers"}, {layer_index}, grease_pencil_dst.attributes_for_write());
Author
Member

I passing most of the variables but had to keep src_to_dst_layer vector.
Using {layer_index} gives an error: C2668: 'blender::bke::gather_attributes': ambiguous call to overloaded function

I passing most of the variables but had to keep `src_to_dst_layer` vector. Using `{layer_index}` gives an error: C2668: 'blender::bke::gather_attributes': ambiguous call to overloaded function
mendio marked this conversation as resolved
@ -1643,0 +1737,4 @@
Object *object_src)
{
using namespace bke::greasepencil;
bool result = false;
Member

Maybe there's a clearer name than "result". Maybe "changed"?

Maybe there's a clearer name than "result". Maybe "changed"?
mendio marked this conversation as resolved
@ -1643,0 +1752,4 @@
bke::CurvesGeometry &curves_src = info.drawing.strokes_for_write();
IndexMaskMemory memory;
IndexMask selected_points = ed::curves::retrieve_selected_points(curves_src, memory);
Member

This newline isn't really helpful IMO, better to visually connect it to the retrieve_selected_points. Also, declare the IndexMask const

This newline isn't really helpful IMO, better to visually connect it to the `retrieve_selected_points`. Also, declare the `IndexMask` const
mendio marked this conversation as resolved
@ -1643,0 +1759,4 @@
/* Insert Keyframe at current frame/layer */
Layer &layer_dst = get_layer_dst(info.layer_index, grease_pencil_src, grease_pencil_dst);
grease_pencil_dst.insert_blank_frame(layer_dst, info.frame_number, 0, BEZT_KEYTYPE_KEYFRAME);
Member

I don't think frames can be inserted into a grease pencil data-block in parallel. So this can't be inside of a parallel_for_each loop really. Either the frames could be added first, or this could just be a regular for loop

I don't think frames can be inserted into a grease pencil data-block in parallel. So this can't be inside of a `parallel_for_each` loop really. Either the frames could be added first, or this could just be a regular for loop
mendio marked this conversation as resolved
@ -1643,0 +1767,4 @@
/* Copy selected points/strokes to new CurvesGeometry. */
const bke::AnonymousAttributePropagationInfo propagation_info{};
drawing_dst->strokes_for_write() = bke::curves_copy_point_selection(
curves_src, selected_points, propagation_info);
Member

Pass {} into curves_copy_point_selection for the propagation info rather than declaring a local variable

Pass `{}` into `curves_copy_point_selection` for the propagation info rather than declaring a local variable
mendio marked this conversation as resolved
@ -1643,0 +1822,4 @@
Object *object_dst = duplicate_grease_pencil_object(
bmain, scene, view_layer, base_prev, grease_pencil_src);
GreasePencil &grease_pencil_dst = *static_cast<GreasePencil *>(object_dst->data);
/* Create Layer. */
Member

Try to avoid comments describing the direct behavior of the code like "create layer" or "select all strokes" or "insert keyframe". These things should be obvious from the code itself. Comments can be a waste of space or a crutch in cases like that-- they're best reserved for describing why decisions were made or non-obvious aspects.

Try to avoid comments describing the direct behavior of the code like "create layer" or "select all strokes" or "insert keyframe". These things should be obvious from the code itself. Comments can be a waste of space or a crutch in cases like that-- they're best reserved for describing _why_ decisions were made or non-obvious aspects.
mendio marked this conversation as resolved
@ -1643,0 +1834,4 @@
/* Select all strokes */
IndexMaskMemory memory;
IndexMask strokes = retrieve_editable_strokes(
*static_cast<Object *>(object_src), info.drawing, memory);
Member

I don't think this static_cast is necessary

I don't think this `static_cast` is necessary
mendio marked this conversation as resolved
@ -1643,0 +1836,4 @@
IndexMask strokes = retrieve_editable_strokes(
*static_cast<Object *>(object_src), info.drawing, memory);
if (!strokes.is_empty()) {
Member

Reverse this if statement and use continue inside it to un-indent the rest of the code

Reverse this if statement and use `continue` inside it to un-indent the rest of the code
Author
Member

It was my first intention, but continue doesn't seem to work: "a continue statement may only be used within a loop"

It was my first intention, but `continue` doesn't seem to work: "a continue statement may only be used within a loop"
Member

Ah, right, since this is in a lambda, return, will do the trick

Ah, right, since this is in a lambda, `return`, will do the trick
mendio marked this conversation as resolved
@ -1643,0 +1877,4 @@
return result;
}
static bool grease_pencil_separate_material(bContext *C,
Member

Use references instead of pointers for values that are expected to be non-null

Use references instead of pointers for values that are expected to be non-null
mendio marked this conversation as resolved
@ -1643,0 +1884,4 @@
Base *base_prev,
Object *object_src)
{
Member

Unnecessary newline

Unnecessary newline
mendio marked this conversation as resolved
@ -1643,0 +1893,4 @@
/* Create a new object for each material. */
for (const int mat_i : IndexRange(object_src->totcol)) {
Member

Unnecessary newline

Unnecessary newline
mendio marked this conversation as resolved
@ -1643,0 +1912,4 @@
const Array<MutableDrawingInfo> drawings_src = retrieve_editable_drawings(*scene,
grease_pencil_src);
threading::parallel_for_each(drawings_src, [&](const MutableDrawingInfo &info) {
/* Get geometry of current drawing. */
Member

Another example of comments that aren't worth it

Another example of comments that aren't worth it
mendio marked this conversation as resolved
@ -1643,0 +1918,4 @@
IndexMask strokes = retrieve_editable_strokes_by_material(
*static_cast<Object *>(object_src), info.drawing, memory, mat_i);
if (!strokes.is_empty()) {
Member

Flip condition and continue to un-indent code

Flip condition and continue to un-indent code
Author
Member

same problem as in #116715 (comment)

same problem as in https://projects.blender.org/blender/blender/pulls/116715#issuecomment-1095976
mendio marked this conversation as resolved
@ -1643,0 +1924,4 @@
/* Insert Keyframe at current frame/layer */
Layer &layer_dst = get_layer_dst(info.layer_index, grease_pencil_src, grease_pencil_dst);
grease_pencil_dst.insert_blank_frame(
Member

This doesn't look threadsafe, make the loop non-parallel or do this step separately first

This doesn't look threadsafe, make the loop non-parallel or do this step separately first
mendio marked this conversation as resolved
@ -1643,0 +1961,4 @@
static int grease_pencil_separate_exec(bContext *C, wmOperator *op)
{
using namespace blender;
Member

This code is already inside the blender namespace

This code is already inside the `blender` namespace
mendio marked this conversation as resolved
@ -1643,0 +1975,4 @@
bool has_selection = false;
/* Cancel if nothing selected. */
if ((mode == SeparateMode::SELECTED)) {
Member

Unnecessary parentheses here. Also, would be clearer to move these checks inside of the relevant switch cases

Unnecessary parentheses here. Also, would be clearer to move these checks inside of the relevant switch cases
mendio marked this conversation as resolved
@ -1643,0 +1978,4 @@
if ((mode == SeparateMode::SELECTED)) {
const Array<MutableDrawingInfo> drawings = retrieve_editable_drawings(*scene,
grease_pencil_src);
threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
Member
  • No need to use write access here
  • There's a utility for checking if anything is selected
  • The parallelism isn't so helpful for such a simple operation. And has_anything_selected is already selected anyway
  • Usually any time you declare a variable but don't assign it a meaningful value (i.e. bool has_selection = false; in this case, there's room for improvement to make the code more readable)

std::all_of(drawings.begin(), drawings.end(), [&](const MutableDrawingInfo &drawing) { return !ed::curves::has_anything_selected(drawing.strokes()); });

- No need to use write access here - There's a utility for checking if anything is selected - The parallelism isn't so helpful for such a simple operation. And `has_anything_selected` is already selected anyway - Usually any time you declare a variable but don't assign it a meaningful value (i.e. `bool has_selection = false;` in this case, there's room for improvement to make the code more readable) `std::all_of(drawings.begin(), drawings.end(), [&](const MutableDrawingInfo &drawing) { return !ed::curves::has_anything_selected(drawing.strokes()); });`
Author
Member

I had to use std::any_of in this case

I had to use std::any_of in this case
mendio marked this conversation as resolved
@ -1643,0 +2026,4 @@
WM_cursor_wait(false);
if (changed) {
Member

Unnecessary empty line

Unnecessary empty line
mendio marked this conversation as resolved
@ -373,0 +425,4 @@
if (material_index == mat_i) {
return editable_material_indices.contains(material_index);
}
else {
Member

else after return is unnecessary

else after return is unnecessary
mendio marked this conversation as resolved
Member

Thanks for looking into this. I don't have a strong opinion about the changed functionality. It seems reasonable. Let me know if you have questions about any of my inline comments.

Thanks for looking into this. I don't have a strong opinion about the changed functionality. It seems reasonable. Let me know if you have questions about any of my inline comments.
Matias Mendiola added 1 commit 2024-01-06 13:51:51 +01:00
Matias Mendiola added 1 commit 2024-01-06 18:52:36 +01:00
Matias Mendiola added 1 commit 2024-01-06 19:32:50 +01:00
Matias Mendiola added 1 commit 2024-01-08 12:12:06 +01:00
Matias Mendiola added 1 commit 2024-01-08 12:31:56 +01:00
Matias Mendiola added 1 commit 2024-01-08 12:49:40 +01:00
Author
Member

Thanks for the review @HooglyBoogly, I hope I managed to resolve all the comments.

Thanks for the review @HooglyBoogly, I hope I managed to resolve all the comments.
Hans Goudey requested changes 2024-01-08 18:24:33 +01:00
@ -1643,0 +1712,4 @@
src_to_dst_layer.append(layer_index);
bke::gather_attributes(grease_pencil_src.attributes(),
bke::AttrDomain::Layer,
{},
Member

It should be possible to use Span({layer_index}), here, directly at the call site

It should be possible to use `Span({layer_index}),` here, directly at the call site
mendio marked this conversation as resolved
@ -1643,0 +1757,4 @@
drawing_dst->strokes_for_write() = bke::curves_copy_point_selection(
curves_src, selected_points, {});
/* Delete selected points from current drawing. */
Member
/* Delete selected points from current drawing. */
curves_src.remove_points(selected_points, {});

This is another case where the code says everything the comment does (just as clearly IMO), making the comment redundant

``` /* Delete selected points from current drawing. */ curves_src.remove_points(selected_points, {}); ``` This is another case where the code says everything the comment does (just as clearly IMO), making the comment redundant
mendio marked this conversation as resolved
@ -1643,0 +1782,4 @@
DEG_id_tag_update(&grease_pencil_dst.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_OBJECT | ND_DRAW, &grease_pencil_dst);
/* Remove unused material slots from source object. */
Member

And here too-- the comment says "remove unused materials" and the code says the same thing

And here too-- the comment says "remove unused materials" and the code says the same thing
mendio marked this conversation as resolved
@ -1643,0 +1802,4 @@
/* Create a new object for each layer. */
for (const Layer *layer_src : grease_pencil_src.layers()) {
Member

Unnecessary newline here

Unnecessary newline here
mendio marked this conversation as resolved
@ -1643,0 +1819,4 @@
for (const MutableDrawingInfo &info : drawings_src) {
bke::CurvesGeometry &curves_src = info.drawing.strokes_for_write();
IndexMaskMemory memory;
const IndexMask strokes = retrieve_editable_strokes(object_src, info.drawing, memory);
Member

And here

And here
mendio marked this conversation as resolved
@ -1643,0 +1831,4 @@
/* Copy strokes to new CurvesGeometry. */
Drawing *drawing_dst = grease_pencil_dst.get_editable_drawing_at(&layer_dst,
info.frame_number);
const bke::AnonymousAttributePropagationInfo propagation_info{};
Member

Just pass {} to both functions individually, that seems better than having the meaningless local variable

Just pass `{}` to both functions individually, that seems better than having the meaningless local variable
mendio marked this conversation as resolved
@ -1643,0 +1876,4 @@
/* Create a new object for each material. */
for (const int mat_i : IndexRange(object_src.totcol)) {
if (mat_i == 0) {
Member

Rather than checking the material index every loop, it's simpler to use IndexRange(object_src.totcol).drop_front(1)

Rather than checking the material index every loop, it's simpler to use `IndexRange(object_src.totcol).drop_front(1)`
mendio marked this conversation as resolved
@ -1643,0 +1898,4 @@
IndexMaskMemory memory;
const IndexMask strokes = retrieve_editable_strokes_by_material(
*static_cast<Object *>(&object_src), info.drawing, memory, mat_i);
Member

Static cast is unnecessary, same with newline after this

Static cast is unnecessary, same with newline after this
mendio marked this conversation as resolved
@ -1643,0 +1932,4 @@
}
if (changed) {
/* Remove unused material slots from source object. */
Member

Redundant comment

Redundant comment
mendio marked this conversation as resolved
Matias Mendiola added 1 commit 2024-01-08 19:23:36 +01:00
Matias Mendiola added 2 commits 2024-01-10 18:14:53 +01:00
Hans Goudey approved these changes 2024-01-10 18:26:47 +01:00
@ -1777,0 +1895,4 @@
};
if (changed) {
Member

Unnecessary whitespace

Unnecessary whitespace
mendio marked this conversation as resolved
@ -1777,0 +1996,4 @@
/* Create a new object for each material. */
for (const int mat_i : IndexRange(object_src.totcol).drop_front(1)) {
Member

Unnecessary whitespace

Unnecessary whitespace
mendio marked this conversation as resolved
@ -373,0 +396,4 @@
IndexMask retrieve_editable_strokes_by_material(Object &object,
const bke::greasepencil::Drawing &drawing,
IndexMaskMemory &memory,
const int &mat_i)
Member

Pass int by value, that's typical for small structs or values

Pass int by value, that's typical for small structs or values
mendio marked this conversation as resolved
Matias Mendiola added 1 commit 2024-01-10 21:24:45 +01:00
Matias Mendiola added 1 commit 2024-01-10 21:31:05 +01:00
Matias Mendiola added 1 commit 2024-01-10 23:08:36 +01:00
Falk David requested changes 2024-01-12 11:03:15 +01:00
Falk David left a comment
Member

Did a pass over this and it generally looks good to me. I just have two remarks

Did a pass over this and it generally looks good to me. I just have two remarks
@ -1777,0 +1826,4 @@
return object_dst;
}
static bke::greasepencil::Layer &get_layer_dst(const int layer_index,
Member

The name is a bit generic for what the function does. Maybe find_or_create_layer_by_name is a bit more specific.

The name is a bit generic for what the function does. Maybe `find_or_create_layer_by_name` is a bit more specific.
mendio marked this conversation as resolved
@ -1777,0 +1844,4 @@
bke::gather_attributes(grease_pencil_src.attributes(),
bke::AttrDomain::Layer,
{},
{".layers"},
Member

I'm not sure what the ".layers" attribute is. I think this can just be {}.

I'm not sure what the `".layers"` attribute is. I think this can just be `{}`.
mendio marked this conversation as resolved
@ -1777,0 +1927,4 @@
/* Create a new object for each layer. */
for (const Layer *layer_src : grease_pencil_src.layers()) {
if (layer_src->is_selected() || layer_src->is_locked()) {
Member

Why are selected layers skipped here?

Why are selected layers skipped here?
Author
Member

We need to keep one of the layers on the source object, these lines prevent the creation of a new object for the selected layer.
In by_material I use the same concept but ommiting the first material because an IndexRange is used there:
for (const int mat_i : IndexRange(object_src.totcol).drop_front(1))

We need to keep one of the layers on the source object, these lines prevent the creation of a new object for the selected layer. In by_material I use the same concept but ommiting the first material because an IndexRange is used there: `for (const int mat_i : IndexRange(object_src.totcol).drop_front(1))`
Matias Mendiola added 2 commits 2024-01-12 15:06:29 +01:00
Matias Mendiola added 1 commit 2024-01-16 15:31:29 +01:00
Pratik Borhade reviewed 2024-01-18 13:00:12 +01:00
@ -1801,0 +2094,4 @@
grease_pencil_src);
has_selection = std::any_of(
drawings.begin(), drawings.end(), [&](const MutableDrawingInfo &info) {
return ed::curves::has_anything_selected(info.drawing.strokes());
Member

Guess this can be simplified. Get selection_attribute_span, then just check selection.contains()

Guess this can be simplified. Get `selection_attribute_span`, then just check `selection.contains()`
Member

IMO this is fine-- this function can deal with various attribute-stored-as-single-value cases a bit better.

IMO this is fine-- this function can deal with various attribute-stored-as-single-value cases a bit better.
mendio marked this conversation as resolved
Pratik Borhade requested changes 2024-01-20 08:22:21 +01:00
Pratik Borhade left a comment
Member

Hi, found few changes

Hi, found few changes
@ -4419,3 +4419,3 @@
op_menu("GPENCIL_MT_layer_active", {"type": 'Y', "value": 'PRESS'}),
# Merge Layer
("gpencil.layer_merge", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
("gpencil.layer_merge", {"type": 'M', "value": 'PRESS', "shift": True, "ctrl": True}, None),
Member

trailing whitespace

trailing whitespace
mendio marked this conversation as resolved
@ -5800,2 +5800,4 @@
layout.menu("VIEW3D_MT_mirror")
layout.separator()
Member

trailing whitespace

trailing whitespace
mendio marked this conversation as resolved
@ -5802,0 +5802,4 @@
layout.separator()
layout.operator_menu_enum("grease_pencil.separate", "mode", text="Separate")
Member

trailing whitespace

trailing whitespace
mendio marked this conversation as resolved
@ -1801,0 +1863,4 @@
}
/* Transfer Layer attributes. */
bke::gather_attributes(grease_pencil_src.attributes(),
Member

getting assert inside this function when source object has only one layer.

getting assert inside this function when source object has only one layer.
Author
Member

The assert is in line 945 in attributte_access.cc when it try to use the function copy_attributes.
Really don't know if there is a problem with my code or inside that function

The assert is in line 945 in `attributte_access.cc` when it try to use the function `copy_attributes`. Really don't know if there is a problem with my code or inside that function
@ -1801,0 +1909,4 @@
info.frame_number);
drawing_dst.strokes_for_write() = bke::curves_copy_point_selection(
curves_src, selected_points, {});
curves_src.remove_points(selected_points, {});
Member

This will only dissolve points and curve won't split after that.
Instead use:
curves_src = remove_points_and_split(curves_src, selected_points);

This will only dissolve points and curve won't split after that. Instead use: `curves_src = remove_points_and_split(curves_src, selected_points);`
mendio marked this conversation as resolved
@ -1801,0 +2083,4 @@
const SeparateMode mode = SeparateMode(RNA_enum_get(op->ptr, "mode"));
bool changed = false;
bool has_selection = false;
Member

I think this can be moved inside case SeparateMode::SELECTED
const bool has_selection = std::any_of()

I think this can be moved inside `case SeparateMode::SELECTED` `const bool has_selection = std::any_of()`
mendio marked this conversation as resolved
Matias Mendiola added 1 commit 2024-01-20 17:50:22 +01:00
Matias Mendiola added 1 commit 2024-01-20 18:35:48 +01:00
Matias Mendiola added 1 commit 2024-01-20 18:47:26 +01:00
Pratik Borhade requested changes 2024-01-22 11:43:33 +01:00
@ -1801,0 +1915,4 @@
drawing_dst.tag_topology_changed();
changed = true;
};
Member

extra semicolon

extra semicolon
mendio marked this conversation as resolved
@ -1801,0 +1992,4 @@
drawing_dst.tag_topology_changed();
changed = true;
};
Member

extra semicolon

extra semicolon
mendio marked this conversation as resolved
@ -1801,0 +2059,4 @@
WM_event_add_notifier(&C, NC_OBJECT | ND_DRAW, &grease_pencil_dst);
changed = true;
};
Member

extra semicolon

extra semicolon
mendio marked this conversation as resolved
Pratik Borhade reviewed 2024-01-22 12:24:08 +01:00
@ -1801,0 +1931,4 @@
DEG_id_tag_update(&grease_pencil_dst.id, ID_RECALC_GEOMETRY);
WM_event_add_notifier(&C, NC_OBJECT | ND_DRAW, &grease_pencil_dst);
remove_unused_materials(&bmain, &object_src);
Member

I don't think we should clear unused materials of source object (neither legacy operator does)

I don't think we should clear unused materials of source object (neither legacy operator does)
mendio marked this conversation as resolved
@ -1801,0 +1948,4 @@
GreasePencil &grease_pencil_src = *static_cast<GreasePencil *>(object_src.data);
/* Create a new object for each layer. */
Member

I'm not sure if this is the plan. @filedescriptor ?

If plan is to separate "selected" layers then I would expect to move them to single object instead of creating new object for each layer

I'm not sure if this is the plan. @filedescriptor ? If plan is to separate "selected" layers then I would expect to move them to single object instead of creating new object for each layer
Member

I am not sure. It seems a bit strange indeed to seperate into individual objects. I would expect it to seperate the selection (or just the active) into one new object.

I am not sure. It seems a bit strange indeed to seperate into individual objects. I would expect it to seperate the selection (or just the active) into one new object.
Author
Member

As I mentioned in the PR description in GPv2 there were three modes for the Separate operator: Selected Point, Selected Strokes and Active Layer. For better consistency with meshes the Separate Operator in this PR has now three modes:

Selected:
Point or strokes is determined now by the mode selection, there is no need to have Separate Point or Separate Stroke

By Materials:
a new mode that separate each material into separate objects, following the mesh Separate operator behaviour

By Layers:
a new mode that separate each layer into separate objects (similar to Separate by materials)

The Separate Active layer in GPv2 (deprecated in this PR) can be easily done by simply selecting all and using Separate Selected. I don't think it's worth having both (Separate Active Layer and Separate by Layers)

As I mentioned in the PR description in GPv2 there were three modes for the Separate operator: Selected Point, Selected Strokes and Active Layer. For better consistency with meshes the Separate Operator in this PR has now three modes: Selected: Point or strokes is determined now by the mode selection, there is no need to have Separate Point or Separate Stroke By Materials: a new mode that separate each material into separate objects, following the mesh Separate operator behaviour By Layers: a new mode that separate each layer into separate objects (similar to Separate by materials) The Separate Active layer in GPv2 (deprecated in this PR) can be easily done by simply selecting all and using Separate Selected. I don't think it's worth having both (Separate Active Layer and Separate by Layers)
@ -1801,0 +1950,4 @@
/* Create a new object for each layer. */
for (const Layer *layer_src : grease_pencil_src.layers()) {
if (layer_src->is_selected() || layer_src->is_locked()) {
Member

!layer_src->is_selected()

`!layer_src->is_selected()`
Author
Member

This line actually prevents creating a new object if the layer is selected. In Separate by Layers we need to keep one layer (selected) on the source object and only create a new object for the rest of the layers.
See my response above to @filedescriptor comment.

This line actually prevents creating a new object if the layer is selected. In Separate by Layers we need to keep one layer (selected) on the source object and only create a new object for the rest of the layers. See my response above to @filedescriptor comment.
Matias Mendiola added 1 commit 2024-02-01 20:34:47 +01:00
Matias Mendiola added 1 commit 2024-02-01 20:58:07 +01:00
Matias Mendiola added 1 commit 2024-02-01 21:19:42 +01:00
Falk David requested changes 2024-02-05 13:08:00 +01:00
Falk David left a comment
Member

Only have a few cleanup comments. I'm fine with the changes if this is how it's supposed to work.

Only have a few cleanup comments. I'm fine with the changes if this is how it's supposed to work.
@ -1696,0 +1745,4 @@
return object_dst;
}
static bke::greasepencil::Layer &find_or_create_layer_by_name(
Member

Maybe find_or_create_layer_in_dst_by_name so it's a bit more clear.

Maybe `find_or_create_layer_in_dst_by_name` so it's a bit more clear.
mendio marked this conversation as resolved
@ -1696,0 +1752,4 @@
const Layer *layer_src = grease_pencil_src.layers().get(layer_index, layer_src);
for (Layer *layer : grease_pencil_dst.layers_for_write()) {
Member

This could be

const int dst_layer_index = grease_pencil_dst.layers_for_write().first_index_try();
if (dst_layer_index != -1) {
   return *grease_pencil_dst.layers_for_write()[dst_layer_index];
}
This could be ``` const int dst_layer_index = grease_pencil_dst.layers_for_write().first_index_try(); if (dst_layer_index != -1) { return *grease_pencil_dst.layers_for_write()[dst_layer_index]; } ```
mendio marked this conversation as resolved
@ -224,6 +224,29 @@ Array<MutableDrawingInfo> retrieve_editable_drawings(const Scene &scene,
return editable_drawings.as_span();
}
Array<MutableDrawingInfo> retrieve_editable_drawings_by_layer(
Member

Maybe retrieve_editable_drawings_from_layer makes it more clear

Maybe `retrieve_editable_drawings_from_layer` makes it more clear
mendio marked this conversation as resolved
@ -318,0 +341,4 @@
IndexMask retrieve_editable_strokes_by_material(Object &object,
const bke::greasepencil::Drawing &drawing,
IndexMaskMemory &memory,
const int mat_i)
Member

This should be before the memory.

This should be before the `memory`.
mendio marked this conversation as resolved
Matias Mendiola added 2 commits 2024-02-05 13:43:23 +01:00
Matias Mendiola added 1 commit 2024-02-05 13:57:59 +01:00
Matias Mendiola added 1 commit 2024-02-05 14:28:07 +01:00
Matias Mendiola added 1 commit 2024-02-05 17:26:48 +01:00
Matias Mendiola added 1 commit 2024-02-05 17:29:29 +01:00
Falk David approved these changes 2024-02-06 12:05:54 +01:00
Falk David merged commit d589251905 into main 2024-02-06 12:06:58 +01:00
Falk David referenced this issue from a commit 2024-02-06 12:06:59 +01:00
Matias Mendiola deleted branch GPv3_OP_Separate 2024-02-06 12:20:37 +01:00
Sign in to join this conversation.
No Label
Interest
Alembic
Interest
Animation & Rigging
Interest
Asset Browser
Interest
Asset Browser Project Overview
Interest
Audio
Interest
Automated Testing
Interest
Blender Asset Bundle
Interest
BlendFile
Interest
Collada
Interest
Compatibility
Interest
Compositing
Interest
Core
Interest
Cycles
Interest
Dependency Graph
Interest
Development Management
Interest
EEVEE
Interest
EEVEE & Viewport
Interest
Freestyle
Interest
Geometry Nodes
Interest
Grease Pencil
Interest
ID Management
Interest
Images & Movies
Interest
Import Export
Interest
Line Art
Interest
Masking
Interest
Metal
Interest
Modeling
Interest
Modifiers
Interest
Motion Tracking
Interest
Nodes & Physics
Interest
OpenGL
Interest
Overlay
Interest
Overrides
Interest
Performance
Interest
Physics
Interest
Pipeline, Assets & IO
Interest
Platforms, Builds & Tests
Interest
Python API
Interest
Render & Cycles
Interest
Render Pipeline
Interest
Sculpt, Paint & Texture
Interest
Text Editor
Interest
Translations
Interest
Triaging
Interest
Undo
Interest
USD
Interest
User Interface
Interest
UV Editing
Interest
VFX & Video
Interest
Video Sequencer
Interest
Virtual Reality
Interest
Vulkan
Interest
Wayland
Interest
Workbench
Interest: X11
Legacy
Blender 2.8 Project
Legacy
Milestone 1: Basic, Local Asset Browser
Legacy
OpenGL Error
Meta
Good First Issue
Meta
Papercut
Meta
Retrospective
Meta
Security
Module
Animation & Rigging
Module
Core
Module
Development Management
Module
EEVEE & Viewport
Module
Grease Pencil
Module
Modeling
Module
Nodes & Physics
Module
Pipeline, Assets & IO
Module
Platforms, Builds & Tests
Module
Python API
Module
Render & Cycles
Module
Sculpt, Paint & Texture
Module
Triaging
Module
User Interface
Module
VFX & Video
Platform
FreeBSD
Platform
Linux
Platform
macOS
Platform
Windows
Priority
High
Priority
Low
Priority
Normal
Priority
Unbreak Now!
Status
Archived
Status
Confirmed
Status
Duplicate
Status
Needs Info from Developers
Status
Needs Information from User
Status
Needs Triage
Status
Resolved
Type
Bug
Type
Design
Type
Known Issue
Type
Patch
Type
Report
Type
To Do
No Milestone
No project
No Assignees
4 Participants
Notifications
Due Date
The due date is invalid or out of range. Please use the format 'yyyy-mm-dd'.

No due date set.

Dependencies

No dependencies set.

Reference: blender/blender#116715
No description provided.