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
3 changed files with 176 additions and 68 deletions
Showing only changes of commit 85c87d901c - Show all commits

View File

@ -63,15 +63,15 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
/* Duplicate drawing array. */
grease_pencil_dst->drawing_array_size = grease_pencil_src->drawing_array_size;
grease_pencil_dst->drawing_array = MEM_cnew_array<GreasePencilDrawingOrReference *>(
grease_pencil_dst->drawing_array = MEM_cnew_array<GreasePencilDrawingBase *>(
grease_pencil_src->drawing_array_size, __func__);
for (int i = 0; i < grease_pencil_src->drawing_array_size; i++) {
const GreasePencilDrawingOrReference *src_drawing_or_ref = grease_pencil_src->drawing_array[i];
switch (src_drawing_or_ref->type) {
const GreasePencilDrawingBase *src_drawing_base = grease_pencil_src->drawing_array[i];
switch (src_drawing_base->type) {
case GP_DRAWING: {
const GreasePencilDrawing *src_drawing = reinterpret_cast<const GreasePencilDrawing *>(
src_drawing_or_ref);
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
src_drawing_base);
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_cnew<GreasePencilDrawing>(__func__));
GreasePencilDrawing *dst_drawing = reinterpret_cast<GreasePencilDrawing *>(
grease_pencil_dst->drawing_array[i]);
@ -86,8 +86,8 @@ static void grease_pencil_copy_data(Main * /*bmain*/,
}
case GP_DRAWING_REFERENCE: {
const GreasePencilDrawingReference *src_drawing_reference =
reinterpret_cast<const GreasePencilDrawingReference *>(src_drawing_or_ref);
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
reinterpret_cast<const GreasePencilDrawingReference *>(src_drawing_base);
grease_pencil_dst->drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_dupallocN(src_drawing_reference));
break;
}
@ -128,10 +128,10 @@ static void grease_pencil_foreach_id(ID *id, LibraryForeachIDData *data)
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, grease_pencil->material_array[i], IDWALK_CB_USER);
}
for (int i = 0; i < grease_pencil->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil->drawing_array[i];
if (drawing_or_ref->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingBase *drawing_base = grease_pencil->drawing_array[i];

How can you be sure here that the potential memory allocated to the batch_cache is freed?

if memory in batch_cache is managed by drawing code, a comment in the runtime struct should specify it.

Would be better to have a proper destructor for these structs anyway imho, even if not really needed right now.

How can you be sure here that the potential memory allocated to the `batch_cache` is freed? if memory in `batch_cache` is managed by drawing code, a comment in the runtime struct should specify it. Would be better to have a proper destructor for these structs anyway imho, even if not really needed right now.
if (drawing_base->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, drawing_reference->id_reference, IDWALK_CB_USER);
}
}
@ -194,10 +194,10 @@ static void grease_pencil_blend_read_lib(BlendLibReader *reader, ID *id)
BLO_read_id_address(reader, grease_pencil->id.lib, &grease_pencil->material_array[i]);
}
for (int i = 0; i < grease_pencil->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil->drawing_array[i];
if (drawing_or_ref->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingBase *drawing_base = grease_pencil->drawing_array[i];
if (drawing_base->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BLO_read_id_address(reader, grease_pencil->id.lib, &drawing_reference->id_reference);
}
}
@ -210,10 +210,10 @@ static void grease_pencil_blend_read_expand(BlendExpander *expander, ID *id)
BLO_expand(expander, grease_pencil->material_array[i]);
}
for (int i = 0; i < grease_pencil->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil->drawing_array[i];
if (drawing_or_ref->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingBase *drawing_base = grease_pencil->drawing_array[i];
if (drawing_base->type == GP_DRAWING_REFERENCE) {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BLO_expand(expander, drawing_reference->id_reference);
}
}
@ -661,10 +661,10 @@ BoundBox *BKE_grease_pencil_boundbox_get(Object *ob)
/* FIXME: this should somehow go through the visible drawings. We don't have access to the
* scene time here, so we probably need to cache the visible drawing for each layer somehow. */
for (int i = 0; i < grease_pencil->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = grease_pencil->drawing_array[i];
switch (drawing_or_ref->type) {
GreasePencilDrawingBase *drawing_base = grease_pencil->drawing_array[i];
switch (drawing_base->type) {
case GP_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
const blender::bke::CurvesGeometry &curves = drawing->geometry.wrap();
if (!curves.bounds_min_max(min, max)) {
@ -824,9 +824,8 @@ static void grease_pencil_grow_drawing_array_by(GreasePencil &self, const int ad
{
BLI_assert(add_capacity > 0);
const int new_drawing_array_size = self.drawing_array_size + add_capacity;
GreasePencilDrawingOrReference **new_drawing_array =
reinterpret_cast<GreasePencilDrawingOrReference **>(
MEM_cnew_array<GreasePencilDrawingOrReference *>(new_drawing_array_size, __func__));
GreasePencilDrawingBase **new_drawing_array = reinterpret_cast<GreasePencilDrawingBase **>(
MEM_cnew_array<GreasePencilDrawingBase *>(new_drawing_array_size, __func__));
blender::uninitialized_relocate_n(
self.drawing_array, self.drawing_array_size, new_drawing_array);
@ -839,9 +838,8 @@ static void grease_pencil_shrink_drawing_array_by(GreasePencil &self, const int
{
BLI_assert(remove_capacity > 0);
const int new_drawing_array_size = self.drawing_array_size - remove_capacity;
GreasePencilDrawingOrReference **new_drawing_array =
reinterpret_cast<GreasePencilDrawingOrReference **>(
MEM_cnew_array<GreasePencilDrawingOrReference *>(new_drawing_array_size, __func__));
GreasePencilDrawingBase **new_drawing_array = reinterpret_cast<GreasePencilDrawingBase **>(
MEM_cnew_array<GreasePencilDrawingBase *>(new_drawing_array_size, __func__));
blender::uninitialized_move_n(self.drawing_array, new_drawing_array_size, new_drawing_array);
MEM_freeN(self.drawing_array);
@ -850,16 +848,15 @@ static void grease_pencil_shrink_drawing_array_by(GreasePencil &self, const int
self.drawing_array_size = new_drawing_array_size;
}
blender::Span<GreasePencilDrawingOrReference *> GreasePencil::drawings() const
blender::Span<GreasePencilDrawingBase *> GreasePencil::drawings() const
{
return blender::Span<GreasePencilDrawingOrReference *>{this->drawing_array,
this->drawing_array_size};
return blender::Span<GreasePencilDrawingBase *>{this->drawing_array, this->drawing_array_size};
}
blender::MutableSpan<GreasePencilDrawingOrReference *> GreasePencil::drawings_for_write()
blender::MutableSpan<GreasePencilDrawingBase *> GreasePencil::drawings_for_write()
{
return blender::MutableSpan<GreasePencilDrawingOrReference *>{this->drawing_array,
this->drawing_array_size};
return blender::MutableSpan<GreasePencilDrawingBase *>{this->drawing_array,
this->drawing_array_size};
}
void GreasePencil::add_empty_drawings(int n)
@ -868,10 +865,10 @@ void GreasePencil::add_empty_drawings(int n)
BLI_assert(n > 0);
const int prev_size = this->drawings().size();
grease_pencil_grow_drawing_array_by(*this, n);
MutableSpan<GreasePencilDrawingOrReference *> new_drawings =
this->drawings_for_write().drop_front(prev_size);
MutableSpan<GreasePencilDrawingBase *> new_drawings = this->drawings_for_write().drop_front(
prev_size);
for (const int i : IndexRange(new_drawings.size())) {
new_drawings[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
new_drawings[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_new<GreasePencilDrawing>(__func__));
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(new_drawings[i]);
new (&drawing->geometry) bke::CurvesGeometry();
@ -913,12 +910,11 @@ void GreasePencil::remove_drawing(int index_to_remove)
}
/* Delete the last drawing. */
GreasePencilDrawingOrReference *drawing_or_ref_to_remove =
this->drawings_for_write()[last_drawing_index];
switch (drawing_or_ref_to_remove->type) {
GreasePencilDrawingBase *drawing_base_to_remove = this->drawings_for_write()[last_drawing_index];
switch (drawing_base_to_remove->type) {
case GP_DRAWING: {
GreasePencilDrawing *drawing_to_remove = reinterpret_cast<GreasePencilDrawing *>(
drawing_or_ref_to_remove);
drawing_base_to_remove);
drawing_to_remove->geometry.wrap().~CurvesGeometry();
MEM_delete(drawing_to_remove->runtime);
drawing_to_remove->runtime = nullptr;
@ -927,7 +923,7 @@ void GreasePencil::remove_drawing(int index_to_remove)
}
case GP_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference_to_remove =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref_to_remove);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base_to_remove);
MEM_freeN(drawing_reference_to_remove);
break;
}
@ -950,18 +946,18 @@ void GreasePencil::foreach_visible_drawing(
{
using namespace blender::bke::greasepencil;
blender::Span<GreasePencilDrawingOrReference *> drawings = this->drawings();
blender::Span<GreasePencilDrawingBase *> drawings = this->drawings();
for (const Layer *layer : this->layers()) {
int index = layer->drawing_index_at(frame);
if (index == -1) {
continue;
}
GreasePencilDrawingOrReference *drawing_or_reference = drawings[index];
if (drawing_or_reference->type == GP_DRAWING) {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_reference);
GreasePencilDrawingBase *drawing_baseerence = drawings[index];
if (drawing_baseerence->type == GP_DRAWING) {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_baseerence);
function(*drawing);
}

cache is named r_data in other shared cache "ensure" functions, might as well be consistent with that

`cache` is named `r_data` in other shared cache "ensure" functions, might as well be consistent with that
else if (drawing_or_reference->type == GP_DRAWING_REFERENCE) {
else if (drawing_baseerence->type == GP_DRAWING_REFERENCE) {
/* TODO */
}
}
@ -1007,10 +1003,10 @@ void GreasePencil::read_drawing_array(BlendDataReader *reader)
BLO_read_pointer_array(reader, (void **)&this->drawing_array);
for (int i = 0; i < this->drawing_array_size; i++) {
BLO_read_data_address(reader, &this->drawing_array[i]);
GreasePencilDrawingOrReference *drawing_or_ref = this->drawing_array[i];
switch (drawing_or_ref->type) {
GreasePencilDrawingBase *drawing_base = this->drawing_array[i];
switch (drawing_base->type) {
case GP_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
drawing->geometry.wrap().blend_read(*reader);
/* Initialize runtime data. */
drawing->geometry.runtime = MEM_new<blender::bke::CurvesGeometryRuntime>(__func__);
@ -1021,7 +1017,7 @@ void GreasePencil::read_drawing_array(BlendDataReader *reader)
}
case GP_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BLO_read_data_address(reader, &drawing_reference->id_reference);
break;
}
@ -1033,17 +1029,17 @@ void GreasePencil::write_drawing_array(BlendWriter *writer)
{
BLO_write_pointer_array(writer, this->drawing_array_size, this->drawing_array);
for (int i = 0; i < this->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = this->drawing_array[i];
switch (drawing_or_ref->type) {
GreasePencilDrawingBase *drawing_base = this->drawing_array[i];
switch (drawing_base->type) {
case GP_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
BLO_write_struct(writer, GreasePencilDrawing, drawing);
drawing->geometry.wrap().blend_write(*writer, this->id);

What about replacing these with slightly more generic functions like this?

template<typename T> static void grow_array(T **array,  int *size, const int add_size) {}
template<typename T> static void shring_array(T **array,  int *size, const int shrink_size) {}

That would allow for simpler variable naming inside, and would tell the reader "there's nothing special going on here, just resizing some arrays" which makes it easier to skim

What about replacing these with slightly more generic functions like this? ``` template<typename T> static void grow_array(T **array, int *size, const int add_size) {} template<typename T> static void shring_array(T **array, int *size, const int shrink_size) {} ``` That would allow for simpler variable naming inside, and would tell the reader "there's nothing special going on here, just resizing some arrays" which makes it easier to skim
break;
}
case GP_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
BLO_write_struct(writer, GreasePencilDrawingReference, drawing_reference);
break;
}
@ -1057,10 +1053,10 @@ void GreasePencil::free_drawing_array()
return;
}
for (int i = 0; i < this->drawing_array_size; i++) {
GreasePencilDrawingOrReference *drawing_or_ref = this->drawing_array[i];
switch (drawing_or_ref->type) {
GreasePencilDrawingBase *drawing_base = this->drawing_array[i];
switch (drawing_base->type) {
case GP_DRAWING: {
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_or_ref);
GreasePencilDrawing *drawing = reinterpret_cast<GreasePencilDrawing *>(drawing_base);
drawing->geometry.wrap().~CurvesGeometry();
MEM_delete(drawing->runtime);
drawing->runtime = nullptr;
@ -1069,7 +1065,7 @@ void GreasePencil::free_drawing_array()
}
case GP_DRAWING_REFERENCE: {
GreasePencilDrawingReference *drawing_reference =
reinterpret_cast<GreasePencilDrawingReference *>(drawing_or_ref);
reinterpret_cast<GreasePencilDrawingReference *>(drawing_base);
MEM_freeN(drawing_reference);
break;
}

View File

@ -184,7 +184,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
}
grease_pencil.drawing_array_size = num_drawings;
grease_pencil.drawing_array = reinterpret_cast<GreasePencilDrawingOrReference **>(
grease_pencil.drawing_array = reinterpret_cast<GreasePencilDrawingBase **>(
MEM_cnew_array<GreasePencilDrawing *>(num_drawings, __func__));
int i = 0, layer_idx = 0;
@ -205,6 +205,9 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
SET_FLAG_FROM_TEST(new_layer.flag, (gpl->flag & GP_LAYER_FRAMELOCK), GP_LAYER_TREE_NODE_MUTE);
SET_FLAG_FROM_TEST(
new_layer.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS);
SET_FLAG_FROM_TEST(new_layer.flag,
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
new_layer.parent_type = static_cast<int8_t>(gpl->partype);
new_layer.blend_mode = static_cast<int8_t>(gpl->blend_mode);
@ -233,7 +236,7 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
copy_v3_v3(new_layer.scale, gpl->scale);
LISTBASE_FOREACH (bGPDframe *, gpf, &gpl->frames) {
grease_pencil.drawing_array[i] = reinterpret_cast<GreasePencilDrawingOrReference *>(
grease_pencil.drawing_array[i] = reinterpret_cast<GreasePencilDrawingBase *>(
MEM_new<GreasePencilDrawing>(__func__));
GreasePencilDrawing &drawing = *reinterpret_cast<GreasePencilDrawing *>(
grease_pencil.drawing_array[i]);
@ -249,6 +252,20 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
}
}
/* Convert the onion skinning settings. */
grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor;
grease_pencil.onion_skinning_settings.mode = gpd.onion_mode;
if (gpd.onion_keytype == -1) {
grease_pencil.onion_skinning_settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
}
else {
grease_pencil.onion_skinning_settings.filter = (1 << gpd.onion_keytype);
}
grease_pencil.onion_skinning_settings.num_frames_before = gpd.gstep;
grease_pencil.onion_skinning_settings.num_frames_after = gpd.gstep_next;
copy_v3_v3(grease_pencil.onion_skinning_settings.color_before, gpd.gcolor_prev);
copy_v3_v3(grease_pencil.onion_skinning_settings.color_after, gpd.gcolor_next);
grease_pencil.runtime->set_active_layer_index(active_layer_index);
BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id);

View File

@ -47,12 +47,28 @@ typedef enum GreasePencilStrokeCapType {
GP_STROKE_CAP_TYPE_MAX,
} GreasePencilStrokeCapType;
/**
* Type of drawing data.
* If `GP_DRAWING` the node is a `GreasePencilDrawing`,
* if `GP_DRAWING_REFERENCE` the node is a `GreasePencilDrawingReference`.
*/
typedef enum GreasePencilDrawingType {
GP_DRAWING = 0,
GP_DRAWING_REFERENCE = 1,
} GreasePencilDrawingType;
typedef struct GreasePencilDrawingOrReference {
/**
* Flag for drawings and drawing references. #GreasePencilDrawingBase.flag
*/
typedef enum GreasePencilDrawingBaseFlag {
/* TODO */
GreasePencilDrawingBaseFlag_TODO
} GreasePencilDrawingBaseFlag;
/**
* Base class for drawings and drawing references (drawings from other objects).
filedescriptor marked this conversation as resolved Outdated

Move below runtime data pointer.

Move below runtime data pointer.
*/
typedef struct GreasePencilDrawingBase {
/**
* One of `GreasePencilDrawingType`.
* Indicates if this is an actual drawing or a drawing referenced from another object.
@ -60,17 +76,17 @@ typedef struct GreasePencilDrawingOrReference {
int8_t type;
char _pad[3];
/**
* Flag. Used to set e.g. the selection status.
* Flag. Used to set e.g. the selection status. See `GreasePencilDrawingBaseFlag`.
*/
uint32_t flag;
} GreasePencilDrawingOrReference;
} GreasePencilDrawingBase;
/**
* A grease pencil drawing is a set of strokes. The data is stored using the `CurvesGeometry` data

I wonder if this user count could be runtime data? Or if not, maybe it's worth mentioning why it isn't in a comment.

I wonder if this user count could be runtime data? Or if not, maybe it's worth mentioning why it isn't in a comment.

I thought about this, but I don't think it can be runtime data. Since there will be keyframe instances, we need to make the user count is saved.

I thought about this, but I don't think it can be runtime data. Since there will be keyframe instances, we need to make the user count is saved.

The connection between keyframe instances and saving the user count isn't super clear to me. Maybe a comment about what the user count is used for here would help?

The connection between keyframe instances and saving the user count isn't super clear to me. Maybe a comment about what the user count is used for here would help?

Maybe it's still better to have this as runtime data. If there is ever a bug where this doesn't get counted correctly, at least a file read could fix it. It should be possible to read this as zero, and increment it for every user?

This is easy to change afterwards though.

Maybe it's still better to have this as runtime data. If there is ever a bug where this doesn't get counted correctly, at least a file read could fix it. It should be possible to read this as zero, and increment it for every user? This is easy to change afterwards though.

I see, re-creating the user count when reading could work indeed.

I see, re-creating the user count when reading could work indeed.
* structure and the custom attributes within it.
*/
typedef struct GreasePencilDrawing {
GreasePencilDrawingOrReference base;
GreasePencilDrawingBase base;
/**
* The stroke data for this drawing.
*/
@ -94,7 +110,7 @@ typedef struct GreasePencilDrawing {
} GreasePencilDrawing;
typedef struct GreasePencilDrawingReference {

What about a single function that returned std::optional rather than a separate "has_" function?

What about a single function that returned `std::optional` rather than a separate "has_" function?
GreasePencilDrawingOrReference base;
GreasePencilDrawingBase base;

Looks like stroke_buffer() can be const

Looks like `stroke_buffer()` can be `const`
/**
* A reference to another GreasePencil data-block.
* If the data-block has multiple drawings, this drawing references all of them sequentially.
@ -237,6 +253,11 @@ typedef struct GreasePencilLayer {
float location[3], rotation[3], scale[3];
} GreasePencilLayer;

typo transform

typo `transform`
/**
* Type of layer node.
* If `GP_LAYER_TREE_LEAF` the node is a `GreasePencilLayerTreeLeaf`,
* if `GP_LAYER_TREE_GROUP` the node is a `GreasePencilLayerTreeGroup`.
*/
typedef enum GreasePencilLayerTreeNodeType {
GP_LAYER_TREE_LEAF = 0,
GP_LAYER_TREE_GROUP = 1,
@ -251,6 +272,7 @@ typedef enum GreasePencilLayerTreeNodeFlag {
GP_LAYER_TREE_NODE_SELECT = (1 << 2),
GP_LAYER_TREE_NODE_MUTE = (1 << 3),
GP_LAYER_TREE_NODE_USE_LIGHTS = (1 << 4),
GP_LAYER_TREE_NODE_USE_ONION_SKINNING = (1 << 5),
} GreasePencilLayerTreeNodeFlag;
typedef struct GreasePencilLayerTreeNode {
@ -297,6 +319,77 @@ typedef struct GreasePencilLayerTreeStorage {
int active_layer_index;
} GreasePencilLayerTreeStorage;
/**
* Flag for the grease pencil data-block. #GreasePencil.flag
*/
typedef enum GreasePencilFlag {
/* TODO */
GreasePencilFlag_TODO
} GreasePencilFlag;
/**
* Onion skinning mode. #GreasePencilOnionSkinningSettings.mode
*/
typedef enum GreasePencilOnionSkinningMode {
GP_ONION_SKINNING_MODE_ABSOLUTE = 0,
GP_ONION_SKINNING_MODE_RELATIVE = 1,
GP_ONION_SKINNING_MODE_SELECTED = 2,
} GreasePencilOnionSkinningMode;
/**
* Flag for filtering the onion skinning per keyframe type.
* #GreasePencilOnionSkinningSettings.filter
* \note needs to match order of `eBezTriple_KeyframeType`.
*/
typedef enum GreasePencilOnionSkinningFilter {
GP_ONION_SKINNING_FILTER_KEYTYPE_KEYFRAME = (1 << 0),
GP_ONION_SKINNING_FILTER_KEYTYPE_EXTREME = (1 << 1),
GP_ONION_SKINNING_FILTER_KEYTYPE_BREAKDOWN = (1 << 2),
GP_ONION_SKINNING_FILTER_KEYTYPE_JITTER = (1 << 3),
GP_ONION_SKINNING_FILTER_KEYTYPE_MOVEHOLD = (1 << 4),
} GreasePencilOnionSkinningFilter;
#define GREASE_PENCIL_ONION_SKINNING_FILTER_ALL \
(GP_ONION_SKINNING_FILTER_KEYTYPE_KEYFRAME | GP_ONION_SKINNING_FILTER_KEYTYPE_EXTREME | \
GP_ONION_SKINNING_FILTER_KEYTYPE_BREAKDOWN | GP_ONION_SKINNING_FILTER_KEYTYPE_JITTER | \
GP_ONION_SKINNING_FILTER_KEYTYPE_MOVEHOLD)
/**
* Per data-block Grease Pencil onion skinning settings.
*/
typedef struct GreasePencilOnionSkinningSettings {
/**
* Opacity for the ghost frames.
*/
float opacity;
/**
* Onion skinning mode. See `GreasePencilOnionSkinningMode`.
*/
int8_t mode;
/**
* Onion skinning filtering flag. See `GreasePencilOnionSkinningFilter`.
*/
uint8_t filter;
char _pad[2];
/**
* Number of ghost frames shown before.
*/
int16_t num_frames_before;
/**
* Number of ghost frames shown after.
*/
int16_t num_frames_after;
/**
* Color of the ghost frames before.
*/
float color_before[3];
/**
* Color of the ghost frames after.
*/
float color_after[3];
char _pad2[4];
} GreasePencilOnionSkinningSettings;
/**
* The grease pencil data-block.
*/
@ -310,7 +403,7 @@ typedef struct GreasePencil {
* data-block. Note that the order of this array is arbitrary. The mapping of drawings to frames
* is done by the layers. See the `Layer` class in `BKE_grease_pencil.hh`.
*/
GreasePencilDrawingOrReference **drawing_array;
GreasePencilDrawingBase **drawing_array;
int drawing_array_size;
char _pad[4];
#ifdef __cplusplus

Grammar: it's data -> its data

Grammar: `it's data` -> `its data`
@ -333,19 +426,21 @@ typedef struct GreasePencil {
struct Material **material_array;
short material_array_size;
char _pad2[2];
/**
* Global flag on the data-block.
*/
uint32_t flag;
/**
* Onion skinning settings.
*/
GreasePencilOnionSkinningSettings onion_skinning_settings;
/**
* Runtime struct pointer.
*/
GreasePencilRuntimeHandle *runtime;
#ifdef __cplusplus
blender::Span<GreasePencilDrawingOrReference *> drawings() const;
blender::MutableSpan<GreasePencilDrawingOrReference *> drawings_for_write();
blender::Span<GreasePencilDrawingBase *> drawings() const;
blender::MutableSpan<GreasePencilDrawingBase *> drawings_for_write();
void add_empty_drawings(int n);
void remove_drawing(int index);
void foreach_visible_drawing(int frame,