Initial Grease Pencil 3.0 stage #106848
|
@ -31,267 +31,58 @@ class Layer;
|
|||
* A TreeNode represents one node in the layer tree.
|
||||
* It can either be a layer or a group. The node has zero children if it is a layer or zero or more
|
||||
* children if it is a group.
|
||||
* This class is mainly used for iteration over the layer tree.
|
||||
*/
|
||||
class TreeNode : public ::GreasePencilLayerTreeNode, NonMovable {
|
||||
using TreeNodeIterFn = FunctionRef<void(TreeNode &)>;
|
||||
using LayerIterFn = FunctionRef<void(Layer &)>;
|
||||
using LayerIndexIterFn = FunctionRef<void(uint64_t, Layer &)>;
|
||||
|
||||
protected:
|
||||
Vector<std::unique_ptr<TreeNode>> children_;
|
||||
|
||||
public:
|
||||
TreeNode(GreasePencilLayerTreeNodeType type)
|
||||
{
|
||||
this->type = type;
|
||||
this->name = nullptr;
|
||||
}
|
||||
TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name)
|
||||
{
|
||||
this->type = type;
|
||||
this->name = BLI_strdup(name.c_str());
|
||||
}
|
||||
TreeNode(const TreeNode &other) : TreeNode(GreasePencilLayerTreeNodeType(other.type))
|
||||
{
|
||||
if (other.name) {
|
||||
this->name = BLI_strdup(other.name);
|
||||
}
|
||||
}
|
||||
explicit TreeNode(GreasePencilLayerTreeNodeType type);
|
||||
explicit TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name);
|
||||
TreeNode(const TreeNode &other);
|
||||
TreeNode &operator=(const TreeNode &other) = delete;
|
||||
virtual ~TreeNode()
|
||||
{
|
||||
if (this->name) {
|
||||
MEM_freeN(this->name);
|
||||
}
|
||||
}
|
||||
virtual ~TreeNode();
|
||||
|
||||
public:
|
||||
class PreOrderRange {
|
||||
class Iterator {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
private:
|
||||
Stack<TreeNode *> next_node_;
|
||||
|
||||
public:
|
||||
explicit Iterator(TreeNode *root)
|
||||
{
|
||||
if (root != nullptr) {
|
||||
for (auto it = root->children_.rbegin(); it != root->children_.rend(); it++) {
|
||||
next_node_.push((*it).get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TreeNode &operator*()
|
||||
{
|
||||
return *next_node_.peek();
|
||||
}
|
||||
|
||||
const TreeNode &operator*() const
|
||||
{
|
||||
return *next_node_.peek();
|
||||
}
|
||||
|
||||
Iterator &operator++()
|
||||
{
|
||||
BLI_assert(!next_node_.is_empty());
|
||||
TreeNode &next_node = *next_node_.pop();
|
||||
for (auto it = next_node.children_.rbegin(); it != next_node.children_.rend(); it++) {
|
||||
next_node_.push((*it).get());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator old = *this;
|
||||
operator++();
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(Iterator &other) const
|
||||
{
|
||||
if (next_node_.size() == 0) {
|
||||
return other.next_node_.size() == 0;
|
||||
}
|
||||
return (next_node_.size() == other.next_node_.size()) &&
|
||||
next_node_.peek() == other.next_node_.peek();
|
||||
}
|
||||
|
||||
bool operator!=(Iterator &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
TreeNode *_root;
|
||||
|
||||
public:
|
||||
explicit PreOrderRange(TreeNode *root) : _root(root) {}
|
||||
|
||||
Iterator begin()
|
||||
{
|
||||
return Iterator(_root);
|
||||
}
|
||||
|
||||
Iterator end()
|
||||
{
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
};
|
||||
|
||||
class PreOrderIndexRange {
|
||||
public:
|
||||
struct Item {
|
||||
const int64_t index;
|
||||
TreeNode &node;
|
||||
};
|
||||
|
||||
private:
|
||||
class Iterator {
|
||||
using iterator_category = std::forward_iterator_tag;
|
||||
|
||||
private:
|
||||
int64_t current_index_;
|
||||
Stack<TreeNode *> next_node_;
|
||||
|
||||
public:
|
||||
explicit Iterator(TreeNode *root)
|
||||
{
|
||||
current_index_ = 0;
|
||||
if (root != nullptr) {
|
||||
for (auto it = root->children_.rbegin(); it != root->children_.rend(); it++) {
|
||||
next_node_.push((*it).get());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Item operator*()
|
||||
{
|
||||
return {current_index_, *next_node_.peek()};
|
||||
}
|
||||
|
||||
Iterator &operator++()
|
||||
{
|
||||
BLI_assert(!next_node_.is_empty());
|
||||
TreeNode &next_node = *next_node_.pop();
|
||||
current_index_++;
|
||||
for (auto it = next_node.children_.rbegin(); it != next_node.children_.rend(); it++) {
|
||||
next_node_.push((*it).get());
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Iterator operator++(int)
|
||||
{
|
||||
Iterator old = *this;
|
||||
operator++();
|
||||
return old;
|
||||
}
|
||||
|
||||
bool operator==(Iterator &other) const
|
||||
{
|
||||
if (next_node_.size() == 0) {
|
||||
return other.next_node_.size() == 0;
|
||||
}
|
||||
return (next_node_.size() == other.next_node_.size()) &&
|
||||
next_node_.peek() == other.next_node_.peek() &&
|
||||
current_index_ == other.current_index_;
|
||||
}
|
||||
|
||||
bool operator!=(Iterator &other) const
|
||||
{
|
||||
return !(*this == other);
|
||||
}
|
||||
};
|
||||
|
||||
private:
|
||||
TreeNode *_root;
|
||||
|
||||
public:
|
||||
explicit PreOrderIndexRange(TreeNode *root) : _root(root) {}
|
||||
|
||||
Iterator begin()
|
||||
{
|
||||
return Iterator(_root);
|
||||
}
|
||||
|
||||
Iterator end()
|
||||
{
|
||||
return Iterator(nullptr);
|
||||
}
|
||||
};
|
||||
Vector<std::unique_ptr<TreeNode>> children;
|
||||
|
||||
public:
|
||||
/**
|
||||
* \returns true if this node is a LayerGroup.
|
||||
*/
|
||||
constexpr bool is_group() const
|
||||
{
|
||||
return this->type == GREASE_PENCIL_LAYER_TREE_GROUP;
|
||||
}
|
||||
|
||||
/**
|
||||
* \returns true if this node is a Layer.
|
||||
*/
|
||||
constexpr bool is_layer() const
|
||||
{
|
||||
return this->type == GREASE_PENCIL_LAYER_TREE_LEAF;
|
||||
}
|
||||
|
||||
LayerGroup &as_group();
|
||||
Layer &as_layer();
|
||||
/**
|
||||
* \returns this tree node as a LayerGroup.
|
||||
* \note This results in undefined behavior if the node is not a LayerGroup.
|
||||
*/
|
||||
const LayerGroup &as_group() const;
|
||||
|
||||
/**
|
||||
* \returns this tree node as a Layer.
|
||||
* \note This results in undefined behavior if the node is not a Layer.
|
||||
*/
|
||||
const Layer &as_layer() const;
|
||||
|
||||
int total_num_children() const
|
||||
{
|
||||
int 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;
|
||||
}
|
||||
/**
|
||||
* \returns this tree node as a mutable LayerGroup.
|
||||
* \note This results in undefined behavior if the node is not a LayerGroup.
|
||||
*/
|
||||
LayerGroup &as_group_for_write();
|
||||
|
||||
PreOrderRange children_in_pre_order();
|
||||
PreOrderIndexRange children_with_index_in_pre_order();
|
||||
|
||||
void foreach_children_pre_order(TreeNodeIterFn function)
|
||||
{
|
||||
for (auto &child : children_) {
|
||||
child->foreach_children_pre_order_recursive_(function);
|
||||
}
|
||||
}
|
||||
|
||||
void foreach_layer_pre_order(LayerIterFn function)
|
||||
{
|
||||
for (auto &child : children_) {
|
||||
child->foreach_layer_pre_order_recursive_(function);
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
void foreach_children_pre_order_recursive_(TreeNodeIterFn function)
|
||||
{
|
||||
function(*this);
|
||||
for (auto &child : children_) {
|
||||
child->foreach_children_pre_order_recursive_(function);
|
||||
}
|
||||
}
|
||||
|
||||
void foreach_layer_pre_order_recursive_(LayerIterFn function)
|
||||
{
|
||||
if (this->is_layer()) {
|
||||
function(this->as_layer());
|
||||
}
|
||||
for (auto &child : children_) {
|
||||
child->foreach_layer_pre_order_recursive_(function);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* \returns this tree node as a mutable Layer.
|
||||
* \note This results in undefined behavior if the node is not a Layer.
|
||||
*/
|
||||
Layer &as_layer_for_write();
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -330,150 +121,110 @@ class Layer : public TreeNode, ::GreasePencilLayer {
|
|||
|
||||
public:
|
||||
Layer() : TreeNode(GREASE_PENCIL_LAYER_TREE_LEAF), frames_() {}
|
||||
Layer(StringRefNull name) : TreeNode(GREASE_PENCIL_LAYER_TREE_LEAF, name), frames_() {}
|
||||
Layer(const Layer &other) : TreeNode(other)
|
||||
{
|
||||
frames_ = other.frames_;
|
||||
}
|
||||
|
||||
const Map<int, GreasePencilFrame> &frames() const
|
||||
{
|
||||
return frames_;
|
||||
}
|
||||
|
||||
Map<int, GreasePencilFrame> &frames_for_write()
|
||||
{
|
||||
sorted_keys_cache_.tag_dirty();
|
||||
return frames_;
|
||||
}
|
||||
|
||||
bool insert_frame(int frame_number, GreasePencilFrame &frame)
|
||||
{
|
||||
sorted_keys_cache_.tag_dirty();
|
||||
return frames_for_write().add(frame_number, frame);
|
||||
}
|
||||
|
||||
bool insert_frame(int frame_number, GreasePencilFrame &&frame)
|
||||
{
|
||||
sorted_keys_cache_.tag_dirty();
|
||||
return frames_for_write().add(frame_number, frame);
|
||||
}
|
||||
|
||||
bool overwrite_frame(int frame_number, GreasePencilFrame &frame)
|
||||
{
|
||||
sorted_keys_cache_.tag_dirty();
|
||||
return frames_for_write().add_overwrite(frame_number, frame);
|
||||
}
|
||||
|
||||
bool overwrite_frame(int frame_number, GreasePencilFrame &&frame)
|
||||
{
|
||||
sorted_keys_cache_.tag_dirty();
|
||||
return frames_for_write().add_overwrite(frame_number, frame);
|
||||
}
|
||||
|
||||
Span<int> sorted_keys() const
|
||||
{
|
||||
sorted_keys_cache_.ensure([&](Vector<int> &r_data) {
|
||||
r_data.clear_and_shrink();
|
||||
r_data.reserve(frames().size());
|
||||
for (int64_t key : frames().keys()) {
|
||||
r_data.append(key);
|
||||
}
|
||||
std::sort(r_data.begin(), r_data.end());
|
||||
});
|
||||
return sorted_keys_cache_.data().as_span();
|
||||
}
|
||||
explicit Layer(StringRefNull name) : TreeNode(GREASE_PENCIL_LAYER_TREE_LEAF, name), frames_() {}
|
||||
Layer(const Layer &other);
|
||||
|
||||
/**
|
||||
* Return the index of the drawing at frame \a frame or -1 if there is no drawing.
|
||||
* \returns the frames mapping.
|
||||
*/
|
||||
int drawing_at(int frame) const
|
||||
{
|
||||
Span<int> sorted_keys = this->sorted_keys();
|
||||
/* Before the first drawing, return no drawing. */
|
||||
if (frame < sorted_keys.first()) {
|
||||
return -1;
|
||||
}
|
||||
/* After or at the last drawing, return the last drawing. */
|
||||
if (frame >= sorted_keys.last()) {
|
||||
return this->frames().lookup(sorted_keys.last()).drawing_index;
|
||||
}
|
||||
/* Search for the drawing. upper_bound will get the drawing just after. */
|
||||
auto it = std::upper_bound(sorted_keys.begin(), sorted_keys.end(), frame);
|
||||
if (it == sorted_keys.end() || it == sorted_keys.begin()) {
|
||||
return -1;
|
||||
}
|
||||
return this->frames().lookup(*std::prev(it)).drawing_index;
|
||||
}
|
||||
const Map<int, GreasePencilFrame> &frames() const;
|
||||
Map<int, GreasePencilFrame> &frames_for_write();
|
||||
|
||||
/**
|
||||
* Inserts the frame into the layer. Fails if there exists a frame at \a frame_number already.
|
||||
* \returns true on success.
|
||||
*/
|
||||
bool insert_frame(int frame_number, GreasePencilFrame &frame);
|
||||
bool insert_frame(int frame_number, GreasePencilFrame &&frame);
|
||||
|
||||
/**
|
||||
* Inserts the frame into the layer. If there exists a frame at \a frame_number already, it is
|
||||
* overwritten.
|
||||
* \returns true on success.
|
||||
*/
|
||||
bool overwrite_frame(int frame_number, GreasePencilFrame &frame);
|
||||
bool overwrite_frame(int frame_number, GreasePencilFrame &&frame);
|
||||
|
||||
/**
|
||||
* Returns the sorted (start) frame numbers of the frames of this layer.
|
||||
* \note This will cache the keys lazily.
|
||||
*/
|
||||
Span<int> sorted_keys() const;
|
||||
|
||||
/**
|
||||
* \returns the index of the drawing at frame \a frame or -1 if there is no drawing.
|
||||
*/
|
||||
int drawing_index_at(int frame) const;
|
||||
};
|
||||
|
||||
/**
|
||||
* A LayerGroup is a grouping of zero or more Layers.
|
||||
*/
|
||||
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(GREASE_PENCIL_LAYER_TREE_GROUP) {}
|
||||
explicit LayerGroup(const StringRefNull name) : TreeNode(GREASE_PENCIL_LAYER_TREE_GROUP, name) {}
|
||||
LayerGroup(const LayerGroup &other) : TreeNode(other)
|
||||
{
|
||||
children_.reserve(other.children_.size());
|
||||
for (const std::unique_ptr<TreeNode> &elem : other.children_) {
|
||||
if (elem.get()->is_group()) {
|
||||
children_.append(std::make_unique<LayerGroup>(elem.get()->as_group()));
|
||||
}
|
||||
else if (elem.get()->is_layer()) {
|
||||
children_.append(std::make_unique<Layer>(elem.get()->as_layer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
LayerGroup(const LayerGroup &other);
|
||||
|
||||
public:
|
||||
void add_group(LayerGroup &group)
|
||||
{
|
||||
children_.append(std::make_unique<LayerGroup>(group));
|
||||
}
|
||||
/**
|
||||
* Adds a group at the end of this group.
|
||||
*/
|
||||
void add_group(LayerGroup &group);
|
||||
void add_group(LayerGroup &&group);
|
||||
|
||||
void add_group(LayerGroup &&group)
|
||||
{
|
||||
children_.append(std::make_unique<LayerGroup>(group));
|
||||
}
|
||||
/**
|
||||
* Adds a layer at the end of this group and returns it.
|
||||
*/
|
||||
Layer &add_layer(Layer &layer);
|
||||
Layer &add_layer(Layer &&layer);
|
||||
|
||||
Layer &add_layer(Layer &layer)
|
||||
{
|
||||
int64_t index = children_.append_and_get_index(std::make_unique<Layer>(layer));
|
||||
return children_[index].get()->as_layer();
|
||||
}
|
||||
/**
|
||||
* Returns the number of direct children in this group.
|
||||
*/
|
||||
int64_t num_direct_children() const;
|
||||
|
||||
Layer &add_layer(Layer &&layer)
|
||||
{
|
||||
int64_t index = children_.append_and_get_index(std::make_unique<Layer>(layer));
|
||||
return children_[index].get()->as_layer();
|
||||
}
|
||||
/**
|
||||
* Returns the total number of children in this group.
|
||||
*/
|
||||
int64_t num_children_total() const;
|
||||
|
||||
int num_children() const
|
||||
{
|
||||
return children_.size();
|
||||
}
|
||||
/**
|
||||
* Removes a child from the group by index.
|
||||
*/
|
||||
void remove_child(int64_t index);
|
||||
|
||||
void remove_child(int64_t index)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < children_.size());
|
||||
children_.remove(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;
|
||||
|
||||
/**
|
||||
* Returns a `Vector` of pointers to all the `Layers`s in this group.
|
||||
*/
|
||||
Vector<Layer *> layers_in_pre_order() const;
|
||||
};
|
||||
|
||||
namespace convert {
|
||||
|
||||
void legacy_gpencil_frame_to_grease_pencil_drawing(GreasePencilDrawing &drawing, bGPDframe &gpf);
|
||||
|
||||
void legacy_gpencil_to_grease_pencil(GreasePencil &grease_pencil, bGPdata &gpd);
|
||||
|
||||
} // namespace convert
|
||||
|
||||
} // namespace greasepencil
|
||||
|
||||
using namespace blender::bke::greasepencil;
|
||||
|
||||
struct StrokePoint {
|
||||
float3 position;
|
||||
float radius;
|
||||
|
@ -494,71 +245,34 @@ class GreasePencilDrawingRuntime {
|
|||
};
|
||||
|
||||
class GreasePencilRuntime {
|
||||
private:
|
||||
LayerGroup root_group_;
|
||||
public:
|
||||
mutable SharedCache<Vector<greasepencil::Layer *>> layer_cache_;
|
||||
|
||||
private:
|
||||
greasepencil::LayerGroup root_group_;
|
||||
int active_layer_index_ = -1;
|
||||
Layer *active_layer_ = nullptr;
|
||||
|
||||
public:
|
||||
GreasePencilRuntime() {}
|
||||
GreasePencilRuntime(const GreasePencilRuntime &other)
|
||||
: root_group_(other.root_group_), active_layer_index_(other.active_layer_index_)
|
||||
{
|
||||
active_layer_ = get_active_layer_from_index(other.active_layer_index_);
|
||||
}
|
||||
GreasePencilRuntime(const GreasePencilRuntime &other);
|
||||
|
||||
/* TODO: There should be a const version of this for reads and a mutable version of this for
|
||||
* writes. */
|
||||
LayerGroup &root_group()
|
||||
{
|
||||
return root_group_;
|
||||
}
|
||||
public:
|
||||
const greasepencil::LayerGroup &root_group() const;
|
||||
greasepencil::LayerGroup &root_group_for_write();
|
||||
|
||||
bool has_active_layer() const
|
||||
{
|
||||
return active_layer_ != nullptr;
|
||||
}
|
||||
bool has_active_layer() const;
|
||||
const greasepencil::Layer &active_layer() const;
|
||||
greasepencil::Layer &active_layer_for_write() const;
|
||||
void set_active_layer_index(int index);
|
||||
int active_layer_index() const;
|
||||
|
||||
const Layer &active_layer() const
|
||||
{
|
||||
BLI_assert(active_layer_ != nullptr);
|
||||
return *active_layer_;
|
||||
}
|
||||
|
||||
Layer &active_layer_for_write() const
|
||||
{
|
||||
BLI_assert(active_layer_ != nullptr);
|
||||
return *active_layer_;
|
||||
}
|
||||
|
||||
void set_active_layer(int index)
|
||||
{
|
||||
active_layer_index_ = index;
|
||||
active_layer_ = get_active_layer_from_index(index);
|
||||
}
|
||||
|
||||
int active_layer_index() const
|
||||
{
|
||||
return active_layer_index_;
|
||||
}
|
||||
void ensure_layer_cache() const;
|
||||
|
||||
public:
|
||||
void *batch_cache = nullptr;
|
||||
|
||||
private:
|
||||
Layer *get_active_layer_from_index(int index)
|
||||
{
|
||||
if (index < 0) {
|
||||
return nullptr;
|
||||
}
|
||||
for (auto item : this->root_group().children_with_index_in_pre_order()) {
|
||||
if (item.node.is_layer() && item.index == index) {
|
||||
return &item.node.as_layer();
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
greasepencil::Layer *get_active_layer_from_index(int index) const;
|
||||
};
|
||||
|
||||
} // namespace blender::bke
|
||||
|
|
|
@ -250,24 +250,36 @@ IDTypeInfo IDType_ID_GP = {
|
|||
|
||||
namespace blender::bke::greasepencil {
|
||||
|
||||
TreeNode::PreOrderRange TreeNode::children_in_pre_order()
|
||||
TreeNode::TreeNode(GreasePencilLayerTreeNodeType type)
|
||||
{
|
||||
return TreeNode::PreOrderRange(this);
|
||||
this->type = type;
|
||||
this->name = nullptr;
|
||||
}
|
||||
|
||||
TreeNode::PreOrderIndexRange TreeNode::children_with_index_in_pre_order()
|
||||
TreeNode::TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name)
|
||||
{
|
||||
return TreeNode::PreOrderIndexRange(this);
|
||||
this->type = type;
|
||||
this->name = BLI_strdup(name.c_str());
|
||||
}
|
||||
|
||||
LayerGroup &TreeNode::as_group()
|
||||
TreeNode::TreeNode(const TreeNode &other)
|
||||
: TreeNode::TreeNode(GreasePencilLayerTreeNodeType(other.type))
|
||||
{
|
||||
return *static_cast<LayerGroup *>(this);
|
||||
if (other.name) {
|
||||
this->name = BLI_strdup(other.name);
|
||||
}
|
||||
}
|
||||
|
||||
Layer &TreeNode::as_layer()
|
||||
TreeNode::~TreeNode()
|
||||
{
|
||||
return *static_cast<Layer *>(this);
|
||||
if (this->name) {
|
||||
MEM_freeN(this->name);
|
||||
}
|
||||
}
|
||||
|
||||
const LayerGroup &TreeNode::as_group() const
|
||||
{
|
||||
return *static_cast<const LayerGroup *>(this);
|
||||
}
|
||||
|
||||
const Layer &TreeNode::as_layer() const
|
||||
|
@ -275,8 +287,282 @@ const Layer &TreeNode::as_layer() const
|
|||
return *static_cast<const Layer *>(this);
|
||||
}
|
||||
|
||||
LayerGroup &TreeNode::as_group_for_write()
|
||||
{
|
||||
return *static_cast<LayerGroup *>(this);
|
||||
}
|
||||
|
||||
Layer &TreeNode::as_layer_for_write()
|
||||
{
|
||||
return *static_cast<Layer *>(this);
|
||||
}
|
||||
|
||||
Layer::Layer(const Layer &other) : TreeNode::TreeNode(other)
|
||||
{
|
||||
this->frames_ = other.frames_;
|
||||
}
|
||||
|
||||
const Map<int, GreasePencilFrame> &Layer::frames() const
|
||||
{
|
||||
return this->frames_;
|
||||
}
|
||||
|
||||
Map<int, GreasePencilFrame> &Layer::frames_for_write()
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
return this->frames_;
|
||||
}
|
||||
|
||||
bool Layer::insert_frame(int frame_number, GreasePencilFrame &frame)
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
return this->frames_for_write().add(frame_number, frame);
|
||||
}
|
||||
|
||||
bool Layer::insert_frame(int frame_number, GreasePencilFrame &&frame)
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
return this->frames_for_write().add(frame_number, frame);
|
||||
}
|
||||
|
||||
bool Layer::overwrite_frame(int frame_number, GreasePencilFrame &frame)
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
return this->frames_for_write().add_overwrite(frame_number, frame);
|
||||
}
|
||||
|
||||
bool Layer::overwrite_frame(int frame_number, GreasePencilFrame &&frame)
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
return this->frames_for_write().add_overwrite(frame_number, frame);
|
||||
}
|
||||
|
||||
Span<int> Layer::sorted_keys() const
|
||||
{
|
||||
this->sorted_keys_cache_.ensure([&](Vector<int> &r_data) {
|
||||
r_data.clear_and_shrink();
|
||||
r_data.reserve(this->frames().size());
|
||||
for (int64_t key : this->frames().keys()) {
|
||||
r_data.append(key);
|
||||
}
|
||||
std::sort(r_data.begin(), r_data.end());
|
||||
});
|
||||
return this->sorted_keys_cache_.data().as_span();
|
||||
}
|
||||
|
||||
int Layer::drawing_index_at(int frame) const
|
||||
{
|
||||
Span<int> sorted_keys = this->sorted_keys();
|
||||
/* Before the first drawing, return no drawing. */
|
||||
if (frame < sorted_keys.first()) {
|
||||
return -1;
|
||||
}
|
||||
/* After or at the last drawing, return the last drawing. */
|
||||
if (frame >= sorted_keys.last()) {
|
||||
return this->frames().lookup(sorted_keys.last()).drawing_index;
|
||||
}
|
||||
/* Search for the drawing. upper_bound will get the drawing just after. */
|
||||
auto it = std::upper_bound(sorted_keys.begin(), sorted_keys.end(), frame);
|
||||
if (it == sorted_keys.end() || it == sorted_keys.begin()) {
|
||||
return -1;
|
||||
}
|
||||
return this->frames().lookup(*std::prev(it)).drawing_index;
|
||||
}
|
||||
|
||||
LayerGroup::LayerGroup(const LayerGroup &other) : TreeNode(other)
|
||||
{
|
||||
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()));
|
||||
}
|
||||
else if (elem.get()->is_layer()) {
|
||||
this->children.append(std::make_unique<Layer>(elem.get()->as_layer()));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::add_group(LayerGroup &group)
|
||||
{
|
||||
this->children.append(std::make_unique<LayerGroup>(group));
|
||||
}
|
||||
|
||||
void LayerGroup::add_group(LayerGroup &&group)
|
||||
{
|
||||
this->children.append(std::make_unique<LayerGroup>(group));
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
int64_t LayerGroup::num_direct_children() const
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
void LayerGroup::remove_child(int64_t index)
|
||||
{
|
||||
BLI_assert(index >= 0 && index < this->children.size());
|
||||
this->children.remove(index);
|
||||
}
|
||||
|
||||
void LayerGroup::foreach_children_pre_order(TreeNodeIterFn function)
|
||||
{
|
||||
for (auto &child : this->children) {
|
||||
function(*child);
|
||||
if (child->is_group()) {
|
||||
child->as_group_for_write().foreach_children_pre_order(function);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void LayerGroup::foreach_children_with_index_pre_order(TreeNodeIndexIterFn function)
|
||||
{
|
||||
Vector<TreeNode *> children = this->children_in_pre_order();
|
||||
for (const int64_t i : IndexRange(children.size())) {
|
||||
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());
|
||||
}
|
||||
}
|
||||
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());
|
||||
}
|
||||
}
|
||||
}
|
||||
return layers;
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name GreasePencilRuntime functions
|
||||
* \{ */
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
GreasePencilRuntime::GreasePencilRuntime(const GreasePencilRuntime &other)
|
||||
: root_group_(other.root_group_), active_layer_index_(other.active_layer_index_)
|
||||
{
|
||||
layer_cache_ = other.layer_cache_;
|
||||
}
|
||||
|
||||
const greasepencil::LayerGroup &GreasePencilRuntime::root_group() const
|
||||
{
|
||||
return this->root_group_;
|
||||
}
|
||||
|
||||
greasepencil::LayerGroup &GreasePencilRuntime::root_group_for_write()
|
||||
{
|
||||
this->layer_cache_.tag_dirty();
|
||||
return this->root_group_;
|
||||
}
|
||||
|
||||
bool GreasePencilRuntime::has_active_layer() const
|
||||
{
|
||||
return this->active_layer_index_ >= 0;
|
||||
}
|
||||
|
||||
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_);
|
||||
}
|
||||
|
||||
void GreasePencilRuntime::set_active_layer_index(int index)
|
||||
{
|
||||
this->active_layer_index_ = index;
|
||||
}
|
||||
|
||||
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();
|
||||
});
|
||||
}
|
||||
|
||||
greasepencil::Layer *GreasePencilRuntime::get_active_layer_from_index(int index) const
|
||||
{
|
||||
this->ensure_layer_cache();
|
||||
return this->layer_cache_.data()[index];
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Grease Pencil kernel functions
|
||||
* \{ */
|
||||
|
||||
void *BKE_grease_pencil_add(Main *bmain, const char *name)
|
||||
{
|
||||
GreasePencil *grease_pencil = static_cast<GreasePencil *>(BKE_id_new(bmain, ID_GP, name));
|
||||
|
@ -356,7 +642,11 @@ void BKE_grease_pencil_data_update(struct Depsgraph * /*depsgraph*/,
|
|||
BKE_object_eval_assign_data(object, &grease_pencil_eval->id, true);
|
||||
}
|
||||
|
||||
/* Draw Cache */
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Draw Cache
|
||||
* \{ */
|
||||
|
||||
void (*BKE_grease_pencil_batch_cache_dirty_tag_cb)(GreasePencil *grease_pencil,
|
||||
int mode) = nullptr;
|
||||
|
@ -376,7 +666,11 @@ void BKE_grease_pencil_batch_cache_free(GreasePencil *grease_pencil)
|
|||
}
|
||||
}
|
||||
|
||||
/* GreasePencilDrawing API */
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Grease Pencil Drawing API
|
||||
* \{ */
|
||||
|
||||
blender::Span<blender::uint3> GreasePencilDrawing::triangles() const
|
||||
{
|
||||
|
@ -454,7 +748,11 @@ blender::Span<blender::bke::StrokePoint> GreasePencilDrawing::stroke_buffer()
|
|||
return this->runtime->stroke_cache.as_span();
|
||||
}
|
||||
|
||||
/* GreasePencil API */
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Grease Pencil data-block API
|
||||
* \{ */
|
||||
|
||||
static void grease_pencil_grow_drawing_array_by(GreasePencil &self, const int add_capacity)
|
||||
{
|
||||
|
@ -533,18 +831,17 @@ void GreasePencil::remove_drawing(int index_to_remove)
|
|||
/* 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, GreasePencilFrame> &frames = layer.frames_for_write();
|
||||
for (auto [key, value] : frames.items()) {
|
||||
if (value.drawing_index == last_drawing_index) {
|
||||
value.drawing_index = index_to_remove;
|
||||
}
|
||||
else if (value.drawing_index == index_to_remove) {
|
||||
value.drawing_index = last_drawing_index;
|
||||
}
|
||||
}
|
||||
});
|
||||
for (Layer *layer : this->layers_for_write()) {
|
||||
blender::Map<int, GreasePencilFrame> &frames = layer->frames_for_write();
|
||||
for (auto [key, value] : frames.items()) {
|
||||
if (value.drawing_index == last_drawing_index) {
|
||||
value.drawing_index = index_to_remove;
|
||||
}
|
||||
else if (value.drawing_index == index_to_remove) {
|
||||
value.drawing_index = last_drawing_index;
|
||||
}
|
||||
}
|
||||
}
|
||||
std::swap(this->drawings_for_write()[index_to_remove],
|
||||
this->drawings_for_write()[last_drawing_index]);
|
||||
}
|
||||
|
@ -571,12 +868,12 @@ void GreasePencil::remove_drawing(int index_to_remove)
|
|||
}
|
||||
|
||||
/* Remove any frame that points to the last drawing. */
|
||||
this->root_group().foreach_layer_pre_order([last_drawing_index](Layer &layer) {
|
||||
blender::Map<int, GreasePencilFrame> &frames = layer.frames_for_write();
|
||||
for (Layer *layer : this->layers_for_write()) {
|
||||
blender::Map<int, GreasePencilFrame> &frames = layer->frames_for_write();
|
||||
frames.remove_if([last_drawing_index](auto item) {
|
||||
return item.value.drawing_index == last_drawing_index;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/* Shrink drawing array. */
|
||||
grease_pencil_shrink_drawing_array_by(*this, 1);
|
||||
|
@ -588,12 +885,8 @@ void GreasePencil::foreach_visible_drawing(
|
|||
using namespace blender::bke::greasepencil;
|
||||
|
||||
blender::Span<GreasePencilDrawingOrReference *> drawings = this->drawings();
|
||||
for (TreeNode &node : this->root_group().children_in_pre_order()) {
|
||||
if (!node.is_layer()) {
|
||||
continue;
|
||||
}
|
||||
Layer &layer = node.as_layer();
|
||||
int index = layer.drawing_at(frame);
|
||||
for (const Layer *layer : this->layers()) {
|
||||
int index = layer->drawing_index_at(frame);
|
||||
if (index == -1) {
|
||||
continue;
|
||||
}
|
||||
|
@ -608,12 +901,41 @@ void GreasePencil::foreach_visible_drawing(
|
|||
}
|
||||
}
|
||||
|
||||
blender::bke::greasepencil::LayerGroup &GreasePencil::root_group()
|
||||
const blender::bke::greasepencil::LayerGroup &GreasePencil::root_group() const
|
||||
{
|
||||
BLI_assert(this->runtime != nullptr);
|
||||
return this->runtime->root_group();
|
||||
}
|
||||
|
||||
blender::bke::greasepencil::LayerGroup &GreasePencil::root_group_for_write()
|
||||
{
|
||||
BLI_assert(this->runtime != nullptr);
|
||||
return this->runtime->root_group_for_write();
|
||||
}
|
||||
|
||||
blender::Span<const blender::bke::greasepencil::Layer *> GreasePencil::layers() const
|
||||
{
|
||||
this->runtime->ensure_layer_cache();
|
||||
return this->runtime->layer_cache_.data();
|
||||
}
|
||||
|
||||
blender::Span<blender::bke::greasepencil::Layer *> GreasePencil::layers_for_write()
|
||||
{
|
||||
this->runtime->ensure_layer_cache();
|
||||
return this->runtime->layer_cache_.data();
|
||||
}
|
||||
|
||||
void GreasePencil::tag_layer_tree_changed()
|
||||
{
|
||||
this->runtime->layer_cache_.tag_dirty();
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Drawing array storage functions
|
||||
* \{ */
|
||||
|
||||
void GreasePencil::read_drawing_array(BlendDataReader *reader)
|
||||
{
|
||||
BLO_read_pointer_array(reader, (void **)&this->drawing_array);
|
||||
|
@ -692,7 +1014,13 @@ void GreasePencil::free_drawing_array()
|
|||
this->drawing_array_size = 0;
|
||||
}
|
||||
|
||||
static void save_tree_node_to_storage(blender::bke::greasepencil::TreeNode &node,
|
||||
/** \} */
|
||||
|
||||
/* ------------------------------------------------------------------- */
|
||||
/** \name Layer Tree storage functions
|
||||
* \{ */
|
||||
|
||||
static void save_tree_node_to_storage(const blender::bke::greasepencil::TreeNode &node,
|
||||
GreasePencilLayerTreeNode *dst)
|
||||
{
|
||||
dst->type = node.type;
|
||||
|
@ -703,7 +1031,7 @@ static void save_tree_node_to_storage(blender::bke::greasepencil::TreeNode &node
|
|||
}
|
||||
}
|
||||
|
||||
static void save_layer_to_storage(blender::bke::greasepencil::Layer &node,
|
||||
static void save_layer_to_storage(const blender::bke::greasepencil::Layer &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
using namespace blender;
|
||||
|
@ -730,7 +1058,7 @@ static void save_layer_to_storage(blender::bke::greasepencil::Layer &node,
|
|||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_leaf);
|
||||
}
|
||||
|
||||
static void save_layer_group_to_storage(blender::bke::greasepencil::LayerGroup &node,
|
||||
static void save_layer_group_to_storage(const blender::bke::greasepencil::LayerGroup &node,
|
||||
GreasePencilLayerTreeNode **dst)
|
||||
{
|
||||
GreasePencilLayerTreeGroup *new_group = MEM_cnew<GreasePencilLayerTreeGroup>(__func__);
|
||||
|
@ -738,7 +1066,7 @@ static void save_layer_group_to_storage(blender::bke::greasepencil::LayerGroup &
|
|||
save_tree_node_to_storage(node, &new_group->base);
|
||||
|
||||
/* Save number of children. */
|
||||
new_group->children_num = node.num_children();
|
||||
new_group->children_num = node.num_direct_children();
|
||||
|
||||
/* Store pointer. */
|
||||
*dst = reinterpret_cast<GreasePencilLayerTreeNode *>(new_group);
|
||||
|
@ -748,25 +1076,24 @@ 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().total_num_children() + 1;
|
||||
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__);
|
||||
|
||||
int i = 0;
|
||||
save_layer_group_to_storage(this->root_group(), &this->layer_tree_storage.nodes[i++]);
|
||||
for (TreeNode &node : this->root_group().children_in_pre_order()) {
|
||||
GreasePencilLayerTreeNode **dst = &this->layer_tree_storage.nodes[i];
|
||||
if (node.is_group()) {
|
||||
LayerGroup &group = node.as_group();
|
||||
save_layer_group_to_storage(group, dst);
|
||||
}
|
||||
else if (node.is_layer()) {
|
||||
Layer &layer = node.as_layer();
|
||||
save_layer_to_storage(layer, dst);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
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();
|
||||
}
|
||||
|
@ -811,10 +1138,11 @@ void GreasePencil::load_layer_tree_from_storage()
|
|||
this->layer_tree_storage.nodes[0]);
|
||||
BLI_assert(root->type == GREASE_PENCIL_LAYER_TREE_GROUP);
|
||||
for (int i = 0; i < reinterpret_cast<GreasePencilLayerTreeGroup *>(root)->children_num; i++) {
|
||||
read_layer_node_recursive(this->runtime->root_group(), this->layer_tree_storage.nodes, i + 1);
|
||||
read_layer_node_recursive(
|
||||
this->runtime->root_group_for_write(), this->layer_tree_storage.nodes, i + 1);
|
||||
}
|
||||
|
||||
this->runtime->set_active_layer(this->layer_tree_storage.active_layer_index);
|
||||
this->runtime->set_active_layer_index(this->layer_tree_storage.active_layer_index);
|
||||
}
|
||||
|
||||
void GreasePencil::read_layer_tree_storage(BlendDataReader *reader)
|
||||
|
@ -903,3 +1231,5 @@ void GreasePencil::free_layer_tree_storage()
|
|||
this->layer_tree_storage.nodes = nullptr;
|
||||
this->layer_tree_storage.nodes_num = 0;
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
|
|
@ -111,7 +111,7 @@ void legacy_gpencil_to_grease_pencil(GreasePencil &grease_pencil, bGPdata &gpd)
|
|||
int i = 0, layer_idx = 0;
|
||||
int active_layer_index = 0;
|
||||
LISTBASE_FOREACH_INDEX (bGPDlayer *, gpl, &gpd.layers, layer_idx) {
|
||||
Layer &new_layer = grease_pencil.root_group().add_layer(Layer(gpl->info));
|
||||
Layer &new_layer = grease_pencil.root_group_for_write().add_layer(Layer(gpl->info));
|
||||
if ((gpl->flag & GP_LAYER_ACTIVE) != 0) {
|
||||
active_layer_index = layer_idx;
|
||||
}
|
||||
|
@ -135,7 +135,7 @@ void legacy_gpencil_to_grease_pencil(GreasePencil &grease_pencil, bGPdata &gpd)
|
|||
}
|
||||
}
|
||||
|
||||
grease_pencil.runtime->set_active_layer(active_layer_index);
|
||||
grease_pencil.runtime->set_active_layer_index(active_layer_index);
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil::convert
|
|
@ -36,10 +36,10 @@ TEST(greasepencil, create_grease_pencil_id)
|
|||
|
||||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(BKE_id_new(ctx.bmain, ID_GP, "GP"));
|
||||
EXPECT_EQ(grease_pencil.drawings().size(), 0);
|
||||
EXPECT_EQ(grease_pencil.root_group().total_num_children(), 0);
|
||||
EXPECT_EQ(grease_pencil.root_group().num_children_total(), 0);
|
||||
}
|
||||
|
||||
TEST(greasepencil, set_active_layer)
|
||||
TEST(greasepencil, set_active_layer_index)
|
||||
{
|
||||
GreasePencilIDTestContext ctx;
|
||||
|
||||
|
@ -49,14 +49,14 @@ TEST(greasepencil, set_active_layer)
|
|||
Layer layer1("Layer1");
|
||||
Layer layer2("Layer2");
|
||||
|
||||
const Layer &layer1_ref = grease_pencil.root_group().add_layer(std::move(layer1));
|
||||
const Layer &layer2_ref = grease_pencil.root_group().add_layer(std::move(layer2));
|
||||
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.runtime->set_active_layer(0);
|
||||
grease_pencil.runtime->set_active_layer_index(0);
|
||||
EXPECT_TRUE(grease_pencil.runtime->has_active_layer());
|
||||
EXPECT_STREQ(layer1_ref.name, grease_pencil.runtime->active_layer().name);
|
||||
|
||||
grease_pencil.runtime->set_active_layer(1);
|
||||
grease_pencil.runtime->set_active_layer_index(1);
|
||||
EXPECT_TRUE(grease_pencil.runtime->has_active_layer());
|
||||
EXPECT_STREQ(layer2_ref.name, grease_pencil.runtime->active_layer().name);
|
||||
|
||||
|
@ -104,16 +104,16 @@ TEST(greasepencil, remove_drawing)
|
|||
|
||||
layer2.insert_frame(0, GreasePencilFrame{1});
|
||||
|
||||
grease_pencil.root_group().add_layer(std::move(layer1));
|
||||
grease_pencil.root_group().add_layer(std::move(layer2));
|
||||
grease_pencil.root_group_for_write().add_layer(std::move(layer1));
|
||||
grease_pencil.root_group_for_write().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) {
|
||||
for (const int layer_i : IndexRange(grease_pencil.layers().size())) {
|
||||
const Layer &layer = *grease_pencil.layers()[layer_i];
|
||||
EXPECT_EQ(layer.frames().size(), expected_frames_size[layer_i]);
|
||||
if (layer_i == 0) {
|
||||
for (const int i : IndexRange(2)) {
|
||||
|
@ -121,8 +121,7 @@ TEST(greasepencil, remove_drawing)
|
|||
expected_frames_pairs_layer0[i][1]);
|
||||
}
|
||||
}
|
||||
layer_i++;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/* --------------------------------------------------------------------------------------------- */
|
||||
|
@ -167,35 +166,23 @@ struct GreasePencilLayerTreeExample {
|
|||
TEST(greasepencil, layer_tree_pre_order_iteration_callback)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
int i = 0;
|
||||
ex.root.foreach_children_pre_order(
|
||||
[&](TreeNode &child) { EXPECT_EQ(child.name, ex.names[i++]); });
|
||||
}
|
||||
|
||||
TEST(greasepencil, layer_tree_pre_order_iteration_loop)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
int i = 0;
|
||||
for (TreeNode &child : ex.root.children_in_pre_order()) {
|
||||
EXPECT_EQ(child.name, ex.names[i++]);
|
||||
}
|
||||
ex.root.foreach_children_with_index_pre_order(
|
||||
[&](uint64_t i, TreeNode &child) { EXPECT_EQ(child.name, ex.names[i]); });
|
||||
}
|
||||
|
||||
TEST(greasepencil, layer_tree_total_size)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
EXPECT_EQ(ex.root.total_num_children(), 7);
|
||||
EXPECT_EQ(ex.root.num_children_total(), 7);
|
||||
}
|
||||
|
||||
TEST(greasepencil, layer_tree_node_types)
|
||||
{
|
||||
GreasePencilLayerTreeExample ex;
|
||||
int i = 0;
|
||||
for (TreeNode &child : ex.root.children_in_pre_order()) {
|
||||
ex.root.foreach_children_with_index_pre_order([&](uint64_t i, TreeNode &child) {
|
||||
EXPECT_EQ(child.is_layer(), ex.is_layer[i]);
|
||||
EXPECT_EQ(child.is_group(), !ex.is_layer[i]);
|
||||
i++;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
} // namespace blender::bke::greasepencil::tests
|
|
@ -124,8 +124,9 @@ class ObjectModule {
|
|||
}
|
||||
|
||||
uint layer_offset = layers_.object_offset_get();
|
||||
grease_pencil.root_group().foreach_layer_pre_order(
|
||||
[&](Layer &layer) { layers_.sync(object, layer, do_layer_blending); });
|
||||
for (const Layer *layer : grease_pencil.layers()) {
|
||||
layers_.sync(object, *layer, do_layer_blending);
|
||||
}
|
||||
|
||||
/* Order rendering using camera Z distance. */
|
||||
float3 position = float3(object->object_to_world[3]);
|
||||
|
|
|
@ -49,10 +49,10 @@ struct PaintOperationExecutor {
|
|||
GreasePencil &grease_pencil = *static_cast<GreasePencil *>(ob_eval->data);
|
||||
if (!grease_pencil.runtime->has_active_layer()) {
|
||||
/* TODO: create a new layer. */
|
||||
grease_pencil.runtime->set_active_layer(0);
|
||||
grease_pencil.runtime->set_active_layer_index(0);
|
||||
}
|
||||
const bke::greasepencil::Layer &active_layer = grease_pencil.runtime->active_layer();
|
||||
int index = active_layer.drawing_at(scene->r.cfra);
|
||||
int index = active_layer.drawing_index_at(scene->r.cfra);
|
||||
BLI_assert(index != -1);
|
||||
|
||||
GreasePencilDrawing &drawing = *reinterpret_cast<GreasePencilDrawing *>(
|
||||
|
@ -90,8 +90,8 @@ void PaintOperation::on_stroke_done(const bContext &C)
|
|||
grease_pencil_eval.runtime->has_active_layer());
|
||||
const bke::greasepencil::Layer &active_layer_orig = grease_pencil_orig.runtime->active_layer();
|
||||
const bke::greasepencil::Layer &active_layer_eval = grease_pencil_eval.runtime->active_layer();
|
||||
int index_orig = active_layer_orig.drawing_at(scene->r.cfra);
|
||||
int index_eval = active_layer_eval.drawing_at(scene->r.cfra);
|
||||
int index_orig = active_layer_orig.drawing_index_at(scene->r.cfra);
|
||||
int index_eval = active_layer_eval.drawing_index_at(scene->r.cfra);
|
||||
BLI_assert(index_orig != -1 && index_eval != -1);
|
||||
|
||||
GreasePencilDrawing &drawing_orig = *reinterpret_cast<GreasePencilDrawing *>(
|
||||
|
|
|
@ -203,7 +203,6 @@ typedef struct GreasePencil {
|
|||
GreasePencilDrawingOrReference **drawing_array;
|
||||
int drawing_array_size;
|
||||
char _pad[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
void read_drawing_array(BlendDataReader *reader);
|
||||
void write_drawing_array(BlendWriter *writer);
|
||||
|
@ -241,7 +240,11 @@ typedef struct GreasePencil {
|
|||
void remove_drawing(int index);
|
||||
void foreach_visible_drawing(int frame,
|
||||
blender::FunctionRef<void(GreasePencilDrawing &)> function);
|
||||
blender::bke::greasepencil::LayerGroup &root_group();
|
||||
const blender::bke::greasepencil::LayerGroup &root_group() const;
|
||||
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_changed();
|
||||
#endif
|
||||
} GreasePencil;
|
||||
|
||||
|
|
Loading…
Reference in New Issue
The
_for_write()
suffix doesn't seem super helpful here TBH, but I guess it doesn't hurt.