{read_more}
// A typical operator exec call...
static int grease_pencil_do_whatever(bContext *C, wmOperator * /*op*/)
{
const Scene *scene = CTX_data_scene(C);
Object *object = CTX_data_active_object(C);
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(object->data);
// How to get "drawings" to edit under GPv3 and iterate over each "drawing":
const Array<MutableDrawingInfo> drawings = retrieve_editable_drawings(*scene, grease_pencil);
threading::parallel_for_each(drawings, [&](const MutableDrawingInfo &info) {
IndexMaskMemory memory;
const IndexMask strokes = ed::greasepencil::retrieve_editable_and_selected_strokes(
*object, info.drawing, memory);
if (strokes.is_empty()) {
return;
}
// Get a curves container to work on inside this drawing... By using
// &curves allows us to later just directly assign a new one. So this way
// we could create new curves easier.
//
// Essentially we don't "edit" the curve, but creates a new one, and there
// are utility functions in `Curves` to allow easy transferring of old data.
bke::CurvesGeometry &curves = info.drawing.strokes_for_write();
// And choose to work with "Select Domain"...
const bke::AttrDomain selection_domain = ED_grease_pencil_selection_domain_get(
scene->toolsettings);
if (selection_domain == bke::AttrDomain::Curve) {
curves.remove_curves(elements, {});
}
else if (selection_domain == bke::AttrDomain::Point) {
curves = remove_points_and_split(curves, elements);
}
// Curves etc...
Array<bool> points_to_delete(curves.points_num()); // 1d array
const int total_points = points_to_delete.as_span().count(false);
// This is how we iterate over curves...
for (const int curve_i : curves.curves_range()) {
const IndexRange points = points_by_curve[curve_i];
const Span<bool> curve_points_to_delete = points_to_delete.as_span().slice(points);
const bool curve_cyclic = src_cyclic[curve_i];
//...
}
}); // End parallel iteration over stroke.
// Create a new curves "container", this is where we actually create new stuff and
// then we put in data...
// If we have counts for individual curves, counts can be accumulated into new offsets
// with convenience functions.
bke::CurvesGeometry dst_curves(total_points, total_curves);
MutableSpan<int> new_curve_offsets = dst_curves.offsets_for_write();
array_utils::copy(dst_curve_counts.as_span(), new_curve_offsets.drop_back(1));
offset_indices::accumulate_counts_to_offsets(new_curve_offsets);
bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
const bke::AttributeAccessor src_attributes = curves.attributes();
// Copy from dst-src matching pairs if data is modified from previous curves.
/* Transfer curve attributes. */
gather_attributes(
src_attributes, bke::AttrDomain::Curve, {}, {"cyclic"}, dst_to_src_curve, dst_attributes);
array_utils::copy(dst_cyclic.as_span(), dst_curves.cyclic_for_write());
// Individual elements delivered by `Span` and `Array` etc can all be accessed with [].
// So `MutableSpan some=other; some[index]=thing;` is valid.
}
2023/12/29 20:03:29 - 2023/12/29 20:55:34