GPv3: Add user count to drawings

Adds a user count to drawings to track how many frames use the drawing.
If the user count hits `0` the drawing should be deleted.

Also adds a function to delete a frame in a layer. This will
decrement the user count of the drawing and delete it if there are no
users left. This is consistent with the way GPv2 worked.

Pull Request: https://projects.blender.org/blender/blender/pulls/110579
This commit is contained in:
Falk David
2023-08-01 17:04:39 +02:00
committed by Falk David
parent b4e4030bd6
commit de8ce4e34b
3 changed files with 72 additions and 3 deletions

View File

@@ -9,6 +9,8 @@
* \brief Low-level operations for grease pencil.
*/
#include <atomic>
#include "BLI_function_ref.hh"
#include "BLI_map.hh"
#include "BLI_math_vector_types.hh"
@@ -62,6 +64,13 @@ class DrawingRuntime {
* Triangle cache for all the strokes in the drawing.
*/
mutable SharedCache<Vector<uint3>> triangles_cache;
/**
* Number of users for this drawing. The users are the frames in the Grease Pencil layers.
* Different frames can refer to the same drawing, so we need to make sure we count these users
* and remove a drawing if it has zero users.
*/
mutable std::atomic<int> user_count = 1;
};
class Drawing : public ::GreasePencilDrawing {
@@ -92,6 +101,22 @@ class Drawing : public ::GreasePencilDrawing {
*/
VArray<float> opacities() const;
MutableSpan<float> opacities_for_write();
/**
* Add a user for this drawing. When a drawing has multiple users, both users are allowed to
* modifify this drawings data.
*/
void add_user() const;
/**
* Removes a user from this drawing. Note that this does not handle deleting the drawing if it
* has not users.
*/
void remove_user() const;
/**
* Returns true for when this drawing has more than one user.
*/
bool is_instanced() const;
bool has_users() const;
};
class LayerGroup;
@@ -504,6 +529,26 @@ class GreasePencilRuntime {
} // namespace blender::bke
inline void blender::bke::greasepencil::Drawing::add_user() const
{
this->runtime->user_count.fetch_add(1, std::memory_order_relaxed);
}
inline void blender::bke::greasepencil::Drawing::remove_user() const
{
this->runtime->user_count.fetch_sub(1, std::memory_order_relaxed);
}
inline bool blender::bke::greasepencil::Drawing::is_instanced() const
{
return this->runtime->user_count.load(std::memory_order_relaxed) > 1;
}
inline bool blender::bke::greasepencil::Drawing::has_users() const
{
return this->runtime->user_count.load(std::memory_order_relaxed) > 0;
}
inline blender::bke::greasepencil::Drawing &GreasePencilDrawing::wrap()
{
return *reinterpret_cast<blender::bke::greasepencil::Drawing *>(this);

View File

@@ -109,7 +109,6 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
break;
}
}
/* TODO: Update drawing user counts. */
}
/* Duplicate layer tree. */
@@ -1384,8 +1383,6 @@ void GreasePencil::add_empty_drawings(const int add_num)
new_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_new<blender::bke::greasepencil::Drawing>(__func__));
}
/* TODO: Update drawing user counts. */
}
bool GreasePencil::insert_blank_frame(blender::bke::greasepencil::Layer &layer,
@@ -1403,6 +1400,32 @@ bool GreasePencil::insert_blank_frame(blender::bke::greasepencil::Layer &layer,
return true;
}
void GreasePencil::remove_frame_at(blender::bke::greasepencil::Layer &layer,
const int frame_number)
{
using namespace blender::bke::greasepencil;
if (!layer.frames().contains(frame_number)) {
return;
}
const GreasePencilFrame &frame_to_remove = layer.frames().lookup(frame_number);
const int drawing_index_to_remove = frame_to_remove.drawing_index;
if (!layer.remove_frame(frame_number)) {
/* If removing the frame was not successful, return early. */
return;
}
GreasePencilDrawingBase *drawing_base = this->drawings(drawing_index_to_remove);
if (drawing_base->type != GP_DRAWING) {
/* If the drawing is referenced from another object, we don't track it's users because we
* cannot delete drawings from another object. Return early. */
return;
}
Drawing &drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base)->wrap();
drawing.remove_user();
if (!drawing.has_users()) {
this->remove_drawing(drawing_index_to_remove);
}
}
void GreasePencil::remove_drawing(const int index_to_remove)
{
using namespace blender::bke::greasepencil;

View File

@@ -485,6 +485,7 @@ typedef struct GreasePencil {
int frame_number,
int duration,
eBezTriple_KeyframeType keytype);
void remove_frame_at(blender::bke::greasepencil::Layer &layer, int frame_number);
void remove_drawing(int index);