Fix: New generic attributes uninitialized after curves draw tool

Add a utility to set attribute values to their default, use it in a few
places that have already done this samething. Also:
- Don't create resolution or cyclic attributes unnecessarily
- Use API function to set new curve's type
- Always create the new selection on the curve domain
- Remove selection before resize to avoid unnecessary work
This commit is contained in:
Hans Goudey 2023-12-16 12:52:22 -05:00
parent 0e8c874166
commit f5adfa6acd
5 changed files with 100 additions and 92 deletions

View File

@ -914,4 +914,9 @@ void copy_attributes_group_to_group(AttributeAccessor src_attributes,
const IndexMask &selection,
MutableAttributeAccessor dst_attributes);
void fill_attribute_range_default(MutableAttributeAccessor dst_attributes,
eAttrDomain domain,
const Set<std::string> &skip,
IndexRange range);
} // namespace blender::bke

View File

@ -1052,4 +1052,25 @@ void copy_attributes_group_to_group(const AttributeAccessor src_attributes,
});
}
void fill_attribute_range_default(MutableAttributeAccessor attributes,
const eAttrDomain domain,
const Set<std::string> &skip,
const IndexRange range)
{
attributes.for_all([&](const AttributeIDRef &id, const AttributeMetaData meta_data) {
if (meta_data.domain != domain) {
return true;
}
if (skip.contains(id.name())) {
return true;
}
GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
const CPPType &type = attribute.span.type();
GMutableSpan data = attribute.span.slice(range);
type.fill_assign_n(type.default_value(), data.data(), data.size());
attribute.finish();
return true;
});
}
} // namespace blender::bke

View File

@ -655,13 +655,16 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
Curves *curves_id = static_cast<Curves *>(obedit->data);
bke::CurvesGeometry &curves = curves_id->geometry.wrap();
const eAttrDomain selection_domain = eAttrDomain(curves_id->selection_domain);
const int curve_index = curves.curves_num();
const bool use_pressure_radius = (cps->flag & CURVE_PAINT_FLAG_PRESSURE_RADIUS) ||
((cps->radius_taper_start != 0.0f) ||
(cps->radius_taper_end != 0.0f));
bke::MutableAttributeAccessor attributes = curves.attributes_for_write();
attributes.remove(".selection");
if (cdd->curve_type == CU_BEZIER) {
/* Allow to interpolate multiple channels */
int dims = 3;
@ -761,30 +764,18 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
if (result == 0) {
curves.resize(curves.points_num() + cubic_spline_len, curve_index + 1);
MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
curve_types[curve_index] = CURVE_TYPE_BEZIER;
curves.update_curve_types();
curves.fill_curve_types(IndexRange(curve_index, 1), CURVE_TYPE_BEZIER);
MutableSpan<float3> positions = curves.positions_for_write();
MutableSpan<float3> handle_positions_l = curves.handle_positions_left_for_write();
MutableSpan<float3> handle_positions_r = curves.handle_positions_right_for_write();
MutableSpan<int8_t> handle_types_l = curves.handle_types_left_for_write();
MutableSpan<int8_t> handle_types_r = curves.handle_types_right_for_write();
MutableSpan<bool> cyclic = curves.cyclic_for_write();
MutableSpan<int> resolution = curves.resolution_for_write();
resolution[curve_index] = 12;
IndexRange new_points = curves.points_by_curve()[curve_index];
MutableSpan<float3> positions = curves.positions_for_write();
const IndexRange new_points = curves.points_by_curve()[curve_index];
bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
bke::SpanAttributeWriter<float> radius_attribute =
curves_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
MutableSpan<float> radii = radius_attribute.span;
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
curves::fill_selection_false(selection.span);
bke::SpanAttributeWriter<float> radii = attributes.lookup_or_add_for_write_only_span<float>(
"radius", ATTR_DOMAIN_POINT);
float *co = cubic_spline;
@ -800,18 +791,14 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
const float radius = (radius_index != -1) ?
(pt[radius_index] * cdd->radius.range) + cdd->radius.min :
radius_max;
radii[i] = radius;
radii.span[i] = radius;
handle_types_l[i] = BEZIER_HANDLE_ALIGN;
handle_types_r[i] = BEZIER_HANDLE_ALIGN;
co += (dims * 3);
}
curves::fill_selection_true(
selection.span,
selection.domain == ATTR_DOMAIN_POINT ? new_points : IndexRange(curve_index, 1));
selection.finish();
// bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
// bezt->f1 = bezt->f2 = bezt->f3 = SELECT;
if (corners_index) {
/* ignore the first and last */
@ -829,9 +816,35 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
}
}
cyclic[curve_index] = bool(calc_flag & CURVE_FIT_CALC_CYCLIC);
radii.finish();
radius_attribute.finish();
bke::AttributeWriter<bool> selection = attributes.lookup_or_add_for_write<bool>(
".selection", ATTR_DOMAIN_CURVE);
selection.varray.set(curve_index, true);
selection.finish();
if (attributes.contains("resolution")) {
curves.resolution_for_write()[curve_index] = 12;
}
if (attributes.contains("cyclic") || bool(calc_flag & CURVE_FIT_CALC_CYCLIC)) {
curves.cyclic_for_write()[curve_index] = true;
}
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_POINT,
{"position",
"radius",
"handle_left",
"handle_right",
"handle_type_left",
"handle_type_right",
".selection"},
new_points);
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_CURVE,
{"curve_type", "resolution", "cyclic", ".selection"},
IndexRange(curve_index, 1));
}
if (corners_index) {
@ -844,20 +857,13 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
}
else { /* CU_POLY */
curves.resize(curves.points_num() + stroke_len, curve_index + 1);
MutableSpan<int8_t> curve_types = curves.curve_types_for_write();
curve_types[curve_index] = CURVE_TYPE_POLY;
curves.update_curve_types();
curves.fill_curve_types(IndexRange(curve_index, 1), CURVE_TYPE_POLY);
IndexRange new_points = curves.points_by_curve()[curve_index];
MutableSpan<float3> positions = curves.positions_for_write();
bke::MutableAttributeAccessor curves_attributes = curves.attributes_for_write();
bke::SpanAttributeWriter<float> radius_attribute =
curves_attributes.lookup_or_add_for_write_only_span<float>("radius", ATTR_DOMAIN_POINT);
MutableSpan<float> radii = radius_attribute.span;
bke::SpanAttributeWriter<float> radii = attributes.lookup_or_add_for_write_only_span<float>(
"radius", ATTR_DOMAIN_POINT);
bke::GSpanAttributeWriter selection = ensure_selection_attribute(
curves, selection_domain, CD_PROP_BOOL);
curves::fill_selection_false(selection.span);
const IndexRange new_points = curves.points_by_curve()[curve_index];
IndexRange::Iterator points_iter = new_points.begin();
@ -872,14 +878,21 @@ static int curves_draw_exec(bContext *C, wmOperator *op)
positions[i][2] = 0.0f;
}
radii[i] = use_pressure_radius ? (selem->pressure * radius_range) + radius_min :
cps->radius_max;
radii.span[i] = use_pressure_radius ? (selem->pressure * radius_range) + radius_min :
cps->radius_max;
}
curves::fill_selection_true(
selection.span,
selection.domain == ATTR_DOMAIN_POINT ? new_points : IndexRange(curve_index, 1));
radii.finish();
bke::AttributeWriter<bool> selection = attributes.lookup_or_add_for_write<bool>(
".selection", ATTR_DOMAIN_CURVE);
selection.varray.set(curve_index, true);
selection.finish();
radius_attribute.finish();
bke::fill_attribute_range_default(
attributes, ATTR_DOMAIN_POINT, {"position", "radius", ".selection"}, new_points);
bke::fill_attribute_range_default(
attributes, ATTR_DOMAIN_CURVE, {"curve_type", ".selection"}, IndexRange(curve_index, 1));
}
WM_event_add_notifier(C, NC_GEOM | ND_DATA, obedit->data);

View File

@ -238,27 +238,14 @@ struct PaintOperationExecutor {
curves.update_curve_types();
/* Initialize the rest of the attributes with default values. */
Set<std::string> attributes_to_skip{{"position",
"curve_type",
"material_index",
"cyclic",
"radius",
"opacity",
"vertex_color"}};
attributes.for_all(
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
if (attributes_to_skip.contains(id.name())) {
return true;
}
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
const CPPType &type = attribute.span.type();
GMutableSpan new_data = attribute.span.slice(attribute.domain == ATTR_DOMAIN_POINT ?
curves.points_range().take_back(1) :
curves.curves_range().take_back(1));
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
attribute.finish();
return true;
});
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_POINT,
{"position", "radius", "opacity", "vertex_color"},
curves.points_range().take_back(1));
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_CURVE,
{"curve_type", "material_index", "cyclic"},
curves.curves_range().take_back(1));
drawing_->tag_topology_changed();
}
@ -417,18 +404,10 @@ struct PaintOperationExecutor {
}
/* Initialize the rest of the attributes with default values. */
Set<std::string> attributes_to_skip{{"position", "radius", "opacity", "vertex_color"}};
attributes.for_all([&](const bke::AttributeIDRef &id, const bke::AttributeMetaData meta_data) {
if (attributes_to_skip.contains(id.name()) || meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
const CPPType &type = attribute.span.type();
GMutableSpan new_data = attribute.span.slice(new_points);
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
attribute.finish();
return true;
});
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_POINT,
{"position", "radius", "opacity", "vertex_color"},
curves.points_range().take_back(1));
}
void execute(PaintOperation &self, const bContext &C, const InputSample &extension_sample)

View File

@ -397,22 +397,12 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
}
/* Explicitly set all other attributes besides those processed above to default values. */
Set<std::string> attributes_to_skip{
{"position", "curve_type", "surface_uv_coordinate", "resolution"}};
attributes.for_all(
[&](const bke::AttributeIDRef &id, const bke::AttributeMetaData /*meta_data*/) {
if (attributes_to_skip.contains(id.name())) {
return true;
}
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
const CPPType &type = attribute.span.type();
GMutableSpan new_data = attribute.span.slice(attribute.domain == ATTR_DOMAIN_POINT ?
outputs.new_points_range :
outputs.new_curves_range);
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
attribute.finish();
return true;
});
bke::fill_attribute_range_default(
attributes, ATTR_DOMAIN_POINT, {"position"}, outputs.new_points_range);
bke::fill_attribute_range_default(attributes,
ATTR_DOMAIN_CURVE,
{"curve_type", "surface_uv_coordinate", "resolution"},
outputs.new_curves_range);
return outputs;
}