Initial Grease Pencil 3.0 stage #106848
|
@ -82,6 +82,17 @@ class TreeNode : public ::GreasePencilLayerTreeNode, NonMovable {
|
|||
Layer &as_layer_for_write();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
* A layer mask stores a reference to a layer that will mask other layers.
|
||||
*/
|
||||
class LayerMask : public ::GreasePencilLayerMask {
|
||||
public:
|
||||
LayerMask();
|
||||
explicit LayerMask(StringRefNull name);
|
||||
LayerMask(const LayerMask &other);
|
||||
~LayerMask();
|
||||
};
|
||||
|
||||
/**
|
||||
* A layer maps drawings to scene frames. It can be thought of as one independent channel in the
|
||||
* timeline.
|
||||
|
@ -114,7 +125,15 @@ class Layer : public TreeNode, public ::GreasePencilLayer {
|
|||
* drawings, then the last referenced drawing is held for the rest of the duration.
|
||||
*/
|
||||
Map<int, GreasePencilFrame> frames_;
|
||||
/**
|
||||
* Caches a sorted vector of the keys of `frames_`.
|
||||
*/
|
||||
mutable SharedCache<Vector<int>> sorted_keys_cache_;
|
||||
/**
|
||||
* A vector of LayerMask. This layer will be masked by the layers referenced in the masks.
|
||||
* A layer can have zero or more layer masks.
|
||||
*/
|
||||
Vector<LayerMask> masks_;
|
||||
|
||||
public:
|
||||
Layer();
|
||||
|
@ -128,6 +147,12 @@ class Layer : public TreeNode, public ::GreasePencilLayer {
|
|||
const Map<int, GreasePencilFrame> &frames() const;
|
||||
Map<int, GreasePencilFrame> &frames_for_write();
|
||||
|
||||
/**
|
||||
* \returns the layer masks.
|
||||
*/
|
||||
const Vector<LayerMask> &masks() const;
|
||||
Vector<LayerMask> &masks_for_write();
|
||||
|
||||
/**
|
||||
Hans Goudey
commented
Better to return a span here maybe? Better to return a span here maybe?
|
||||
* Inserts the frame into the layer. Fails if there exists a frame at \a frame_number already.
|
||||
* \returns true on success.
|
||||
|
|
|
@ -298,19 +298,45 @@ Layer &TreeNode::as_layer_for_write()
|
|||
return *static_cast<Layer *>(this);
|
||||
}
|
||||
|
||||
Layer::Layer() : TreeNode::TreeNode(GP_LAYER_TREE_LEAF), frames_()
|
||||
LayerMask::LayerMask()
|
||||
{
|
||||
this->layer_name = nullptr;
|
||||
}
|
||||
filedescriptor marked this conversation as resolved
Outdated
Falk David
commented
Make sure to not overwrite Make sure to not overwrite `min` and `max` but account any value already present. E.g. use `math::min_max(...)`.
|
||||
|
||||
LayerMask::LayerMask(StringRefNull name)
|
||||
{
|
||||
this->layer_name = BLI_strdup(name.c_str());
|
||||
}
|
||||
|
||||
LayerMask::LayerMask(const LayerMask &other) : LayerMask()
|
||||
{
|
||||
if (other.layer_name) {
|
||||
this->layer_name = BLI_strdup(other.layer_name);
|
||||
}
|
||||
}
|
||||
|
||||
LayerMask::~LayerMask()
|
||||
{
|
||||
if (this->layer_name) {
|
||||
MEM_freeN(this->layer_name);
|
||||
}
|
||||
}
|
||||
|
||||
Layer::Layer() : TreeNode::TreeNode(GP_LAYER_TREE_LEAF), frames_(), masks_()
|
||||
{
|
||||
this->parsubstr = nullptr;
|
||||
this->viewlayer_name = nullptr;
|
||||
}
|
||||
|
||||
Layer::Layer(StringRefNull name) : TreeNode::TreeNode(GP_LAYER_TREE_LEAF, name), frames_()
|
||||
Layer::Layer(StringRefNull name)
|
||||
: TreeNode::TreeNode(GP_LAYER_TREE_LEAF, name), frames_(), masks_()
|
||||
{
|
||||
this->parsubstr = nullptr;
|
||||
this->viewlayer_name = nullptr;
|
||||
}
|
||||
|
||||
Layer::Layer(const Layer &other) : TreeNode::TreeNode(other), frames_(other.frames_)
|
||||
Layer::Layer(const Layer &other)
|
||||
: TreeNode::TreeNode(other), frames_(other.frames_), masks_(other.masks_)
|
||||
{
|
||||
this->parsubstr = nullptr;
|
||||
this->viewlayer_name = nullptr;
|
||||
|
@ -343,6 +369,16 @@ Map<int, GreasePencilFrame> &Layer::frames_for_write()
|
|||
return this->frames_;
|
||||
}
|
||||
|
||||
const Vector<LayerMask> &Layer::masks() const
|
||||
{
|
||||
return this->masks_;
|
||||
}
|
||||
|
||||
Vector<LayerMask> &Layer::masks_for_write()
|
||||
{
|
||||
return this->masks_;
|
||||
}
|
||||
|
||||
bool Layer::insert_frame(int frame_number, GreasePencilFrame &frame)
|
||||
{
|
||||
this->sorted_keys_cache_.tag_dirty();
|
||||
|
@ -1094,6 +1130,13 @@ static void save_layer_to_storage(const blender::bke::greasepencil::Layer &node,
|
|||
if (node.viewlayer_name) {
|
||||
new_leaf->layer.viewlayer_name = BLI_strdup(node.viewlayer_name);
|
||||
}
|
||||
BLI_listbase_clear(&new_leaf->layer.masks_storage);
|
||||
for (const bke::greasepencil::LayerMask &mask : node.masks()) {
|
||||
GreasePencilLayerMask *new_mask = MEM_cnew<GreasePencilLayerMask>(__func__);
|
||||
new_mask->layer_name = BLI_strdup(mask.layer_name);
|
||||
new_mask->flag = mask.flag;
|
||||
BLI_addtail(&new_leaf->layer.masks_storage, new_mask);
|
||||
}
|
||||
new_leaf->layer.opacity = node.opacity;
|
||||
copy_v4_v4(new_leaf->layer.tint_color, node.tint_color);
|
||||
copy_v3_v3(new_leaf->layer.location, node.location);
|
||||
|
@ -1162,6 +1205,12 @@ static void read_layer_from_storage(blender::bke::greasepencil::LayerGroup &curr
|
|||
if (node_leaf->layer.viewlayer_name) {
|
||||
new_layer.viewlayer_name = BLI_strdup(node_leaf->layer.viewlayer_name);
|
||||
}
|
||||
Vector<LayerMask> masks = new_layer.masks_for_write();
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &node_leaf->layer.masks_storage) {
|
||||
LayerMask new_mask = LayerMask(mask->name);
|
||||
new_mask.flag = mask->flag;
|
||||
masks.append(std::move(new_mask));
|
||||
}
|
||||
new_layer.opacity = node_leaf->layer.opacity;
|
||||
copy_v4_v4(new_layer.tint_color, node_leaf->layer.tint_color);
|
||||
copy_v3_v3(new_layer.location, node_leaf->layer.location);
|
||||
|
@ -1236,6 +1285,10 @@ void GreasePencil::read_layer_tree_storage(BlendDataReader *reader)
|
|||
BLO_read_data_address(reader, &node_leaf->layer.frames_storage.values);
|
||||
BLO_read_data_address(reader, &node_leaf->layer.parsubstr);
|
||||
BLO_read_data_address(reader, &node_leaf->layer.viewlayer_name);
|
||||
BLO_read_list(reader, &node_leaf->layer.masks_storage);
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &node_leaf->layer.masks_storage) {
|
||||
BLO_read_data_address(reader, &mask->layer_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GP_LAYER_TREE_GROUP: {
|
||||
|
@ -1267,6 +1320,10 @@ void GreasePencil::write_layer_tree_storage(BlendWriter *writer)
|
|||
node_leaf->layer.frames_storage.values);
|
||||
BLO_write_string(writer, node_leaf->layer.parsubstr);
|
||||
BLO_write_string(writer, node_leaf->layer.viewlayer_name);
|
||||
BLO_write_struct_list(writer, GreasePencilLayerMask, &node_leaf->layer.masks_storage);
|
||||
LISTBASE_FOREACH (GreasePencilLayerMask *, mask, &node_leaf->layer.masks_storage) {
|
||||
BLO_write_string(writer, mask->layer_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case GP_LAYER_TREE_GROUP: {
|
||||
|
@ -1302,6 +1359,12 @@ void GreasePencil::free_layer_tree_storage()
|
|||
if (node_leaf->layer.viewlayer_name) {
|
||||
MEM_freeN(node_leaf->layer.viewlayer_name);
|
||||
}
|
||||
LISTBASE_FOREACH_MUTABLE (GreasePencilLayerMask *, mask, &node_leaf->layer.masks_storage) {
|
||||
if (mask->layer_name) {
|
||||
MEM_freeN(mask->layer_name);
|
||||
}
|
||||
MEM_freeN(mask);
|
||||
}
|
||||
MEM_freeN(node_leaf);
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -219,6 +219,13 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
|||
if (viewlayername_len > 0) {
|
||||
new_layer.viewlayer_name = BLI_strdupn(gpl->viewlayername, viewlayername_len);
|
||||
}
|
||||
/* Convert the layer masks. */
|
||||
Vector<LayerMask> masks = new_layer.masks_for_write();
|
||||
LISTBASE_FOREACH (bGPDlayer_Mask *, mask, &gpl->mask_layers) {
|
||||
LayerMask new_mask = LayerMask(mask->name);
|
||||
new_mask.flag = mask->flag;
|
||||
masks.append(std::move(new_mask));
|
||||
}
|
||||
new_layer.opacity = gpl->opacity;
|
||||
copy_v4_v4(new_layer.tint_color, gpl->tintcolor);
|
||||
copy_v3_v3(new_layer.location, gpl->location);
|
||||
|
|
|
@ -139,6 +139,31 @@ typedef struct GreasePencilLayerFramesMapStorage {
|
|||
char _pad[4];
|
||||
} GreasePencilLayerFramesMapStorage;
|
||||
|
||||
/**
|
||||
* Flag for layer masks. #GreasePencilLayerMask.flag
|
||||
*/
|
||||
typedef enum GreasePencilLayerMaskFlag {
|
||||
GP_LAYER_MASK_HIDE = (1 << 0),
|
||||
GP_LAYER_MASK_INVERT = (1 << 1),
|
||||
} GreasePencilLayerMaskFlag;
|
||||
|
||||
/**
|
||||
* A grease pencil layer mask stores the name of a layer that is the mask.
|
||||
*/
|
||||
typedef struct GreasePencilLayerMask {
|
||||
struct GreasePencilLayerMask *next, *prev;
|
||||
/**
|
||||
* The name of the layer that is the mask.
|
||||
* \note Null-terminated.
|
||||
*/
|
||||
char *layer_name;
|
||||
/**
|
||||
* Layer mask flag. See `GreasePencilLayerMaskFlag`.
|
||||
*/
|
||||
uint16_t flag;
|
||||
char _pad[6];
|
||||
} GreasePencilLayerMask;
|
||||
|
||||
/**
|
||||
* Type of parent of a layer. #GreasePencilLayer.parent_type
|
||||
*/
|
||||
|
@ -193,6 +218,10 @@ typedef struct GreasePencilLayer {
|
|||
* \note Null-terminated.
|
||||
*/
|
||||
char *viewlayer_name;
|
||||
/**
|
||||
* List of `GreasePencilLayerMask`.
|
||||
*/
|
||||
ListBase masks_storage;
|
||||
/**
|
||||
* Opacity of the layer.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue
The
_for_write()
suffix doesn't seem super helpful here TBH, but I guess it doesn't hurt.