Initial Grease Pencil 3.0 stage #106848

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

View File

@ -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();
Review

The _for_write() suffix doesn't seem super helpful here TBH, but I guess it doesn't hurt.

The `_for_write()` suffix doesn't seem super helpful here TBH, but I guess it doesn't hurt.
};
/**
@ -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

View File

@ -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;
}
/** \} */

View File

@ -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

View File

@ -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

View File

@ -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]);

View File

@ -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 *>(

View File

@ -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;