Initial Grease Pencil 3.0 stage #106848

Merged
Falk David merged 224 commits from filedescriptor/blender:grease-pencil-v3 into main 2023-05-30 11:14:22 +02:00
3 changed files with 127 additions and 3 deletions
Showing only changes of commit db356e6c57 - Show all commits

View File

@ -441,10 +441,10 @@ blender::Span<blender::bke::StrokePoint> GreasePencilDrawing::stroke_buffer()
/* GreasePencil API */
static void grease_pencil_grow_drawing_array_by(GreasePencil &self, const int added_capacity)
static void grease_pencil_grow_drawing_array_by(GreasePencil &self, const int add_capacity)
{
BLI_assert(added_capacity > 0);
const int new_drawing_array_size = self.drawing_array_size + added_capacity;
BLI_assert(add_capacity > 0);
const int new_drawing_array_size = self.drawing_array_size + add_capacity;
GreasePencilDrawingOrReference **new_drawing_array =
reinterpret_cast<GreasePencilDrawingOrReference **>(
MEM_cnew_array<GreasePencilDrawingOrReference *>(new_drawing_array_size, __func__));
@ -456,6 +456,21 @@ static void grease_pencil_grow_drawing_array_by(GreasePencil &self, const int ad
self.drawing_array_size = new_drawing_array_size;
}
static void grease_pencil_shrink_drawing_array_by(GreasePencil &self, const int remove_capacity)
{
BLI_assert(remove_capacity > 0);
const int new_drawing_array_size = self.drawing_array_size - remove_capacity;
GreasePencilDrawingOrReference **new_drawing_array =
reinterpret_cast<GreasePencilDrawingOrReference **>(
MEM_cnew_array<GreasePencilDrawingOrReference *>(new_drawing_array_size, __func__));
blender::uninitialized_move_n(self.drawing_array, new_drawing_array_size, new_drawing_array);
MEM_freeN(self.drawing_array);
self.drawing_array = new_drawing_array;
self.drawing_array_size = new_drawing_array_size;
}
blender::Span<GreasePencilDrawingOrReference *> GreasePencil::drawings() const
{
return blender::Span<GreasePencilDrawingOrReference *>{this->drawing_array,
@ -479,9 +494,76 @@ void GreasePencil::add_empty_drawings(int n)
for (const int i : IndexRange(new_drawings.size())) {
new_drawings[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
MEM_new<GreasePencilDrawing>(__func__));
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(new_drawings[i]);
new (&drawing->geometry) bke::CurvesGeometry();
}
}
void GreasePencil::remove_drawing(int index_to_remove)
{
using namespace blender::bke::gpencil;
/* In order to not change the indices of the drawings, we do the following to the drawing to be
* removed:
* - If the drawing (A) is not the last one:
* 1.1) Find any frames in the layers that reference the last drawing (B) and point them to
* A's index.
* 1.2) Swap drawing A with drawing B.
* 2) Destroy A and shrink the array by one.
* 3) Remove any frames in the layers that reference the A's index.
*/
BLI_assert(this->drawing_array_size > 0);
BLI_assert(index_to_remove >= 0 && index_to_remove < this->drawing_array_size);
/* Move the drawing that should be removed to the last index. */
const int last_drawing_index = this->drawing_array_size - 1;
if (index_to_remove != last_drawing_index) {
this->root_group().foreach_layer_pre_order(
[last_drawing_index, index_to_remove](Layer &layer) {
blender::Map<int, int> &frames = layer.frames_for_write();
for (auto item : frames.items()) {
if (item.value == last_drawing_index) {
item.value = index_to_remove;
}
else if (item.value == index_to_remove) {
item.value = last_drawing_index;
}
}
});
std::swap(this->drawings_for_write()[index_to_remove],
this->drawings_for_write()[last_drawing_index]);
}
/* Delete the last drawing. */
GreasePencilDrawingOrReference *drawing_or_ref_to_remove =
this->drawings_for_write()[last_drawing_index];
switch (drawing_or_ref_to_remove->type) {
case GREASE_PENCIL_DRAWING: {
GreasePencilDrawing *drawing_to_remove = reinterpret_cast<GreasePencilDrawing *>(
drawing_or_ref_to_remove);
drawing_to_remove->geometry.wrap().~CurvesGeometry();
MEM_delete(drawing_to_remove->runtime);
drawing_to_remove->runtime = nullptr;
MEM_freeN(drawing_to_remove);
break;
}
case GREASE_PENCIL_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference_to_remove =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref_to_remove);
MEM_freeN(drawing_reference_to_remove);
break;
}
}
/* Remove any frame that points to the last drawing. */
this->root_group().foreach_layer_pre_order([last_drawing_index](Layer &layer) {
blender::Map<int, int> &frames = layer.frames_for_write();
frames.remove_if([last_drawing_index](auto item) { return item.value == last_drawing_index; });
});
/* Shrink drawing array. */
grease_pencil_shrink_drawing_array_by(*this, 1);
}
void GreasePencil::foreach_visible_drawing(
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
{

View File

@ -3,6 +3,7 @@
#include "testing/testing.h"
#include "BKE_curves.hh"
#include "BKE_grease_pencil.hh"
#include "BKE_idtype.h"
#include "BKE_lib_id.h"
@ -49,6 +50,46 @@ TEST(gpencil, add_empty_drawings)
EXPECT_EQ(grease_pencil.drawings().size(), 3);
}
TEST(gpencil, remove_drawing)
{
GreasePencilIDTestContext ctx;
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "GP"));
grease_pencil.add_empty_drawings(3);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(
grease_pencil.drawings_for_write()[1]);
drawing->geometry.wrap().resize(0, 10);
Layer layer1("Layer1");
Layer layer2("Layer2");
layer1.frames_for_write().add(0, 0);
layer1.frames_for_write().add(10, 1);
layer1.frames_for_write().add(20, 2);
layer2.frames_for_write().add(0, 1);
grease_pencil.root_group().add_layer(std::move(layer1));
grease_pencil.root_group().add_layer(std::move(layer2));
grease_pencil.remove_drawing(1);
EXPECT_EQ(grease_pencil.drawings().size(), 2);
static int expected_frames_size[] = {2, 0};
static int expected_frames_pairs_layer0[][2] = {{0, 0}, {20, 1}};
int layer_i = 0;
grease_pencil.root_group().foreach_layer_pre_order([&](Layer &layer) {
EXPECT_EQ(layer.frames().size(), expected_frames_size[layer_i]);
if (layer_i == 0) {
for (const int i : IndexRange(2)) {
EXPECT_EQ(layer.frames().lookup(expected_frames_pairs_layer0[i][0]),
expected_frames_pairs_layer0[i][1]);
}
}
layer_i++;
});
}
/* --------------------------------------------------------------------------------------------- */
/* Layer Tree Tests. */

View File

@ -181,6 +181,7 @@ typedef struct GreasePencil {
blender::Span<GreasePencilDrawingOrReference *> drawings() const;
blender::MutableSpan<GreasePencilDrawingOrReference *> drawings_for_write();
void add_empty_drawings(int n);
void remove_drawing(int index);
void foreach_visible_drawing(int frame,
blender::FunctionRef<void(GreasePencilDrawing &)> function);
void read_drawing_array(BlendDataReader *reader);