Changeset View
Changeset View
Standalone View
Standalone View
source/blender/editors/sculpt_paint/curves_sculpt_ops.cc
| Show First 20 Lines • Show All 357 Lines • ▼ Show 20 Lines | static int select_random_exec(bContext *C, wmOperator *op) | ||||
| const float min_value = RNA_float_get(op->ptr, "min"); | const float min_value = RNA_float_get(op->ptr, "min"); | ||||
| const auto next_partial_random_value = [&]() { | const auto next_partial_random_value = [&]() { | ||||
| return rng.get_float() * (1.0f - min_value) + min_value; | return rng.get_float() * (1.0f - min_value) + min_value; | ||||
| }; | }; | ||||
| const auto next_bool_random_value = [&]() { return rng.get_float() <= probability; }; | const auto next_bool_random_value = [&]() { return rng.get_float() <= probability; }; | ||||
| for (Curves *curves_id : unique_curves) { | for (Curves *curves_id : unique_curves) { | ||||
| CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); | CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); | ||||
| const bool was_anything_selected = curves::has_anything_selected(*curves_id); | const bool was_anything_selected = curves::has_anything_selected(curves); | ||||
| bke::SpanAttributeWriter<float> attribute = float_selection_ensure(*curves_id); | bke::SpanAttributeWriter<float> attribute = float_selection_ensure(*curves_id); | ||||
| MutableSpan<float> selection = attribute.span; | MutableSpan<float> selection = attribute.span; | ||||
| if (!was_anything_selected) { | if (!was_anything_selected) { | ||||
| selection.fill(1.0f); | selection.fill(1.0f); | ||||
| } | } | ||||
| const OffsetIndices points_by_curve = curves.points_by_curve(); | const OffsetIndices points_by_curve = curves.points_by_curve(); | ||||
| switch (curves_id->selection_domain) { | switch (curves_id->selection_domain) { | ||||
| ▲ Show 20 Lines • Show All 137 Lines • ▼ Show 20 Lines | RNA_def_float(ot->srna, | ||||
| 0.0f, | 0.0f, | ||||
| 1.0f); | 1.0f); | ||||
| RNA_def_boolean(ot->srna, | RNA_def_boolean(ot->srna, | ||||
| "constant_per_curve", | "constant_per_curve", | ||||
| true, | true, | ||||
| "Constant per Curve", | "Constant per Curve", | ||||
| "The generated random number is the same for every control point of a curve"); | "The generated random number is the same for every control point of a curve"); | ||||
| } | } | ||||
| namespace select_end { | |||||
| static bool select_end_poll(bContext *C) | |||||
| { | |||||
| if (!curves::editable_curves_poll(C)) { | |||||
| return false; | |||||
| } | |||||
| const Curves *curves_id = static_cast<const Curves *>(CTX_data_active_object(C)->data); | |||||
| if (curves_id->selection_domain != ATTR_DOMAIN_POINT) { | |||||
| CTX_wm_operator_poll_msg_set(C, "Only available in point selection mode"); | |||||
| return false; | |||||
| } | |||||
| return true; | |||||
| } | |||||
| static int select_end_exec(bContext *C, wmOperator *op) | |||||
| { | |||||
| VectorSet<Curves *> unique_curves = curves::get_unique_editable_curves(*C); | |||||
| const bool end_points = RNA_boolean_get(op->ptr, "end_points"); | |||||
| const int amount = RNA_int_get(op->ptr, "amount"); | |||||
| for (Curves *curves_id : unique_curves) { | |||||
| CurvesGeometry &curves = CurvesGeometry::wrap(curves_id->geometry); | |||||
| bke::MutableAttributeAccessor attributes = curves.attributes_for_write(); | |||||
| const bool was_anything_selected = curves::has_anything_selected(*curves_id); | |||||
| curves::ensure_selection_attribute(*curves_id, CD_PROP_BOOL); | |||||
| bke::GSpanAttributeWriter selection = attributes.lookup_for_write_span(".selection"); | |||||
| if (!was_anything_selected) { | |||||
| curves::fill_selection_true(selection.span); | |||||
| } | |||||
| const OffsetIndices points_by_curve = curves.points_by_curve(); | |||||
| selection.span.type().to_static_type_tag<bool, float>([&](auto type_tag) { | |||||
| using T = typename decltype(type_tag)::type; | |||||
| if constexpr (std::is_void_v<T>) { | |||||
| BLI_assert_unreachable(); | |||||
| } | |||||
| else { | |||||
| MutableSpan<T> selection_typed = selection.span.typed<T>(); | |||||
| threading::parallel_for(curves.curves_range(), 256, [&](const IndexRange range) { | |||||
| for (const int curve_i : range) { | |||||
| const IndexRange points = points_by_curve[curve_i]; | |||||
| if (end_points) { | |||||
| selection_typed.slice(points.drop_back(amount)).fill(T(0)); | |||||
| } | |||||
| else { | |||||
| selection_typed.slice(points.drop_front(amount)).fill(T(0)); | |||||
| } | |||||
| } | |||||
| }); | |||||
| } | |||||
| }); | |||||
| selection.finish(); | |||||
| /* Use #ID_RECALC_GEOMETRY instead of #ID_RECALC_SELECT because it is handled as a generic | |||||
| * attribute for now. */ | |||||
| DEG_id_tag_update(&curves_id->id, ID_RECALC_GEOMETRY); | |||||
| WM_event_add_notifier(C, NC_GEOM | ND_DATA, curves_id); | |||||
| } | |||||
| return OPERATOR_FINISHED; | |||||
| } | |||||
| } // namespace select_end | |||||
| static void SCULPT_CURVES_OT_select_end(wmOperatorType *ot) | |||||
| { | |||||
| ot->name = "Select End"; | |||||
| ot->idname = __func__; | |||||
| ot->description = "Select end points of curves"; | |||||
| ot->exec = select_end::select_end_exec; | |||||
| ot->poll = select_end::select_end_poll; | |||||
| ot->flag = OPTYPE_REGISTER | OPTYPE_UNDO; | |||||
| RNA_def_boolean(ot->srna, | |||||
| "end_points", | |||||
| true, | |||||
| "End Points", | |||||
| "Select points at the end of the curve as opposed to the beginning"); | |||||
| RNA_def_int( | |||||
| ot->srna, "amount", 1, 0, INT32_MAX, "Amount", "Number of points to select", 0, INT32_MAX); | |||||
| } | |||||
| namespace select_grow { | namespace select_grow { | ||||
| struct GrowOperatorDataPerCurve : NonCopyable, NonMovable { | struct GrowOperatorDataPerCurve : NonCopyable, NonMovable { | ||||
| Curves *curves_id; | Curves *curves_id; | ||||
| Vector<int64_t> selected_point_indices; | Vector<int64_t> selected_point_indices; | ||||
| Vector<int64_t> unselected_point_indices; | Vector<int64_t> unselected_point_indices; | ||||
| IndexMask selected_points; | IndexMask selected_points; | ||||
| IndexMask unselected_points; | IndexMask unselected_points; | ||||
| ▲ Show 20 Lines • Show All 266 Lines • ▼ Show 20 Lines | case RIGHTMOUSE: { | ||||
| return OPERATOR_CANCELLED; | return OPERATOR_CANCELLED; | ||||
| } | } | ||||
| } | } | ||||
| return OPERATOR_RUNNING_MODAL; | return OPERATOR_RUNNING_MODAL; | ||||
| } | } | ||||
| } // namespace select_grow | } // namespace select_grow | ||||
| static void SCULPT_CURVES_OT_select_grow(wmOperatorType *ot) | static void SCULPT_CURVES_OT_select_grow(wmOperatorType *ot) | ||||
HooglyBoogly: Not sure I agree with this rename, the operator is part of the "sculpt curves" area, like… | |||||
Done Inline ActionsAh yes, I wanted to ask you about this. The issue is that in python this would also appear as curves.select_random/curves.select_grow. So I added the sculpt part in the name of the actual operator. I'm open to another, better, solution of course! filedescriptor: Ah yes, I wanted to ask you about this. The issue is that in python this would also appear as… | |||||
Not Done Inline ActionsHmm, why is that? In current master I see this: >>> bpy.ops.sculpt_curves.
brush_stroke(
min_distance_edit(
select_end(
select_grow(
select_random(
>>> bpy.ops.curves
<module 'bpy.ops.curves'>HooglyBoogly: Hmm, why is that? In current master I see this:
```
>>> bpy.ops.sculpt_curves. | |||||
Done Inline ActionsYou're absolutely right, my bad. Reverting... filedescriptor: You're absolutely right, my bad. Reverting... | |||||
| { | { | ||||
| ot->name = "Select Grow"; | ot->name = "Select Grow"; | ||||
| ot->idname = __func__; | ot->idname = __func__; | ||||
| ot->description = "Select curves which are close to curves that are selected already"; | ot->description = "Select curves which are close to curves that are selected already"; | ||||
| ot->invoke = select_grow::select_grow_invoke; | ot->invoke = select_grow::select_grow_invoke; | ||||
| ot->modal = select_grow::select_grow_modal; | ot->modal = select_grow::select_grow_modal; | ||||
| ot->poll = curves::editable_curves_poll; | ot->poll = curves::editable_curves_poll; | ||||
| ▲ Show 20 Lines • Show All 363 Lines • ▼ Show 20 Lines | |||||
| * \{ */ | * \{ */ | ||||
| void ED_operatortypes_sculpt_curves() | void ED_operatortypes_sculpt_curves() | ||||
| { | { | ||||
| using namespace blender::ed::sculpt_paint; | using namespace blender::ed::sculpt_paint; | ||||
| WM_operatortype_append(SCULPT_CURVES_OT_brush_stroke); | WM_operatortype_append(SCULPT_CURVES_OT_brush_stroke); | ||||
| WM_operatortype_append(CURVES_OT_sculptmode_toggle); | WM_operatortype_append(CURVES_OT_sculptmode_toggle); | ||||
| WM_operatortype_append(SCULPT_CURVES_OT_select_random); | WM_operatortype_append(SCULPT_CURVES_OT_select_random); | ||||
| WM_operatortype_append(SCULPT_CURVES_OT_select_end); | |||||
| WM_operatortype_append(SCULPT_CURVES_OT_select_grow); | WM_operatortype_append(SCULPT_CURVES_OT_select_grow); | ||||
| WM_operatortype_append(SCULPT_CURVES_OT_min_distance_edit); | WM_operatortype_append(SCULPT_CURVES_OT_min_distance_edit); | ||||
| } | } | ||||
| /** \} */ | /** \} */ | ||||
Not sure I agree with this rename, the operator is part of the "sculpt curves" area, like others, make sense to keep that name prefix IMO. Same with select_random