GPv3: Onion Skinning
Implements the GPv2 onion skinning functionality. There are no functional changes exept for the `use_ghosts_always` option, which has been removed. This was used to show onion skinning in the final render. Pull Request: https://projects.blender.org/blender/blender/pulls/119792
This commit is contained in:
@@ -231,6 +231,72 @@ class DATA_PT_grease_pencil_layer_relations(LayerDataButtonsPanel, Panel):
|
||||
col.prop_search(layer, "viewlayer_render", context.scene, "view_layers", text="View Layer")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_onion_skinning(DataButtonsPanel, Panel):
|
||||
bl_label = "Onion Skinning"
|
||||
|
||||
def draw(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
|
||||
col = layout.column()
|
||||
col.prop(grease_pencil, "onion_mode")
|
||||
col.prop(grease_pencil, "onion_factor", text="Opacity", slider=True)
|
||||
col.prop(grease_pencil, "onion_keyframe_type")
|
||||
|
||||
if grease_pencil.onion_mode == 'ABSOLUTE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(grease_pencil, "ghost_before_range", text="Frames Before")
|
||||
col.prop(grease_pencil, "ghost_after_range", text="Frames After")
|
||||
elif grease_pencil.onion_mode == 'RELATIVE':
|
||||
col = layout.column(align=True)
|
||||
col.prop(grease_pencil, "ghost_before_range", text="Keyframes Before")
|
||||
col.prop(grease_pencil, "ghost_after_range", text="Keyframes After")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_onion_skinning_custom_colors(DataButtonsPanel, Panel):
|
||||
bl_parent_id = "DATA_PT_grease_pencil_onion_skinning"
|
||||
bl_label = "Custom Colors"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw_header(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
self.layout.prop(grease_pencil, "use_ghost_custom_colors", text="")
|
||||
|
||||
def draw(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
layout.enabled = grease_pencil.users <= 1 and grease_pencil.use_ghost_custom_colors
|
||||
|
||||
layout.prop(grease_pencil, "before_color", text="Before")
|
||||
layout.prop(grease_pencil, "after_color", text="After")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_onion_skinning_display(DataButtonsPanel, Panel):
|
||||
bl_parent_id = "DATA_PT_grease_pencil_onion_skinning"
|
||||
bl_label = "Display"
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
def draw(self, context):
|
||||
grease_pencil = context.grease_pencil
|
||||
|
||||
layout = self.layout
|
||||
layout.use_property_split = True
|
||||
# This was done in GPv2 but it's not entirely clear why. Presumably it was
|
||||
# to indicate that the settings will affect the onion skinning of the
|
||||
# other users.
|
||||
layout.enabled = grease_pencil.users <= 1
|
||||
|
||||
col = layout.column(align=True)
|
||||
col.prop(grease_pencil, "use_onion_fade", text="Fade")
|
||||
sub = layout.column()
|
||||
sub.active = grease_pencil.onion_mode in {'RELATIVE', 'SELECTED'}
|
||||
sub.prop(grease_pencil, "use_onion_loop", text="Show Start Frame")
|
||||
|
||||
|
||||
class DATA_PT_grease_pencil_settings(DataButtonsPanel, Panel):
|
||||
bl_label = "Settings"
|
||||
|
||||
@@ -257,6 +323,9 @@ classes = (
|
||||
DATA_PT_grease_pencil_layer_masks,
|
||||
DATA_PT_grease_pencil_layer_transform,
|
||||
DATA_PT_grease_pencil_layer_relations,
|
||||
DATA_PT_grease_pencil_onion_skinning,
|
||||
DATA_PT_grease_pencil_onion_skinning_custom_colors,
|
||||
DATA_PT_grease_pencil_onion_skinning_display,
|
||||
DATA_PT_grease_pencil_settings,
|
||||
DATA_PT_grease_pencil_custom_props,
|
||||
GREASE_PENCIL_MT_grease_pencil_add_layer_extra,
|
||||
|
||||
@@ -7861,6 +7861,8 @@ class VIEW3D_PT_overlay_grease_pencil_options(Panel):
|
||||
'OBJECT': iface_("Grease Pencil"),
|
||||
}[context.mode], translate=False)
|
||||
|
||||
layout.prop(overlay, "use_gpencil_onion_skin", text="Onion Skin")
|
||||
|
||||
if ob.mode in {'EDIT'}:
|
||||
split = layout.split()
|
||||
col = split.column()
|
||||
|
||||
@@ -105,6 +105,7 @@ set(SRC_DNA_DEFAULTS_INC
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_fluid_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_gpencil_modifier_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_grease_pencil_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_image_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_lattice_defaults.h
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/makesdna/DNA_light_defaults.h
|
||||
|
||||
@@ -703,7 +703,8 @@ inline void TreeNode::set_selected(const bool selected)
|
||||
}
|
||||
inline bool TreeNode::use_onion_skinning() const
|
||||
{
|
||||
return ((this->flag & GP_LAYER_TREE_NODE_USE_ONION_SKINNING) != 0);
|
||||
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
|
||||
{
|
||||
|
||||
@@ -42,6 +42,7 @@
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_ref.hh"
|
||||
#include "BLI_string_utils.hh"
|
||||
#include "BLI_utildefines.h"
|
||||
#include "BLI_vector_set.hh"
|
||||
#include "BLI_virtual_array.hh"
|
||||
|
||||
@@ -52,6 +53,7 @@
|
||||
#include "DNA_ID.h"
|
||||
#include "DNA_ID_enums.h"
|
||||
#include "DNA_brush_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_material_types.h"
|
||||
@@ -80,10 +82,12 @@ static void grease_pencil_init_data(ID *id)
|
||||
using namespace blender::bke;
|
||||
|
||||
GreasePencil *grease_pencil = reinterpret_cast<GreasePencil *>(id);
|
||||
BLI_assert(MEMCMP_STRUCT_AFTER_IS_ZERO(grease_pencil, id));
|
||||
|
||||
MEMCPY_STRUCT_AFTER(grease_pencil, DNA_struct_default_get(GreasePencil), id);
|
||||
|
||||
grease_pencil->root_group_ptr = MEM_new<greasepencil::LayerGroup>(__func__);
|
||||
grease_pencil->active_layer = nullptr;
|
||||
grease_pencil->flag |= GREASE_PENCIL_ANIM_CHANNEL_EXPANDED;
|
||||
|
||||
CustomData_reset(&grease_pencil->layers_data);
|
||||
|
||||
|
||||
@@ -581,8 +581,8 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
||||
SET_FLAG_FROM_TEST(
|
||||
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_LIGHTS), GP_LAYER_TREE_NODE_USE_LIGHTS);
|
||||
SET_FLAG_FROM_TEST(new_layer.base.flag,
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN),
|
||||
GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
|
||||
(gpl->onion_flag & GP_LAYER_ONIONSKIN) == 0,
|
||||
GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
|
||||
SET_FLAG_FROM_TEST(
|
||||
new_layer.base.flag, (gpl->flag & GP_LAYER_USE_MASK) == 0, GP_LAYER_TREE_NODE_HIDE_MASKS);
|
||||
|
||||
@@ -646,18 +646,28 @@ void legacy_gpencil_to_grease_pencil(Main &bmain, GreasePencil &grease_pencil, b
|
||||
grease_pencil.vertex_group_active_index = gpd.vertex_group_active_index;
|
||||
|
||||
/* Convert the onion skinning settings. */
|
||||
grease_pencil.onion_skinning_settings.opacity = gpd.onion_factor;
|
||||
grease_pencil.onion_skinning_settings.mode = gpd.onion_mode;
|
||||
GreasePencilOnionSkinningSettings &settings = grease_pencil.onion_skinning_settings;
|
||||
settings.opacity = gpd.onion_factor;
|
||||
settings.mode = gpd.onion_mode;
|
||||
SET_FLAG_FROM_TEST(settings.flag,
|
||||
((gpd.onion_flag & GP_ONION_GHOST_PREVCOL) != 0 &&
|
||||
(gpd.onion_flag & GP_ONION_GHOST_NEXTCOL) != 0),
|
||||
GP_ONION_SKINNING_USE_CUSTOM_COLORS);
|
||||
SET_FLAG_FROM_TEST(
|
||||
settings.flag, (gpd.onion_flag & GP_ONION_FADE) != 0, GP_ONION_SKINNING_USE_FADE);
|
||||
SET_FLAG_FROM_TEST(
|
||||
settings.flag, (gpd.onion_flag & GP_ONION_LOOP) != 0, GP_ONION_SKINNING_SHOW_LOOP);
|
||||
/* Convert keytype filter to a bit flag. */
|
||||
if (gpd.onion_keytype == -1) {
|
||||
grease_pencil.onion_skinning_settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
|
||||
settings.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL;
|
||||
}
|
||||
else {
|
||||
grease_pencil.onion_skinning_settings.filter = (1 << gpd.onion_keytype);
|
||||
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);
|
||||
settings.num_frames_before = gpd.gstep;
|
||||
settings.num_frames_after = gpd.gstep_next;
|
||||
copy_v3_v3(settings.color_before, gpd.gcolor_prev);
|
||||
copy_v3_v3(settings.color_after, gpd.gcolor_next);
|
||||
|
||||
BKE_id_materials_copy(&bmain, &gpd.id, &grease_pencil.id);
|
||||
|
||||
|
||||
@@ -261,6 +261,49 @@ static void gpencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd
|
||||
*r_alpha *= pd->xray_alpha;
|
||||
}
|
||||
|
||||
static float4 grease_pencil_layer_final_tint_and_alpha_get(const GPENCIL_PrivateData *pd,
|
||||
const GreasePencil &grease_pencil,
|
||||
const int onion_id,
|
||||
float *r_alpha)
|
||||
{
|
||||
const bool use_onion = (onion_id != 0);
|
||||
if (use_onion) {
|
||||
const bool use_onion_custom_col = (grease_pencil.onion_skinning_settings.flag &
|
||||
GP_ONION_SKINNING_USE_CUSTOM_COLORS) != 0;
|
||||
const bool use_onion_fade = (grease_pencil.onion_skinning_settings.flag &
|
||||
GP_ONION_SKINNING_USE_FADE) != 0;
|
||||
const bool use_next_col = onion_id > 0;
|
||||
|
||||
const float onion_factor = grease_pencil.onion_skinning_settings.opacity;
|
||||
const float3 color_next(grease_pencil.onion_skinning_settings.color_after);
|
||||
const float3 color_prev(grease_pencil.onion_skinning_settings.color_before);
|
||||
|
||||
const float4 onion_col_custom = (use_onion_custom_col) ?
|
||||
(use_next_col ? float4(color_next, 1.0f) :
|
||||
float4(color_prev, 1.0f)) :
|
||||
float4(U.gpencil_new_layer_col);
|
||||
|
||||
*r_alpha = use_onion_fade ? (1.0f / abs(onion_id)) : 0.5f;
|
||||
*r_alpha *= onion_factor;
|
||||
*r_alpha = (onion_factor > 0.0f) ? clamp_f(*r_alpha, 0.1f, 1.0f) :
|
||||
clamp_f(*r_alpha, 0.01f, 1.0f);
|
||||
*r_alpha *= pd->xray_alpha;
|
||||
|
||||
return onion_col_custom;
|
||||
}
|
||||
|
||||
/* Layer tint is not a property in GPv3 anymore. It's only used for onion skinning. The previous
|
||||
* property is replaced by a tint modifier during conversion. */
|
||||
float4 layer_tint(0.0f);
|
||||
if (GPENCIL_SIMPLIFY_TINT(pd->scene)) {
|
||||
layer_tint[3] = 0.0f;
|
||||
}
|
||||
*r_alpha = 1.0f;
|
||||
*r_alpha *= pd->xray_alpha;
|
||||
|
||||
return layer_tint;
|
||||
}
|
||||
|
||||
/* Random color by layer. */
|
||||
static void gpencil_layer_random_color_get(const Object *ob,
|
||||
const bGPDlayer *gpl,
|
||||
@@ -473,7 +516,7 @@ GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number)
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
|
||||
const Object *ob,
|
||||
const blender::bke::greasepencil::Layer &layer,
|
||||
std::optional<int> /*onion_id*/,
|
||||
const int onion_id,
|
||||
GPENCIL_tObject *tgp_ob)
|
||||
|
||||
{
|
||||
@@ -501,10 +544,9 @@ GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
|
||||
float thickness_scale = (is_screenspace) ? -1.0f : 1.0f / 1000.0f;
|
||||
float layer_opacity = grease_pencil_layer_final_opacity_get(pd, ob, grease_pencil, layer);
|
||||
|
||||
float4 layer_tint(0.0f);
|
||||
float layer_alpha = pd->xray_alpha;
|
||||
/* TODO: Onion skinning! */
|
||||
// gpencil_layer_final_tint_and_alpha_get(pd, gpd, gpl, gpf, layer_tint, &layer_alpha);
|
||||
const float4 layer_tint = grease_pencil_layer_final_tint_and_alpha_get(
|
||||
pd, grease_pencil, onion_id, &layer_alpha);
|
||||
|
||||
/* Create the new layer descriptor. */
|
||||
GPENCIL_tLayer *tgp_layer = static_cast<GPENCIL_tLayer *>(BLI_memblock_alloc(pd->gp_layer_pool));
|
||||
|
||||
@@ -338,7 +338,7 @@ GPENCIL_tLayer *gpencil_layer_cache_get(GPENCIL_tObject *tgp_ob, int number);
|
||||
GPENCIL_tLayer *grease_pencil_layer_cache_add(GPENCIL_PrivateData *pd,
|
||||
const Object *ob,
|
||||
const blender::bke::greasepencil::Layer &layer,
|
||||
std::optional<int> onion_id,
|
||||
int onion_id,
|
||||
GPENCIL_tObject *tgp_ob);
|
||||
/**
|
||||
* Creates a linked list of material pool containing all materials assigned for a given object.
|
||||
|
||||
@@ -614,6 +614,9 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData
|
||||
const blender::Bounds<float3> bounds = grease_pencil.bounds_min_max_eval().value_or(
|
||||
blender::Bounds(float3(0)));
|
||||
|
||||
const bool do_onion = !pd->is_render && pd->do_onion;
|
||||
const bool do_multi_frame = (pd->scene->toolsettings->gpencil_flags &
|
||||
GP_USE_MULTI_FRAME_EDITING) != 0;
|
||||
const bool use_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0;
|
||||
GPENCIL_tObject *tgp_ob = gpencil_object_cache_add(pd, ob, use_stroke_order_3d, bounds);
|
||||
|
||||
@@ -658,14 +661,17 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData
|
||||
};
|
||||
|
||||
int t_offset = 0;
|
||||
const Vector<DrawingInfo> drawings = retrieve_visible_drawings(*pd->scene, grease_pencil);
|
||||
/* Note that we loop over all the drawings (including the onion skinned ones) to make sure we
|
||||
* match the offsets of the batch cache. */
|
||||
const Vector<DrawingInfo> drawings = retrieve_visible_drawings(*pd->scene, grease_pencil, true);
|
||||
const Span<const Layer *> layers = grease_pencil.layers();
|
||||
for (const DrawingInfo info : drawings) {
|
||||
const Layer &layer = *layers[info.layer_index];
|
||||
|
||||
drawcall_flush();
|
||||
|
||||
GPENCIL_tLayer *tgp_layer = grease_pencil_layer_cache_add(pd, ob, layer, {}, tgp_ob);
|
||||
GPENCIL_tLayer *tgp_layer = grease_pencil_layer_cache_add(
|
||||
pd, ob, layer, info.onion_id, tgp_ob);
|
||||
|
||||
const bool use_lights = pd->use_lighting &&
|
||||
((layer.base.flag & GP_LAYER_TREE_NODE_USE_LIGHTS) != 0) &&
|
||||
@@ -714,9 +720,9 @@ static GPENCIL_tObject *grease_pencil_object_cache_populate(GPENCIL_PrivateData
|
||||
OB_MODE_WEIGHT_PAINT,
|
||||
OB_MODE_VERTEX_PAINT) &&
|
||||
info.frame_number != pd->cfra && pd->use_multiedit_lines_only;
|
||||
/* bool is_onion = gpl && gpf && gpf->runtime.onion_id != 0; */
|
||||
const bool is_onion = false;
|
||||
const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0);
|
||||
const bool is_onion = info.onion_id != 0;
|
||||
const bool hide_onion = is_onion && ((gp_style->flag & GP_MATERIAL_HIDE_ONIONSKIN) != 0 ||
|
||||
(!do_onion && !do_multi_frame));
|
||||
|
||||
const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0;
|
||||
const int num_stroke_vertices = (points.size() +
|
||||
|
||||
@@ -293,7 +293,7 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene,
|
||||
}
|
||||
|
||||
int t_offset = 0;
|
||||
const Vector<DrawingInfo> drawings = retrieve_visible_drawings(*scene, grease_pencil);
|
||||
const Vector<DrawingInfo> drawings = retrieve_visible_drawings(*scene, grease_pencil, true);
|
||||
for (const DrawingInfo info : drawings) {
|
||||
const bool is_screenspace = false;
|
||||
const bool is_stroke_order_3d = (grease_pencil.flag & GREASE_PENCIL_STROKE_ORDER_3D) != 0;
|
||||
@@ -332,8 +332,16 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene,
|
||||
const int material_index = stroke_materials[stroke_i];
|
||||
MaterialGPencilStyle *gp_style = BKE_gpencil_material_settings(ob, material_index + 1);
|
||||
|
||||
const bool hide_onion = info.onion_id != 0;
|
||||
const bool hide_material = (gp_style->flag & GP_MATERIAL_HIDE) != 0;
|
||||
if (hide_material) {
|
||||
|
||||
const int num_stroke_triangles = (points.size() >= 3) ? (points.size() - 2) : 0;
|
||||
const int num_stroke_vertices = (points.size() +
|
||||
int(cyclic[stroke_i] && (points.size() >= 3)));
|
||||
|
||||
if (hide_material || hide_onion) {
|
||||
t_offset += num_stroke_triangles;
|
||||
t_offset += num_stroke_vertices * 2;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -341,22 +349,19 @@ static void OVERLAY_outline_grease_pencil(OVERLAY_PrivateData *pd, Scene *scene,
|
||||
|
||||
const bool show_stroke = (gp_style->flag & GP_MATERIAL_STROKE_SHOW) != 0;
|
||||
const bool show_fill = (points.size() >= 3) && (gp_style->flag & GP_MATERIAL_FILL_SHOW) != 0;
|
||||
const bool is_cyclic = cyclic[stroke_i] && (points.size() > 2);
|
||||
const int num_stroke_triangles = points.size() - 2;
|
||||
const int num_stroke_vertices = (points.size() + int(is_cyclic));
|
||||
|
||||
if (show_fill) {
|
||||
int vfirst = t_offset * 3;
|
||||
int vcount = num_stroke_triangles * 3;
|
||||
DRW_shgroup_call_range(grp, ob, geom, vfirst, vcount);
|
||||
int v_first = t_offset * 3;
|
||||
int v_count = num_stroke_triangles * 3;
|
||||
DRW_shgroup_call_range(grp, ob, geom, v_first, v_count);
|
||||
}
|
||||
|
||||
t_offset += num_stroke_triangles;
|
||||
|
||||
if (show_stroke) {
|
||||
int vfirst = t_offset * 3;
|
||||
int vcount = num_stroke_vertices * 2 * 3;
|
||||
DRW_shgroup_call_range(grp, ob, geom, vfirst, vcount);
|
||||
int v_first = t_offset * 3;
|
||||
int v_count = num_stroke_vertices * 2 * 3;
|
||||
DRW_shgroup_call_range(grp, ob, geom, v_first, v_count);
|
||||
}
|
||||
t_offset += num_stroke_vertices * 2;
|
||||
});
|
||||
|
||||
@@ -229,7 +229,7 @@ static void grease_pencil_edit_batch_ensure(Object &object,
|
||||
|
||||
/* Get the visible drawings. */
|
||||
const Vector<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil);
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, false);
|
||||
|
||||
const Span<const Layer *> layers = grease_pencil.layers();
|
||||
|
||||
@@ -423,7 +423,7 @@ static void grease_pencil_geom_batch_ensure(Object &object,
|
||||
|
||||
/* Get the visible drawings. */
|
||||
const Vector<ed::greasepencil::DrawingInfo> drawings =
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil);
|
||||
ed::greasepencil::retrieve_visible_drawings(scene, grease_pencil, true);
|
||||
|
||||
/* First, count how many vertices and triangles are needed for the whole object. Also record the
|
||||
* offsets into the curves for the vertices and triangles. */
|
||||
|
||||
@@ -230,9 +230,132 @@ static std::pair<int, int> get_minmax_selected_frame_numbers(const GreasePencil
|
||||
return std::pair<int, int>(frame_min, frame_max);
|
||||
}
|
||||
|
||||
static Array<int> get_frame_numbers_for_layer(const bke::greasepencil::Layer &layer,
|
||||
const int current_frame,
|
||||
const bool use_multi_frame_editing)
|
||||
static std::optional<int> get_frame_id(const bke::greasepencil::Layer &layer,
|
||||
const GreasePencilFrame &frame,
|
||||
const int frame_number,
|
||||
const int frame_index,
|
||||
const int current_frame,
|
||||
const int current_frame_index,
|
||||
const int last_frame,
|
||||
const int last_frame_index,
|
||||
const bool use_multi_frame_editing,
|
||||
const bool do_onion_skinning,
|
||||
const bool is_before_first,
|
||||
const GreasePencilOnionSkinningSettings onion_settings)
|
||||
{
|
||||
if (use_multi_frame_editing) {
|
||||
if (frame.is_selected()) {
|
||||
if (do_onion_skinning) {
|
||||
return (frame_number < current_frame) ? -1 : 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
if (do_onion_skinning && layer.use_onion_skinning()) {
|
||||
/* Keyframe type filter. */
|
||||
if (onion_settings.filter != 0 && (onion_settings.filter & (1 << frame.type)) == 0) {
|
||||
return {};
|
||||
}
|
||||
/* Selected mode filter. */
|
||||
if (onion_settings.mode == GP_ONION_SKINNING_MODE_SELECTED && !frame.is_selected()) {
|
||||
return {};
|
||||
}
|
||||
|
||||
int delta = 0;
|
||||
if (onion_settings.mode == GP_ONION_SKINNING_MODE_ABSOLUTE) {
|
||||
delta = frame_number - current_frame;
|
||||
}
|
||||
else {
|
||||
delta = frame_index - current_frame_index;
|
||||
}
|
||||
|
||||
if (is_before_first) {
|
||||
delta++;
|
||||
}
|
||||
if ((onion_settings.flag & GP_ONION_SKINNING_SHOW_LOOP) != 0 &&
|
||||
(-delta > onion_settings.num_frames_before || delta > onion_settings.num_frames_after))
|
||||
{
|
||||
/* We wrap the value using the last frame and 0 as reference. */
|
||||
/* FIXME: This might not be good for animations not starting at 0. */
|
||||
int shift = 0;
|
||||
if (onion_settings.mode == GP_ONION_SKINNING_MODE_ABSOLUTE) {
|
||||
shift = last_frame;
|
||||
}
|
||||
else {
|
||||
shift = last_frame_index;
|
||||
}
|
||||
delta += (delta < 0) ? (shift + 1) : -(shift + 1);
|
||||
}
|
||||
/* Frame range filter. */
|
||||
if (ELEM(onion_settings.mode,
|
||||
GP_ONION_SKINNING_MODE_ABSOLUTE,
|
||||
GP_ONION_SKINNING_MODE_RELATIVE) &&
|
||||
(-delta > onion_settings.num_frames_before || delta > onion_settings.num_frames_after))
|
||||
{
|
||||
return {};
|
||||
}
|
||||
|
||||
return delta;
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
static Array<std::pair<int, int>> get_visible_frames_for_layer(
|
||||
const GreasePencil &grease_pencil,
|
||||
const bke::greasepencil::Layer &layer,
|
||||
const int current_frame,
|
||||
const bool use_multi_frame_editing,
|
||||
const bool do_onion_skinning)
|
||||
{
|
||||
GreasePencilOnionSkinningSettings onion_settings = grease_pencil.onion_skinning_settings;
|
||||
Vector<std::pair<int, int>> frame_numbers;
|
||||
const Span<int> sorted_keys = layer.sorted_keys();
|
||||
if (sorted_keys.is_empty()) {
|
||||
return {};
|
||||
}
|
||||
const std::optional<bke::greasepencil::FramesMapKey> current_frame_key = layer.frame_key_at(
|
||||
current_frame);
|
||||
const int current_frame_index = current_frame_key.has_value() ?
|
||||
sorted_keys.first_index(*current_frame_key) :
|
||||
0;
|
||||
const int last_frame = sorted_keys.last();
|
||||
const int last_frame_index = sorted_keys.index_range().last();
|
||||
const bool is_before_first = (current_frame < sorted_keys.first());
|
||||
for (const int frame_i : sorted_keys.index_range()) {
|
||||
const int frame_number = sorted_keys[frame_i];
|
||||
if (frame_number == current_frame) {
|
||||
continue;
|
||||
}
|
||||
const GreasePencilFrame &frame = layer.frames().lookup(frame_number);
|
||||
const std::optional<int> frame_id = get_frame_id(layer,
|
||||
frame,
|
||||
frame_number,
|
||||
frame_i,
|
||||
current_frame,
|
||||
current_frame_index,
|
||||
last_frame,
|
||||
last_frame_index,
|
||||
use_multi_frame_editing,
|
||||
do_onion_skinning,
|
||||
is_before_first,
|
||||
onion_settings);
|
||||
if (!frame_id.has_value()) {
|
||||
/* Drawing on this frame is not visible. */
|
||||
continue;
|
||||
}
|
||||
|
||||
frame_numbers.append({frame_number, *frame_id});
|
||||
}
|
||||
|
||||
frame_numbers.append({current_frame, 0});
|
||||
|
||||
return frame_numbers.as_span();
|
||||
}
|
||||
|
||||
static Array<int> get_editable_frames_for_layer(const bke::greasepencil::Layer &layer,
|
||||
const int current_frame,
|
||||
const bool use_multi_frame_editing)
|
||||
{
|
||||
Vector<int> frame_numbers;
|
||||
if (use_multi_frame_editing) {
|
||||
@@ -271,7 +394,7 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings(const Scene &scene,
|
||||
if (!layer.is_editable()) {
|
||||
continue;
|
||||
}
|
||||
const Array<int> frame_numbers = get_frame_numbers_for_layer(
|
||||
const Array<int> frame_numbers = get_editable_frames_for_layer(
|
||||
layer, current_frame, use_multi_frame_editing);
|
||||
for (const int frame_number : frame_numbers) {
|
||||
if (Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, frame_number)) {
|
||||
@@ -309,7 +432,7 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings_with_falloff(const Scene &
|
||||
if (!layer.is_editable()) {
|
||||
continue;
|
||||
}
|
||||
const Array<int> frame_numbers = get_frame_numbers_for_layer(
|
||||
const Array<int> frame_numbers = get_editable_frames_for_layer(
|
||||
layer, current_frame, use_multi_frame_editing);
|
||||
for (const int frame_number : frame_numbers) {
|
||||
if (Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, frame_number)) {
|
||||
@@ -340,7 +463,7 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer(
|
||||
GP_USE_MULTI_FRAME_EDITING) != 0;
|
||||
|
||||
Vector<MutableDrawingInfo> editable_drawings;
|
||||
const Array<int> frame_numbers = get_frame_numbers_for_layer(
|
||||
const Array<int> frame_numbers = get_editable_frames_for_layer(
|
||||
layer, current_frame, use_multi_frame_editing);
|
||||
for (const int frame_number : frame_numbers) {
|
||||
if (Drawing *drawing = grease_pencil.get_editable_drawing_at(layer, frame_number)) {
|
||||
@@ -353,7 +476,8 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer(
|
||||
}
|
||||
|
||||
Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
const GreasePencil &grease_pencil)
|
||||
const GreasePencil &grease_pencil,
|
||||
const bool do_onion_skinning)
|
||||
{
|
||||
using namespace blender::bke::greasepencil;
|
||||
const int current_frame = scene.r.cfra;
|
||||
@@ -368,11 +492,11 @@ Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
if (!layer.is_visible()) {
|
||||
continue;
|
||||
}
|
||||
const Array<int> frame_numbers = get_frame_numbers_for_layer(
|
||||
layer, current_frame, use_multi_frame_editing);
|
||||
for (const int frame_number : frame_numbers) {
|
||||
const Array<std::pair<int, int>> frames = get_visible_frames_for_layer(
|
||||
grease_pencil, layer, current_frame, use_multi_frame_editing, do_onion_skinning);
|
||||
for (const auto &[frame_number, onion_id] : frames) {
|
||||
if (const Drawing *drawing = grease_pencil.get_drawing_at(layer, frame_number)) {
|
||||
visible_drawings.append({*drawing, layer_i, frame_number});
|
||||
visible_drawings.append({*drawing, layer_i, frame_number, onion_id});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -180,6 +180,11 @@ struct DrawingInfo {
|
||||
const bke::greasepencil::Drawing &drawing;
|
||||
const int layer_index;
|
||||
const int frame_number;
|
||||
/* This is used by the onion skinning system. A value of 0 means the drawing is on the current
|
||||
* frame. Negative values are before the current frame, positive values are drawings after the
|
||||
* current frame. The magnitude of the value indicates how far the drawing is from the current
|
||||
* frame (either in absolute frames, or in number of keyframes). */
|
||||
const int onion_id;
|
||||
};
|
||||
struct MutableDrawingInfo {
|
||||
bke::greasepencil::Drawing &drawing;
|
||||
@@ -194,7 +199,8 @@ Vector<MutableDrawingInfo> retrieve_editable_drawings_with_falloff(const Scene &
|
||||
Vector<MutableDrawingInfo> retrieve_editable_drawings_from_layer(
|
||||
const Scene &scene, GreasePencil &grease_pencil, const bke::greasepencil::Layer &layer);
|
||||
Vector<DrawingInfo> retrieve_visible_drawings(const Scene &scene,
|
||||
const GreasePencil &grease_pencil);
|
||||
const GreasePencil &grease_pencil,
|
||||
bool do_onion_skinning);
|
||||
|
||||
IndexMask retrieve_editable_strokes(Object &grease_pencil_object,
|
||||
const bke::greasepencil::Drawing &drawing,
|
||||
|
||||
@@ -263,6 +263,10 @@ class LayerViewItem : public AbstractTreeViewItem {
|
||||
ICON_CLIPUV_HLT;
|
||||
uiItemR(sub, &layer_ptr, "use_masks", UI_ITEM_R_ICON_ONLY, nullptr, icon_mask);
|
||||
|
||||
sub = uiLayoutRow(&row, true);
|
||||
uiLayoutSetActive(sub, layer_.parent_group().use_onion_skinning());
|
||||
uiItemR(sub, &layer_ptr, "use_onion_skinning", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
|
||||
sub = uiLayoutRow(&row, true);
|
||||
uiLayoutSetActive(sub, layer_.parent_group().is_visible());
|
||||
uiItemR(sub, &layer_ptr, "hide", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
@@ -349,6 +353,12 @@ class LayerGroupViewItem : public AbstractTreeViewItem {
|
||||
ICON_CLIPUV_HLT;
|
||||
uiItemR(sub, &group_ptr, "use_masks", UI_ITEM_R_ICON_ONLY, nullptr, icon_mask);
|
||||
|
||||
sub = uiLayoutRow(&row, true);
|
||||
if (group_.as_node().parent_group()) {
|
||||
uiLayoutSetActive(sub, group_.as_node().parent_group()->use_onion_skinning());
|
||||
}
|
||||
uiItemR(sub, &group_ptr, "use_onion_skinning", UI_ITEM_R_ICON_ONLY, nullptr, ICON_NONE);
|
||||
|
||||
sub = uiLayoutRow(&row, true);
|
||||
if (group_.as_node().parent_group()) {
|
||||
uiLayoutSetActive(sub, group_.as_node().parent_group()->is_visible());
|
||||
|
||||
38
source/blender/makesdna/DNA_grease_pencil_defaults.h
Normal file
38
source/blender/makesdna/DNA_grease_pencil_defaults.h
Normal file
@@ -0,0 +1,38 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup DNA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
/* clang-format off */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name Grease Pencil Struct
|
||||
* \{ */
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencilOnionSkinningSettings \
|
||||
{ \
|
||||
.opacity = 0.5f, \
|
||||
.mode = GP_ONION_SKINNING_MODE_RELATIVE, \
|
||||
.flag = (GP_ONION_SKINNING_USE_FADE | GP_ONION_SKINNING_USE_CUSTOM_COLORS), \
|
||||
.filter = GREASE_PENCIL_ONION_SKINNING_FILTER_ALL, \
|
||||
.num_frames_before = 1, \
|
||||
.num_frames_after = 1, \
|
||||
.color_before = {0.145098f, 0.419608f, 0.137255f}, \
|
||||
.color_after = {0.125490f, 0.082353f, 0.529412f},\
|
||||
}
|
||||
|
||||
|
||||
#define _DNA_DEFAULT_GreasePencil \
|
||||
{ \
|
||||
.flag = GREASE_PENCIL_ANIM_CHANNEL_EXPANDED, \
|
||||
.onion_skinning_settings = _DNA_DEFAULT_GreasePencilOnionSkinningSettings, \
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* clang-format on */
|
||||
@@ -238,7 +238,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),
|
||||
GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING = (1 << 5),
|
||||
GP_LAYER_TREE_NODE_EXPANDED = (1 << 6),
|
||||
GP_LAYER_TREE_NODE_HIDE_MASKS = (1 << 7),
|
||||
} GreasePencilLayerTreeNodeFlag;
|
||||
@@ -352,6 +352,15 @@ typedef enum GreasePencilOnionSkinningMode {
|
||||
GP_ONION_SKINNING_MODE_SELECTED = 2,
|
||||
} GreasePencilOnionSkinningMode;
|
||||
|
||||
typedef enum GreasePencilOnionSkinningFlag {
|
||||
/* Use custom colors (per object-data) for onion skinning. */
|
||||
GP_ONION_SKINNING_USE_CUSTOM_COLORS = (1 << 0),
|
||||
/* Fade the opacity of ghost frames further away from the current frame. */
|
||||
GP_ONION_SKINNING_USE_FADE = (1 << 1),
|
||||
/* Show looping frames in onion skinning. */
|
||||
GP_ONION_SKINNING_SHOW_LOOP = (1 << 2),
|
||||
} GreasePencilOnionSkinningFlag;
|
||||
|
||||
/**
|
||||
* Flag for filtering the onion skinning per keyframe type.
|
||||
* #GreasePencilOnionSkinningSettings.filter
|
||||
@@ -378,15 +387,13 @@ typedef struct GreasePencilOnionSkinningSettings {
|
||||
* Opacity for the ghost frames.
|
||||
*/
|
||||
float opacity;
|
||||
/**
|
||||
* Onion skinning mode. See `GreasePencilOnionSkinningMode`.
|
||||
*/
|
||||
/* #GreasePencilOnionSkinningMode. */
|
||||
int8_t mode;
|
||||
/**
|
||||
* Onion skinning filtering flag. See `GreasePencilOnionSkinningFilter`.
|
||||
*/
|
||||
/* #GreasePencilOnionSkinningFlag. */
|
||||
uint8_t flag;
|
||||
/* #GreasePencilOnionSkinningFilter. */
|
||||
uint8_t filter;
|
||||
char _pad[2];
|
||||
char _pad[1];
|
||||
/**
|
||||
* Number of ghost frames shown before.
|
||||
*/
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
#include "DNA_curves_types.h"
|
||||
#include "DNA_fluid_types.h"
|
||||
#include "DNA_gpencil_modifier_types.h"
|
||||
#include "DNA_grease_pencil_types.h"
|
||||
#include "DNA_image_types.h"
|
||||
#include "DNA_key_types.h"
|
||||
#include "DNA_lattice_types.h"
|
||||
@@ -120,6 +121,7 @@
|
||||
#include "DNA_curves_defaults.h"
|
||||
#include "DNA_fluid_defaults.h"
|
||||
#include "DNA_gpencil_modifier_defaults.h"
|
||||
#include "DNA_grease_pencil_defaults.h"
|
||||
#include "DNA_image_defaults.h"
|
||||
#include "DNA_lattice_defaults.h"
|
||||
#include "DNA_light_defaults.h"
|
||||
@@ -181,6 +183,9 @@ SDNA_DEFAULT_DECL_STRUCT(Image);
|
||||
/* DNA_curves_defaults.h */
|
||||
SDNA_DEFAULT_DECL_STRUCT(Curves);
|
||||
|
||||
/* DNA_grease_pencil_defaults.h */
|
||||
SDNA_DEFAULT_DECL_STRUCT(GreasePencil);
|
||||
|
||||
/* DNA_lattice_defaults.h */
|
||||
SDNA_DEFAULT_DECL_STRUCT(Lattice);
|
||||
|
||||
@@ -429,6 +434,9 @@ const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||
/* DNA_curves_defaults.h */
|
||||
SDNA_DEFAULT_DECL(Curves),
|
||||
|
||||
/* DNA_grease_pencil_defaults.h */
|
||||
SDNA_DEFAULT_DECL(GreasePencil),
|
||||
|
||||
/* DNA_lattice_defaults.h */
|
||||
SDNA_DEFAULT_DECL(Lattice),
|
||||
|
||||
|
||||
@@ -400,8 +400,9 @@ static void rna_def_grease_pencil_layer(BlenderRNA *brna)
|
||||
|
||||
/* Onion Skinning. */
|
||||
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_USE_ONION_SKINNING);
|
||||
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_OFF, 1);
|
||||
RNA_def_property_boolean_negative_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Onion Skinning", "Display onion skins before and after the current frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
@@ -542,6 +543,148 @@ static void rna_def_grease_pencil_layer_group(BlenderRNA *brna)
|
||||
"The visibility of drawings in the layers in this group is affected by "
|
||||
"the layers in the masks lists");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_onion_skinning", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_ui_icon(prop, ICON_ONIONSKIN_OFF, 1);
|
||||
RNA_def_property_boolean_negative_sdna(
|
||||
prop, "GreasePencilLayerTreeNode", "flag", GP_LAYER_TREE_NODE_HIDE_ONION_SKINNING);
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Onion Skinning", "Display onion skins before and after the current frame");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_onion_skinning(StructRNA *srna)
|
||||
{
|
||||
PropertyRNA *prop;
|
||||
|
||||
static EnumPropertyItem prop_enum_onion_modes_items[] = {
|
||||
{GP_ONION_SKINNING_MODE_ABSOLUTE,
|
||||
"ABSOLUTE",
|
||||
0,
|
||||
"Frames",
|
||||
"Frames in absolute range of the scene frame"},
|
||||
{GP_ONION_SKINNING_MODE_RELATIVE,
|
||||
"RELATIVE",
|
||||
0,
|
||||
"Keyframes",
|
||||
"Frames in relative range of the Grease Pencil keyframes"},
|
||||
{GP_ONION_SKINNING_MODE_SELECTED, "SELECTED", 0, "Selected", "Only selected keyframes"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
static EnumPropertyItem prop_enum_onion_keyframe_type_items[] = {
|
||||
{GREASE_PENCIL_ONION_SKINNING_FILTER_ALL, "ALL", 0, "All", "Include all Keyframe types"},
|
||||
{GP_ONION_SKINNING_FILTER_KEYTYPE_KEYFRAME,
|
||||
"KEYFRAME",
|
||||
ICON_KEYTYPE_KEYFRAME_VEC,
|
||||
"Keyframe",
|
||||
"Normal keyframe, e.g. for key poses"},
|
||||
{GP_ONION_SKINNING_FILTER_KEYTYPE_BREAKDOWN,
|
||||
"BREAKDOWN",
|
||||
ICON_KEYTYPE_BREAKDOWN_VEC,
|
||||
"Breakdown",
|
||||
"A breakdown pose, e.g. for transitions between key poses"},
|
||||
{GP_ONION_SKINNING_FILTER_KEYTYPE_MOVEHOLD,
|
||||
"MOVING_HOLD",
|
||||
ICON_KEYTYPE_MOVING_HOLD_VEC,
|
||||
"Moving Hold",
|
||||
"A keyframe that is part of a moving hold"},
|
||||
{GP_ONION_SKINNING_FILTER_KEYTYPE_EXTREME,
|
||||
"EXTREME",
|
||||
ICON_KEYTYPE_EXTREME_VEC,
|
||||
"Extreme",
|
||||
"An 'extreme' pose, or some other purpose as needed"},
|
||||
{GP_ONION_SKINNING_FILTER_KEYTYPE_JITTER,
|
||||
"JITTER",
|
||||
ICON_KEYTYPE_JITTER_VEC,
|
||||
"Jitter",
|
||||
"A filler or baked keyframe for keying on ones, or some other purpose as needed"},
|
||||
{0, nullptr, 0, nullptr, nullptr},
|
||||
};
|
||||
|
||||
prop = RNA_def_property(srna, "ghost_before_range", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "onion_skinning_settings.num_frames_before");
|
||||
RNA_def_property_range(prop, 0, 120);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Frames Before",
|
||||
"Maximum number of frames to show before current frame "
|
||||
"(0 = don't show any frames before current)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "ghost_after_range", PROP_INT, PROP_NONE);
|
||||
RNA_def_property_int_sdna(prop, nullptr, "onion_skinning_settings.num_frames_after");
|
||||
RNA_def_property_range(prop, 0, 120);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop,
|
||||
"Frames After",
|
||||
"Maximum number of frames to show after current frame "
|
||||
"(0 = don't show any frames after current)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_ghost_custom_colors", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "onion_skinning_settings.flag", GP_ONION_SKINNING_USE_CUSTOM_COLORS);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop, "Use Custom Ghost Colors", "Use custom colors for ghost frames");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "before_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "onion_skinning_settings.color_before");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop, "Before Color", "Base color for ghosts before the active frame");
|
||||
RNA_def_property_update(prop,
|
||||
NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL,
|
||||
"rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "after_color", PROP_FLOAT, PROP_COLOR);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "onion_skinning_settings.color_after");
|
||||
RNA_def_property_array(prop, 3);
|
||||
RNA_def_property_range(prop, 0.0f, 1.0f);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop, "After Color", "Base color for ghosts after the active frame");
|
||||
RNA_def_property_update(prop,
|
||||
NC_SCREEN | NC_SCENE | ND_TOOLSETTINGS | ND_DATA | NC_GPENCIL,
|
||||
"rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "onion_mode", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "onion_skinning_settings.mode");
|
||||
RNA_def_property_enum_items(prop, prop_enum_onion_modes_items);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop, "Mode", "Mode to display frames");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "onion_keyframe_type", PROP_ENUM, PROP_NONE);
|
||||
RNA_def_property_enum_sdna(prop, nullptr, "onion_skinning_settings.filter");
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_enum_items(prop, prop_enum_onion_keyframe_type_items);
|
||||
RNA_def_property_ui_text(prop, "Filter by Type", "Type of keyframe (for filtering)");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_onion_fade", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "onion_skinning_settings.flag", GP_ONION_SKINNING_USE_FADE);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Fade", "Display onion keyframes with a fade in color transparency");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "use_onion_loop", PROP_BOOLEAN, PROP_NONE);
|
||||
RNA_def_property_boolean_sdna(
|
||||
prop, nullptr, "onion_skinning_settings.flag", GP_ONION_SKINNING_SHOW_LOOP);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(
|
||||
prop, "Show Start Frame", "Display onion keyframes for looping animations");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
prop = RNA_def_property(srna, "onion_factor", PROP_FLOAT, PROP_NONE);
|
||||
RNA_def_property_float_sdna(prop, nullptr, "onion_skinning_settings.opacity");
|
||||
RNA_def_property_range(prop, 0.0, 1.0f);
|
||||
RNA_def_parameter_clear_flags(prop, PROP_ANIMATABLE, ParameterFlag(0));
|
||||
RNA_def_property_ui_text(prop, "Onion Opacity", "Change fade opacity of displayed onion frames");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
}
|
||||
|
||||
static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
||||
@@ -632,6 +775,9 @@ static void rna_def_grease_pencil_data(BlenderRNA *brna)
|
||||
"Stroke Depth Order",
|
||||
"Defines how the strokes are ordered in 3D space (for objects not displayed 'In Front')");
|
||||
RNA_def_property_update(prop, NC_GPENCIL | ND_DATA, "rna_grease_pencil_update");
|
||||
|
||||
/* Onion skinning. */
|
||||
rna_def_grease_pencil_onion_skinning(srna);
|
||||
}
|
||||
|
||||
void RNA_def_grease_pencil(BlenderRNA *brna)
|
||||
|
||||
Reference in New Issue
Block a user