Initial Grease Pencil 3.0 stage #106848
|
@ -30,6 +30,7 @@ class Layer;
|
|||
* children if it is a group.
|
||||
*/
|
||||
class TreeNode : public ::GreasePencilLayerTreeNode, NonMovable {
|
||||
friend class LayerGroup;
|
||||
public:
|
||||
explicit TreeNode(GreasePencilLayerTreeNodeType type);
|
||||
explicit TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name);
|
||||
|
@ -37,8 +38,9 @@ class TreeNode : public ::GreasePencilLayerTreeNode, NonMovable {
|
|||
TreeNode &operator=(const TreeNode &other) = delete;
|
||||
virtual ~TreeNode();
|
||||
|
||||
|
||||
public:
|
||||
Vector<std::unique_ptr<TreeNode>> children;
|
||||
private:
|
||||
std::unique_ptr<LayerGroup> parent_ = nullptr;
|
||||
Vector<std::unique_ptr<TreeNode>> children_;
|
||||
|
||||
public:
|
||||
/**
|
||||
|
@ -158,7 +160,7 @@ class Layer : public TreeNode, public ::GreasePencilLayer {
|
|||
*/
|
||||
bool is_visible() const;
|
||||
/**
|
||||
* \return true if the layer is locked.
|
||||
* \return true if the layer is locked.
|
||||
Falk David
commented
Put out of line. Put out of line.
|
||||
*/
|
||||
bool is_locked() const;
|
||||
|
||||
Hans Goudey
commented
The function is "is_locked" and the comment says "return if it is locked". This sort of comment doesn't add anything IMO, just wastes space. If there is a comment, maybe it should use a different word besides "locked" to describe the state. Or there doesn't need to be a comment at all. The function is "is_locked" and the comment says "return if it is locked". This sort of comment doesn't add anything IMO, just wastes space. If there is a comment, maybe it should use a different word besides "locked" to describe the state. Or there doesn't need to be a comment at all.
|
||||
|
@ -198,16 +200,16 @@ class Layer : public TreeNode, public ::GreasePencilLayer {
|
|||
* A LayerGroup is a grouping of zero or more Layers.
|
||||
Falk David
commented
Put out of line. Put out of line.
|
||||
*/
|
||||
class LayerGroup : public TreeNode {
|
||||
using TreeNodeIterFn = FunctionRef<void(TreeNode &)>;
|
||||
using TreeNodeIndexIterFn = FunctionRef<void(int64_t, TreeNode &)>;
|
||||
using LayerIterFn = FunctionRef<void(Layer &)>;
|
||||
using LayerIndexIterFn = FunctionRef<void(int64_t, Layer &)>;
|
||||
|
||||
public:
|
||||
LayerGroup() : TreeNode(GP_LAYER_TREE_GROUP) {}
|
||||
explicit LayerGroup(const StringRefNull name) : TreeNode(GP_LAYER_TREE_GROUP, name) {}
|
||||
LayerGroup(const LayerGroup &other);
|
||||
|
||||
private:
|
||||
Falk David
commented
Put out of line. Put out of line.
|
||||
mutable CacheMutex children_cache_mutex_;
|
||||
mutable Vector<TreeNode *> children_cache_;
|
||||
Bastien Montagne
commented
Not sure what is a 'pre-order vector'? or is a typo? Like Not sure what is a 'pre-order vector'? or is a typo? Like `pre-ordered vector`? Same below.
|
||||
mutable Vector<Layer *> layer_cache_;
|
||||
|
||||
public:
|
||||
/**
|
||||
* Adds a group at the end of this group.
|
||||
|
@ -236,21 +238,23 @@ class LayerGroup : public TreeNode {
|
|||
*/
|
||||
void remove_child(int64_t index);
|
||||
|
||||
/**
|
||||
* Calls \a function on every `TreeNode` in this group.
|
||||
*/
|
||||
void foreach_children_pre_order(TreeNodeIterFn function);
|
||||
void foreach_children_with_index_pre_order(TreeNodeIndexIterFn function);
|
||||
|
||||
/**
|
||||
* Returns a `Vector` of pointers to all the `TreeNode`s in this group.
|
||||
*/
|
||||
Vector<TreeNode *> children_in_pre_order() const;
|
||||
Span<const TreeNode *> children() const;
|
||||
Span<TreeNode *> children_for_write();
|
||||
|
||||
/**
|
||||
* Returns a `Vector` of pointers to all the `Layers`s in this group.
|
||||
*/
|
||||
filedescriptor marked this conversation as resolved
Outdated
Falk David
commented
Since the map will have to change to store more than just an index as the value, make sure to update the comment too. Since the map will have to change to store more than just an index as the value, make sure to update the comment too.
|
||||
Vector<Layer *> layers_in_pre_order() const;
|
||||
Span<const Layer *> layers() const;
|
||||
Span<Layer *> layers_for_write();
|
||||
|
||||
void print_children(StringRefNull header) const;
|
||||
|
||||
private:
|
||||
void ensure_children_cache() const;
|
||||
void tag_children_cache_dirty() const;
|
||||
};
|
||||
|
||||
namespace convert {
|
||||
|
@ -299,9 +303,6 @@ class GreasePencilDrawingRuntime {
|
|||
};
|
||||
Hans Goudey
commented
Looks like this should be private maybe? It has a Looks like this should be private maybe? It has a `_` suffix.
|
||||
|
||||
class GreasePencilRuntime {
|
||||
private:
|
||||
mutable SharedCache<Vector<greasepencil::Layer *>> layer_cache_;
|
||||
|
||||
public:
|
||||
void *batch_cache = nullptr;
|
||||
|
||||
|
@ -325,13 +326,6 @@ class GreasePencilRuntime {
|
|||
greasepencil::Layer &active_layer_for_write() const;
|
||||
Hans Goudey
commented
These two functions should never have to be called outside of the These two functions should never have to be called outside of the `ID` callbacks in `grease_pencil.cc`; IMO they make more sense as static functions there. Probably better to keep that storage for DNA thing as localized as possible.
|
||||
void set_active_layer_index(int index);
|
||||
int active_layer_index() const;
|
||||
|
||||
void ensure_layer_cache() const;
|
||||
|
||||
void tag_layer_tree_topology_changed();
|
||||
|
||||
private:
|
||||
greasepencil::Layer *get_active_layer_from_index(int index) const;
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
Hans Goudey
commented
Member variables come before functions https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Class_Layout Member variables come before functions https://wiki.blender.org/wiki/Style_Guide/C_Cpp#Class_Layout
|
||||
|
|
|
@ -431,7 +431,7 @@ Span<int> Layer::sorted_keys() const
|
|||
}
|
||||
std::sort(r_data.begin(), r_data.end());
|
||||
});
|
||||
return this->sorted_keys_cache_.data().as_span();
|
||||
return this->sorted_keys_cache_.data();
|
||||
Hans Goudey
commented
`.as_span()` shouldn't be necessary here.
|
||||
}
|
||||
|
||||
int Layer::drawing_index_at(int frame) const
|
||||
Hans Goudey
commented
`int frame` -> `const int frame`
|
||||
|
@ -464,123 +464,147 @@ void Layer::tag_frames_map_keys_changed()
|
|||
|
||||
LayerGroup::LayerGroup(const LayerGroup &other) : TreeNode(other)
|
||||
{
|
||||
this->children.reserve(other.children.size());
|
||||
for (const std::unique_ptr<TreeNode> &elem : other.children) {
|
||||
this->children_.reserve(other.children_.size());
|
||||
for (const std::unique_ptr<TreeNode> &elem : other.children_) {
|
||||
if (elem.get()->is_group()) {
|
||||
this->children.append(std::make_unique<LayerGroup>(elem.get()->as_group()));
|
||||
this->children_.append(std::make_unique<LayerGroup>(elem.get()->as_group()));
|
||||
}
|
||||
else if (elem.get()->is_layer()) {
|
||||
this->children.append(std::make_unique<Layer>(elem.get()->as_layer()));
|
||||
this->children_.append(std::make_unique<Layer>(elem.get()->as_layer()));
|
||||
}
|
||||
this->children_.last().get()->parent_.reset(this);
|
||||
}
|
||||
this->tag_children_cache_dirty();
|
||||
}
|
||||
|
||||
void LayerGroup::add_group(LayerGroup &group)
|
||||
{
|
||||
this->children.append(std::make_unique<LayerGroup>(group));
|
||||
this->children_.append(std::make_unique<LayerGroup>(group));
|
||||
this->children_.last().get()->parent_.reset(this);
|
||||
this->tag_children_cache_dirty();
|
||||
}
|
||||
Hans Goudey
commented
I believe it's standard to Is there a need for overloads for I believe it's standard to `std::move` from a `T &&`
Is there a need for overloads for `T &` and `T &&`? What's the benefit of that?
|
||||
|
||||
void LayerGroup::add_group(LayerGroup &&group)
|
||||
{
|
||||
this->children.append(std::make_unique<LayerGroup>(group));
|
||||
this->children_.append(std::make_unique<LayerGroup>(group));
|
||||
this->children_.last().get()->parent_.reset(this);
|
||||
this->tag_children_cache_dirty();
|
||||
}
|
||||
|
||||
Layer &LayerGroup::add_layer(Layer &layer)
|
||||
{
|
||||
int64_t index = children.append_and_get_index(std::make_unique<Layer>(layer));
|
||||
return children[index].get()->as_layer_for_write();
|
||||
children_.append(std::make_unique<Layer>(layer));
|
||||
this->children_.last().get()->parent_.reset(this);
|
||||
this->tag_children_cache_dirty();
|
||||
return children_.last().get()->as_layer_for_write();
|
||||
}
|
||||
|
||||
Layer &LayerGroup::add_layer(Layer &&layer)
|
||||
{
|
||||
int64_t index = children.append_and_get_index(std::make_unique<Layer>(layer));
|
||||
return children[index].get()->as_layer_for_write();
|
||||
children_.append(std::make_unique<Layer>(std::move(layer)));
|
||||
this->children_.last().get()->parent_.reset(this);
|
||||
this->tag_children_cache_dirty();
|
||||
return children_.last().get()->as_layer_for_write();
|
||||
}
|
||||
|
||||
int64_t LayerGroup::num_direct_children() const
|
||||
{
|
||||
return children.size();
|
||||
return children_.size();
|
||||
}
|
||||
|
||||
int64_t LayerGroup::num_children_total() const
|
||||
{
|
||||
int64_t total = 0;
|
||||
Stack<TreeNode *> stack;
|
||||
for (auto it = this->children.rbegin(); it != this->children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
while (!stack.is_empty()) {
|
||||
TreeNode &next_node = *stack.pop();
|
||||
total++;
|
||||
for (auto it = next_node.children.rbegin(); it != next_node.children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
}
|
||||
return total;
|
||||
this->ensure_children_cache();
|
||||
return this->children_cache_.size();
|
||||
}
|
||||
|
||||
void LayerGroup::remove_child(int64_t index)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < this->children.size());
|
||||
this->children.remove(index);
|
||||
BLI_assert(index >= 0 && index < this->children_.size());
|
||||
this->children_.remove(index);
|
||||
this->tag_children_cache_dirty();
|
||||
}
|
||||
|
||||
void LayerGroup::foreach_children_pre_order(TreeNodeIterFn function)
|
||||
Span<const TreeNode *> LayerGroup::children() const
|
||||
{
|
||||
for (auto &child : this->children) {
|
||||
function(*child);
|
||||
if (child->is_group()) {
|
||||
child->as_group_for_write().foreach_children_pre_order(function);
|
||||
this->ensure_children_cache();
|
||||
return this->children_cache_.as_span();
|
||||
}
|
||||
|
||||
Span<TreeNode *> LayerGroup::children_for_write()
|
||||
{
|
||||
this->ensure_children_cache();
|
||||
return this->children_cache_.as_span();
|
||||
}
|
||||
|
||||
Span<const Layer *> LayerGroup::layers() const
|
||||
{
|
||||
this->ensure_children_cache();
|
||||
return this->layer_cache_.as_span();
|
||||
}
|
||||
|
||||
Span<Layer *> LayerGroup::layers_for_write()
|
||||
{
|
||||
this->ensure_children_cache();
|
||||
return this->layer_cache_.as_span();
|
||||
}
|
||||
|
||||
void LayerGroup::print_children(StringRefNull header) const
|
||||
{
|
||||
std::cout << header << std::endl;
|
||||
Stack<std::pair<int, TreeNode *>> next_node;
|
||||
for (auto it = this->children_.rbegin(); it != this->children_.rend(); it++) {
|
||||
next_node.push(std::make_pair(1, (*it).get()));
|
||||
}
|
||||
while (!next_node.is_empty()) {
|
||||
auto [indent, node] = next_node.pop();
|
||||
for (int i = 0; i < indent; i++) {
|
||||
std::cout << " ";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::foreach_children_with_index_pre_order(TreeNodeIndexIterFn function)
|
||||
{
|
||||
Vector<TreeNode *> children = this->children_in_pre_order();
|
||||
for (const int64_t i : children.index_range()) {
|
||||
function(i, *children[i]);
|
||||
}
|
||||
}
|
||||
|
||||
Vector<TreeNode *> LayerGroup::children_in_pre_order() const
|
||||
{
|
||||
Vector<TreeNode *> children;
|
||||
|
||||
Stack<TreeNode *> stack;
|
||||
for (auto it = this->children.rbegin(); it != this->children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
while (!stack.is_empty()) {
|
||||
TreeNode &next_node = *stack.pop();
|
||||
children.append(&next_node);
|
||||
for (auto it = next_node.children.rbegin(); it != next_node.children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
if (node->is_layer()) {
|
||||
std::cout << node->name;
|
||||
}
|
||||
}
|
||||
return children;
|
||||
}
|
||||
|
||||
Vector<Layer *> LayerGroup::layers_in_pre_order() const
|
||||
{
|
||||
Vector<Layer *> layers;
|
||||
|
||||
Stack<TreeNode *> stack;
|
||||
for (auto it = this->children.rbegin(); it != this->children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
while (!stack.is_empty()) {
|
||||
TreeNode &next_node = *stack.pop();
|
||||
if (next_node.is_layer()) {
|
||||
layers.append(&next_node.as_layer_for_write());
|
||||
}
|
||||
else {
|
||||
for (auto it = next_node.children.rbegin(); it != next_node.children.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
else if (node->is_group()) {
|
||||
std::cout << node->name << ": ";
|
||||
for (auto it = node->children_.rbegin(); it != node->children_.rend(); it++) {
|
||||
next_node.push(std::make_pair(indent + 1, (*it).get()));
|
||||
}
|
||||
}
|
||||
std::cout << std::endl;
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::ensure_children_cache() const
|
||||
{
|
||||
this->children_cache_mutex_.ensure([&]() {
|
||||
this->children_cache_.clear_and_shrink();
|
||||
this->layer_cache_.clear_and_shrink();
|
||||
|
||||
Stack<TreeNode *> stack;
|
||||
for (auto it = this->children_.rbegin(); it != this->children_.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
while (!stack.is_empty()) {
|
||||
TreeNode *next_node = stack.pop();
|
||||
this->children_cache_.append(next_node);
|
||||
if (next_node->is_layer()) {
|
||||
this->layer_cache_.append(&next_node->as_layer_for_write());
|
||||
}
|
||||
else if (next_node->is_group()) {
|
||||
for (auto it = next_node->children_.rbegin(); it != next_node->children_.rend(); it++) {
|
||||
stack.push((*it).get());
|
||||
}
|
||||
}
|
||||
Hans Goudey
commented
It probably shouldn't be a It probably shouldn't be a `SharedCache` then. Either that or it should cache indices rather than pointers?
Falk David
commented
Ah yes, I don't see a way it can be a shared cache then. Ah yes, I don't see a way it can be a shared cache then.
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
void LayerGroup::tag_children_cache_dirty() const
|
||||
{
|
||||
this->children_cache_mutex_.tag_dirty();
|
||||
if (this->parent_) {
|
||||
this->parent_.get()->tag_children_cache_dirty();
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil
|
||||
|
@ -594,8 +618,6 @@ namespace blender::bke {
|
|||
GreasePencilRuntime::GreasePencilRuntime(const GreasePencilRuntime &other)
|
||||
: root_group_(other.root_group_), active_layer_index_(other.active_layer_index_)
|
||||
{
|
||||
/* We cannot copy this cache, because the pointers in that cache become invalid. */
|
||||
layer_cache_.tag_dirty();
|
||||
}
|
||||
|
||||
const greasepencil::LayerGroup &GreasePencilRuntime::root_group() const
|
||||
|
@ -610,12 +632,12 @@ greasepencil::LayerGroup &GreasePencilRuntime::root_group_for_write()
|
|||
|
||||
Span<const greasepencil::Layer *> GreasePencilRuntime::layers() const
|
||||
{
|
||||
return this->layer_cache_.data();
|
||||
return this->root_group().layers();
|
||||
}
|
||||
|
||||
Span<greasepencil::Layer *> GreasePencilRuntime::layers_for_write()
|
||||
{
|
||||
return this->layer_cache_.data();
|
||||
return this->root_group_for_write().layers_for_write();
|
||||
}
|
||||
|
||||
bool GreasePencilRuntime::has_active_layer() const
|
||||
|
@ -626,13 +648,7 @@ bool GreasePencilRuntime::has_active_layer() const
|
|||
const greasepencil::Layer &GreasePencilRuntime::active_layer() const
|
||||
{
|
||||
BLI_assert(this->active_layer_index_ >= 0);
|
||||
return *get_active_layer_from_index(this->active_layer_index_);
|
||||
}
|
||||
|
||||
greasepencil::Layer &GreasePencilRuntime::active_layer_for_write() const
|
||||
{
|
||||
BLI_assert(this->active_layer_index_ >= 0);
|
||||
return *get_active_layer_from_index(this->active_layer_index_);
|
||||
return *this->root_group().layers()[this->active_layer_index_];
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::set_active_layer_index(int index)
|
||||
|
@ -645,24 +661,6 @@ int GreasePencilRuntime::active_layer_index() const
|
|||
return this->active_layer_index_;
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::ensure_layer_cache() const
|
||||
{
|
||||
this->layer_cache_.ensure([this](Vector<greasepencil::Layer *> &data) {
|
||||
data = this->root_group_.layers_in_pre_order();
|
||||
});
|
||||
}
|
||||
|
||||
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();
|
||||
return this->layer_cache_.data()[index];
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/** \} */
|
||||
|
@ -737,16 +735,12 @@ void BKE_grease_pencil_data_update(struct Depsgraph * /*depsgraph*/,
|
|||
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(object->data);
|
||||
/* Evaluate modifiers. */
|
||||
/* TODO. */
|
||||
/* TODO: modifiers. */
|
||||
|
||||
/* Assign evaluated object. */
|
||||
/* TODO: Get eval from modifiers geometry set. */
|
||||
GreasePencil *grease_pencil_eval = (GreasePencil *)BKE_id_copy_ex(
|
||||
nullptr, &grease_pencil->id, nullptr, LIB_ID_COPY_LOCALIZE);
|
||||
// if (grease_pencil_eval == nullptr) {
|
||||
// grease_pencil_eval = BKE_grease_pencil_new_nomain();
|
||||
// BKE_object_eval_assign_data(object, &grease_pencil_eval->id, true);
|
||||
// }
|
||||
BKE_object_eval_assign_data(object, &grease_pencil_eval->id, true);
|
||||
}
|
||||
|
||||
|
@ -784,7 +778,7 @@ blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
|
|||
{
|
||||
using namespace blender;
|
||||
const bke::GreasePencilDrawingRuntime &runtime = *this->runtime;
|
||||
runtime.triangles_cache.ensure([&](Vector<uint3> &cache) {
|
||||
runtime.triangles_cache.ensure([&](Vector<uint3> &r_data) {
|
||||
MemArena *pf_arena = BLI_memarena_new(BLI_MEMARENA_STD_BUFSIZE, __func__);
|
||||
|
||||
const bke::CurvesGeometry &curves = this->geometry.wrap();
|
||||
|
@ -792,17 +786,18 @@ blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
|
|||
const offset_indices::OffsetIndices<int> points_by_curve = curves.points_by_curve();
|
||||
|
||||
int total_triangles = 0;
|
||||
Array<int> tris_offests(curves.curves_num());
|
||||
for (int curve_i : curves.curves_range()) {
|
||||
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
|
||||
IndexRange points = points_by_curve[curve_i];
|
||||
if (points.size() > 2) {
|
||||
tris_offests[curve_i] = total_triangles;
|
||||
total_triangles += points.size() - 2;
|
||||
}
|
||||
}
|
||||
|
||||
cache.resize(total_triangles);
|
||||
r_data.resize(total_triangles);
|
||||
|
||||
int t = 0;
|
||||
for (int curve_i : curves.curves_range()) {
|
||||
for (const int curve_i : curves.curves_range()) {
|
||||
const IndexRange points = points_by_curve[curve_i];
|
||||
|
||||
if (points.size() < 3) {
|
||||
|
@ -810,9 +805,9 @@ blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
|
|||
}
|
||||
|
||||
const int num_trinagles = points.size() - 2;
|
||||
MutableSpan<uint3> r_tris = r_data.as_mutable_span().slice(tris_offests[curve_i],
|
||||
num_trinagles);
|
||||
|
||||
uint(*tris)[3] = static_cast<uint(*)[3]>(
|
||||
BLI_memarena_alloc(pf_arena, sizeof(*tris) * size_t(num_trinagles)));
|
||||
float(*projverts)[2] = static_cast<float(*)[2]>(
|
||||
BLI_memarena_alloc(pf_arena, sizeof(*projverts) * size_t(points.size())));
|
||||
|
||||
|
@ -824,13 +819,8 @@ blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
|
|||
mul_v2_m3v3(projverts[i], axis_mat.ptr(), positions[points[i]]);
|
||||
}
|
||||
|
||||
BLI_polyfill_calc_arena(projverts, points.size(), 0, tris, pf_arena);
|
||||
|
||||
for (const int i : IndexRange(num_trinagles)) {
|
||||
cache[t] = uint3(tris[i]);
|
||||
t++;
|
||||
}
|
||||
|
||||
BLI_polyfill_calc_arena(
|
||||
projverts, points.size(), 0, reinterpret_cast<uint32_t(*)[3]>(r_tris.data()), pf_arena);
|
||||
BLI_memarena_clear(pf_arena);
|
||||
}
|
||||
|
||||
|
@ -1023,20 +1013,19 @@ blender::bke::greasepencil::LayerGroup &GreasePencil::root_group_for_write()
|
|||
blender::Span<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const
|
||||
{
|
||||
BLI_assert(this->runtime != nullptr);
|
||||
this->runtime->ensure_layer_cache();
|
||||
return this->runtime->layers();
|
||||
return this->runtime->root_group().layers();
|
||||
}
|
||||
|
||||
blender::Span<blender::bke::greasepencil::Layer *> GreasePencil::layers_for_write()
|
||||
{
|
||||
BLI_assert(this->runtime != nullptr);
|
||||
this->runtime->ensure_layer_cache();
|
||||
return this->runtime->layers_for_write();
|
||||
return this->runtime->root_group_for_write().layers_for_write();
|
||||
}
|
||||
|
||||
void GreasePencil::tag_layer_tree_topology_changed()
|
||||
void GreasePencil::print_layer_tree()
|
||||
{
|
||||
this->runtime->tag_layer_tree_topology_changed();
|
||||
using namespace blender::bke::greasepencil;
|
||||
this->root_group().print_children("Layer Tree:");
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
@ -1281,29 +1270,28 @@ static void load_layer_tree_from_storage_ex(blender::bke::GreasePencilRuntime &r
|
|||
}
|
||||
BLI_assert(total_nodes_read + 1 == storage.nodes_num);
|
||||
runtime.set_active_layer_index(storage.active_layer_index);
|
||||
|
||||
runtime.tag_layer_tree_topology_changed();
|
||||
}
|
||||
static void save_layer_tree_to_storage_ex(const blender::bke::GreasePencilRuntime &runtime,
|
||||
GreasePencilLayerTreeStorage &storage)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
/* We always store the root group, so we have to add one here. */
|
||||
int num_tree_nodes = runtime.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(runtime.root_group(), &storage.nodes[0]);
|
||||
Hans Goudey
commented
Looks like drawings are allocated with Looks like drawings are allocated with `MEM_new` above, which means they should be deallocated with `MEM_delete`.
|
||||
Span<const TreeNode *> children = runtime.root_group().children_in_pre_order();
|
||||
Span<const TreeNode *> children = runtime.root_group().children();
|
||||
for (const int node_i : children.index_range()) {
|
||||
const TreeNode &node = *children[node_i];
|
||||
const TreeNode *node = children[node_i];
|
||||
GreasePencilLayerTreeNode **dst = &storage.nodes[node_i + 1];
|
||||
if (node.is_group()) {
|
||||
const LayerGroup &group = node.as_group();
|
||||
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();
|
||||
else if (node->is_layer()) {
|
||||
const Layer &layer = node->as_layer();
|
||||
save_layer_to_storage(layer, dst);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -57,7 +57,6 @@ 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();
|
||||
|
@ -68,8 +67,13 @@ TEST(greasepencil, save_layer_tree_to_storage)
|
|||
grease_pencil.runtime = MEM_new<blender::bke::GreasePencilRuntime>(__func__);
|
||||
grease_pencil.load_layer_tree_from_storage();
|
||||
|
||||
grease_pencil.root_group_for_write().foreach_children_with_index_pre_order(
|
||||
[&](uint64_t i, TreeNode &child) { EXPECT_STREQ(child.name, names[i].data()); });
|
||||
grease_pencil.print_layer_tree();
|
||||
|
||||
Span<const TreeNode *> children = grease_pencil.root_group().children();
|
||||
for (const int i : children.index_range()) {
|
||||
const TreeNode &child = *children[i];
|
||||
EXPECT_STREQ(child.name, names[i].data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(greasepencil, set_active_layer_index)
|
||||
|
@ -84,7 +88,6 @@ 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());
|
||||
|
@ -142,7 +145,6 @@ 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);
|
||||
|
@ -201,11 +203,15 @@ struct GreasePencilLayerTreeExample {
|
|||
}
|
||||
};
|
||||
|
||||
TEST(greasepencil, layer_tree_pre_order_iteration_callback)
|
||||
TEST(greasepencil, layer_tree_pre_order_iteration)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
ex.root.foreach_children_with_index_pre_order(
|
||||
[&](uint64_t i, TreeNode &child) { EXPECT_EQ(child.name, ex.names[i]); });
|
||||
|
||||
Span<const TreeNode *> children = ex.root.children();
|
||||
for (const int i : children.index_range()) {
|
||||
const TreeNode &child = *children[i];
|
||||
EXPECT_STREQ(child.name, ex.names[i].data());
|
||||
}
|
||||
}
|
||||
|
||||
TEST(greasepencil, layer_tree_total_size)
|
||||
|
@ -217,10 +223,12 @@ TEST(greasepencil, layer_tree_total_size)
|
|||
TEST(greasepencil, layer_tree_node_types)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
ex.root.foreach_children_with_index_pre_order([&](uint64_t i, TreeNode &child) {
|
||||
Span<const TreeNode *> children = ex.root.children();
|
||||
for (const int i : children.index_range()) {
|
||||
const TreeNode &child = *children[i];
|
||||
EXPECT_EQ(child.is_layer(), ex.is_layer[i]);
|
||||
EXPECT_EQ(child.is_group(), !ex.is_layer[i]);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil::tests
|
|
@ -456,7 +456,8 @@ typedef struct GreasePencil {
|
|||
blender::bke::greasepencil::LayerGroup &root_group_for_write();
|
||||
blender::Span<const blender::bke::greasepencil::Layer *> layers() const;
|
||||
blender::Span<blender::bke::greasepencil::Layer *> layers_for_write();
|
||||
void tag_layer_tree_topology_changed();
|
||||
|
||||
void print_layer_tree();
|
||||
#endif
|
||||
} GreasePencil;
|
||||
|
||||
|
|
Is there a particular reason you remove copy assignment but keep copy construction defined?
Just because copying should be explicit. And removing the copy assignment constructor avoids errors.