Fix: Grease Pencil: Strokes are locked when material index is out-of-range
When the material index of a stroke is out-of-range of the material slots, the strokes are never editable. This makes it hard to even re-assign the material or otherwise remove such strokes. A negative index can happen when curves are added while a Grease Pencil object has no material slots (see #123887). Since `material_index` is a generic attribute and should be allowed any value, strokes with out-of-range indices should be considered editable by default. This patch slightly changes the `get_editable_material_indices` function for tools, such that only __valid__ materials with the "Locked" flag set are considered non-editable. Pull Request: https://projects.blender.org/blender/blender/pulls/132806
This commit is contained in:
@@ -870,21 +870,21 @@ Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
return visible_drawings;
|
||||
}
|
||||
|
||||
static VectorSet<int> get_editable_material_indices(Object &object)
|
||||
static VectorSet<int> get_locked_material_indices(Object &object)
|
||||
{
|
||||
BLI_assert(object.type == OB_GREASE_PENCIL);
|
||||
VectorSet<int> editable_material_indices;
|
||||
VectorSet<int> locked_material_indices;
|
||||
for (const int mat_i : IndexRange(object.totcol)) {
|
||||
Material *material = BKE_object_material_get(&object, mat_i + 1);
|
||||
/* The editable materials are unlocked and not hidden. */
|
||||
if (material != nullptr && material->gp_style != nullptr &&
|
||||
(material->gp_style->flag & GP_MATERIAL_LOCKED) == 0 &&
|
||||
(material->gp_style->flag & GP_MATERIAL_HIDE) == 0)
|
||||
((material->gp_style->flag & GP_MATERIAL_LOCKED) != 0 ||
|
||||
(material->gp_style->flag & GP_MATERIAL_HIDE) != 0))
|
||||
{
|
||||
editable_material_indices.add_new(mat_i);
|
||||
locked_material_indices.add_new(mat_i);
|
||||
}
|
||||
}
|
||||
return editable_material_indices;
|
||||
return locked_material_indices;
|
||||
}
|
||||
|
||||
static VectorSet<int> get_hidden_material_indices(Object &object)
|
||||
@@ -939,24 +939,24 @@ IndexMask retrieve_editable_strokes(Object &object,
|
||||
}
|
||||
|
||||
/* Get all the editable material indices */
|
||||
VectorSet<int> editable_material_indices = get_editable_material_indices(object);
|
||||
if (editable_material_indices.is_empty()) {
|
||||
return {};
|
||||
VectorSet<int> locked_material_indices = get_locked_material_indices(object);
|
||||
if (locked_material_indices.is_empty()) {
|
||||
return curves_range;
|
||||
}
|
||||
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
const VArray<int> materials = *attributes.lookup<int>("material_index", bke::AttrDomain::Curve);
|
||||
if (!materials) {
|
||||
/* If the attribute does not exist then the default is the first material. */
|
||||
if (editable_material_indices.contains(0)) {
|
||||
return curves_range;
|
||||
if (locked_material_indices.contains(0)) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
return curves_range;
|
||||
}
|
||||
/* Get all the strokes that have their material unlocked. */
|
||||
return IndexMask::from_predicate(
|
||||
curves_range, GrainSize(4096), memory, [&](const int64_t curve_i) {
|
||||
return editable_material_indices.contains(materials[curve_i]);
|
||||
return !locked_material_indices.contains(materials[curve_i]);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1000,30 +1000,31 @@ IndexMask retrieve_editable_strokes_by_material(Object &object,
|
||||
{
|
||||
using namespace blender;
|
||||
|
||||
const bke::CurvesGeometry &curves = drawing.strokes();
|
||||
const IndexRange curves_range = curves.curves_range();
|
||||
|
||||
/* Get all the editable material indices */
|
||||
VectorSet<int> editable_material_indices = get_editable_material_indices(object);
|
||||
if (editable_material_indices.is_empty()) {
|
||||
return {};
|
||||
VectorSet<int> locked_material_indices = get_locked_material_indices(object);
|
||||
if (locked_material_indices.is_empty()) {
|
||||
return curves_range;
|
||||
}
|
||||
|
||||
const bke::CurvesGeometry &curves = drawing.strokes();
|
||||
const IndexRange curves_range = drawing.strokes().curves_range();
|
||||
const bke::AttributeAccessor attributes = curves.attributes();
|
||||
|
||||
const VArray<int> materials = *attributes.lookup<int>("material_index", bke::AttrDomain::Curve);
|
||||
if (!materials) {
|
||||
/* If the attribute does not exist then the default is the first material. */
|
||||
if (editable_material_indices.contains(0)) {
|
||||
return curves_range;
|
||||
if (locked_material_indices.contains(0)) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
return curves_range;
|
||||
}
|
||||
/* Get all the strokes that share the same material and have it unlocked. */
|
||||
return IndexMask::from_predicate(
|
||||
curves_range, GrainSize(4096), memory, [&](const int64_t curve_i) {
|
||||
const int material_index = materials[curve_i];
|
||||
if (material_index == mat_i) {
|
||||
return editable_material_indices.contains(material_index);
|
||||
return !locked_material_indices.contains(material_index);
|
||||
}
|
||||
return false;
|
||||
});
|
||||
@@ -1050,9 +1051,9 @@ IndexMask retrieve_editable_points(Object &object,
|
||||
}
|
||||
|
||||
/* Get all the editable material indices */
|
||||
VectorSet<int> editable_material_indices = get_editable_material_indices(object);
|
||||
if (editable_material_indices.is_empty()) {
|
||||
return {};
|
||||
VectorSet<int> locked_material_indices = get_locked_material_indices(object);
|
||||
if (locked_material_indices.is_empty()) {
|
||||
return points_range;
|
||||
}
|
||||
|
||||
/* Propagate the material index to the points. */
|
||||
@@ -1060,15 +1061,15 @@ IndexMask retrieve_editable_points(Object &object,
|
||||
const VArray<int> materials = *attributes.lookup<int>("material_index", bke::AttrDomain::Point);
|
||||
if (!materials) {
|
||||
/* If the attribute does not exist then the default is the first material. */
|
||||
if (editable_material_indices.contains(0)) {
|
||||
return points_range;
|
||||
if (locked_material_indices.contains(0)) {
|
||||
return {};
|
||||
}
|
||||
return {};
|
||||
return points_range;
|
||||
}
|
||||
/* Get all the points that are part of a stroke with an unlocked material. */
|
||||
return IndexMask::from_predicate(
|
||||
points_range, GrainSize(4096), memory, [&](const int64_t point_i) {
|
||||
return editable_material_indices.contains(materials[point_i]);
|
||||
return !locked_material_indices.contains(materials[point_i]);
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user