930 lines
28 KiB
C++
930 lines
28 KiB
C++
/* SPDX-FileCopyrightText: 2023 Blender Authors
|
|
*
|
|
* SPDX-License-Identifier: GPL-2.0-or-later */
|
|
|
|
#pragma once
|
|
|
|
/** \file
|
|
* \ingroup bke
|
|
* \brief Low-level operations for grease pencil.
|
|
*/
|
|
|
|
#include <atomic>
|
|
|
|
#include "BLI_array_utils.hh"
|
|
#include "BLI_color.hh"
|
|
#include "BLI_function_ref.hh"
|
|
#include "BLI_implicit_sharing_ptr.hh"
|
|
#include "BLI_map.hh"
|
|
#include "BLI_math_matrix_types.hh"
|
|
#include "BLI_math_vector_types.hh"
|
|
#include "BLI_shared_cache.hh"
|
|
#include "BLI_utility_mixins.hh"
|
|
#include "BLI_virtual_array.hh"
|
|
|
|
#include "DNA_gpencil_legacy_types.h"
|
|
#include "DNA_grease_pencil_types.h"
|
|
|
|
struct Main;
|
|
struct Depsgraph;
|
|
struct Scene;
|
|
struct Object;
|
|
struct Material;
|
|
|
|
namespace blender::bke {
|
|
|
|
namespace greasepencil {
|
|
|
|
class DrawingRuntime {
|
|
public:
|
|
/**
|
|
* Triangle cache for all the strokes in the drawing.
|
|
*/
|
|
mutable SharedCache<Vector<uint3>> triangles_cache;
|
|
|
|
/**
|
|
* Normal vector cache for every stroke. Computed using Newell's method.
|
|
*/
|
|
mutable SharedCache<Vector<float3>> curve_plane_normals_cache;
|
|
|
|
mutable SharedCache<Vector<float4x2>> curve_texture_matrices;
|
|
|
|
/**
|
|
* Number of users for this drawing. The users are the frames in the Grease Pencil layers.
|
|
* Different frames can refer to the same drawing, so we need to make sure we count these users
|
|
* and remove a drawing if it has zero users.
|
|
*/
|
|
mutable std::atomic<int> user_count = 1;
|
|
};
|
|
|
|
class Drawing : public ::GreasePencilDrawing {
|
|
public:
|
|
Drawing();
|
|
Drawing(const Drawing &other);
|
|
~Drawing();
|
|
|
|
const bke::CurvesGeometry &strokes() const;
|
|
bke::CurvesGeometry &strokes_for_write();
|
|
/**
|
|
* The triangles for all the fills in the geometry.
|
|
*/
|
|
Span<uint3> triangles() const;
|
|
/**
|
|
* Normal vectors for a plane that fits the stroke.
|
|
*/
|
|
Span<float3> curve_plane_normals() const;
|
|
void tag_texture_matrices_changed();
|
|
void tag_positions_changed();
|
|
void tag_topology_changed();
|
|
|
|
/**
|
|
* Returns the matrices that transform from a 3D point in layer-space to a 2D point in
|
|
* texture-space.
|
|
*/
|
|
Span<float4x2> texture_matrices() const;
|
|
/**
|
|
* Sets the matrices the that transform from a 3D point in layer-space to a 2D point in
|
|
* texture-space
|
|
*/
|
|
void set_texture_matrices(Span<float4x2> matrices, const IndexMask &selection);
|
|
|
|
/**
|
|
* Radii of the points. Values are expected to be in blender units.
|
|
*/
|
|
VArray<float> radii() const;
|
|
MutableSpan<float> radii_for_write();
|
|
|
|
/**
|
|
* Opacity array for the points.
|
|
* Used by the render engine as an alpha value so they are expected to
|
|
* be between 0 and 1 inclusive.
|
|
*/
|
|
VArray<float> opacities() const;
|
|
MutableSpan<float> opacities_for_write();
|
|
|
|
/**
|
|
* Vertex colors of the points. Default is black.
|
|
*/
|
|
VArray<ColorGeometry4f> vertex_colors() const;
|
|
MutableSpan<ColorGeometry4f> vertex_colors_for_write();
|
|
|
|
/**
|
|
* Add a user for this drawing. When a drawing has multiple users, both users are allowed to
|
|
* modify this drawings data.
|
|
*/
|
|
void add_user() const;
|
|
/**
|
|
* Removes a user from this drawing. Note that this does not handle deleting the drawing if it
|
|
* has not users.
|
|
*/
|
|
void remove_user() const;
|
|
/**
|
|
* Returns true for when this drawing has more than one user.
|
|
*/
|
|
bool is_instanced() const;
|
|
bool has_users() const;
|
|
};
|
|
|
|
class DrawingReference : public ::GreasePencilDrawingReference {
|
|
public:
|
|
DrawingReference();
|
|
DrawingReference(const DrawingReference &other);
|
|
~DrawingReference();
|
|
};
|
|
|
|
const Drawing *get_eval_grease_pencil_layer_drawing(const GreasePencil &grease_pencil,
|
|
int layer_index);
|
|
Drawing *get_eval_grease_pencil_layer_drawing_for_write(GreasePencil &grease_pencil,
|
|
int layer_index);
|
|
/**
|
|
* Copies the drawings from one array to another. Assumes that \a dst_drawings is allocated but not
|
|
* initialized, e.g. it will allocate new drawings and store the pointers.
|
|
*/
|
|
void copy_drawing_array(Span<const GreasePencilDrawingBase *> src_drawings,
|
|
MutableSpan<GreasePencilDrawingBase *> dst_drawings);
|
|
|
|
class LayerGroup;
|
|
class Layer;
|
|
|
|
/* Defines the common functions used by #TreeNode, #Layer, and #LayerGroup.
|
|
* Note: Because we cannot mix C-style and C++ inheritance (all of these three classes wrap a
|
|
* C-struct that already uses "inheritance"), we define and implement these methods on all these
|
|
* classes individually. This just means that we can call `layer->name()` directly instead of
|
|
* having to write `layer->as_node().name()`. For #Layer and #LayerGroup the calls are just
|
|
* forwarded to #TreeNode. */
|
|
#define TREENODE_COMMON_METHODS \
|
|
StringRefNull name() const; \
|
|
void set_name(StringRefNull new_name); \
|
|
bool is_visible() const; \
|
|
void set_visible(bool visible); \
|
|
bool is_locked() const; \
|
|
void set_locked(bool locked); \
|
|
bool is_editable() const; \
|
|
bool is_selected() const; \
|
|
void set_selected(bool selected); \
|
|
bool use_onion_skinning() const; \
|
|
bool use_masks() const; \
|
|
bool is_child_of(const LayerGroup &group) const;
|
|
|
|
/* Implements the forwarding of the methods defined by #TREENODE_COMMON_METHODS. */
|
|
#define TREENODE_COMMON_METHODS_FORWARD_IMPL(class_name) \
|
|
inline StringRefNull class_name::name() const \
|
|
{ \
|
|
return this->as_node().name(); \
|
|
} \
|
|
inline void class_name::set_name(StringRefNull new_name) \
|
|
{ \
|
|
return this->as_node().set_name(new_name); \
|
|
} \
|
|
inline bool class_name::is_visible() const \
|
|
{ \
|
|
return this->as_node().is_visible(); \
|
|
} \
|
|
inline void class_name::set_visible(const bool visible) \
|
|
{ \
|
|
this->as_node().set_visible(visible); \
|
|
} \
|
|
inline bool class_name::is_locked() const \
|
|
{ \
|
|
return this->as_node().is_locked(); \
|
|
} \
|
|
inline void class_name::set_locked(const bool locked) \
|
|
{ \
|
|
this->as_node().set_locked(locked); \
|
|
} \
|
|
inline bool class_name::is_editable() const \
|
|
{ \
|
|
return this->as_node().is_editable(); \
|
|
} \
|
|
inline bool class_name::is_selected() const \
|
|
{ \
|
|
return this->as_node().is_selected(); \
|
|
} \
|
|
inline void class_name::set_selected(const bool selected) \
|
|
{ \
|
|
this->as_node().set_selected(selected); \
|
|
} \
|
|
inline bool class_name::use_onion_skinning() const \
|
|
{ \
|
|
return this->as_node().use_onion_skinning(); \
|
|
} \
|
|
inline bool class_name::use_masks() const \
|
|
{ \
|
|
return this->as_node().use_masks(); \
|
|
} \
|
|
inline bool class_name::is_child_of(const LayerGroup &group) const \
|
|
{ \
|
|
return this->as_node().is_child_of(group); \
|
|
}
|
|
|
|
/**
|
|
* 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.
|
|
*/
|
|
class TreeNode : public ::GreasePencilLayerTreeNode {
|
|
public:
|
|
TreeNode();
|
|
explicit TreeNode(GreasePencilLayerTreeNodeType type);
|
|
explicit TreeNode(GreasePencilLayerTreeNodeType type, StringRefNull name);
|
|
TreeNode(const TreeNode &other);
|
|
~TreeNode();
|
|
|
|
public:
|
|
/* Define the common functions for #TreeNode. */
|
|
TREENODE_COMMON_METHODS;
|
|
/**
|
|
* \returns true if this node is a #LayerGroup.
|
|
*/
|
|
bool is_group() const;
|
|
/**
|
|
* \returns true if this node is a #Layer.
|
|
*/
|
|
bool is_layer() const;
|
|
|
|
/**
|
|
* \returns this node as a #Layer.
|
|
*/
|
|
Layer &as_layer();
|
|
const Layer &as_layer() const;
|
|
|
|
/**
|
|
* \returns this node as a #LayerGroup.
|
|
*/
|
|
LayerGroup &as_group();
|
|
const LayerGroup &as_group() const;
|
|
|
|
/**
|
|
* \returns the parent layer group or nullptr for the root group.
|
|
*/
|
|
LayerGroup *parent_group() const;
|
|
TreeNode *parent_node() const;
|
|
|
|
/**
|
|
* \returns the number of non-null parents of the node.
|
|
*/
|
|
int64_t depth() const;
|
|
};
|
|
|
|
/**
|
|
* 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();
|
|
};
|
|
|
|
/**
|
|
* Structure used to transform frames in a grease pencil layer.
|
|
*/
|
|
struct LayerTransformData {
|
|
enum FrameTransformationStatus { TRANS_CLEAR, TRANS_INIT, TRANS_RUNNING };
|
|
|
|
/* Map of frame keys describing the transformation of the frames. Keys of the map are the source
|
|
* frame indices, and the values of the map are the destination frame indices. */
|
|
Map<int, int> frames_destination;
|
|
|
|
/* Copy of the layer frames map. This allows to display the transformation while running, without
|
|
* removing any drawing. */
|
|
Map<int, GreasePencilFrame> frames_copy;
|
|
/* Map containing the duration (in frames) for each frame in the layer that has a fixed duration,
|
|
* i.e. each frame that is not an implicit hold. */
|
|
Map<int, int> frames_duration;
|
|
|
|
/* Temporary copy of duplicated frames before we decide on a place to insert them.
|
|
* Used in the move+duplicate operator. */
|
|
Map<int, GreasePencilFrame> temp_frames_buffer;
|
|
|
|
FrameTransformationStatus status{TRANS_CLEAR};
|
|
};
|
|
|
|
/* The key of a GreasePencilFrame in the frames map is the starting scene frame number (int) of
|
|
* that frame. */
|
|
using FramesMapKey = int;
|
|
|
|
class LayerRuntime {
|
|
public:
|
|
/**
|
|
* This Map maps a scene frame number (key) to a GreasePencilFrame. This struct holds an index
|
|
* (drawing_index) to the drawing in the GreasePencil->drawings array. The frame number indicates
|
|
* the first frame the drawing is shown. The end time is implicitly defined by the next greater
|
|
* frame number (key) in the map. If the value mapped to (index) is -1, no drawing is shown at
|
|
* this frame.
|
|
*
|
|
* \example:
|
|
*
|
|
* {0: 0, 5: 1, 10: -1, 12: 2, 16: -1}
|
|
*
|
|
* In this example there are three drawings (drawing #0, drawing #1 and drawing #2). The first
|
|
* drawing starts at frame 0 and ends at frame 5 (exclusive). The second drawing starts at
|
|
* frame 5 and ends at frame 10. Finally, the third drawing starts at frame 12 and ends at
|
|
* frame 16.
|
|
*
|
|
* | | | | | | | | | | |1|1|1|1|1|1|1|
|
|
* Scene Frame: |0|1|2|3|4|5|6|7|8|9|0|1|2|3|4|5|6|...
|
|
* Drawing: [#0 ][#1 ] [#2 ]
|
|
*
|
|
* \note If a drawing references another data-block, all of the drawings in that data-block are
|
|
* mapped sequentially to the frames (frame-by-frame). If another frame starts, the rest of the
|
|
* referenced drawings are discarded. If the frame is longer than the number of referenced
|
|
* drawings, then the last referenced drawing is held for the rest of the duration.
|
|
*/
|
|
Map<FramesMapKey, GreasePencilFrame> frames_;
|
|
/**
|
|
* Caches a sorted vector of the keys of `frames_`.
|
|
*/
|
|
mutable SharedCache<Vector<FramesMapKey>> 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_;
|
|
|
|
/* Runtime data used for frame transformations. */
|
|
LayerTransformData trans_data_;
|
|
|
|
public:
|
|
/* Reset all runtime data. */
|
|
void clear();
|
|
};
|
|
|
|
/**
|
|
* A layer maps drawings to scene frames. It can be thought of as one independent channel in the
|
|
* timeline.
|
|
*/
|
|
class Layer : public ::GreasePencilLayer {
|
|
public:
|
|
Layer();
|
|
explicit Layer(StringRefNull name);
|
|
Layer(const Layer &other);
|
|
~Layer();
|
|
|
|
public:
|
|
/* Define the common functions for #TreeNode. */
|
|
TREENODE_COMMON_METHODS;
|
|
/**
|
|
* \returns the layer as a `TreeNode`.
|
|
*/
|
|
const TreeNode &as_node() const;
|
|
TreeNode &as_node();
|
|
|
|
/**
|
|
* \returns the parent #LayerGroup of this layer.
|
|
*/
|
|
LayerGroup &parent_group() const;
|
|
|
|
/**
|
|
* \returns the frames mapping.
|
|
*/
|
|
const Map<FramesMapKey, GreasePencilFrame> &frames() const;
|
|
Map<FramesMapKey, GreasePencilFrame> &frames_for_write();
|
|
|
|
bool is_empty() const;
|
|
|
|
/**
|
|
* Adds a new frame into the layer frames map.
|
|
* Fails if there already exists a frame at \a key that is not a null-frame.
|
|
* Null-frame at \a key and subsequent null-frames are removed.
|
|
*
|
|
* If \a duration is 0, the frame is marked as an implicit hold (see `GP_FRAME_IMPLICIT_HOLD`).
|
|
* Otherwise adds an additional null-frame at \a key + \a duration, if necessary, to
|
|
* indicate the end of the added frame.
|
|
*
|
|
* \returns a pointer to the added frame on success, otherwise nullptr.
|
|
*/
|
|
GreasePencilFrame *add_frame(FramesMapKey key, int drawing_index, int duration = 0);
|
|
/**
|
|
* Removes a frame with \a key from the frames map.
|
|
*
|
|
* Fails if the map does not contain a frame with \a key or in the specific case where
|
|
* the previous frame has a fixed duration (is not marked as an implicit hold) and the frame to
|
|
* remove is a null frame.
|
|
*
|
|
* Will remove null frames after the frame to remove.
|
|
* \return true on success.
|
|
*/
|
|
bool remove_frame(FramesMapKey key);
|
|
|
|
/**
|
|
* Returns the sorted keys (start frame numbers) of the frames of this layer.
|
|
* \note This will cache the keys lazily.
|
|
*/
|
|
Span<FramesMapKey> sorted_keys() const;
|
|
|
|
/**
|
|
* \returns the index of the active drawing at frame \a frame_number or -1 if there is no
|
|
* drawing. */
|
|
int drawing_index_at(const int frame_number) const;
|
|
|
|
/**
|
|
* \returns true if there is a drawing on this layer at \a frame_number.
|
|
*/
|
|
bool has_drawing_at(const int frame_number) const;
|
|
|
|
/**
|
|
* \returns the key of the active frame at \a frame_number or #std::nullopt if there is no frame.
|
|
*/
|
|
std::optional<FramesMapKey> frame_key_at(int frame_number) const;
|
|
|
|
/**
|
|
* \returns a pointer to the active frame at \a frame_number or nullptr if there is no frame.
|
|
*/
|
|
const GreasePencilFrame *frame_at(const int frame_number) const;
|
|
GreasePencilFrame *frame_at(const int frame_number);
|
|
|
|
/**
|
|
* \returns the frame duration of the active frame at \a frame_number or -1 if there is no active
|
|
* frame or the active frame is the last frame.
|
|
*/
|
|
int get_frame_duration_at(const int frame_number) const;
|
|
|
|
void tag_frames_map_changed();
|
|
|
|
/**
|
|
* Should be called whenever the keys in the frames map have changed. E.g. when new keys were
|
|
* added, removed or updated.
|
|
*/
|
|
void tag_frames_map_keys_changed();
|
|
|
|
/**
|
|
* Prepare the DNA #GreasePencilLayer data before blend-file writing.
|
|
*/
|
|
void prepare_for_dna_write();
|
|
|
|
/**
|
|
* Update from DNA #GreasePencilLayer data after blend-file reading.
|
|
*/
|
|
void update_from_dna_read();
|
|
|
|
/**
|
|
* Returns the transformation from layer space to object space.
|
|
*/
|
|
float4x4 to_object_space(const Object &object) const;
|
|
|
|
/**
|
|
* Returns the transformation from layer space to world space.
|
|
*/
|
|
float4x4 to_world_space(const Object &object) const;
|
|
|
|
/**
|
|
* Returns the name of the parent bone. Should only be used in case the parent object is an
|
|
* armature.
|
|
*/
|
|
StringRefNull parent_bone_name() const;
|
|
void set_parent_bone_name(const char *new_name);
|
|
|
|
/**
|
|
* Returns the view layer name that this layer should be rendered in or an empty
|
|
* `StringRefNull` if no such name is set.
|
|
*/
|
|
StringRefNull view_layer_name() const;
|
|
void set_view_layer_name(const char *new_name);
|
|
|
|
private:
|
|
using SortedKeysIterator = const int *;
|
|
|
|
private:
|
|
GreasePencilFrame *add_frame_internal(int frame_number, int drawing_index);
|
|
|
|
/**
|
|
* Removes null frames starting from \a begin until \a end (excluded) or until a non-null frame
|
|
* is reached. \param begin, end: Iterators into the `sorted_keys` span. \returns an iterator to
|
|
* the element after the last null-frame that was removed.
|
|
*/
|
|
SortedKeysIterator remove_leading_null_frames_in_range(SortedKeysIterator begin,
|
|
SortedKeysIterator end);
|
|
|
|
/**
|
|
* The local transform of the layer (in layer space, not object space).
|
|
*/
|
|
float4x4 local_transform() const;
|
|
|
|
/**
|
|
* Get the parent to world matrix for this layer.
|
|
*/
|
|
float4x4 parent_to_world(const Object &parent) const;
|
|
};
|
|
|
|
class LayerGroupRuntime {
|
|
public:
|
|
/**
|
|
* CacheMutex for `nodes_cache_` and `layer_cache_`;
|
|
*/
|
|
mutable CacheMutex nodes_cache_mutex_;
|
|
/**
|
|
* Caches all the nodes of this group in a single pre-ordered vector.
|
|
*/
|
|
mutable Vector<TreeNode *> nodes_cache_;
|
|
/**
|
|
* Caches all the layers in this group in a single pre-ordered vector.
|
|
*/
|
|
mutable Vector<Layer *> layer_cache_;
|
|
/**
|
|
* Caches all the layer groups in this group in a single pre-ordered vector.
|
|
*/
|
|
mutable Vector<LayerGroup *> layer_group_cache_;
|
|
};
|
|
|
|
/**
|
|
* A LayerGroup is a grouping of zero or more Layers.
|
|
*/
|
|
class LayerGroup : public ::GreasePencilLayerTreeGroup {
|
|
friend struct ::GreasePencil;
|
|
|
|
public:
|
|
LayerGroup();
|
|
explicit LayerGroup(StringRefNull name);
|
|
LayerGroup(const LayerGroup &other);
|
|
~LayerGroup();
|
|
|
|
LayerGroup &operator=(const LayerGroup &other);
|
|
|
|
public:
|
|
/* Define the common functions for #TreeNode. */
|
|
TREENODE_COMMON_METHODS;
|
|
/**
|
|
* \returns the group as a `TreeNode`.
|
|
*/
|
|
const TreeNode &as_node() const;
|
|
TreeNode &as_node();
|
|
|
|
/**
|
|
* Returns the number of direct nodes in this group.
|
|
*/
|
|
int64_t num_direct_nodes() const;
|
|
|
|
/**
|
|
* Returns the total number of nodes in this group.
|
|
*/
|
|
int64_t num_nodes_total() const;
|
|
|
|
/**
|
|
* Returns a `Span` of pointers to all the `TreeNode`s in this group.
|
|
*/
|
|
Span<const TreeNode *> nodes() const;
|
|
Span<TreeNode *> nodes_for_write();
|
|
|
|
/**
|
|
* Returns a `Span` of pointers to all the `Layer`s in this group.
|
|
*/
|
|
Span<const Layer *> layers() const;
|
|
Span<Layer *> layers_for_write();
|
|
|
|
/**
|
|
* Returns a `Span` of pointers to all the `LayerGroups`s in this group.
|
|
*/
|
|
Span<const LayerGroup *> groups() const;
|
|
Span<LayerGroup *> groups_for_write();
|
|
|
|
/**
|
|
* Returns a pointer to the node with \a name. If no such node was found, returns nullptr.
|
|
*/
|
|
const TreeNode *find_node_by_name(StringRefNull name) const;
|
|
TreeNode *find_node_by_name(StringRefNull name);
|
|
|
|
/**
|
|
* Print the nodes. For debugging purposes.
|
|
*/
|
|
void print_nodes(StringRefNull header) const;
|
|
|
|
/**
|
|
* Prepare the DNA #GreasePencilLayerTreeGroup data before blend-file writing.
|
|
*/
|
|
void prepare_for_dna_write();
|
|
|
|
/**
|
|
* Update from DNA #GreasePencilLayerTreeGroup data after blend-file reading.
|
|
*/
|
|
void update_from_dna_read();
|
|
|
|
protected:
|
|
/**
|
|
* Adds a new layer named \a name at the end of this group and returns it.
|
|
*/
|
|
Layer &add_layer(StringRefNull name);
|
|
Layer &add_layer(const Layer &duplicate_layer);
|
|
/**
|
|
* Adds a new group named \a name at the end of this group and returns it.
|
|
*/
|
|
LayerGroup &add_group(StringRefNull name);
|
|
/**
|
|
* Adds an existing \a node at the end of this group.
|
|
*/
|
|
TreeNode &add_node(TreeNode &node);
|
|
|
|
/**
|
|
* Adds an existing \a node before \a link of this group.
|
|
*/
|
|
void add_node_before(TreeNode &node, TreeNode &link);
|
|
/**
|
|
* Adds an existing \a node after \a link of this group.
|
|
*/
|
|
void add_node_after(TreeNode &node, TreeNode &link);
|
|
|
|
/**
|
|
* Move child \a node up/down by \a step.
|
|
*/
|
|
void move_node_up(TreeNode &node, int step = 1);
|
|
void move_node_down(TreeNode &node, int step = 1);
|
|
/**
|
|
* Move child \a node to the top/bottom.
|
|
*/
|
|
void move_node_top(TreeNode &node);
|
|
void move_node_bottom(TreeNode &node);
|
|
|
|
/**
|
|
* Unlink the node from the list of nodes in this group.
|
|
* \returns true, if the node was successfully unlinked.
|
|
*/
|
|
bool unlink_node(TreeNode &link);
|
|
|
|
private:
|
|
void ensure_nodes_cache() const;
|
|
void tag_nodes_cache_dirty() const;
|
|
};
|
|
|
|
inline void Drawing::add_user() const
|
|
{
|
|
this->runtime->user_count.fetch_add(1, std::memory_order_relaxed);
|
|
}
|
|
inline void Drawing::remove_user() const
|
|
{
|
|
this->runtime->user_count.fetch_sub(1, std::memory_order_relaxed);
|
|
}
|
|
inline bool Drawing::is_instanced() const
|
|
{
|
|
return this->runtime->user_count.load(std::memory_order_relaxed) > 1;
|
|
}
|
|
inline bool Drawing::has_users() const
|
|
{
|
|
return this->runtime->user_count.load(std::memory_order_relaxed) > 0;
|
|
}
|
|
|
|
inline bool TreeNode::is_group() const
|
|
{
|
|
return this->type == GP_LAYER_TREE_GROUP;
|
|
}
|
|
inline bool TreeNode::is_layer() const
|
|
{
|
|
return this->type == GP_LAYER_TREE_LEAF;
|
|
}
|
|
inline bool TreeNode::is_visible() const
|
|
{
|
|
return ((this->flag & GP_LAYER_TREE_NODE_HIDE) == 0) &&
|
|
(!this->parent_group() || this->parent_group()->as_node().is_visible());
|
|
}
|
|
inline void TreeNode::set_visible(const bool visible)
|
|
{
|
|
SET_FLAG_FROM_TEST(this->flag, !visible, GP_LAYER_TREE_NODE_HIDE);
|
|
}
|
|
inline bool TreeNode::is_locked() const
|
|
{
|
|
return ((this->flag & GP_LAYER_TREE_NODE_LOCKED) != 0) ||
|
|
(this->parent_group() && this->parent_group()->as_node().is_locked());
|
|
}
|
|
inline void TreeNode::set_locked(const bool locked)
|
|
{
|
|
SET_FLAG_FROM_TEST(this->flag, locked, GP_LAYER_TREE_NODE_LOCKED);
|
|
}
|
|
inline bool TreeNode::is_editable() const
|
|
{
|
|
return this->is_visible() && !this->is_locked();
|
|
}
|
|
inline bool TreeNode::is_selected() const
|
|
{
|
|
return (this->flag & GP_LAYER_TREE_NODE_SELECT) != 0;
|
|
}
|
|
inline void TreeNode::set_selected(const bool selected)
|
|
{
|
|
SET_FLAG_FROM_TEST(this->flag, selected, GP_LAYER_TREE_NODE_SELECT);
|
|
}
|
|
inline bool TreeNode::use_onion_skinning() const
|
|
{
|
|
return ((this->flag & GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING) == 0) &&
|
|
(!this->parent_group() || this->parent_group()->as_node().use_onion_skinning());
|
|
}
|
|
inline bool TreeNode::use_masks() const
|
|
{
|
|
return ((this->flag & GP_LAYER_TREE_NODE_HIDE_MASKS) == 0) &&
|
|
(!this->parent_group() || this->parent_group()->as_node().use_masks());
|
|
}
|
|
inline bool TreeNode::is_child_of(const LayerGroup &group) const
|
|
{
|
|
if (const LayerGroup *parent = this->parent_group()) {
|
|
if (parent == &group) {
|
|
return true;
|
|
}
|
|
return parent->is_child_of(group);
|
|
}
|
|
return false;
|
|
}
|
|
inline StringRefNull TreeNode::name() const
|
|
{
|
|
return (this->GreasePencilLayerTreeNode::name != nullptr) ?
|
|
this->GreasePencilLayerTreeNode::name :
|
|
StringRefNull();
|
|
}
|
|
inline const TreeNode &LayerGroup::as_node() const
|
|
{
|
|
return *reinterpret_cast<const TreeNode *>(this);
|
|
}
|
|
inline TreeNode &LayerGroup::as_node()
|
|
{
|
|
return *reinterpret_cast<TreeNode *>(this);
|
|
}
|
|
|
|
inline const TreeNode &Layer::as_node() const
|
|
{
|
|
return *reinterpret_cast<const TreeNode *>(this);
|
|
}
|
|
inline TreeNode &Layer::as_node()
|
|
{
|
|
return *reinterpret_cast<TreeNode *>(this);
|
|
}
|
|
|
|
TREENODE_COMMON_METHODS_FORWARD_IMPL(Layer);
|
|
inline bool Layer::is_empty() const
|
|
{
|
|
return (this->frames().is_empty());
|
|
}
|
|
inline LayerGroup &Layer::parent_group() const
|
|
{
|
|
return *this->as_node().parent_group();
|
|
}
|
|
|
|
TREENODE_COMMON_METHODS_FORWARD_IMPL(LayerGroup);
|
|
|
|
} // namespace greasepencil
|
|
|
|
class GreasePencilRuntime {
|
|
public:
|
|
/**
|
|
* Allocated and freed by the drawing code. See `DRW_grease_pencil_batch_cache_*` functions.
|
|
*/
|
|
void *batch_cache = nullptr;
|
|
/* The frame on which the object was evaluated (only valid for evaluated object). */
|
|
int eval_frame = 0;
|
|
|
|
public:
|
|
GreasePencilRuntime() {}
|
|
~GreasePencilRuntime() {}
|
|
};
|
|
|
|
class GreasePencilDrawingEditHints {
|
|
public:
|
|
const greasepencil::Drawing *drawing_orig;
|
|
ImplicitSharingPtrAndData positions_data;
|
|
|
|
std::optional<Span<float3>> positions() const;
|
|
std::optional<MutableSpan<float3>> positions_for_write();
|
|
};
|
|
|
|
/**
|
|
* Used to propagate deformation data through modifier evaluation.
|
|
*/
|
|
class GreasePencilEditHints {
|
|
public:
|
|
/**
|
|
* Original data that the edit hints below are meant to be used for.
|
|
*/
|
|
const GreasePencil &grease_pencil_id_orig;
|
|
|
|
GreasePencilEditHints(const GreasePencil &grease_pencil_id_orig)
|
|
: grease_pencil_id_orig(grease_pencil_id_orig)
|
|
{
|
|
}
|
|
|
|
/**
|
|
* Array of #GreasePencilDrawingEditHints. There is one edit hint for each evaluated drawing.
|
|
* Note: The index for each element is the layer index.
|
|
*/
|
|
std::optional<Array<GreasePencilDrawingEditHints>> drawing_hints;
|
|
};
|
|
|
|
} // namespace blender::bke
|
|
|
|
inline blender::bke::greasepencil::Drawing &GreasePencilDrawing::wrap()
|
|
{
|
|
return *reinterpret_cast<blender::bke::greasepencil::Drawing *>(this);
|
|
}
|
|
inline const blender::bke::greasepencil::Drawing &GreasePencilDrawing::wrap() const
|
|
{
|
|
return *reinterpret_cast<const blender::bke::greasepencil::Drawing *>(this);
|
|
}
|
|
|
|
inline blender::bke::greasepencil::DrawingReference &GreasePencilDrawingReference::wrap()
|
|
{
|
|
return *reinterpret_cast<blender::bke::greasepencil::DrawingReference *>(this);
|
|
}
|
|
inline const blender::bke::greasepencil::DrawingReference &GreasePencilDrawingReference::wrap()
|
|
const
|
|
{
|
|
return *reinterpret_cast<const blender::bke::greasepencil::DrawingReference *>(this);
|
|
}
|
|
|
|
inline GreasePencilFrame GreasePencilFrame::null()
|
|
{
|
|
return GreasePencilFrame{-1, 0, 0};
|
|
}
|
|
|
|
inline bool GreasePencilFrame::is_null() const
|
|
{
|
|
return this->drawing_index == -1;
|
|
}
|
|
|
|
inline bool GreasePencilFrame::is_implicit_hold() const
|
|
{
|
|
return (this->flag & GP_FRAME_IMPLICIT_HOLD) != 0;
|
|
}
|
|
|
|
inline bool GreasePencilFrame::is_selected() const
|
|
{
|
|
return (this->flag & GP_FRAME_SELECTED) != 0;
|
|
}
|
|
|
|
inline blender::bke::greasepencil::TreeNode &GreasePencilLayerTreeNode::wrap()
|
|
{
|
|
return *reinterpret_cast<blender::bke::greasepencil::TreeNode *>(this);
|
|
}
|
|
inline const blender::bke::greasepencil::TreeNode &GreasePencilLayerTreeNode::wrap() const
|
|
{
|
|
return *reinterpret_cast<const blender::bke::greasepencil::TreeNode *>(this);
|
|
}
|
|
|
|
inline blender::bke::greasepencil::Layer &GreasePencilLayer::wrap()
|
|
{
|
|
return *reinterpret_cast<blender::bke::greasepencil::Layer *>(this);
|
|
}
|
|
inline const blender::bke::greasepencil::Layer &GreasePencilLayer::wrap() const
|
|
{
|
|
return *reinterpret_cast<const blender::bke::greasepencil::Layer *>(this);
|
|
}
|
|
|
|
inline blender::bke::greasepencil::LayerGroup &GreasePencilLayerTreeGroup::wrap()
|
|
{
|
|
return *reinterpret_cast<blender::bke::greasepencil::LayerGroup *>(this);
|
|
}
|
|
inline const blender::bke::greasepencil::LayerGroup &GreasePencilLayerTreeGroup::wrap() const
|
|
{
|
|
return *reinterpret_cast<const blender::bke::greasepencil::LayerGroup *>(this);
|
|
}
|
|
|
|
inline const GreasePencilDrawingBase *GreasePencil::drawing(int64_t index) const
|
|
{
|
|
return this->drawings()[index];
|
|
}
|
|
inline GreasePencilDrawingBase *GreasePencil::drawing(int64_t index)
|
|
{
|
|
return this->drawings()[index];
|
|
}
|
|
|
|
inline const blender::bke::greasepencil::LayerGroup &GreasePencil::root_group() const
|
|
{
|
|
return this->root_group_ptr->wrap();
|
|
}
|
|
inline blender::bke::greasepencil::LayerGroup &GreasePencil::root_group()
|
|
{
|
|
return this->root_group_ptr->wrap();
|
|
}
|
|
|
|
inline bool GreasePencil::has_active_layer() const
|
|
{
|
|
return (this->active_layer != nullptr);
|
|
}
|
|
|
|
void *BKE_grease_pencil_add(Main *bmain, const char *name);
|
|
GreasePencil *BKE_grease_pencil_new_nomain();
|
|
GreasePencil *BKE_grease_pencil_copy_for_eval(const GreasePencil *grease_pencil_src);
|
|
void BKE_grease_pencil_data_update(Depsgraph *depsgraph, Scene *scene, Object *object);
|
|
void BKE_grease_pencil_duplicate_drawing_array(const GreasePencil *grease_pencil_src,
|
|
GreasePencil *grease_pencil_dst);
|
|
|
|
int BKE_grease_pencil_object_material_index_get_by_name(Object *ob, const char *name);
|
|
Material *BKE_grease_pencil_object_material_new(Main *bmain,
|
|
Object *ob,
|
|
const char *name,
|
|
int *r_index);
|
|
Material *BKE_grease_pencil_object_material_from_brush_get(Object *ob, Brush *brush);
|
|
Material *BKE_grease_pencil_object_material_ensure_by_name(Main *bmain,
|
|
Object *ob,
|
|
const char *name,
|
|
int *r_index);
|
|
Material *BKE_grease_pencil_brush_material_get(Brush *brush);
|
|
Material *BKE_grease_pencil_object_material_ensure_from_brush(Main *bmain,
|
|
Object *ob,
|
|
Brush *brush);
|
|
Material *BKE_grease_pencil_object_material_ensure_from_active_input_brush(Main *bmain,
|
|
Object *ob,
|
|
Brush *brush);
|
|
Material *BKE_grease_pencil_object_material_ensure_from_active_input_material(Object *ob);
|
|
Material *BKE_grease_pencil_object_material_ensure_active(Object *ob);
|
|
void BKE_grease_pencil_material_remap(GreasePencil *grease_pencil, const uint *remap, int totcol);
|
|
void BKE_grease_pencil_material_index_remove(GreasePencil *grease_pencil, int index);
|
|
|
|
bool BKE_grease_pencil_references_cyclic_check(const GreasePencil *id_reference,
|
|
const GreasePencil *grease_pencil);
|
|
bool BKE_grease_pencil_material_index_used(GreasePencil *grease_pencil, int index);
|