Initial Grease Pencil 3.0 stage #106848
|
@ -441,10 +441,10 @@ blender::Span<blender::bke::StrokePoint> GreasePencilDrawing::stroke_buffer()
|
||||||
|
|
||||||
/* GreasePencil API */
|
/* 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);
|
BLI_assert(add_capacity > 0);
|
||||||
const int new_drawing_array_size = self.drawing_array_size + added_capacity;
|
const int new_drawing_array_size = self.drawing_array_size + add_capacity;
|
||||||
GreasePencilDrawingOrReference **new_drawing_array =
|
GreasePencilDrawingOrReference **new_drawing_array =
|
||||||
reinterpret_cast<GreasePencilDrawingOrReference **>(
|
reinterpret_cast<GreasePencilDrawingOrReference **>(
|
||||||
MEM_cnew_array<GreasePencilDrawingOrReference *>(new_drawing_array_size, __func__));
|
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;
|
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
|
blender::Span<GreasePencilDrawingOrReference *> GreasePencil::drawings() const
|
||||||
{
|
{
|
||||||
return blender::Span<GreasePencilDrawingOrReference *>{this->drawing_array,
|
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())) {
|
for (const int i : IndexRange(new_drawings.size())) {
|
||||||
new_drawings[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
|
new_drawings[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
|
||||||
MEM_new<GreasePencilDrawing>(__func__));
|
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(
|
void GreasePencil::foreach_visible_drawing(
|
||||||
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
|
int frame, blender::FunctionRef<void(GreasePencilDrawing &)> function)
|
||||||
{
|
{
|
||||||
|
|
|
@ -3,6 +3,7 @@
|
||||||
|
|
||||||
#include "testing/testing.h"
|
#include "testing/testing.h"
|
||||||
|
|
||||||
|
#include "BKE_curves.hh"
|
||||||
#include "BKE_grease_pencil.hh"
|
#include "BKE_grease_pencil.hh"
|
||||||
#include "BKE_idtype.h"
|
#include "BKE_idtype.h"
|
||||||
#include "BKE_lib_id.h"
|
#include "BKE_lib_id.h"
|
||||||
|
@ -49,6 +50,46 @@ TEST(gpencil, add_empty_drawings)
|
||||||
EXPECT_EQ(grease_pencil.drawings().size(), 3);
|
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. */
|
/* Layer Tree Tests. */
|
||||||
|
|
||||||
|
|
|
@ -181,6 +181,7 @@ typedef struct GreasePencil {
|
||||||
blender::Span<GreasePencilDrawingOrReference *> drawings() const;
|
blender::Span<GreasePencilDrawingOrReference *> drawings() const;
|
||||||
blender::MutableSpan<GreasePencilDrawingOrReference *> drawings_for_write();
|
blender::MutableSpan<GreasePencilDrawingOrReference *> drawings_for_write();
|
||||||
void add_empty_drawings(int n);
|
void add_empty_drawings(int n);
|
||||||
|
void remove_drawing(int index);
|
||||||
void foreach_visible_drawing(int frame,
|
void foreach_visible_drawing(int frame,
|
||||||
blender::FunctionRef<void(GreasePencilDrawing &)> function);
|
blender::FunctionRef<void(GreasePencilDrawing &)> function);
|
||||||
void read_drawing_array(BlendDataReader *reader);
|
void read_drawing_array(BlendDataReader *reader);
|
||||||
|
|
Loading…
Reference in New Issue