GPv3: Replace int
with FramesMapKey
This adds the `FramesMapKey` alias to the `blender::bke::greasepencil` namespace. Pull Request: https://projects.blender.org/blender/blender/pulls/110714
This commit is contained in:
parent
0c8785a249
commit
b2f61b5c8a
@ -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
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user