Initial Grease Pencil 3.0 stage #106848
|
@ -308,6 +308,11 @@ class GreasePencilRuntime {
|
|||
|
||||
void ensure_layer_cache() const;
|
||||
|
||||
|
||||
void load_layer_tree_from_storage(GreasePencilLayerTreeStorage &storage);
|
||||
void save_layer_tree_to_storage(GreasePencilLayerTreeStorage &storage);
|
||||
|
||||
void tag_layer_tree_topology_changed();
|
||||
|
||||
public:
|
||||
void *batch_cache = nullptr;
|
||||
|
||||
|
|
|
@ -577,7 +577,6 @@ const greasepencil::LayerGroup &GreasePencilRuntime::root_group() const
|
|||
|
||||
greasepencil::LayerGroup &GreasePencilRuntime::root_group_for_write()
|
||||
{
|
||||
this->layer_cache_.tag_dirty();
|
||||
return this->root_group_;
|
||||
}
|
||||
|
||||
|
@ -615,6 +614,193 @@ void GreasePencilRuntime::ensure_layer_cache() const
|
|||
});
|
||||
}
|
||||
|
||||
static void read_layer_from_storage(blender::bke::greasepencil::LayerGroup ¤t_group,
|
||||
GreasePencilLayerTreeLeaf *node_leaf)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
Layer new_layer(node_leaf->base.name);
|
||||
for (int i = 0; i < node_leaf->layer.frames_storage.size; i++) {
|
||||
new_layer.insert_frame(node_leaf->layer.frames_storage.keys[i],
|
||||
node_leaf->layer.frames_storage.values[i]);
|
||||
}
|
||||
new_layer.parent_type = node_leaf->layer.parent_type;
|
||||
new_layer.blend_mode = node_leaf->layer.blend_mode;
|
||||
new_layer.parent = node_leaf->layer.parent;
|
||||
if (node_leaf->layer.parsubstr) {
|
||||
new_layer.parsubstr = BLI_strdup(node_leaf->layer.parsubstr);
|
||||
}
|
||||
if (node_leaf->layer.viewlayer_name) {
|
||||
new_layer.viewlayer_name = BLI_strdup(node_leaf->layer.viewlayer_name);
|
||||
}
|
||||
Vector<LayerMask> masks = new_layer.masks_for_write();
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &node_leaf->layer.masks_storage) {
|
||||
LayerMask new_mask = LayerMask(mask->name);
|
||||
new_mask.flag = mask->flag;
|
||||
masks.append(std::move(new_mask));
|
||||
}
|
||||
new_layer.opacity = node_leaf->layer.opacity;
|
||||
copy_v4_v4(new_layer.tint_color, node_leaf->layer.tint_color);
|
||||
copy_v3_v3(new_layer.location, node_leaf->layer.location);
|
||||
copy_v3_v3(new_layer.rotation, node_leaf->layer.rotation);
|
||||
copy_v3_v3(new_layer.scale, node_leaf->layer.scale);
|
||||
current_group.add_layer(std::move(new_layer));
|
||||
}
|
||||
|
||||
static int read_layer_node_recursive(blender::bke::greasepencil::LayerGroup ¤t_group,
|
||||
GreasePencilLayerTreeNode **nodes,
|
||||
int node_index)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
GreasePencilLayerTreeNode *node = nodes[node_index];
|
||||
int total_nodes_read = 0;
|
||||
switch (node->type) {
|
||||
case GP_LAYER_TREE_LEAF: {
|
||||
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf *>(node);
|
||||
read_layer_from_storage(current_group, node_leaf);
|
||||
total_nodes_read++;
|
||||
break;
|
||||
}
|
||||
case GP_LAYER_TREE_GROUP: {
|
||||
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(node);
|
||||
/* Read layer group. */
|
||||
LayerGroup new_group(group->base.name);
|
||||
for (int i = 0; i < group->children_num; i++) {
|
||||
total_nodes_read += read_layer_node_recursive(
|
||||
new_group, nodes, node_index + total_nodes_read + 1);
|
||||
}
|
||||
current_group.add_group(std::move(new_group));
|
||||
total_nodes_read++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_nodes_read;
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::load_layer_tree_from_storage(GreasePencilLayerTreeStorage &storage)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
if (storage.nodes_num == 0 || !storage.nodes) {
|
||||
return;
|
||||
}
|
||||
/* The first node should be the root group. */
|
||||
GreasePencilLayerTreeNode *root = reinterpret_cast<GreasePencilLayerTreeNode *>(
|
||||
storage.nodes[0]);
|
||||
Bastien Montagne
commented
This should not be needed, This should not be needed, `BKE_id_new_nomain` already calls `BKE_libblock_init_empty` which calls the relevant `initi_data` callback.
|
||||
BLI_assert(root->type == GP_LAYER_TREE_GROUP);
|
||||
int total_nodes_read = 0;
|
||||
for (int i = 0; i < reinterpret_cast<GreasePencilLayerTreeGroup *>(root)->children_num; i++) {
|
||||
HooglyBoogly marked this conversation as resolved
Outdated
Hans Goudey
commented
Other geometry data-block types have "min max" functions that take the data-block as an argument rather than the object. I hope to remove the object level function in the future, so for consistency, having the data-block function here would be nice. Other geometry data-block types have "min max" functions that take the data-block as an argument rather than the object. I hope to remove the object level function in the future, so for consistency, having the data-block function here would be nice.
|
||||
total_nodes_read += read_layer_node_recursive(
|
||||
this->root_group_, storage.nodes, total_nodes_read + 1);
|
||||
}
|
||||
BLI_assert(total_nodes_read + 1 == storage.nodes_num);
|
||||
this->set_active_layer_index(storage.active_layer_index);
|
||||
|
||||
this->tag_layer_tree_topology_changed();
|
||||
}
|
||||
|
||||
static void save_tree_node_to_storage(const blender::bke::greasepencil::TreeNode &node,
|
||||
GreasePencilLayerTreeNode *dst)
|
||||
{
|
||||
dst->type = node.type;
|
||||
copy_v3_v3_uchar(dst->color, node.color);
|
||||
dst->flag = node.flag;
|
||||
if (node.name) {
|
||||
dst->name = BLI_strdup(node.name);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_layer_to_storage(const blender::bke::greasepencil::Layer &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerTreeLeaf *new_leaf = MEM_cnew<GreasePencilLayerTreeLeaf>(__func__);
|
||||
/* Save properties. */
|
||||
save_tree_node_to_storage(node, &new_leaf->base);
|
||||
|
||||
/* Save frames map. */
|
||||
const int frames_size = node.frames().size();
|
||||
if (frames_size > 0) {
|
||||
new_leaf->layer.frames_storage.size = frames_size;
|
||||
new_leaf->layer.frames_storage.keys = MEM_cnew_array<int>(frames_size, __func__);
|
||||
new_leaf->layer.frames_storage.values = MEM_cnew_array<GreasePencilFrame>(frames_size,
|
||||
__func__);
|
||||
|
||||
MutableSpan<int> keys{new_leaf->layer.frames_storage.keys, frames_size};
|
||||
MutableSpan<GreasePencilFrame> values{new_leaf->layer.frames_storage.values, frames_size};
|
||||
keys.copy_from(node.sorted_keys());
|
||||
for (int i : keys.index_range()) {
|
||||
values[i] = node.frames().lookup(keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
new_leaf->layer.parent_type = node.parent_type;
|
||||
new_leaf->layer.blend_mode = node.blend_mode;
|
||||
new_leaf->layer.parent = node.parent;
|
||||
if (node.parsubstr) {
|
||||
new_leaf->layer.parsubstr = BLI_strdup(node.parsubstr);
|
||||
}
|
||||
if (node.viewlayer_name) {
|
||||
new_leaf->layer.viewlayer_name = BLI_strdup(node.viewlayer_name);
|
||||
}
|
||||
BLI_listbase_clear(&new_leaf->layer.masks_storage);
|
||||
for (const bke::greasepencil::LayerMask &mask : node.masks()) {
|
||||
GreasePencilLayerMask *new_mask = MEM_cnew<GreasePencilLayerMask>(__func__);
|
||||
new_mask->layer_name = BLI_strdup(mask.layer_name);
|
||||
new_mask->flag = mask.flag;
|
||||
BLI_addtail(&new_leaf->layer.masks_storage, new_mask);
|
||||
}
|
||||
new_leaf->layer.opacity = node.opacity;
|
||||
copy_v4_v4(new_leaf->layer.tint_color, node.tint_color);
|
||||
copy_v3_v3(new_leaf->layer.location, node.location);
|
||||
copy_v3_v3(new_leaf->layer.rotation, node.rotation);
|
||||
copy_v3_v3(new_leaf->layer.scale, node.scale);
|
||||
|
||||
/* Store pointer. */
|
||||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_leaf);
|
||||
}
|
||||
|
||||
static void save_layer_group_to_storage(const blender::bke::greasepencil::LayerGroup &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
GreasePencilLayerTreeGroup *new_group = MEM_cnew<GreasePencilLayerTreeGroup>(__func__);
|
||||
/* Save properties. */
|
||||
save_tree_node_to_storage(node, &new_group->base);
|
||||
|
||||
/* Save number of children. */
|
||||
new_group->children_num = node.num_direct_children();
|
||||
|
||||
/* Store pointer. */
|
||||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_group);
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::save_layer_tree_to_storage(GreasePencilLayerTreeStorage &storage)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
/* We always store the root group, so we have to add one here. */
|
||||
int num_tree_nodes = this->root_group_.num_children_total() + 1;
|
||||
storage.nodes_num = num_tree_nodes;
|
||||
storage.nodes = MEM_cnew_array<GreasePencilLayerTreeNode *>(num_tree_nodes, __func__);
|
||||
|
||||
save_layer_group_to_storage(this->root_group_, &storage.nodes[0]);
|
||||
this->root_group_.foreach_children_with_index_pre_order([&](uint64_t i, TreeNode &node) {
|
||||
GreasePencilLayerTreeNode **dst = &storage.nodes[i + 1];
|
||||
if (node.is_group()) {
|
||||
const LayerGroup &group = node.as_group();
|
||||
save_layer_group_to_storage(group, dst);
|
||||
}
|
||||
else if (node.is_layer()) {
|
||||
Hans Goudey
commented
Please search the patch for this, I mentioned it last time too `offset_indices::OffsetIndices` -> `OffsetIndices`
Please search the patch for this, I mentioned it last time too
|
||||
const Layer &layer = node.as_layer();
|
||||
save_layer_to_storage(layer, dst);
|
||||
}
|
||||
});
|
||||
|
||||
storage.active_layer_index = this->active_layer_index_;
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::tag_layer_tree_topology_changed()
|
||||
{
|
||||
this->layer_cache_.tag_dirty();
|
||||
}
|
||||
|
||||
greasepencil::Layer *GreasePencilRuntime::get_active_layer_from_index(int index) const
|
||||
{
|
||||
this->ensure_layer_cache();
|
||||
|
@ -987,9 +1173,9 @@ blender::Span<blender::bke::greasepencil::Layer *> GreasePencil::layers_for_writ
|
|||
return this->runtime->layer_cache_.data();
|
||||
}
|
||||
|
||||
void GreasePencil::tag_layer_tree_changed()
|
||||
void GreasePencil::tag_layer_tree_topology_changed()
|
||||
{
|
||||
this->runtime->layer_cache_.tag_dirty();
|
||||
this->runtime->tag_layer_tree_topology_changed();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -1082,187 +1268,14 @@ void GreasePencil::free_drawing_array()
|
|||
/** \name Layer Tree storage functions
|
||||
* \{ */
|
||||
|
||||
static void save_tree_node_to_storage(const blender::bke::greasepencil::TreeNode &node,
|
||||
GreasePencilLayerTreeNode *dst)
|
||||
{
|
||||
dst->type = node.type;
|
||||
copy_v3_v3_uchar(dst->color, node.color);
|
||||
dst->flag = node.flag;
|
||||
if (node.name) {
|
||||
dst->name = BLI_strdup(node.name);
|
||||
}
|
||||
}
|
||||
|
||||
static void save_layer_to_storage(const blender::bke::greasepencil::Layer &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
using namespace blender;
|
||||
GreasePencilLayerTreeLeaf *new_leaf = MEM_cnew<GreasePencilLayerTreeLeaf>(__func__);
|
||||
/* Save properties. */
|
||||
save_tree_node_to_storage(node, &new_leaf->base);
|
||||
|
||||
/* Save frames map. */
|
||||
const int frames_size = node.frames().size();
|
||||
if (frames_size > 0) {
|
||||
new_leaf->layer.frames_storage.size = frames_size;
|
||||
new_leaf->layer.frames_storage.keys = MEM_cnew_array<int>(frames_size, __func__);
|
||||
new_leaf->layer.frames_storage.values = MEM_cnew_array<GreasePencilFrame>(frames_size,
|
||||
__func__);
|
||||
|
||||
MutableSpan<int> keys{new_leaf->layer.frames_storage.keys, frames_size};
|
||||
MutableSpan<GreasePencilFrame> values{new_leaf->layer.frames_storage.values, frames_size};
|
||||
keys.copy_from(node.sorted_keys());
|
||||
for (int i : keys.index_range()) {
|
||||
values[i] = node.frames().lookup(keys[i]);
|
||||
}
|
||||
}
|
||||
|
||||
new_leaf->layer.parent_type = node.parent_type;
|
||||
new_leaf->layer.blend_mode = node.blend_mode;
|
||||
new_leaf->layer.parent = node.parent;
|
||||
if (node.parsubstr) {
|
||||
new_leaf->layer.parsubstr = BLI_strdup(node.parsubstr);
|
||||
}
|
||||
if (node.viewlayer_name) {
|
||||
new_leaf->layer.viewlayer_name = BLI_strdup(node.viewlayer_name);
|
||||
}
|
||||
BLI_listbase_clear(&new_leaf->layer.masks_storage);
|
||||
for (const bke::greasepencil::LayerMask &mask : node.masks()) {
|
||||
GreasePencilLayerMask *new_mask = MEM_cnew<GreasePencilLayerMask>(__func__);
|
||||
new_mask->layer_name = BLI_strdup(mask.layer_name);
|
||||
new_mask->flag = mask.flag;
|
||||
BLI_addtail(&new_leaf->layer.masks_storage, new_mask);
|
||||
}
|
||||
new_leaf->layer.opacity = node.opacity;
|
||||
copy_v4_v4(new_leaf->layer.tint_color, node.tint_color);
|
||||
copy_v3_v3(new_leaf->layer.location, node.location);
|
||||
copy_v3_v3(new_leaf->layer.rotation, node.rotation);
|
||||
copy_v3_v3(new_leaf->layer.scale, node.scale);
|
||||
|
||||
/* Store pointer. */
|
||||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_leaf);
|
||||
}
|
||||
|
||||
static void save_layer_group_to_storage(const blender::bke::greasepencil::LayerGroup &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
GreasePencilLayerTreeGroup *new_group = MEM_cnew<GreasePencilLayerTreeGroup>(__func__);
|
||||
/* Save properties. */
|
||||
save_tree_node_to_storage(node, &new_group->base);
|
||||
|
||||
/* Save number of children. */
|
||||
new_group->children_num = node.num_direct_children();
|
||||
|
||||
/* Store pointer. */
|
||||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_group);
|
||||
}
|
||||
|
||||
void GreasePencil::save_layer_tree_to_storage()
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
/* We always store the root group, so we have to add one here. */
|
||||
int num_tree_nodes = this->root_group_for_write().num_children_total() + 1;
|
||||
this->layer_tree_storage.nodes_num = num_tree_nodes;
|
||||
this->layer_tree_storage.nodes = MEM_cnew_array<GreasePencilLayerTreeNode *>(num_tree_nodes,
|
||||
__func__);
|
||||
|
||||
save_layer_group_to_storage(this->root_group_for_write(), &this->layer_tree_storage.nodes[0]);
|
||||
this->root_group_for_write().foreach_children_with_index_pre_order(
|
||||
[this](uint64_t i, TreeNode &node) {
|
||||
GreasePencilLayerTreeNode **dst = &this->layer_tree_storage.nodes[i + 1];
|
||||
if (node.is_group()) {
|
||||
const LayerGroup &group = node.as_group();
|
||||
save_layer_group_to_storage(group, dst);
|
||||
}
|
||||
else if (node.is_layer()) {
|
||||
const Layer &layer = node.as_layer();
|
||||
save_layer_to_storage(layer, dst);
|
||||
}
|
||||
});
|
||||
|
||||
this->layer_tree_storage.active_layer_index = this->runtime->active_layer_index();
|
||||
}
|
||||
|
||||
static void read_layer_from_storage(blender::bke::greasepencil::LayerGroup ¤t_group,
|
||||
GreasePencilLayerTreeLeaf *node_leaf)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
Layer new_layer(node_leaf->base.name);
|
||||
for (int i = 0; i < node_leaf->layer.frames_storage.size; i++) {
|
||||
new_layer.insert_frame(node_leaf->layer.frames_storage.keys[i],
|
||||
node_leaf->layer.frames_storage.values[i]);
|
||||
}
|
||||
new_layer.parent_type = node_leaf->layer.parent_type;
|
||||
new_layer.blend_mode = node_leaf->layer.blend_mode;
|
||||
new_layer.parent = node_leaf->layer.parent;
|
||||
if (node_leaf->layer.parsubstr) {
|
||||
new_layer.parsubstr = BLI_strdup(node_leaf->layer.parsubstr);
|
||||
}
|
||||
if (node_leaf->layer.viewlayer_name) {
|
||||
new_layer.viewlayer_name = BLI_strdup(node_leaf->layer.viewlayer_name);
|
||||
}
|
||||
Vector<LayerMask> masks = new_layer.masks_for_write();
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &node_leaf->layer.masks_storage) {
|
||||
LayerMask new_mask = LayerMask(mask->name);
|
||||
new_mask.flag = mask->flag;
|
||||
masks.append(std::move(new_mask));
|
||||
}
|
||||
new_layer.opacity = node_leaf->layer.opacity;
|
||||
copy_v4_v4(new_layer.tint_color, node_leaf->layer.tint_color);
|
||||
copy_v3_v3(new_layer.location, node_leaf->layer.location);
|
||||
copy_v3_v3(new_layer.rotation, node_leaf->layer.rotation);
|
||||
copy_v3_v3(new_layer.scale, node_leaf->layer.scale);
|
||||
current_group.add_layer(std::move(new_layer));
|
||||
}
|
||||
|
||||
static int read_layer_node_recursive(blender::bke::greasepencil::LayerGroup ¤t_group,
|
||||
GreasePencilLayerTreeNode **nodes,
|
||||
int node_index)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
GreasePencilLayerTreeNode *node = nodes[node_index];
|
||||
int total_nodes_read = 0;
|
||||
switch (node->type) {
|
||||
case GP_LAYER_TREE_LEAF: {
|
||||
GreasePencilLayerTreeLeaf *node_leaf = reinterpret_cast<GreasePencilLayerTreeLeaf *>(node);
|
||||
read_layer_from_storage(current_group, node_leaf);
|
||||
total_nodes_read++;
|
||||
break;
|
||||
}
|
||||
case GP_LAYER_TREE_GROUP: {
|
||||
GreasePencilLayerTreeGroup *group = reinterpret_cast<GreasePencilLayerTreeGroup *>(node);
|
||||
/* Read layer group. */
|
||||
LayerGroup new_group(group->base.name);
|
||||
for (int i = 0; i < group->children_num; i++) {
|
||||
total_nodes_read += read_layer_node_recursive(
|
||||
new_group, nodes, node_index + total_nodes_read + 1);
|
||||
}
|
||||
current_group.add_group(std::move(new_group));
|
||||
total_nodes_read++;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return total_nodes_read;
|
||||
this->runtime->save_layer_tree_to_storage(this->layer_tree_storage);
|
||||
}
|
||||
|
||||
void GreasePencil::load_layer_tree_from_storage()
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
if (this->layer_tree_storage.nodes_num == 0 || !this->layer_tree_storage.nodes) {
|
||||
return;
|
||||
}
|
||||
/* The first node should be the root group. */
|
||||
GreasePencilLayerTreeNode *root = reinterpret_cast<GreasePencilLayerTreeNode *>(
|
||||
this->layer_tree_storage.nodes[0]);
|
||||
BLI_assert(root->type == GP_LAYER_TREE_GROUP);
|
||||
int total_nodes_read = 0;
|
||||
for (int i = 0; i < reinterpret_cast<GreasePencilLayerTreeGroup *>(root)->children_num; i++) {
|
||||
total_nodes_read += read_layer_node_recursive(this->runtime->root_group_for_write(),
|
||||
this->layer_tree_storage.nodes,
|
||||
total_nodes_read + 1);
|
||||
}
|
||||
BLI_assert(total_nodes_read + 1 == this->layer_tree_storage.nodes_num);
|
||||
this->runtime->set_active_layer_index(this->layer_tree_storage.active_layer_index);
|
||||
this->runtime->load_layer_tree_from_storage(this->layer_tree_storage);
|
||||
}
|
||||
|
||||
void GreasePencil::read_layer_tree_storage(BlendDataReader *reader)
|
||||
|
|
|
@ -57,6 +57,7 @@ TEST(greasepencil, save_layer_tree_to_storage)
|
|||
group.add_group(std::move(group2));
|
||||
grease_pencil.root_group_for_write().add_group(std::move(group));
|
||||
grease_pencil.root_group_for_write().add_layer(Layer(names[6]));
|
||||
grease_pencil.tag_layer_tree_topology_changed();
|
||||
|
||||
/* Save to storage. */
|
||||
grease_pencil.free_layer_tree_storage();
|
||||
|
@ -83,6 +84,7 @@ TEST(greasepencil, set_active_layer_index)
|
|||
|
||||
const Layer &layer1_ref = grease_pencil.root_group_for_write().add_layer(std::move(layer1));
|
||||
const Layer &layer2_ref = grease_pencil.root_group_for_write().add_layer(std::move(layer2));
|
||||
grease_pencil.tag_layer_tree_topology_changed();
|
||||
|
||||
grease_pencil.runtime->set_active_layer_index(0);
|
||||
EXPECT_TRUE(grease_pencil.runtime->has_active_layer());
|
||||
|
@ -138,6 +140,7 @@ TEST(greasepencil, remove_drawing)
|
|||
|
||||
grease_pencil.root_group_for_write().add_layer(std::move(layer1));
|
||||
grease_pencil.root_group_for_write().add_layer(std::move(layer2));
|
||||
grease_pencil.tag_layer_tree_topology_changed();
|
||||
|
||||
grease_pencil.remove_drawing(1);
|
||||
EXPECT_EQ(grease_pencil.drawings().size(), 2);
|
||||
|
|
|
@ -451,7 +451,7 @@ typedef struct GreasePencil {
|
|||
blender::bke::greasepencil::LayerGroup &root_group_for_write();
|
||||
blender::Span<const blender::bke::greasepencil::Layer *> layers() const;
|
||||
Hans Goudey
commented
This sort of API function (dealing with one index at a time) can be a bit dangerous since it can easily lead to quadratic behavior if it's called many times. I wonder if a This sort of API function (dealing with one index at a time) can be a bit dangerous since it can easily lead to quadratic behavior if it's called many times. I wonder if a `remove_drawings(IndexMask drawings_to_remove)` function would work a bit better
|
||||
blender::Span<blender::bke::greasepencil::Layer *> layers_for_write();
|
||||
void tag_layer_tree_changed();
|
||||
void tag_layer_tree_topology_changed();
|
||||
#endif
|
||||
} GreasePencil;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Put out of line.