92 if (fcu && fcu->
bezt) {
105 FCurve **fcurves =
static_cast<FCurve **
>(alloca(
sizeof(*fcurves) * fkc_len));
107 for (
int i = 0;
i < fkc_len;
i++) {
108 if (fcurves[
i] && fcurves[
i]->bezt) {
123 const float *keyed_frames,
124 int keyed_frames_len)
132 for (
int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
133 const float evaltime = keyed_frames[frame_index];
144 while (frame_index < keyed_frames_len) {
145 const float evaltime = keyed_frames[frame_index];
146 const float bezt_time = roundf(bezt->
vec[1][0]);
155 if (bezt == bezt_end) {
161 while (frame_index < keyed_frames_len) {
173 char path_xform[256];
176 const int path_xform_prefix_len =
SNPRINTF(path_xform,
"pose.bones[\"%s\"]", pchan_name_esc);
177 char *path_xform_suffix = path_xform + path_xform_prefix_len;
178 const int path_xform_suffix_maxncpy =
sizeof(path_xform) - path_xform_prefix_len;
196 FCurve_KeyCache loc[3], eul[3], quat[4], rotAxis[3], rotAngle, scale[3], rotmode;
197 } fkc_pchan = {{{
nullptr}}};
199#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
200 BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
201 action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
203#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
204 BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
205 action_flip_pchan_cache_fcurve_assign_array( \
206 fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)
216#undef FCURVE_ASSIGN_VALUE
217#undef FCURVE_ASSIGN_ARRAY
220#define FCURVE_CHANNEL_LEN (sizeof(fkc_pchan) / sizeof(FCurve_KeyCache))
222 int fcurve_array_len = 0;
226 if (fkc->
fcurve !=
nullptr) {
227 fcurve_array[fcurve_array_len++] = fkc->
fcurve;
232 if (fcurve_array_len == 0) {
237 int keyed_frames_len;
239 fcurve_array, fcurve_array_len, &keyed_frames_len);
244 if (fkc->
fcurve ==
nullptr) {
251 float flip_mtx[4][4];
258 if (!
STREQ(pchan_name_flip, pchan->
name)) {
262 float arm_mat_inv[4][4];
267 for (
int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
271 bPoseChannel pchan_temp = blender::dna::shallow_copy(*pchan);
274#define READ_VALUE_FLT(id) \
275 if (fkc_pchan.id.fcurve_eval != nullptr) { \
276 pchan_temp.id = fkc_pchan.id.fcurve_eval[frame_index]; \
280#define READ_VALUE_INT(id) \
281 if (fkc_pchan.id.fcurve_eval != nullptr) { \
282 pchan_temp.id = floorf(fkc_pchan.id.fcurve_eval[frame_index] + 0.5f); \
286#define READ_ARRAY_FLT(id) \
287 for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
288 READ_VALUE_FLT(id[i]); \
304 float chan_mat[4][4];
322 const float unit_x[3] = {1.0f, 0.0f, 0.0f};
323 const bool is_x_axis_orthogonal = (pchan_flip ==
nullptr) &&
325 if (is_x_axis_orthogonal) {
327 float extra_mat[4][4] = {
328 {-1.0f, 0.0f, 0.0f, 0.0f},
329 {0.0f, 1.0f, 0.0f, 0.0f},
330 {0.0f, 0.0f, -1.0f, 0.0f},
331 {0.0f, 0.0f, 0.0f, 1.0f},
339#define WRITE_VALUE_FLT(id) \
340 if (fkc_pchan.id.fcurve_eval != nullptr) { \
341 BezTriple *bezt = fkc_pchan.id.bezt_array[frame_index]; \
342 if (bezt != nullptr) { \
343 const float delta = pchan_temp.id - bezt->vec[1][1]; \
344 bezt->vec[0][1] += delta; \
345 bezt->vec[1][1] += delta; \
346 bezt->vec[2][1] += delta; \
351#define WRITE_ARRAY_FLT(id) \
352 for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
353 WRITE_VALUE_FLT(id[i]); \
366#undef WRITE_ARRAY_FLT
367#undef WRITE_VALUE_FLT
371 for (
int i = 0;
i < fcurve_array_len;
i++) {
393 const char *path_pose_prefix =
"pose.bones[\"";
394 const int path_pose_prefix_len = strlen(path_pose_prefix);
402 if (!
STRPREFIX(fcu->rna_path, path_pose_prefix)) {
406 const char *name_esc = fcu->rna_path + path_pose_prefix_len;
410 if (
UNLIKELY(name_esc_end ==
nullptr)) {
415 const size_t name_esc_len = size_t(name_esc_end - name_esc);
420 if (
UNLIKELY(name_len >=
sizeof(name))) {
427 if (!
STREQ(name_flip, name)) {
430 char *path_flip =
BLI_sprintfN(
"pose.bones[\"%s%s", name_flip_esc, name_esc_end);
432 fcu->rna_path = path_flip;
434 if (fcu->grp !=
nullptr) {
448 if (!
STREQ(name_flip, agrp->name)) {
449 STRNCPY(agrp->name, name_flip);
462 for (
Object *
object : objects) {
465 slot = action.
slot(0);
467 if (!flipped_slots.
add(slot)) {
Functions for backward compatibility with the legacy Action API.
Blender kernel action and pose functionality.
bPoseChannel * BKE_pose_channel_find_name(const bPose *pose, const char *name)
void BKE_pchan_apply_mat4(bPoseChannel *pchan, const float mat[4][4], bool use_compat)
void BKE_pchan_to_mat4(const bPoseChannel *pchan, float r_chanmat[4][4])
float * BKE_fcurves_calc_keyed_frames(FCurve **fcurve_array, int fcurve_array_len, int *r_frames_len)
void BKE_fcurve_pathcache_destroy(FCurvePathCache *fcache)
FCurvePathCache * BKE_fcurve_pathcache_create(blender::Span< FCurve * > fcurves)
void BKE_fcurve_handles_recalc_ex(FCurve *fcu, eBezTriple_Flag handle_sel_flag)
FCurve * BKE_fcurve_pathcache_find(const FCurvePathCache *fcache, const char rna_path[], int array_index)
float evaluate_fcurve_only_curve(const FCurve *fcu, float evaltime)
int BKE_fcurve_pathcache_find_array(const FCurvePathCache *fcache, const char *rna_path, FCurve **fcurve_result, int fcurve_result_len)
#define LISTBASE_FOREACH(type, var, list)
void mul_m4_m4m4(float R[4][4], const float A[4][4], const float B[4][4])
bool invert_m4_m4(float inverse[4][4], const float mat[4][4])
void unit_m4(float m[4][4])
MINLINE float dot_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
char * BLI_sprintfN(const char *__restrict format,...) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL(1) ATTR_MALLOC ATTR_PRINTF_FORMAT(1
size_t size_t size_t const char * BLI_str_escape_find_quote(const char *str) ATTR_NONNULL(1)
size_t size_t size_t BLI_str_unescape(char *__restrict dst, const char *__restrict src, size_t src_maxncpy) ATTR_NONNULL(1
#define SNPRINTF(dst, format,...)
char * STRNCPY(char(&dst)[N], const char *src)
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
size_t BLI_string_flip_side_name(char *name_dst, const char *name_src, bool strip_number, size_t name_dst_maxncpy) ATTR_NONNULL(1
void DEG_id_tag_update(ID *id, unsigned int flags)
Object is a sort of wrapper for general info.
Read Guarded memory(de)allocation.
#define READ_VALUE_FLT(id)
static void action_flip_pchan_rna_paths(bAction *act)
static void action_flip_pchan_cache_fcurve_assign_value(FCurve_KeyCache *fkc, int index, const char *path, FCurvePathCache *fcache)
#define WRITE_ARRAY_FLT(id)
static void action_flip_pchan_cache_init(FCurve_KeyCache *fkc, const float *keyed_frames, int keyed_frames_len)
static void action_flip_pchan_cache_fcurve_assign_array(FCurve_KeyCache *fkc, int fkc_len, const char *path, FCurvePathCache *fcache)
#define READ_VALUE_INT(id)
#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix)
#define FCURVE_CHANNEL_LEN
void BKE_action_flip_with_pose(bAction *act, blender::Span< Object * > objects)
static void action_flip_pchan(Object *ob_arm, const bPoseChannel *pchan, FCurvePathCache *fcache)
#define WRITE_VALUE_FLT(id)
#define READ_ARRAY_FLT(id)
#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index)
const Slot * slot(int64_t index) const
void * MEM_malloc_arrayN(size_t len, size_t size, const char *str)
void MEM_freeN(void *vmemh)
Vector< const FCurve * > fcurves_all(const bAction *action)
Vector< bActionGroup * > channel_groups_all(bAction *action)
Span< FCurve * > fcurves_for_action_slot(Action &action, slot_handle_t slot_handle)
Slot * generic_slot_for_autoassign(const ID &animated_id, Action &action, StringRefNull last_slot_identifier)