93 if (fcu && fcu->
bezt) {
106 FCurve **fcurves =
static_cast<FCurve **
>(alloca(
sizeof(*fcurves) * fkc_len));
108 for (
int i = 0;
i < fkc_len;
i++) {
109 if (fcurves[
i] && fcurves[
i]->bezt) {
124 const float *keyed_frames,
125 int keyed_frames_len)
133 for (
int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
134 const float evaltime = keyed_frames[frame_index];
145 while (frame_index < keyed_frames_len) {
146 const float evaltime = keyed_frames[frame_index];
147 const float bezt_time =
roundf(bezt->
vec[1][0]);
156 if (bezt == bezt_end) {
162 while (frame_index < keyed_frames_len) {
174 char path_xform[256];
175 char pchan_name_esc[
sizeof(pchan->
name) * 2];
178 path_xform,
"pose.bones[\"%s\"]", pchan_name_esc);
179 char *path_xform_suffix = path_xform + path_xform_prefix_len;
180 const int path_xform_suffix_maxncpy =
sizeof(path_xform) - path_xform_prefix_len;
198 FCurve_KeyCache loc[3], eul[3], quat[4], rotAxis[3], rotAngle, scale[3], rotmode;
199 } fkc_pchan = {{{
nullptr}}};
201#define FCURVE_ASSIGN_VALUE(id, path_test_suffix, index) \
202 BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
203 action_flip_pchan_cache_fcurve_assign_value(&fkc_pchan.id, index, path_xform, fcache)
205#define FCURVE_ASSIGN_ARRAY(id, path_test_suffix) \
206 BLI_strncpy(path_xform_suffix, path_test_suffix, path_xform_suffix_maxncpy); \
207 action_flip_pchan_cache_fcurve_assign_array( \
208 fkc_pchan.id, ARRAY_SIZE(fkc_pchan.id), path_xform, fcache)
218#undef FCURVE_ASSIGN_VALUE
219#undef FCURVE_ASSIGN_ARRAY
222#define FCURVE_CHANNEL_LEN (sizeof(fkc_pchan) / sizeof(FCurve_KeyCache))
224 int fcurve_array_len = 0;
228 if (fkc->
fcurve !=
nullptr) {
229 fcurve_array[fcurve_array_len++] = fkc->
fcurve;
234 if (fcurve_array_len == 0) {
239 int keyed_frames_len;
241 fcurve_array, fcurve_array_len, &keyed_frames_len);
246 if (fkc->
fcurve ==
nullptr) {
253 float flip_mtx[4][4];
260 if (!
STREQ(pchan_name_flip, pchan->
name)) {
264 float arm_mat_inv[4][4];
269 for (
int frame_index = 0; frame_index < keyed_frames_len; frame_index++) {
273 bPoseChannel pchan_temp = blender::dna::shallow_copy(*pchan);
276#define READ_VALUE_FLT(id) \
277 if (fkc_pchan.id.fcurve_eval != nullptr) { \
278 pchan_temp.id = fkc_pchan.id.fcurve_eval[frame_index]; \
282#define READ_VALUE_INT(id) \
283 if (fkc_pchan.id.fcurve_eval != nullptr) { \
284 pchan_temp.id = floorf(fkc_pchan.id.fcurve_eval[frame_index] + 0.5f); \
288#define READ_ARRAY_FLT(id) \
289 for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
290 READ_VALUE_FLT(id[i]); \
306 float chan_mat[4][4];
324 const float unit_x[3] = {1.0f, 0.0f, 0.0f};
325 const bool is_x_axis_orthogonal = (pchan_flip ==
nullptr) &&
327 if (is_x_axis_orthogonal) {
329 float extra_mat[4][4] = {
330 {-1.0f, 0.0f, 0.0f, 0.0f},
331 {0.0f, 1.0f, 0.0f, 0.0f},
332 {0.0f, 0.0f, -1.0f, 0.0f},
333 {0.0f, 0.0f, 0.0f, 1.0f},
341#define WRITE_VALUE_FLT(id) \
342 if (fkc_pchan.id.fcurve_eval != nullptr) { \
343 BezTriple *bezt = fkc_pchan.id.bezt_array[frame_index]; \
344 if (bezt != nullptr) { \
345 const float delta = pchan_temp.id - bezt->vec[1][1]; \
346 bezt->vec[0][1] += delta; \
347 bezt->vec[1][1] += delta; \
348 bezt->vec[2][1] += delta; \
353#define WRITE_ARRAY_FLT(id) \
354 for (int i = 0; i < ARRAY_SIZE(pchan_temp.id); i++) { \
355 WRITE_VALUE_FLT(id[i]); \
368#undef WRITE_ARRAY_FLT
369#undef WRITE_VALUE_FLT
373 for (
int i = 0;
i < fcurve_array_len;
i++) {
395 const char *path_pose_prefix =
"pose.bones[\"";
396 const int path_pose_prefix_len = strlen(path_pose_prefix);
404 if (!
STRPREFIX(fcu->rna_path, path_pose_prefix)) {
408 const char *name_esc = fcu->rna_path + path_pose_prefix_len;
412 if (
UNLIKELY(name_esc_end ==
nullptr)) {
417 const size_t name_esc_len = size_t(name_esc_end - name_esc);
432 char *path_flip =
BLI_sprintfN(
"pose.bones[\"%s%s", name_flip_esc, name_esc_end);
434 fcu->rna_path = path_flip;
436 if (fcu->grp !=
nullptr) {
450 if (!
STREQ(name_flip, agrp->name)) {
464 for (
Object *
object : objects) {
467 slot = action.
slot(0);
469 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
size_t BLI_str_escape(char *__restrict dst, const char *__restrict src, size_t dst_maxncpy) ATTR_NONNULL(1
#define SNPRINTF_UTF8(dst, format,...)
#define STRNCPY_UTF8(dst, src)
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)