34#include "RNA_prototypes.hh"
64constexpr const char *slot_default_name =
"Slot";
69constexpr const char *slot_untyped_prefix =
"XX";
71constexpr const char *layer_default_name =
"Layer";
86 const int new_array_num = *
num + add_num;
99 (*array)[*
num - 1] = item;
106 const int new_array_num = *
num + 1;
110 new_array[index] = item;
116 *
num = new_array_num;
122 const int new_array_num = *
num - shrink_num;
123 if (new_array_num == 0) {
136 *
num = new_array_num;
142 const int new_array_num = *
num - 1;
150 *
num = new_array_num;
161 const int new_array_num = *
num - 1;
165 if (index < new_array_num) {
166 new_array[index] = (*array)[new_array_num];
172 *
num = new_array_num;
186 T *
array,
const int num,
const int range_start,
const int range_end,
const int to)
193 if (
ELEM(range_start, range_end, to)) {
197 if (to < range_start) {
199 T *mid =
array + range_start;
200 T *end =
array + range_end;
201 std::rotate(start, mid, end);
204 T *start =
array + range_start;
205 T *mid =
array + range_end;
206 T *end =
array + to + range_end - range_start;
207 std::rotate(start, mid, end);
257 if (name.has_value()) {
280 Layer &layer = (*dna_layer_ptr)->wrap();
287 if (layer_index < 0) {
311 if (layer->
strips().is_empty()) {
312 layer->strip_add(*
this, Strip::Type::Keyframe);
323 for (
const int64_t layer_index : this->
layers().index_range()) {
324 const Layer *visit_layer = this->
layer(layer_index);
325 if (visit_layer == &
layer) {
334 for (
const int64_t slot_index : this->
slots().index_range()) {
335 const Slot *visit_slot = this->
slot(slot_index);
336 if (visit_slot == &
slot) {
374 if (
slot->handle == handle) {
383 auto check_name_is_used = [&](
const StringRef name) ->
bool {
384 for (
const Slot *slot_iter : action.
slots()) {
385 if (slot_iter == &slot) {
389 if (slot_iter->identifier == name) {
408 "Action Slot display names must not be empty");
410 "Action Slot's existing identifier lacks the two-character type prefix, which "
411 "would make the display name copy meaningless due to early null termination.");
419 slot.idtype = idtype;
420 slot.identifier_ensure_prefix();
439 "Action Slot identifiers must be large enough for a 2-letter ID code + the display name");
458 if (!adt || adt->
action !=
this) {
485Slot &Action::slot_allocate()
487 Slot &
slot = *MEM_new<Slot>(__func__);
528 slot.identifier_ensure_prefix();
551 slot_identifier = animated_id.
name;
561 slot.identifier_ensure_prefix();
568 Slot &slot = (*dna_slot_ptr)->wrap();
576 if (slot_index < 0) {
582 strip_data->slot_data_remove(slot_to_remove.
handle);
598 const int from_slot_index = this->
slots().first_index_try(&slot);
608 slot->set_active(
slot->handle == slot_handle);
615 if (
slot->is_active()) {
649 if (strip->type() == Strip::Type::Keyframe && strip->data_index == index) {
656 MEM_delete<StripKeyframeData>(
668 const int old_index = this->strip_keyframe_data_array_num;
671 if (strip->type() == Strip::Type::Keyframe && strip->data_index == old_index) {
672 strip->data_index = index;
705 return this->
layer(0);
708void Action::slot_identifier_ensure_prefix(
Slot &slot)
723 if (
slot.has_idtype()) {
729 this->slot_identifier_ensure_prefix(
slot);
754 bool found_key =
false;
755 float found_key_frame = 0.0f;
758 switch (fcu->totvert) {
770 const float this_key_frame = fcu->bezt !=
nullptr ? fcu->bezt[0].vec[1][0] :
774 found_key_frame = this_key_frame;
780 if (!
compare_ff(found_key_frame, this_key_frame, 0.001f)) {
822 fcurves_to_consider = legacy_fcurves;
834 const bool include_modifiers)
836 float min = 999999999.0f,
max = -999999999.0f;
837 bool foundvert =
false, foundmod =
false;
839 for (
const FCurve *fcu : fcurves) {
862 if ((include_modifiers) && (fcu->modifiers.last)) {
903 if (foundvert || foundmod) {
907 return float2{0.0f, 0.0f};
919 allocation_name.
c_str());
920 for (
int i : this->
strips().index_range()) {
921 Strip *strip_copy = MEM_new<Strip>(allocation_name.
c_str(), *
this->strip(
i));
922 copy->strip_array[
i] = strip_copy;
925 return &
copy->wrap();
958 Strip &
strip = Strip::create(owning_action, strip_type);
968 Strip &strip = (*dna_strip_ptr)->wrap();
975 if (strip_index < 0) {
979 const Strip::Type strip_type =
strip.type();
980 const int data_index =
strip.data_index;
989 switch (strip_type) {
990 case Strip::Type::Keyframe:
1000 for (
const int64_t strip_index : this->
strips().index_range()) {
1013 memset(
this, 0,
sizeof(*
this));
1014 this->
runtime = MEM_new<SlotRuntime>(__func__);
1019 this->
runtime = MEM_new<SlotRuntime>(__func__);
1030 this->
runtime = MEM_new<SlotRuntime>(__func__);
1041 const int animated_idtype =
GS(animated_id.
name);
1042 return this->
idtype == animated_idtype;
1047 return this->
idtype != 0;
1102 return this->
runtime->users.as_span();
1114 this->
runtime->users.append_non_duplicates(&animated_id);
1126 users.remove_if([&](
const ID *user) {
return user == &animated_id; });
1137 return slot_untyped_prefix;
1141 *
reinterpret_cast<short *
>(name) = this->
idtype;
1176 this->
identifier[0] = slot_untyped_prefix[0];
1177 this->
identifier[1] = slot_untyped_prefix[1];
1191 return dna_action->wrap();
1207 BKE_report(
nullptr,
RPT_ERROR,
"Cannot change action, as it is still being edited in NLA");
1244 if (adt && adt->
action == &action) {
1260 if (!slot && action.
slots().size() == 1) {
1274 const bool is_correct_action = adt && adt->
action == &action;
1275 if (!is_correct_action && !
assign_action(&action, animated_id)) {
1295 auto visit_action_use = [&](
const Action &used_action,
slot_handle_t used_slot_handle) ->
bool {
1296 const bool is_used = (&used_action == &action && used_slot_handle == slot_handle);
1301 return !looped_until_end;
1308 char *slot_identifier)
1319 "Could not set action '%s' to animate ID '%s', as it does not have suitably rooted "
1320 "paths for this purpose",
1321 action_to_assign->
id.
name + 2,
1328 if (action_ptr_ref) {
1332 nullptr, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1339 action_ptr_ref =
nullptr;
1342 if (!action_to_assign) {
1348 action_ptr_ref = action_to_assign;
1354 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1370 if (!last_slot_identifier.
is_empty()) {
1386 const bool last_used_identifier_is_typed = last_slot_identifier.
substr(0, 2) !=
1387 slot_untyped_prefix;
1388 if (!last_used_identifier_is_typed) {
1389 const std::string with_idtype_prefix =
StringRef(animated_id.
name, 2) +
1390 last_slot_identifier.
substr(2);
1406 if (last_used_identifier_is_typed) {
1407 const std::string with_untyped_prefix =
StringRef(slot_untyped_prefix) +
1408 last_slot_identifier.
substr(2);
1442 if (action.
slots().size() == 1) {
1456 char *slot_identifier)
1459 if (!action_ptr_ref) {
1464 Action &action = action_ptr_ref->wrap();
1467 if (slot_to_assign) {
1468 if (!action.
slots().contains(slot_to_assign)) {
1481 if (slot_to_unassign) {
1497 if (!slot_to_assign) {
1502 slot_handle_ref = slot_to_assign->
handle;
1513 char *slot_identifier)
1522 if (!action_ptr_ref) {
1529 Slot *slot = action_ptr_ref->wrap().slot_for_handle(slot_handle_to_assign);
1531 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1541 if (dna_action->
idroot == 0) {
1552 return action.
idroot == id_code;
1570 Slot *slot_to_assign,
1602 return &adt->
action->wrap();
1608 if (!adt || !adt->
action) {
1610 return std::nullopt;
1617 return std::nullopt;
1620 return std::make_pair(&action, slot);
1634 case Strip::Type::Keyframe: {
1646 return strip->wrap();
1649bool Strip::is_infinite()
const
1651 return this->
frame_start == -std::numeric_limits<float>::infinity() &&
1652 this->
frame_end == std::numeric_limits<float>::infinity();
1655bool Strip::contains_frame(
const float frame_time)
const
1660bool Strip::is_last_frame(
const float frame_time)
const
1671 "only the end frame can be at positive infinity");
1673 "only the start frame can be at negative infinity");
1735 if (channels->slot_handle == slot_handle) {
1753 const auto *const_channels = const_this->channelbag_for_slot(slot_handle);
1754 return const_cast<Channelbag *
>(const_channels);
1773 "Cannot add channelbag for already-registered slot");
1776 Channelbag &channels = MEM_new<ActionChannelbag>(__func__)->wrap();
1801 Channelbag &channelbag = (*dna_channelbag_ptr)->wrap();
1802 MEM_delete(&channelbag);
1808 if (channelbag_index < 0) {
1840 Channelbag &target_cbag = *MEM_new<animrig::Channelbag>(__func__, *source_cbag);
1862 return *existing_fcurve;
1893 this->restore_channel_group_invariants();
1907 const int add_fcurve_num = int(fcurve_descriptors.
size());
1908 const bool make_first_active = prev_fcurve_num == 0;
1911 struct CurvePathIndex {
1914 bool operator==(
const CurvePathIndex &o)
const
1917 return this->array_index == o.array_index && this->rna_path == o.rna_path;
1925 unique_curves.
reserve(prev_fcurve_num);
1927 CurvePathIndex path_index;
1929 path_index.array_index =
fcurve->array_index;
1930 unique_curves.
add(path_index);
1938 new_fcurves.
resize(add_fcurve_num);
1939 int curve_index = prev_fcurve_num;
1940 for (
int i = 0;
i < add_fcurve_num;
i++) {
1943 CurvePathIndex path_index;
1944 path_index.rna_path = desc.
rna_path;
1948 new_fcurves[
i] =
nullptr;
1963 this->
fcurve_array, this->fcurve_array_num, curve_index, curve_index + 1, insert_index);
1969 for (index = index + 1; index < this->group_array_num; index++) {
1982 if (make_first_active) {
1992 this->restore_channel_group_invariants();
2036 const int64_t fcurve_index = this->
fcurves().first_index_try(&fcurve_to_detach);
2037 if (fcurve_index < 0) {
2050 if (group_index != -1) {
2055 const int group_index = this->
channel_groups().first_index_try(group);
2056 this->channel_group_remove_raw(group_index);
2061 &this->fcurve_array_num,
2066 this->restore_channel_group_invariants();
2077 const int fcurve_index = this->
fcurves().first_index_try(&fcurve);
2078 BLI_assert_msg(fcurve_index >= 0,
"FCurve not in this channel bag.");
2083 this->restore_channel_group_invariants();
2092 group->fcurve_range_start = 0;
2093 group->fcurve_range_length = 0;
2129 if (fcurve.
totvert != 1 || fcurve.
bezt ==
nullptr) {
2133 const float period = cycle_range[1] - cycle_range[0];
2134 if (period < 0.1f) {
2139 const float frame_offset = fcurve.
bezt[0].
vec[1][0] - cycle_range[0];
2140 const float fix =
floorf(frame_offset / period) * period;
2142 fcurve.
bezt[0].
vec[0][0] -= fix;
2143 fcurve.
bezt[0].
vec[1][0] -= fix;
2144 fcurve.
bezt[0].
vec[2][0] -= fix;
2153 fcurve.
bezt[1].
vec[0][0] += period;
2154 fcurve.
bezt[1].
vec[1][0] += period;
2155 fcurve.
bezt[1].
vec[2][0] += period;
2164 const std::optional<float2> cycle_range)
2168 FCurve *fcurve =
nullptr;
2174 if (channels !=
nullptr) {
2175 fcurve = channels->
fcurve_find(fcurve_descriptor);
2180 std::fprintf(stderr,
2181 "FCurve %s[%d] for slot %s was not created due to either the Only Insert "
2182 "Available setting or Replace keyframing mode.\n",
2191 std::fprintf(stderr,
2192 "FCurve %s[%d] for slot %s doesn't allow inserting keys.\n",
2199 if (cycle_range && (*cycle_range)[0] < (*cycle_range)[1]) {
2215 fcurve, time_value, settings, insert_key_flags);
2218 std::fprintf(stderr,
2219 "Could not insert key into FCurve %s[%d] for slot %s.\n",
2223 return insert_vert_result;
2256 this->restore_channel_group_invariants();
2348 if (fcurve_array_index >= group->fcurve_range_start &&
2349 fcurve_array_index < (group->fcurve_range_start + group->fcurve_range_length))
2365 int fcurve_index = 0;
2394 name[0] ==
'\0' ?
DATA_(
"Group") : name);
2415 const int group_index = this->
channel_groups().first_index_try(&group);
2416 if (group_index == -1) {
2432 this->channel_group_remove_raw(group_index);
2433 this->restore_channel_group_invariants();
2442 const int group_index = this->
channel_groups().first_index_try(&group);
2443 BLI_assert_msg(group_index >= 0,
"Group not in this channel bag.");
2454 this->restore_channel_group_invariants();
2464 this->restore_channel_group_invariants();
2467void Channelbag::channel_group_remove_raw(
const int group_index)
2475void Channelbag::restore_channel_group_invariants()
2479 int start_index = 0;
2481 group->fcurve_range_start = start_index;
2482 start_index += group->fcurve_range_length;
2545 switch (strip->type()) {
2546 case animrig::Strip::Type::Keyframe: {
2564 const_cast<const Action &
>(action), slot_handle);
2592 if (act ==
nullptr) {
2596 Action &action = act->wrap();
2615 FCurve *fcu = channelbag->fcurve_find(fcurve_descriptor);
2633 if (act ==
nullptr) {
2637 Action &action = act->wrap();
2656 const size_t quoted_name_size = data_name.
size() + 1;
2657 char *quoted_name =
static_cast<char *
>(alloca(quoted_name_size));
2664 fcurve.
rna_path, collection_rna_path.
c_str(), quoted_name, quoted_name_size))
2668 if (quoted_name != data_name) {
2684 if (predicate(fcurve)) {
2685 found.append(&fcurve);
2697 for (
FCurve *fcurve : fcurves) {
2698 if (predicate(*fcurve)) {
2712 if (predicate(*fcurve)) {
2726 if (act ==
nullptr) {
2751 if (
ptr ==
nullptr ||
ptr->owner_id ==
nullptr) {
2760 Action &action = dna_action.wrap();
2796 BLI_assert(act->wrap().is_empty() || act->wrap().is_action_legacy());
2804 if (fcu !=
nullptr) {
2809 std::optional<PropertyType> prop_type = std::nullopt;
2810 std::optional<PropertySubType> prop_subtype = std::nullopt;
2811 if (
ptr !=
nullptr) {
2816 &id_ptr, fcurve_descriptor.
rna_path.
c_str(), &resolved_ptr, &resolved_prop);
2824 "Did not expect a prop_type to be passed in. This is fine, but does need some "
2825 "changes to action_fcurve_ensure_legacy() to deal with it");
2827 "Did not expect a prop_subtype to be passed in. This is fine, but does need some "
2828 "changes to action_fcurve_ensure_legacy() to deal with it");
2839 if (agrp ==
nullptr) {
2843 if (
ptr && (
ptr->type == &RNA_PoseBone) &&
ptr->data) {
2880 for (
Strip *strip : layer->strips()) {
2881 if (!(strip->type() == Strip::Type::Keyframe)) {
2886 const bool is_detached = bag->fcurve_detach(fcurve_to_detach);
2898 FCurve &fcurve_to_attach,
2899 std::optional<StringRefNull> group_name)
2909 printf(
"Cannot find slot handle %d on Action %s, unable to attach F-Curve %s[%d] to it!\n",
2923 bActionGroup &group = cbag.channel_group_ensure(*group_name);
2924 cbag.fcurve_assign_to_channel_group(fcurve_to_attach, group);
2935 std::optional<std::string> group_name;
2937 group_name = fcurve.
grp->
name;
2949 while (!channelbag_src.
fcurves().is_empty()) {
2954 std::optional<std::string> group_name;
2956 group_name = fcurve.
grp->
name;
2959 const bool is_detached = channelbag_src.
fcurve_detach(fcurve);
2978 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
2979 if (fcurve_index == -1) {
2983 if (
fcurve.grp == &to_group) {
2988 if (
fcurve.grp !=
nullptr) {
2989 fcurve.grp->fcurve_range_length--;
2990 if (
fcurve.grp->fcurve_range_length == 0) {
2992 this->channel_group_remove_raw(group_index);
2994 this->restore_channel_group_invariants();
3004 this->restore_channel_group_invariants();
3011 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
3012 if (fcurve_index == -1) {
3016 if (
fcurve.grp ==
nullptr) {
3030 const int old_group_index = this->
channel_groups().first_index_try(old_group);
3031 this->channel_group_remove_raw(old_group_index);
3034 this->restore_channel_group_invariants();
3045 if (primary_id &&
get_action(*primary_id) == &action) {
3052 if (slot ==
nullptr) {
3057 if (
users.size() == 1) {
3066 if (
users.contains(primary_id)) {
3076 if (
users.is_empty()) {
3079 if (
users.contains(primary_id)) {
3087 const Action &action = dna_action.wrap();
3099 if (action.
layers().is_empty()) {
3109 if (layer.
strips().is_empty()) {
3131 std::string suffix =
"_layered";
3137 const std::string layered_action_name = std::string(legacy_name) + suffix;
3140 Action &converted_action = dna_action->wrap();
3143 Strip &strip = layer.
strip_add(converted_action, Strip::Type::Keyframe);
3164 if (fcu->grp != group) {
3174 return &converted_action;
3216 channelbag->slot_handle = target_slot.
handle;
3226 for (
ID *user : source_slot.
users(bmain)) {
3227 const auto assign_other_action = [&](
ID & ,
3230 char *slot_identifier) ->
bool {
3233 if (action_ptr_ref != &from_action) {
3239 *user, &to_action, action_ptr_ref, slot_handle_ref, slot_identifier);
3240 BLI_assert_msg(assign_ok,
"Expecting slotted Actions to always be assignable");
3245 &target_slot, *user, action_ptr_ref, slot_handle_ref, slot_identifier);
Functions and classes to work with Actions.
Functionality to iterate an Action in various ways.
Functions for backward compatibility with the legacy Action API.
Functions to work with AnimData.
Functions to modify FCurves.
Blender kernel action and pose functionality.
void action_group_colors_set_from_posebone(bActionGroup *grp, const bPoseChannel *pchan)
void action_groups_add_channel(bAction *act, bActionGroup *agrp, FCurve *fcurve)
bAction * BKE_action_add(Main *bmain, const char name[])
bActionGroup * action_groups_add_new(bAction *act, const char name[])
bActionGroup * BKE_action_group_find_name(bAction *act, const char name[])
bool BKE_animdata_action_ensure_idroot(const ID *owner, bAction *action)
AnimData * BKE_animdata_ensure_id(ID *id)
bool id_can_have_animdata(const ID *id)
bool BKE_animdata_action_editable(const AnimData *adt)
AnimData * BKE_animdata_from_id(const ID *id)
FCurve * BKE_fcurve_copy(const FCurve *fcu)
bool BKE_fcurve_is_keyframable(const FCurve *fcu)
FModifier * add_fmodifier(ListBase *modifiers, int type, FCurve *owner_fcu)
FCurve * BKE_fcurve_find(ListBase *list, const char rna_path[], int array_index)
void BKE_fcurve_free(FCurve *fcu)
bool BKE_fcurve_calc_range(const FCurve *fcu, float *r_min, float *r_max, bool selected_keys_only)
#define FOREACH_MAIN_LISTBASE_ID_END
#define FOREACH_MAIN_LISTBASE_ID_BEGIN(_lb, _id)
#define FOREACH_MAIN_LISTBASE_END
#define FOREACH_MAIN_LISTBASE_BEGIN(_bmain, _lb)
void BKE_reportf(ReportList *reports, eReportType type, const char *format,...) ATTR_PRINTF_FORMAT(3
void BKE_report(ReportList *reports, eReportType type, const char *message)
#define BLI_assert_unreachable()
#define BLI_assert_msg(a, msg)
#define LISTBASE_FOREACH(type, var, list)
BLI_INLINE bool BLI_listbase_is_empty(const ListBase *lb)
void BLI_addtail(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
#define LISTBASE_FOREACH_INDEX(type, var, list, index_var)
bool BLI_remlink_safe(ListBase *listbase, void *vlink) ATTR_NONNULL(1)
int BLI_listbase_count(const ListBase *listbase) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1)
MINLINE float max_ff(float a, float b)
MINLINE float min_ff(float a, float b)
MINLINE int compare_ff(float a, float b, float max_diff)
ATTR_WARN_UNUSED_RESULT const size_t num
bool bool BLI_str_quoted_substr(const char *__restrict str, const char *__restrict prefix, char *result, size_t result_maxncpy)
char * BLI_strncpy_utf8(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define STRNCPY_UTF8(dst, src)
size_t void BLI_uniquename_cb(blender::FunctionRef< bool(blender::StringRefNull)> unique_check, const char *defname, char delim, char *name, size_t name_maxncpy) ATTR_NONNULL(2
#define UNUSED_VARS_NDEBUG(...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION_NO_FLUSH
struct ActionSlotRuntimeHandle ActionSlotRuntimeHandle
struct bActionGroup bActionGroup
#define DNA_struct_default_get(struct_name)
#define DNA_struct_default_alloc(struct_name)
Read Guarded memory(de)allocation.
Internal C++ functions to deal with Actions, Slots, and their runtime data.
bool operator==(const AssetWeakReference &a, const AssetWeakReference &b)
static bool visit_strip(NlaStrip *strip, blender::FunctionRef< bool(NlaStrip *)> callback)
unsigned long long int uint64_t
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
bool add(const Key &key, const Value &value)
const Value & lookup(const Key &key) const
void reserve(const int64_t n)
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr bool is_empty() const
constexpr bool is_empty() const
constexpr StringRef substr(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr const char * data() const
constexpr const char * c_str() const
void append(const T &value)
void resize(const int64_t new_size)
void slot_active_set(slot_handle_t slot_handle)
Slot & slot_add_for_id(const ID &animated_id)
float2 get_frame_range_of_slot(slot_handle_t slot_handle) const ATTR_WARN_UNUSED_RESULT
void layer_keystrip_ensure()
void slot_display_name_define(Slot &slot, StringRefNull new_display_name)
float2 get_frame_range() const ATTR_WARN_UNUSED_RESULT
bool is_cyclic() const ATTR_WARN_UNUSED_RESULT
int strip_keyframe_data_append(StripKeyframeData *strip_data)
void slot_identifier_propagate(Main &bmain, const Slot &slot)
const Layer * layer(int64_t index) const
void slot_identifier_set(Main &bmain, Slot &slot, StringRefNull new_identifier)
int64_t find_slot_index(const Slot &slot) const
Layer * get_layer_for_keyframing()
const Slot * slot(int64_t index) const
void slot_idtype_define(Slot &slot, ID_Type idtype)
blender::Span< const Layer * > layers() const
void slot_move_to_index(Slot &slot, int to_slot_index)
bool is_action_legacy() const
bool is_action_layered() const
bool has_keyframes(slot_handle_t action_slot_handle) const ATTR_WARN_UNUSED_RESULT
void slot_display_name_set(Main &bmain, Slot &slot, StringRefNull new_display_name)
void strip_keyframe_data_remove_if_unused(int index)
int64_t find_layer_index(const Layer &layer) const
Slot & slot_add_for_id_type(ID_Type idtype)
blender::Span< const Slot * > slots() const
bool layer_remove(Layer &layer_to_remove)
Slot * slot_find_by_identifier(StringRefNull slot_identifier)
float2 get_frame_range_of_keys(bool include_modifiers) const ATTR_WARN_UNUSED_RESULT
void slot_identifier_define(Slot &slot, StringRefNull new_identifier)
bool slot_remove(Slot &slot_to_remove)
Slot * slot_for_handle(slot_handle_t handle)
bool has_single_frame() const ATTR_WARN_UNUSED_RESULT
Span< const StripKeyframeData * > strip_keyframe_data() const
bool is_slot_animated(slot_handle_t slot_handle) const
void slot_setup_for_id(Slot &slot, const ID &animated_id)
Layer & layer_add(std::optional< StringRefNull > name)
Span< FCurve * > fcurves()
bool channel_group_remove(bActionGroup &group)
const FCurve * fcurve(int64_t index) const
void fcurve_remove_by_index(int64_t fcurve_index)
bool fcurve_detach(FCurve &fcurve_to_detach)
void fcurve_move_to_index(FCurve &fcurve, int to_fcurve_index)
bool fcurve_assign_to_channel_group(FCurve &fcurve, bActionGroup &to_group)
bActionGroup & channel_group_create(StringRefNull name)
bool fcurve_remove(FCurve &fcurve_to_remove)
const bActionGroup * channel_group(int64_t index) const
FCurve & fcurve_create(Main *bmain, const FCurveDescriptor &fcurve_descriptor)
const bActionGroup * channel_group_find(StringRef name) const
Vector< FCurve * > fcurve_create_many(Main *bmain, Span< FCurveDescriptor > fcurve_descriptors)
void fcurve_detach_by_index(int64_t fcurve_index)
int channel_group_find_index(const bActionGroup *group) const
FCurve & fcurve_ensure(Main *bmain, const FCurveDescriptor &fcurve_descriptor)
FCurve * fcurve_create_unique(Main *bmain, const FCurveDescriptor &fcurve_descriptor)
const FCurve * fcurve_find(const FCurveDescriptor &fcurve_descriptor) const
bool fcurve_ungroup(FCurve &fcurve)
void fcurve_append(FCurve &fcurve)
blender::Span< const FCurve * > fcurves() const
void channel_group_move_to_index(bActionGroup &group, int to_group_index)
int channel_group_containing_index(int fcurve_array_index)
blender::Span< const bActionGroup * > channel_groups() const
bActionGroup & channel_group_ensure(StringRefNull name)
bool strip_remove(Action &owning_action, Strip &strip)
blender::Span< const Strip * > strips() const
Layer * duplicate_with_shallow_strip_copies(StringRefNull allocation_name) const
const Strip * strip(int64_t index) const
Strip & strip_add(Action &owning_action, Strip::Type strip_type)
int64_t find_strip_index(const Strip &strip) const
static void users_invalidate(Main &bmain)
Vector< ID * > runtime_users()
StringRef identifier_prefix() const
void users_add(ID &animated_id)
void set_active(bool active)
void identifier_ensure_prefix()
bool is_suitable_for(const ID &animated_id) const
std::string idtype_string() const
static constexpr int identifier_length_min
void set_expanded(bool expanded)
static constexpr int identifier_length_max
void set_selected(bool selected)
Span< ID * > users(Main &bmain) const
static constexpr slot_handle_t unassigned
StringRefNull identifier_without_prefix() const
void users_remove(ID &animated_id)
const Channelbag * channelbag_for_slot(const Slot &slot) const
int64_t find_channelbag_index(const Channelbag &channelbag) const
void slot_data_remove(slot_handle_t slot_handle)
void slot_data_duplicate(slot_handle_t source_slot_handle, slot_handle_t target_slot_handle)
static constexpr Strip::Type TYPE
Channelbag & channelbag_for_slot_add(const Slot &slot)
SingleKeyingResult keyframe_insert(Main *bmain, const Slot &slot, const FCurveDescriptor &fcurve_descriptor, float2 time_value, const KeyframeSettings &settings, eInsertKeyFlags insert_key_flags=INSERTKEY_NOFLAGS, std::optional< float2 > cycle_range=std::nullopt)
Channelbag & channelbag_for_slot_ensure(const Slot &slot)
blender::Span< const Channelbag * > channelbags() const
bool channelbag_remove(Channelbag &channelbag_to_remove)
const Channelbag * channelbag(int64_t index) const
StripKeyframeData()=default
const T & data(const Action &owning_action) const
float length(VecOp< float, D >) RET
#define ID_IS_EDITABLE(_id)
#define MEM_reallocN(vmemh, len)
#define ID_IS_OVERRIDE_LIBRARY(_id)
void * MEM_calloc_arrayN(size_t len, size_t size, const char *str)
void * MEM_callocN(size_t len, const char *str)
void * MEM_dupallocN(const void *vmemh)
void MEM_freeN(void *vmemh)
void rebuild_slot_user_cache(Main &bmain)
Vector< const FCurve * > fcurves_all(const bAction *action)
bool action_treat_as_legacy(const bAction &action)
void action_fcurve_attach(Action &action, slot_handle_t action_slot, FCurve &fcurve_to_attach, std::optional< StringRefNull > group_name)
void foreach_fcurve_in_action_slot(Action &action, slot_handle_t handle, FunctionRef< void(FCurve &fcurve)> callback)
bool action_fcurve_remove(Action &action, FCurve &fcu)
static void shrink_array_and_swap_remove(T **array, int *num, const int index)
void assert_baklava_phase_1_invariants(const Action &action)
static void strip_ptr_destructor(ActionStrip **dna_strip_ptr)
bool fcurve_matches_collection_path(const FCurve &fcurve, StringRefNull collection_rna_path, StringRefNull data_name)
static bool is_id_using_action_slot(const ID &animated_id, const Action &action, const slot_handle_t slot_handle)
static animrig::Layer & ActionLayer_alloc()
void channelbag_fcurves_move(Channelbag &channelbag_dst, Channelbag &channelbag_src)
static void slot_ptr_destructor(ActionSlot **dna_slot_ptr)
Vector< FCurve * > fcurves_in_listbase_filtered(ListBase fcurves, FunctionRef< bool(const FCurve &fcurve)> predicate)
static void array_shift_range(T *array, const int num, const int range_start, const int range_end, const int to)
Vector< FCurve * > fcurves_in_action_slot_filtered(bAction *act, slot_handle_t slot_handle, FunctionRef< bool(const FCurve &fcurve)> predicate)
Slot * assign_action_ensure_slot_for_keying(Action &action, ID &animated_id)
FCurve * create_fcurve_for_channel(const FCurveDescriptor &fcurve_descriptor)
void action_fcurve_move(Action &action_dst, slot_handle_t action_slot_dst, Action &action_src, FCurve &fcurve)
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyType prop_type)
Action & action_add(Main &bmain, StringRefNull name)
const animrig::Channelbag * channelbag_for_action_slot(const Action &action, slot_handle_t slot_handle)
ActionSlotAssignmentResult assign_tmpaction_and_slot_handle(bAction *action, slot_handle_t slot_handle, OwnedAnimData owned_adt)
static void layer_ptr_destructor(ActionLayer **dna_layer_ptr)
slot_handle_t first_slot_handle(const ::bAction &dna_action)
static void cyclic_keying_ensure_modifier(FCurve &fcurve)
Slot & duplicate_slot(Action &action, const Slot &slot)
static void grow_array_and_append(T **array, int *num, T item)
Vector< FCurve * > fcurves_in_span_filtered(Span< FCurve * > fcurves, FunctionRef< bool(const FCurve &fcurve)> predicate)
bool generic_assign_action(ID &animated_id, bAction *action_to_assign, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_identifier)
static void clone_slot(const Slot &from, Slot &to)
static float2 get_frame_range_of_fcurves(Span< const FCurve * > fcurves, bool include_modifiers)
FCurve * action_fcurve_ensure_legacy(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, const FCurveDescriptor &fcurve_descriptor)
static void cyclic_keying_ensure_cycle_range_exists(FCurve &fcurve, const float2 cycle_range)
ID * action_slot_get_id_best_guess(Main &bmain, Slot &slot, ID *primary_id)
ActionSlotAssignmentResult generic_assign_action_slot(Slot *slot_to_assign, ID &animated_id, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_identifier)
ActionSlotAssignmentResult assign_action_and_slot(Action *action, Slot *slot_to_assign, ID &animated_id)
decltype(::ActionSlot::handle) slot_handle_t
bool is_action_assignable_to(const bAction *dna_action, ID_Type id_code)
Channelbag & action_channelbag_ensure(bAction &dna_action, ID &animated_id)
SingleKeyingResult insert_vert_fcurve(FCurve *fcu, const float2 position, const KeyframeSettings &settings, eInsertKeyFlags flag)
Main Key-framing API call.
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
ID * action_slot_get_id_for_keying(Main &bmain, Action &action, slot_handle_t slot_handle, ID *primary_id)
static void shrink_array_and_remove(T **array, int *num, const int index)
static void grow_array_and_insert(T **array, int *num, const int index, T item)
const FCurve * fcurve_find(Span< const FCurve * > fcurves, const FCurveDescriptor &fcurve_descriptor)
Action * get_action(ID &animated_id)
bool assign_tmpaction(bAction *action, OwnedAnimData owned_adt)
static void fcurve_ptr_noop_destructor(FCurve **)
FCurve * action_fcurve_ensure_ex(Main *bmain, bAction *act, const char group[], PointerRNA *ptr, const FCurveDescriptor &fcurve_descriptor)
static void fcurve_ptr_destructor(FCurve **fcurve_ptr)
Action * convert_to_layered_action(Main &bmain, const Action &legacy_action)
bool unassign_action(ID &animated_id)
bool action_fcurve_detach(Action &action, FCurve &fcurve_to_detach)
bool assign_action(bAction *action, ID &animated_id)
FCurve * fcurve_find_in_assigned_slot(AnimData &adt, const FCurveDescriptor &fcurve_descriptor)
std::optional< std::pair< Action *, Slot * > > get_action_slot_pair(ID &animated_id)
static void grow_array(T **array, int *num, const int add_num)
FCurve & action_fcurve_ensure(Main *bmain, bAction &action, ID &animated_id, const FCurveDescriptor &fcurve_descriptor)
bool key_insertion_may_create_fcurve(eInsertKeyFlags insert_key_flags)
FCurve * fcurve_find_in_action(bAction *act, const FCurveDescriptor &fcurve_descriptor)
static void shrink_array(T **array, int *num, const int shrink_num)
static void channelbag_ptr_destructor(ActionChannelbag **dna_channelbag_ptr)
ActionSlotAssignmentResult generic_assign_action_slot_handle(slot_handle_t slot_handle_to_assign, ID &animated_id, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *slot_identifier)
ActionSlotAssignmentResult assign_action_slot(Slot *slot_to_assign, ID &animated_id)
bool foreach_action_slot_use_with_references(ID &animated_id, FunctionRef< bool(ID &animated_id, bAction *&action_ptr_ref, slot_handle_t &slot_handle_ref, char *last_slot_identifier)> callback)
void move_slot(Main &bmain, Slot &slot, Action &from_action, Action &to_action)
Slot * generic_slot_for_autoassign(const ID &animated_id, Action &action, StringRefNull last_slot_identifier)
bool foreach_action_slot_use(const ID &animated_id, FunctionRef< bool(const Action &action, slot_handle_t slot_handle)> callback)
static void slot_identifier_ensure_unique(Action &action, Slot &slot)
@ FCURVE_NOT_KEYFRAMEABLE
ActionSlotAssignmentResult
FCurve * fcurve_find_in_action_slot(bAction *act, slot_handle_t slot_handle, const FCurveDescriptor &fcurve_descriptor)
void remove_index(T **items, int *items_num, int *active_index, const int index, void(*destruct_item)(T *))
void clear(T **items, int *items_num, int *active_index, void(*destruct_item)(T *))
uint64_t get_default_hash(const T &v, const Args &...args)
VecBase< float, 2 > float2
void uninitialized_relocate_n(T *src, int64_t n, T *dst)
void uninitialized_move_n(T *src, int64_t n, T *dst)
static void copy(bNodeTree *dest_ntree, bNode *dest_node, const bNode *src_node)
static void unique_name(bNode *node)
PropertyType RNA_property_type(PropertyRNA *prop)
PropertySubType RNA_property_subtype(PropertyRNA *prop)
PointerRNA RNA_id_pointer_create(ID *id)
bool RNA_path_resolve_property(const PointerRNA *ptr, const char *path, PointerRNA *r_ptr, PropertyRNA **r_prop)
struct bActionGroup ** group_array
struct FCurve ** fcurve_array
struct ActionStrip ** strip_array
ActionSlotRuntimeHandle * runtime
struct ActionChannelbag ** channelbag_array
char last_slot_identifier[66]
char tmp_last_slot_identifier[66]
bool is_action_slot_to_id_map_dirty
struct ActionChannelbag * channelbag
struct ActionSlot ** slot_array
struct ActionStripKeyframeData ** strip_keyframe_data_array
struct ActionLayer ** layer_array
int strip_keyframe_data_array_num
std::optional< blender::StringRefNull > channel_group
std::optional< PropertySubType > prop_subtype
std::optional< PropertyType > prop_type