34#include "RNA_prototypes.hh"
68constexpr const char *slot_default_name =
"Slot";
73constexpr const char *slot_untyped_prefix =
"XX";
75constexpr const char *layer_default_name =
"Layer";
90 const int new_array_num = *
num + add_num;
103 (*array)[*
num - 1] = item;
110 const int new_array_num = *
num + 1;
114 new_array[index] = item;
120 *
num = new_array_num;
126 const int new_array_num = *
num - shrink_num;
127 if (new_array_num == 0) {
140 *
num = new_array_num;
146 const int new_array_num = *
num - 1;
154 *
num = new_array_num;
165 const int new_array_num = *
num - 1;
169 if (index < new_array_num) {
170 new_array[index] = (*array)[new_array_num];
176 *
num = new_array_num;
190 T *
array,
const int num,
const int range_start,
const int range_end,
const int to)
197 if (
ELEM(range_start, range_end, to)) {
201 if (to < range_start) {
203 T *mid =
array + range_start;
204 T *end =
array + range_end;
205 std::rotate(start, mid, end);
208 T *start =
array + range_start;
209 T *mid =
array + range_end;
210 T *end =
array + to + range_end - range_start;
211 std::rotate(start, mid, end);
261 if (
name.has_value()) {
284 Layer &layer = (*dna_layer_ptr)->wrap();
291 if (layer_index < 0) {
315 if (layer->
strips().is_empty()) {
316 layer->strip_add(*
this, Strip::Type::Keyframe);
327 for (
const int64_t layer_index : this->
layers().index_range()) {
328 const Layer *visit_layer = this->
layer(layer_index);
329 if (visit_layer == &
layer) {
338 for (
const int64_t slot_index : this->
slots().index_range()) {
339 const Slot *visit_slot = this->
slot(slot_index);
340 if (visit_slot == &
slot) {
378 if (
slot->handle == handle) {
387 auto check_name_is_used = [&](
const StringRef name) ->
bool {
388 for (
const Slot *slot_iter : action.
slots()) {
389 if (slot_iter == &slot) {
393 if (slot_iter->identifier ==
name) {
412 "Action Slot display names must not be empty");
414 "Action Slot's existing identifier lacks the two-character type prefix, which "
415 "would make the display name copy meaningless due to early null termination.");
423 slot.idtype = idtype;
424 slot.identifier_ensure_prefix();
443 "Action Slot identifiers must be large enough for a 2-letter ID code + the display name");
462 if (!adt || adt->
action !=
this) {
489Slot &Action::slot_allocate()
491 Slot &
slot = *MEM_new<Slot>(__func__);
532 slot.identifier_ensure_prefix();
555 slot_identifier = animated_id.
name;
565 slot.identifier_ensure_prefix();
572 Slot &slot = (*dna_slot_ptr)->wrap();
580 if (slot_index < 0) {
586 strip_data->slot_data_remove(slot_to_remove.
handle);
602 const int from_slot_index = this->
slots().first_index_try(&slot);
612 slot->set_active(
slot->handle == slot_handle);
619 if (
slot->is_active()) {
653 if (strip->type() == Strip::Type::Keyframe && strip->data_index == index) {
660 MEM_delete<StripKeyframeData>(
672 const int old_index = this->strip_keyframe_data_array_num;
675 if (strip->type() == Strip::Type::Keyframe && strip->data_index == old_index) {
676 strip->data_index = index;
709 return this->
layer(0);
712void Action::slot_identifier_ensure_prefix(
Slot &slot)
727 if (
slot.has_idtype()) {
733 this->slot_identifier_ensure_prefix(
slot);
758 bool found_key =
false;
759 float found_key_frame = 0.0f;
762 switch (fcu->totvert) {
774 const float this_key_frame = fcu->bezt !=
nullptr ? fcu->bezt[0].vec[1][0] :
778 found_key_frame = this_key_frame;
784 if (!
compare_ff(found_key_frame, this_key_frame, 0.001f)) {
826 fcurves_to_consider = legacy_fcurves;
838 const bool include_modifiers)
840 float min = 999999999.0f,
max = -999999999.0f;
841 bool foundvert =
false, foundmod =
false;
843 for (
const FCurve *fcu : fcurves) {
866 if ((include_modifiers) && (fcu->modifiers.last)) {
907 if (foundvert || foundmod) {
911 return float2{0.0f, 0.0f};
923 allocation_name.
c_str());
924 for (
int i : this->
strips().index_range()) {
925 Strip *strip_copy = MEM_new<Strip>(allocation_name.
c_str(), *this->strip(
i));
926 copy->strip_array[
i] = strip_copy;
929 return &
copy->wrap();
962 Strip &
strip = Strip::create(owning_action, strip_type);
972 Strip &strip = (*dna_strip_ptr)->wrap();
979 if (strip_index < 0) {
983 const Strip::Type strip_type =
strip.type();
984 const int data_index =
strip.data_index;
993 switch (strip_type) {
994 case Strip::Type::Keyframe:
1004 for (
const int64_t strip_index : this->
strips().index_range()) {
1019 this->
runtime = MEM_new<SlotRuntime>(__func__);
1024 this->
runtime = MEM_new<SlotRuntime>(__func__);
1035 this->
runtime = MEM_new<SlotRuntime>(__func__);
1046 const int animated_idtype =
GS(animated_id.
name);
1047 return this->
idtype == animated_idtype;
1052 return this->
idtype != 0;
1107 return this->
runtime->users.as_span();
1119 this->
runtime->users.append_non_duplicates(&animated_id);
1131 users.remove_if([&](
const ID *user) {
return user == &animated_id; });
1142 return slot_untyped_prefix;
1146 *
reinterpret_cast<short *
>(
name) = this->
idtype;
1181 this->
identifier[0] = slot_untyped_prefix[0];
1182 this->
identifier[1] = slot_untyped_prefix[1];
1195 return dna_action->wrap();
1211 BKE_report(
nullptr,
RPT_ERROR,
"Cannot change action, as it is still being edited in NLA");
1248 if (adt && adt->
action == &action) {
1264 if (!slot && action.
slots().size() == 1) {
1278 const bool is_correct_action = adt && adt->
action == &action;
1279 if (!is_correct_action && !
assign_action(&action, animated_id)) {
1299 auto visit_action_use = [&](
const Action &used_action,
slot_handle_t used_slot_handle) ->
bool {
1300 const bool is_used = (&used_action == &action && used_slot_handle == slot_handle);
1305 return !looped_until_end;
1312 char *slot_identifier)
1323 "Could not set action '%s' to animate ID '%s', as it does not have suitably rooted "
1324 "paths for this purpose",
1325 action_to_assign->
id.
name + 2,
1332 if (action_ptr_ref) {
1336 nullptr, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1343 action_ptr_ref =
nullptr;
1346 if (!action_to_assign) {
1352 action_ptr_ref = action_to_assign;
1358 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1374 if (!last_slot_identifier.
is_empty()) {
1390 const bool last_used_identifier_is_typed = last_slot_identifier.
substr(0, 2) !=
1391 slot_untyped_prefix;
1392 if (!last_used_identifier_is_typed) {
1393 const std::string with_idtype_prefix =
StringRef(animated_id.
name, 2) +
1394 last_slot_identifier.
substr(2);
1410 if (last_used_identifier_is_typed) {
1411 const std::string with_untyped_prefix =
StringRef(slot_untyped_prefix) +
1412 last_slot_identifier.
substr(2);
1446 if (action.
slots().size() == 1) {
1460 char *slot_identifier)
1463 if (!action_ptr_ref) {
1468 Action &action = action_ptr_ref->wrap();
1471 if (slot_to_assign) {
1472 if (!action.
slots().contains(slot_to_assign)) {
1485 if (slot_to_unassign) {
1501 if (!slot_to_assign) {
1506 slot_handle_ref = slot_to_assign->
handle;
1517 char *slot_identifier)
1526 if (!action_ptr_ref) {
1533 Slot *slot = action_ptr_ref->wrap().slot_for_handle(slot_handle_to_assign);
1535 slot, animated_id, action_ptr_ref, slot_handle_ref, slot_identifier);
1545 if (dna_action->
idroot == 0) {
1556 return action.
idroot == id_code;
1574 Slot *slot_to_assign,
1606 return &adt->
action->wrap();
1612 if (!adt || !adt->
action) {
1614 return std::nullopt;
1621 return std::nullopt;
1624 return std::make_pair(&action, slot);
1638 case Strip::Type::Keyframe: {
1650 return strip->wrap();
1653bool Strip::is_infinite()
const
1655 return this->
frame_start == -std::numeric_limits<float>::infinity() &&
1656 this->
frame_end == std::numeric_limits<float>::infinity();
1659bool Strip::contains_frame(
const float frame_time)
const
1664bool Strip::is_last_frame(
const float frame_time)
const
1675 "only the end frame can be at positive infinity");
1677 "only the start frame can be at negative infinity");
1739 if (channels->slot_handle == slot_handle) {
1757 const auto *const_channels = const_this->channelbag_for_slot(slot_handle);
1758 return const_cast<Channelbag *
>(const_channels);
1777 "Cannot add channelbag for already-registered slot");
1780 Channelbag &channels = MEM_new<ActionChannelbag>(__func__)->wrap();
1805 Channelbag &channelbag = (*dna_channelbag_ptr)->wrap();
1806 MEM_delete(&channelbag);
1812 if (channelbag_index < 0) {
1844 Channelbag &target_cbag = *MEM_new<animrig::Channelbag>(__func__, *source_cbag);
1866 return *existing_fcurve;
1897 this->restore_channel_group_invariants();
1911 const int add_fcurve_num = int(fcurve_descriptors.
size());
1912 const bool make_first_active = prev_fcurve_num == 0;
1915 struct CurvePathIndex {
1918 bool operator==(
const CurvePathIndex &o)
const
1921 return this->array_index == o.array_index && this->rna_path == o.rna_path;
1929 unique_curves.
reserve(prev_fcurve_num);
1931 CurvePathIndex path_index;
1933 path_index.array_index =
fcurve->array_index;
1934 unique_curves.
add(path_index);
1942 new_fcurves.
resize(add_fcurve_num);
1943 int curve_index = prev_fcurve_num;
1944 for (
int i = 0;
i < add_fcurve_num;
i++) {
1947 CurvePathIndex path_index;
1948 path_index.rna_path = desc.
rna_path;
1952 new_fcurves[
i] =
nullptr;
1967 this->
fcurve_array, this->fcurve_array_num, curve_index, curve_index + 1, insert_index);
1973 for (index = index + 1; index < this->group_array_num; index++) {
1986 if (make_first_active) {
1996 this->restore_channel_group_invariants();
2040 const int64_t fcurve_index = this->
fcurves().first_index_try(&fcurve_to_detach);
2041 if (fcurve_index < 0) {
2054 if (group_index != -1) {
2059 const int group_index = this->
channel_groups().first_index_try(group);
2060 this->channel_group_remove_raw(group_index);
2065 &this->fcurve_array_num,
2070 this->restore_channel_group_invariants();
2081 const int fcurve_index = this->
fcurves().first_index_try(&fcurve);
2082 BLI_assert_msg(fcurve_index >= 0,
"FCurve not in this channel bag.");
2087 this->restore_channel_group_invariants();
2096 group->fcurve_range_start = 0;
2097 group->fcurve_range_length = 0;
2133 if (fcurve.
totvert != 1 || fcurve.
bezt ==
nullptr) {
2137 const float period = cycle_range[1] - cycle_range[0];
2138 if (period < 0.1f) {
2143 const float frame_offset = fcurve.
bezt[0].
vec[1][0] - cycle_range[0];
2144 const float fix =
floorf(frame_offset / period) * period;
2146 fcurve.
bezt[0].
vec[0][0] -= fix;
2147 fcurve.
bezt[0].
vec[1][0] -= fix;
2148 fcurve.
bezt[0].
vec[2][0] -= fix;
2157 fcurve.
bezt[1].
vec[0][0] += period;
2158 fcurve.
bezt[1].
vec[1][0] += period;
2159 fcurve.
bezt[1].
vec[2][0] += period;
2168 const std::optional<float2> cycle_range)
2172 FCurve *fcurve =
nullptr;
2178 if (channels !=
nullptr) {
2179 fcurve = channels->
fcurve_find(fcurve_descriptor);
2185 "FCurve %s[%d] for slot %s was not created due to either the Only Insert "
2186 "Available setting or Replace keyframing mode.\n",
2196 "FCurve %s[%d] for slot %s doesn't allow inserting keys.\n",
2203 if (cycle_range && (*cycle_range)[0] < (*cycle_range)[1]) {
2219 fcurve, time_value, settings, insert_key_flags);
2223 "Could not insert key into FCurve %s[%d] for slot %s.\n",
2227 return insert_vert_result;
2260 this->restore_channel_group_invariants();
2352 if (fcurve_array_index >= group->fcurve_range_start &&
2353 fcurve_array_index < (group->fcurve_range_start + group->fcurve_range_length))
2369 int fcurve_index = 0;
2419 const int group_index = this->
channel_groups().first_index_try(&group);
2420 if (group_index == -1) {
2436 this->channel_group_remove_raw(group_index);
2437 this->restore_channel_group_invariants();
2446 const int group_index = this->
channel_groups().first_index_try(&group);
2447 BLI_assert_msg(group_index >= 0,
"Group not in this channel bag.");
2458 this->restore_channel_group_invariants();
2468 this->restore_channel_group_invariants();
2471void Channelbag::channel_group_remove_raw(
const int group_index)
2479void Channelbag::restore_channel_group_invariants()
2483 int start_index = 0;
2485 group->fcurve_range_start = start_index;
2486 start_index += group->fcurve_range_length;
2549 switch (strip->type()) {
2550 case animrig::Strip::Type::Keyframe: {
2568 const_cast<const Action &
>(action), slot_handle);
2596 if (act ==
nullptr) {
2600 Action &action = act->wrap();
2619 FCurve *fcu = channelbag->fcurve_find(fcurve_descriptor);
2637 if (act ==
nullptr) {
2641 Action &action = act->wrap();
2660 const size_t quoted_name_size = data_name.
size() + 1;
2661 char *quoted_name =
static_cast<char *
>(alloca(quoted_name_size));
2668 fcurve.
rna_path, collection_rna_path.
c_str(), quoted_name, quoted_name_size))
2672 if (quoted_name != data_name) {
2688 if (predicate(fcurve)) {
2689 found.append(&fcurve);
2701 for (
FCurve *fcurve : fcurves) {
2702 if (predicate(*fcurve)) {
2716 if (predicate(*fcurve)) {
2730 if (act ==
nullptr) {
2755 if (
ptr ==
nullptr ||
ptr->owner_id ==
nullptr) {
2764 Action &action = dna_action.wrap();
2800 BLI_assert(act->wrap().is_empty() || act->wrap().is_action_legacy());
2808 if (fcu !=
nullptr) {
2813 std::optional<PropertyType> prop_type = std::nullopt;
2814 std::optional<PropertySubType> prop_subtype = std::nullopt;
2815 if (
ptr !=
nullptr) {
2820 &id_ptr, fcurve_descriptor.
rna_path.
c_str(), &resolved_ptr, &resolved_prop);
2828 "Did not expect a prop_type to be passed in. This is fine, but does need some "
2829 "changes to action_fcurve_ensure_legacy() to deal with it");
2831 "Did not expect a prop_subtype to be passed in. This is fine, but does need some "
2832 "changes to action_fcurve_ensure_legacy() to deal with it");
2843 if (agrp ==
nullptr) {
2847 if (
ptr && (
ptr->type == &RNA_PoseBone) &&
ptr->data) {
2884 for (
Strip *strip : layer->strips()) {
2885 if (!(strip->type() == Strip::Type::Keyframe)) {
2890 const bool is_detached = bag->fcurve_detach(fcurve_to_detach);
2902 FCurve &fcurve_to_attach,
2903 std::optional<StringRefNull> group_name)
2913 printf(
"Cannot find slot handle %d on Action %s, unable to attach F-Curve %s[%d] to it!\n",
2927 bActionGroup &group = cbag.channel_group_ensure(*group_name);
2928 cbag.fcurve_assign_to_channel_group(fcurve_to_attach, group);
2939 std::optional<std::string> group_name;
2941 group_name = fcurve.
grp->
name;
2953 while (!channelbag_src.
fcurves().is_empty()) {
2958 std::optional<std::string> group_name;
2960 group_name = fcurve.
grp->
name;
2963 const bool is_detached = channelbag_src.
fcurve_detach(fcurve);
2982 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
2983 if (fcurve_index == -1) {
2987 if (
fcurve.grp == &to_group) {
2992 if (
fcurve.grp !=
nullptr) {
2993 fcurve.grp->fcurve_range_length--;
2994 if (
fcurve.grp->fcurve_range_length == 0) {
2996 this->channel_group_remove_raw(group_index);
2998 this->restore_channel_group_invariants();
3008 this->restore_channel_group_invariants();
3015 const int fcurve_index = this->fcurves().first_index_try(&
fcurve);
3016 if (fcurve_index == -1) {
3020 if (
fcurve.grp ==
nullptr) {
3034 const int old_group_index = this->
channel_groups().first_index_try(old_group);
3035 this->channel_group_remove_raw(old_group_index);
3038 this->restore_channel_group_invariants();
3049 if (primary_id &&
get_action(*primary_id) == &action) {
3056 if (slot ==
nullptr) {
3061 if (
users.size() == 1) {
3070 if (
users.contains(primary_id)) {
3080 if (
users.is_empty()) {
3083 if (
users.contains(primary_id)) {
3091 const Action &action = dna_action.wrap();
3103 if (action.
layers().is_empty()) {
3113 if (layer.
strips().is_empty()) {
3135 std::string suffix =
"_layered";
3141 const std::string layered_action_name = std::string(legacy_name) + suffix;
3144 Action &converted_action = dna_action->wrap();
3147 Strip &strip = layer.
strip_add(converted_action, Strip::Type::Keyframe);
3168 if (fcu->grp != group) {
3178 return &converted_action;
3220 channelbag->slot_handle = target_slot.
handle;
3230 for (
ID *user : source_slot.
users(bmain)) {
3231 const auto assign_other_action = [&](
ID & ,
3234 char *slot_identifier) ->
bool {
3237 if (action_ptr_ref != &from_action) {
3243 *user, &to_action, action_ptr_ref, slot_handle_ref, slot_identifier);
3244 BLI_assert_msg(assign_ok,
"Expecting slotted Actions to always be assignable");
3249 &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(...)
#define CLOG_WARN(clg_ref,...)
void DEG_id_tag_update(ID *id, unsigned int flags)
void DEG_relations_tag_update(Main *bmain)
@ ID_RECALC_ANIMATION_NO_FLUSH
#define ID_IS_EDITABLE(_id)
#define ID_IS_OVERRIDE_LIBRARY(_id)
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.
#define MEM_reallocN(vmemh, len)
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 * 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
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 tmp_last_slot_identifier[258]
char last_slot_identifier[258]
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