GPv3: Replace int with FramesMapKey #110714

Merged
Falk David merged 2 commits from filedescriptor/blender:gpv3-cleanup-frames-map-key into main 2023-08-02 14:02:29 +02:00
3 changed files with 59 additions and 59 deletions

View File

@ -192,6 +192,10 @@ class LayerMask : public ::GreasePencilLayerMask {
~LayerMask();
};
/* The key of a GreasePencilFrame in the frames map is the starting scene frame number (int) of
* that frame. */
using FramesMapKey = int;
class LayerRuntime {
public:
/**
@ -219,11 +223,11 @@ class LayerRuntime {
* referenced drawings are discarded. If the frame is longer than the number of referenced
* drawings, then the last referenced drawing is held for the rest of the duration.
*/
Map<int, GreasePencilFrame> frames_;
Map<FramesMapKey, GreasePencilFrame> frames_;
/**
* Caches a sorted vector of the keys of `frames_`.
*/
mutable SharedCache<Vector<int>> sorted_keys_cache_;
mutable SharedCache<Vector<FramesMapKey>> sorted_keys_cache_;
/**
* A vector of LayerMask. This layer will be masked by the layers referenced in the masks.
* A layer can have zero or more layer masks.
@ -262,8 +266,8 @@ class Layer : public ::GreasePencilLayer {
/**
* \returns the frames mapping.
*/
const Map<int, GreasePencilFrame> &frames() const;
Map<int, GreasePencilFrame> &frames_for_write();
const Map<FramesMapKey, GreasePencilFrame> &frames() const;
Map<FramesMapKey, GreasePencilFrame> &frames_for_write();
bool is_visible() const;
bool is_locked() const;
@ -273,34 +277,33 @@ class Layer : public ::GreasePencilLayer {
/**
* Adds a new frame into the layer frames map.
* Fails if there already exists a frame at \a frame_number that is not a null-frame.
* Null-frame at \a frame_number and subsequent null-frames are removed.
* Fails if there already exists a frame at \a key that is not a null-frame.
* Null-frame at \a key and subsequent null-frames are removed.
*
* If \a duration is 0, the frame is marked as an implicit hold (see `GP_FRAME_IMPLICIT_HOLD`).
* Otherwise adds an additional null-frame at \a frame_number + \a duration, if necessary, to
* Otherwise adds an additional null-frame at \a key + \a duration, if necessary, to
* indicate the end of the added frame.
*
* \returns a pointer to the added frame on success, otherwise nullptr.
*/
GreasePencilFrame *add_frame(int frame_number, int drawing_index, int duration = 0);
GreasePencilFrame *add_frame(FramesMapKey key, int drawing_index, int duration = 0);
/**
* Removes a frame with \a start_frame_number from the frames map.
* Removes a frame with \a key from the frames map.
*
* Fails if the map does not contain a frame with \a frame_number or in the specific case where
* Fails if the map does not contain a frame with \a key or in the specific case where
* the previous frame has a fixed duration (is not marked as an implicit hold) and the frame to
* remove is a null frame.
*
* Will remove null frames after the frame to remove.
* \param start_frame_number: the first frame number of the frame to be removed.
* \return true on success.
*/
bool remove_frame(int start_frame_number);
bool remove_frame(FramesMapKey key);
/**
* Returns the sorted (start) frame numbers of the frames of this layer.
* Returns the sorted keys (start frame numbers) of the frames of this layer.
* \note This will cache the keys lazily.
*/
Span<int> sorted_keys() const;
Span<FramesMapKey> sorted_keys() const;
/**
* \returns the index of the active drawing at frame \a frame_number or -1 if there is no
@ -326,7 +329,7 @@ class Layer : public ::GreasePencilLayer {
private:
GreasePencilFrame *add_frame_internal(int frame_number, int drawing_index);
int frame_index_at(int frame_number) const;
FramesMapKey frame_key_at(int frame_number) const;
/**
* Removes null frames starting from \a begin until \a end (excluded) or until a non-null frame
* is reached. \param begin, end: Iterators into the `sorted_keys` span. \returns an iterator to

View File

@ -612,47 +612,45 @@ Layer::SortedKeysIterator Layer::remove_leading_null_frames_in_range(
return next_it;
}
GreasePencilFrame *Layer::add_frame_internal(const int frame_number, const int drawing_index)
GreasePencilFrame *Layer::add_frame_internal(const FramesMapKey key, const int drawing_index)
{
BLI_assert(drawing_index != -1);
if (!this->frames().contains(frame_number)) {
if (!this->frames().contains(key)) {
GreasePencilFrame frame{};
frame.drawing_index = drawing_index;
this->frames_for_write().add_new(frame_number, frame);
this->frames_for_write().add_new(key, frame);
this->tag_frames_map_keys_changed();
return this->frames_for_write().lookup_ptr(frame_number);
return this->frames_for_write().lookup_ptr(key);
}
/* Overwrite null-frames. */
if (this->frames().lookup(frame_number).is_null()) {
if (this->frames().lookup(key).is_null()) {
GreasePencilFrame frame{};
frame.drawing_index = drawing_index;
this->frames_for_write().add_overwrite(frame_number, frame);
this->frames_for_write().add_overwrite(key, frame);
this->tag_frames_map_changed();
return this->frames_for_write().lookup_ptr(frame_number);
return this->frames_for_write().lookup_ptr(key);
}
return nullptr;
}
GreasePencilFrame *Layer::add_frame(const int frame_number,
GreasePencilFrame *Layer::add_frame(const FramesMapKey key,
const int drawing_index,
const int duration)
{
BLI_assert(duration >= 0);
GreasePencilFrame *frame = this->add_frame_internal(frame_number, drawing_index);
GreasePencilFrame *frame = this->add_frame_internal(key, drawing_index);
if (frame == nullptr) {
return nullptr;
}
Span<int> sorted_keys = this->sorted_keys();
const int end_frame_number = frame_number + duration;
/* Finds the next greater frame_number that is stored in the map. */
SortedKeysIterator next_frame_number_it = std::upper_bound(
sorted_keys.begin(), sorted_keys.end(), frame_number);
Span<FramesMapKey> sorted_keys = this->sorted_keys();
const FramesMapKey end_key = key + duration;
/* Finds the next greater key that is stored in the map. */
SortedKeysIterator next_key_it = std::upper_bound(sorted_keys.begin(), sorted_keys.end(), key);
/* If the next frame we found is at the end of the frame we're inserting, then we are done. */
if (next_frame_number_it != sorted_keys.end() && *next_frame_number_it == end_frame_number) {
if (next_key_it != sorted_keys.end() && *next_key_it == end_key) {
return frame;
}
next_frame_number_it = this->remove_leading_null_frames_in_range(next_frame_number_it,
sorted_keys.end());
next_key_it = this->remove_leading_null_frames_in_range(next_key_it, sorted_keys.end());
/* If the duration is set to 0, the frame is marked as an implicit hold.*/
if (duration == 0) {
frame->flag |= GP_FRAME_IMPLICIT_HOLD;
@ -660,58 +658,57 @@ GreasePencilFrame *Layer::add_frame(const int frame_number,
}
/* If the next frame comes after the end of the frame we're inserting (or if there are no more
* frames), add a null-frame. */
if (next_frame_number_it == sorted_keys.end() || *next_frame_number_it > end_frame_number) {
this->frames_for_write().add_new(end_frame_number, GreasePencilFrame::null());
if (next_key_it == sorted_keys.end() || *next_key_it > end_key) {
this->frames_for_write().add_new(end_key, GreasePencilFrame::null());
this->tag_frames_map_keys_changed();
}
return frame;
}
bool Layer::remove_frame(const int start_frame_number)
bool Layer::remove_frame(const FramesMapKey key)
{
/* If the frame number is not in the frames map, do nothing. */
if (!this->frames().contains(start_frame_number)) {
if (!this->frames().contains(key)) {
return false;
}
if (this->frames().size() == 1) {
this->frames_for_write().remove_contained(start_frame_number);
this->frames_for_write().remove_contained(key);
this->tag_frames_map_keys_changed();
return true;
}
Span<int> sorted_keys = this->sorted_keys();
Span<FramesMapKey> sorted_keys = this->sorted_keys();
/* Find the index of the frame to remove in the `sorted_keys` array. */
SortedKeysIterator remove_frame_number_it = std::lower_bound(
sorted_keys.begin(), sorted_keys.end(), start_frame_number);
SortedKeysIterator remove_key_it = std::lower_bound(sorted_keys.begin(), sorted_keys.end(), key);
/* If there is a next frame: */
if (std::next(remove_frame_number_it) != sorted_keys.end()) {
SortedKeysIterator next_frame_number_it = std::next(remove_frame_number_it);
this->remove_leading_null_frames_in_range(next_frame_number_it, sorted_keys.end());
if (std::next(remove_key_it) != sorted_keys.end()) {
SortedKeysIterator next_key_it = std::next(remove_key_it);
this->remove_leading_null_frames_in_range(next_key_it, sorted_keys.end());
}
/* If there is a previous frame: */
if (remove_frame_number_it != sorted_keys.begin()) {
SortedKeysIterator prev_frame_number_it = std::prev(remove_frame_number_it);
const GreasePencilFrame &prev_frame = this->frames().lookup(*prev_frame_number_it);
if (remove_key_it != sorted_keys.begin()) {
SortedKeysIterator prev_key_it = std::prev(remove_key_it);
const GreasePencilFrame &prev_frame = this->frames().lookup(*prev_key_it);
/* If the previous frame is not an implicit hold (e.g. it has a fixed duration) and it's not a
* null frame, we cannot just delete the frame. We need to replace it with a null frame. */
if (!prev_frame.is_implicit_hold() && !prev_frame.is_null()) {
this->frames_for_write().lookup(start_frame_number) = GreasePencilFrame::null();
this->frames_for_write().lookup(key) = GreasePencilFrame::null();
/* Since the original frame was replaced with a null frame, we consider the frame to be
* successfully removed here. */
return true;
}
}
/* Finally, remove the actual frame. */
this->frames_for_write().remove_contained(start_frame_number);
this->frames_for_write().remove_contained(key);
this->tag_frames_map_keys_changed();
return true;
}
Span<int> Layer::sorted_keys() const
Span<FramesMapKey> Layer::sorted_keys() const
{
this->runtime->sorted_keys_cache_.ensure([&](Vector<int> &r_data) {
this->runtime->sorted_keys_cache_.ensure([&](Vector<FramesMapKey> &r_data) {
r_data.reinitialize(this->frames().size());
int i = 0;
for (int64_t key : this->frames().keys()) {
for (FramesMapKey key : this->frames().keys()) {
r_data[i++] = key;
}
std::sort(r_data.begin(), r_data.end());
@ -719,7 +716,7 @@ Span<int> Layer::sorted_keys() const
return this->runtime->sorted_keys_cache_.data();
}
int Layer::frame_index_at(const int frame_number) const
FramesMapKey Layer::frame_key_at(const int frame_number) const
{
Span<int> sorted_keys = this->sorted_keys();
/* No keyframes, return no drawing. */
@ -744,14 +741,14 @@ int Layer::frame_index_at(const int frame_number) const
const GreasePencilFrame *Layer::frame_at(const int frame_number) const
{
const int frame_index = this->frame_index_at(frame_number);
return (frame_index == -1) ? nullptr : this->frames().lookup_ptr(frame_index);
const FramesMapKey frame_key = this->frame_key_at(frame_number);
return (frame_key == -1) ? nullptr : this->frames().lookup_ptr(frame_key);
}
GreasePencilFrame *Layer::frame_at(const int frame_number)
{
const int frame_index = this->frame_index_at(frame_number);
return (frame_index == -1) ? nullptr : this->frames_for_write().lookup_ptr(frame_index);
const FramesMapKey frame_key = this->frame_key_at(frame_number);
return (frame_key == -1) ? nullptr : this->frames_for_write().lookup_ptr(frame_key);
}
int Layer::drawing_index_at(const int frame_number) const

View File

@ -173,7 +173,7 @@ struct GreasePencilLayerFramesExample {
* Scene Frame: |0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|...
* Drawing: [#0 ][#1 ] [#2 ]
*/
const int sorted_keys[5] = {0, 5, 10, 12, 16};
const FramesMapKey sorted_keys[5] = {0, 5, 10, 12, 16};
GreasePencilFrame sorted_values[5] = {{0}, {1}, {-1}, {2}, {-1}};
Layer layer;
@ -230,7 +230,7 @@ TEST(greasepencil, add_frame_duration_check_duration)
{
GreasePencilLayerFramesExample ex;
EXPECT_TRUE(ex.layer.add_frame(17, 3, 10));
Span<int> sorted_keys = ex.layer.sorted_keys();
Span<FramesMapKey> sorted_keys = ex.layer.sorted_keys();
EXPECT_EQ(sorted_keys.size(), 7);
EXPECT_EQ(sorted_keys[6] - sorted_keys[5], 10);
}
@ -247,7 +247,7 @@ TEST(greasepencil, add_frame_duration_override_null_frames)
EXPECT_EQ(layer.drawing_index_at(0), 1);
EXPECT_EQ(layer.drawing_index_at(1), 3);
EXPECT_EQ(layer.drawing_index_at(11), -1);
Span<int> sorted_keys = layer.sorted_keys();
Span<FramesMapKey> sorted_keys = layer.sorted_keys();
EXPECT_EQ(sorted_keys.size(), 3);
EXPECT_EQ(sorted_keys[0], 0);
EXPECT_EQ(sorted_keys[1], 1);