2023-08-15 16:20:26 +02:00
|
|
|
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
2023-05-31 16:19:06 +02:00
|
|
|
*
|
|
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
2022-07-22 15:39:41 +02:00
|
|
|
|
|
|
|
#include "BKE_curves.hh"
|
|
|
|
#include "BKE_geometry_set.hh"
|
2023-10-12 15:42:04 +02:00
|
|
|
#include "BKE_grease_pencil.hh"
|
2022-07-22 15:39:41 +02:00
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
namespace blender::bke {
|
2022-07-22 15:39:41 +02:00
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
GeometryComponentEditData::GeometryComponentEditData() : GeometryComponent(Type::Edit) {}
|
2022-07-22 15:39:41 +02:00
|
|
|
|
|
|
|
GeometryComponent *GeometryComponentEditData::copy() const
|
|
|
|
{
|
|
|
|
GeometryComponentEditData *new_component = new GeometryComponentEditData();
|
|
|
|
if (curves_edit_hints_) {
|
|
|
|
new_component->curves_edit_hints_ = std::make_unique<CurvesEditHints>(*curves_edit_hints_);
|
|
|
|
}
|
2023-10-12 15:42:04 +02:00
|
|
|
if (grease_pencil_edit_hints_) {
|
|
|
|
new_component->grease_pencil_edit_hints_ = std::make_unique<GreasePencilEditHints>(
|
|
|
|
*grease_pencil_edit_hints_);
|
|
|
|
}
|
2022-07-22 15:39:41 +02:00
|
|
|
return new_component;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool GeometryComponentEditData::owns_direct_data() const
|
|
|
|
{
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void GeometryComponentEditData::ensure_owns_direct_data()
|
|
|
|
{
|
|
|
|
/* Nothing to do. */
|
|
|
|
}
|
BLI: support weak users and version in implicit sharing info
The main goal of these changes is to support checking if some data has
been changed over time. This is used by the WIP simulation nodes during
baking to detect which attributes have to be stored in every frame because
they have changed.
By using a combination of a weak user count and a version counter, it is
possible to detect that an attribute (or any data controlled by implicit
sharing) has not been changed with O(1) memory and time. It's still
possible that the data has been changed multiple times and is the same
in the end and beginning of course. That wouldn't be detected using this
mechanism.
The `ImplicitSharingInfo` struct has a new weak user count. A weak
reference is one that does not keep the referenced data alive, but makes sure
that the `ImplicitSharingInfo` itself is not deleted. If some piece of
data has one strong and multiple weak users, it is still mutable. If the
strong user count goes down to zero, the referenced data is freed.
Remaining weak users can check for this condition using `is_expired`.
This is a bit similar to `std::weak_ptr` but there is an important difference:
a weak user can not become a strong user while one can create a `shared_ptr`
from a `weak_ptr`. This restriction is necessary, because some code might
be changing the referenced data assuming that it is the only owner. If
another thread suddenly adds a new owner, the data would be shared again
and the first thread would not have been allowed to modify the data in
the first place.
There is also a new integer version counter in `ImplicitSharingInfo`.
It is incremented whenever some code wants to modify the referenced data.
Obviously, this can only be done when the data is not shared because then
it would be immutable. By comparing an old and new version number of the
same sharing info, one can check if the data has been modified. One has
to keep a weak reference to the sharing info together with the old version
number to ensure that the new sharing info is still the same as the old one.
Without this, it can happen that the sharing info was freed and a new
one was allocated at the same pointer address. Using a strong reference
for this purpose does not work, because then the data would never be
modified because it's shared.
2023-04-28 12:03:42 +02:00
|
|
|
|
|
|
|
void GeometryComponentEditData::clear()
|
|
|
|
{
|
|
|
|
BLI_assert(this->is_mutable() || this->is_expired());
|
|
|
|
curves_edit_hints_.reset();
|
2023-10-12 15:42:04 +02:00
|
|
|
grease_pencil_edit_hints_.reset();
|
BLI: support weak users and version in implicit sharing info
The main goal of these changes is to support checking if some data has
been changed over time. This is used by the WIP simulation nodes during
baking to detect which attributes have to be stored in every frame because
they have changed.
By using a combination of a weak user count and a version counter, it is
possible to detect that an attribute (or any data controlled by implicit
sharing) has not been changed with O(1) memory and time. It's still
possible that the data has been changed multiple times and is the same
in the end and beginning of course. That wouldn't be detected using this
mechanism.
The `ImplicitSharingInfo` struct has a new weak user count. A weak
reference is one that does not keep the referenced data alive, but makes sure
that the `ImplicitSharingInfo` itself is not deleted. If some piece of
data has one strong and multiple weak users, it is still mutable. If the
strong user count goes down to zero, the referenced data is freed.
Remaining weak users can check for this condition using `is_expired`.
This is a bit similar to `std::weak_ptr` but there is an important difference:
a weak user can not become a strong user while one can create a `shared_ptr`
from a `weak_ptr`. This restriction is necessary, because some code might
be changing the referenced data assuming that it is the only owner. If
another thread suddenly adds a new owner, the data would be shared again
and the first thread would not have been allowed to modify the data in
the first place.
There is also a new integer version counter in `ImplicitSharingInfo`.
It is incremented whenever some code wants to modify the referenced data.
Obviously, this can only be done when the data is not shared because then
it would be immutable. By comparing an old and new version number of the
same sharing info, one can check if the data has been modified. One has
to keep a weak reference to the sharing info together with the old version
number to ensure that the new sharing info is still the same as the old one.
Without this, it can happen that the sharing info was freed and a new
one was allocated at the same pointer address. Using a strong reference
for this purpose does not work, because then the data would never be
modified because it's shared.
2023-04-28 12:03:42 +02:00
|
|
|
}
|
2022-07-22 15:39:41 +02:00
|
|
|
|
2023-10-12 15:42:04 +02:00
|
|
|
static void remember_deformed_curve_positions_if_necessary(
|
|
|
|
const Curves *curves_id, GeometryComponentEditData &edit_component)
|
2022-07-22 15:39:41 +02:00
|
|
|
{
|
|
|
|
if (!edit_component.curves_edit_hints_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (edit_component.curves_edit_hints_->positions.has_value()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (curves_id == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
2023-06-15 22:18:28 +02:00
|
|
|
const CurvesGeometry &curves = curves_id->geometry.wrap();
|
2022-07-22 15:39:41 +02:00
|
|
|
const int points_num = curves.points_num();
|
|
|
|
if (points_num != edit_component.curves_edit_hints_->curves_id_orig.geometry.point_num) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
edit_component.curves_edit_hints_->positions.emplace(points_num);
|
|
|
|
edit_component.curves_edit_hints_->positions->as_mutable_span().copy_from(curves.positions());
|
|
|
|
}
|
2023-06-15 22:18:28 +02:00
|
|
|
|
2023-10-12 15:42:04 +02:00
|
|
|
static void remember_deformed_grease_pencil_if_necessary(const GreasePencil *grease_pencil,
|
|
|
|
GeometryComponentEditData &edit_component)
|
|
|
|
{
|
|
|
|
if (!edit_component.grease_pencil_edit_hints_) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (edit_component.grease_pencil_edit_hints_->drawing_hints.has_value()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
if (grease_pencil == nullptr) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
const GreasePencil &orig_grease_pencil =
|
|
|
|
edit_component.grease_pencil_edit_hints_->grease_pencil_id_orig;
|
|
|
|
const Span<const bke::greasepencil::Layer *> layers = grease_pencil->layers();
|
|
|
|
const Span<const bke::greasepencil::Layer *> orig_layers = orig_grease_pencil.layers();
|
|
|
|
const int layers_num = layers.size();
|
|
|
|
if (layers_num != orig_layers.size()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
edit_component.grease_pencil_edit_hints_->drawing_hints.emplace(layers_num);
|
|
|
|
MutableSpan<GreasePencilDrawingEditHints> all_hints =
|
|
|
|
*edit_component.grease_pencil_edit_hints_->drawing_hints;
|
|
|
|
for (const int layer_index : layers.index_range()) {
|
|
|
|
const bke::greasepencil::Drawing *drawing = greasepencil::get_eval_grease_pencil_layer_drawing(
|
|
|
|
*grease_pencil, layer_index);
|
|
|
|
const bke::greasepencil::Layer &orig_layer = *orig_layers[layer_index];
|
|
|
|
const bke::greasepencil::Drawing *orig_drawing = orig_grease_pencil.get_drawing_at(
|
|
|
|
&orig_layer, grease_pencil->runtime->eval_frame);
|
|
|
|
GreasePencilDrawingEditHints &drawing_hints = all_hints[layer_index];
|
|
|
|
|
|
|
|
if (!drawing || !orig_drawing) {
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (drawing->strokes().points_num() != orig_drawing->strokes().points_num()) {
|
|
|
|
continue;
|
|
|
|
}
|
2023-10-17 19:29:52 +02:00
|
|
|
drawing_hints.positions.emplace(drawing->strokes().positions());
|
2023-10-12 15:42:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void GeometryComponentEditData::remember_deformed_positions_if_necessary(GeometrySet &geometry)
|
|
|
|
{
|
|
|
|
/* This component should be created at the start of object evaluation if it's necessary. */
|
|
|
|
if (!geometry.has<GeometryComponentEditData>()) {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
GeometryComponentEditData &edit_component =
|
|
|
|
geometry.get_component_for_write<GeometryComponentEditData>();
|
|
|
|
remember_deformed_curve_positions_if_necessary(geometry.get_curves(), edit_component);
|
|
|
|
remember_deformed_grease_pencil_if_necessary(geometry.get_grease_pencil(), edit_component);
|
|
|
|
}
|
|
|
|
|
2023-06-15 22:18:28 +02:00
|
|
|
} // namespace blender::bke
|