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];
1190 return dna_action->wrap();
1206 BKE_report(
nullptr,
RPT_ERROR,
"Cannot change action, as it is still being edited in NLA");
1243 if (adt && adt->
action == &action) {
1259 if (!slot && action.
slots().size() == 1) {
1273 const bool is_correct_action = adt && adt->
action == &action;
1274 if (!is_correct_action && !
assign_action(&action, animated_id)) {
1294 auto visit_action_use = [&](
const Action &used_action,
slot_handle_t used_slot_handle) ->
bool {
1295 const bool is_used = (&used_action == &action && used_slot_handle == slot_handle);
1300 return !looped_until_end;
1307 char *slot_identifier)
1318 "Could not set action '%s' to animate ID '%s', as it does not have suitably rooted "
1319 "paths for this purpose",
1320 action_to_assign->
id.
name + 2,
1327 if (action_ptr_ref) {
1331 nullptr, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1338 action_ptr_ref =
nullptr;
1341 if (!action_to_assign) {
1347 action_ptr_ref = action_to_assign;
1353 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1369 if (!last_slot_identifier.
is_empty()) {
1385 const bool last_used_identifier_is_typed = last_slot_identifier.
substr(0, 2) !=
1386 slot_untyped_prefix;
1387 if (!last_used_identifier_is_typed) {
1388 const std::string with_idtype_prefix =
StringRef(animated_id.
name, 2) +
1389 last_slot_identifier.
substr(2);
1405 if (last_used_identifier_is_typed) {
1406 const std::string with_untyped_prefix =
StringRef(slot_untyped_prefix) +
1407 last_slot_identifier.
substr(2);
1441 if (action.
slots().size() == 1) {
1455 char *slot_identifier)
1458 if (!action_ptr_ref) {
1463 Action &action = action_ptr_ref->wrap();
1466 if (slot_to_assign) {
1467 if (!action.
slots().contains(slot_to_assign)) {
1480 if (slot_to_unassign) {
1496 if (!slot_to_assign) {
1501 slot_handle_ref = slot_to_assign->
handle;
1512 char *slot_identifier)
1521 if (!action_ptr_ref) {
1528 Slot *slot = action_ptr_ref->wrap().slot_for_handle(slot_handle_to_assign);
1530 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1540 if (dna_action->
idroot == 0) {
1551 return action.
idroot == id_code;
1569 Slot *slot_to_assign,
1601 return &adt->
action->wrap();
1607 if (!adt || !adt->
action) {
1609 return std::nullopt;
1616 return std::nullopt;
1619 return std::make_pair(&action, slot);
1633 case Strip::Type::Keyframe: {
1645 return strip->wrap();
1648bool Strip::is_infinite()
const
1650 return this->
frame_start == -std::numeric_limits<float>::infinity() &&
1651 this->
frame_end == std::numeric_limits<float>::infinity();
1654bool Strip::contains_frame(
const float frame_time)
const
1659bool Strip::is_last_frame(
const float frame_time)
const
1670 "only the end frame can be at positive infinity");
1672 "only the start frame can be at negative infinity");
1734 if (channels->slot_handle == slot_handle) {
1752 const auto *const_channels = const_this->channelbag_for_slot(slot_handle);
1753 return const_cast<Channelbag *
>(const_channels);
1772 "Cannot add channelbag for already-registered slot");
1775 Channelbag &channels = MEM_new<ActionChannelbag>(__func__)->wrap();
1800 Channelbag &channelbag = (*dna_channelbag_ptr)->wrap();
1801 MEM_delete(&channelbag);
1807 if (channelbag_index < 0) {
1839 Channelbag &target_cbag = *MEM_new<animrig::Channelbag>(__func__, *source_cbag);
1861 return *existing_fcurve;
1892 this->restore_channel_group_invariants();
1906 const int add_fcurve_num = int(fcurve_descriptors.
size());
1907 const bool make_first_active = prev_fcurve_num == 0;
1910 struct CurvePathIndex {
1913 bool operator==(
const CurvePathIndex &o)
const
1916 return this->array_index == o.array_index && this->rna_path == o.rna_path;
1924 unique_curves.
reserve(prev_fcurve_num);
1926 CurvePathIndex path_index;
1928 path_index.array_index =
fcurve->array_index;
1929 unique_curves.
add(path_index);
1937 new_fcurves.
resize(add_fcurve_num);
1938 int curve_index = prev_fcurve_num;
1939 for (
int i = 0;
i < add_fcurve_num;
i++) {
1942 CurvePathIndex path_index;
1943 path_index.rna_path = desc.
rna_path;
1947 new_fcurves[
i] =
nullptr;
1962 this->
fcurve_array, this->fcurve_array_num, curve_index, curve_index + 1, insert_index);
1968 for (index = index + 1; index < this->group_array_num; index++) {
1981 if (make_first_active) {
1991 this->restore_channel_group_invariants();
2035 const int64_t fcurve_index = this->
fcurves().first_index_try(&fcurve_to_detach);
2036 if (fcurve_index < 0) {
2049 if (group_index != -1) {
2054 const int group_index = this->
channel_groups().first_index_try(group);
2055 this->channel_group_remove_raw(group_index);
2060 &this->fcurve_array_num,
2065 this->restore_channel_group_invariants();
2076 const int fcurve_index = this->
fcurves().first_index_try(&fcurve);
2077 BLI_assert_msg(fcurve_index >= 0,
"FCurve not in this channel bag.");
2082 this->restore_channel_group_invariants();
2091 group->fcurve_range_start = 0;
2092 group->fcurve_range_length = 0;
2128 if (fcurve.
totvert != 1 || fcurve.
bezt ==
nullptr) {
2132 const float period = cycle_range[1] - cycle_range[0];
2133 if (period < 0.1f) {
2138 const float frame_offset = fcurve.
bezt[0].
vec[1][0] - cycle_range[0];
2139 const float fix =
floorf(frame_offset / period) * period;
2141 fcurve.
bezt[0].
vec[0][0] -= fix;
2142 fcurve.
bezt[0].
vec[1][0] -= fix;
2143 fcurve.
bezt[0].
vec[2][0] -= fix;
2152 fcurve.
bezt[1].
vec[0][0] += period;
2153 fcurve.
bezt[1].
vec[1][0] += period;
2154 fcurve.
bezt[1].
vec[2][0] += period;
2163 const std::optional<float2> cycle_range)
2167 FCurve *fcurve =
nullptr;
2173 if (channels !=
nullptr) {
2174 fcurve = channels->
fcurve_find(fcurve_descriptor);
2179 std::fprintf(stderr,
2180 "FCurve %s[%d] for slot %s was not created due to either the Only Insert "
2181 "Available setting or Replace keyframing mode.\n",
2190 std::fprintf(stderr,
2191 "FCurve %s[%d] for slot %s doesn't allow inserting keys.\n",
2198 if (cycle_range && (*cycle_range)[0] < (*cycle_range)[1]) {
2214 fcurve, time_value, settings, insert_key_flags);
2217 std::fprintf(stderr,
2218 "Could not insert key into FCurve %s[%d] for slot %s.\n",
2222 return insert_vert_result;
2255 this->restore_channel_group_invariants();
2347 if (fcurve_array_index >= group->fcurve_range_start &&
2348 fcurve_array_index < (group->fcurve_range_start + group->fcurve_range_length))
2364 int fcurve_index = 0;
2393 name[0] ==
'\0' ?
DATA_(
"Group") : name);
2414 const int group_index = this->
channel_groups().first_index_try(&group);
2415 if (group_index == -1) {
2431 this->channel_group_remove_raw(group_index);
2432 this->restore_channel_group_invariants();
2441 const int group_index = this->
channel_groups().first_index_try(&group);
2442 BLI_assert_msg(group_index >= 0,
"Group not in this channel bag.");
2453 this->restore_channel_group_invariants();
2463 this->restore_channel_group_invariants();
2466void Channelbag::channel_group_remove_raw(
const int group_index)
2474void Channelbag::restore_channel_group_invariants()
2478 int start_index = 0;
2480 group->fcurve_range_start = start_index;
2481 start_index += group->fcurve_range_length;
2544 switch (strip->type()) {
2545 case animrig::Strip::Type::Keyframe: {
2563 const_cast<const Action &
>(action), slot_handle);
2591 if (act ==
nullptr) {
2595 Action &action = act->wrap();
2614 FCurve *fcu = channelbag->fcurve_find(fcurve_descriptor);
2632 if (act ==
nullptr) {
2636 Action &action = act->wrap();
2655 const size_t quoted_name_size = data_name.
size() + 1;
2656 char *quoted_name =
static_cast<char *
>(alloca(quoted_name_size));
2663 fcurve.
rna_path, collection_rna_path.
c_str(), quoted_name, quoted_name_size))
2667 if (quoted_name != data_name) {
2683 if (predicate(fcurve)) {
2684 found.append(&fcurve);
2696 for (
FCurve *fcurve : fcurves) {
2697 if (predicate(*fcurve)) {
2711 if (predicate(*fcurve)) {
2725 if (act ==
nullptr) {
2750 if (
ptr ==
nullptr ||
ptr->owner_id ==
nullptr) {
2759 Action &action = dna_action.wrap();
2795 BLI_assert(act->wrap().is_empty() || act->wrap().is_action_legacy());
2803 if (fcu !=
nullptr) {
2808 std::optional<PropertyType> prop_type = std::nullopt;
2809 std::optional<PropertySubType> prop_subtype = std::nullopt;
2810 if (
ptr !=
nullptr) {
2815 &id_ptr, fcurve_descriptor.
rna_path.
c_str(), &resolved_ptr, &resolved_prop);
2823 "Did not expect a prop_type to be passed in. This is fine, but does need some "
2824 "changes to action_fcurve_ensure_legacy() to deal with it");
2826 "Did not expect a prop_subtype to be passed in. This is fine, but does need some "
2827 "changes to action_fcurve_ensure_legacy() to deal with it");
2838 if (agrp ==
nullptr) {
2842 if (
ptr && (
ptr->type == &RNA_PoseBone) &&
ptr->data) {
2879 for (
Strip *strip : layer->strips()) {
2880 if (!(strip->type() == Strip::Type::Keyframe)) {
2885 const bool is_detached = bag->fcurve_detach(fcurve_to_detach);
2897 FCurve &fcurve_to_attach,
2898 std::optional<StringRefNull> group_name)
2908 printf(
"Cannot find slot handle %d on Action %s, unable to attach F-Curve %s[%d] to it!\n",
2922 bActionGroup &group = cbag.channel_group_ensure(*group_name);
2923 cbag.fcurve_assign_to_channel_group(fcurve_to_attach, group);
2934 std::optional<std::string> group_name;
2936 group_name = fcurve.
grp->
name;
2948 while (!channelbag_src.
fcurves().is_empty()) {
2953 std::optional<std::string> group_name;
2955 group_name = fcurve.
grp->
name;
2958 const bool is_detached = channelbag_src.
fcurve_detach(fcurve);
2977 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
2978 if (fcurve_index == -1) {
2982 if (
fcurve.grp == &to_group) {
2987 if (
fcurve.grp !=
nullptr) {
2988 fcurve.grp->fcurve_range_length--;
2989 if (
fcurve.grp->fcurve_range_length == 0) {
2991 this->channel_group_remove_raw(group_index);
2993 this->restore_channel_group_invariants();
3003 this->restore_channel_group_invariants();
3010 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
3011 if (fcurve_index == -1) {
3015 if (
fcurve.grp ==
nullptr) {
3029 const int old_group_index = this->
channel_groups().first_index_try(old_group);
3030 this->channel_group_remove_raw(old_group_index);
3033 this->restore_channel_group_invariants();
3044 if (primary_id &&
get_action(*primary_id) == &action) {
3051 if (slot ==
nullptr) {
3056 if (
users.size() == 1) {
3065 if (
users.contains(primary_id)) {
3075 if (
users.is_empty()) {
3078 if (
users.contains(primary_id)) {
3086 const Action &action = dna_action.wrap();
3098 if (action.
layers().is_empty()) {
3108 if (layer.
strips().is_empty()) {
3130 std::string suffix =
"_layered";
3136 const std::string layered_action_name = std::string(legacy_name) + suffix;
3139 Action &converted_action = dna_action->wrap();
3142 Strip &strip = layer.
strip_add(converted_action, Strip::Type::Keyframe);
3163 if (fcu->grp != group) {
3173 return &converted_action;
3215 channelbag->slot_handle = target_slot.
handle;
3225 for (
ID *user : source_slot.
users(bmain)) {
3226 const auto assign_other_action = [&](
ID & ,
3229 char *slot_identifier) ->
bool {
3232 if (action_ptr_ref != &from_action) {
3238 *user, &to_action, action_ptr_ref, slot_handle_ref, slot_identifier);
3239 BLI_assert_msg(assign_ok,
"Expecting slotted Actions to always be assignable");
3244 &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)
void id_us_clear_real(ID *id)
#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