Files
workinf_Blender_Wasm/blender-5.2.0/source/blender/animrig/ANIM_keyframing.hh
2026-08-12 04:47:48 -04:00

313 lines
11 KiB
C++

/* SPDX-FileCopyrightText: 2023 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup animrig
*
* \brief Functions to insert, delete or modify keyframes.
*/
#pragma once
#include <array>
#include "BLI_string_ref.hh"
#include "DNA_anim_types.h"
#include "DNA_userdef_types.h"
#include "BKE_report.hh"
#include "RNA_path.hh"
#include "RNA_types.hh"
namespace blender {
struct ID;
struct Main;
struct Scene;
struct AnimationEvalContext;
struct NlaKeyframingContext;
namespace animrig {
/**
* Represents a single success/failure in the keyframing process.
*
* What is considered "single" depends on the level at which the failure
* happens. For example, it can be at the level of a single key on a single
* fcurve, all the way up to the level of an entire ID not being animatable.
* Both are considered "single" events.
*/
enum class SingleKeyingResult {
SUCCESS = 0,
/* TODO: remove `UNKNOWN_FAILURE` and replace all usages with proper, specific
* cases. This is needed right now as a stop-gap while progressively moving
* the keyframing code over to propagate errors properly. */
UNKNOWN_FAILURE,
CANNOT_CREATE_FCURVE,
FCURVE_NOT_KEYFRAMEABLE,
NO_KEY_NEEDED,
UNABLE_TO_INSERT_TO_NLA_STACK,
ID_NOT_EDITABLE,
ID_NOT_ANIMATABLE,
NO_VALID_LAYER,
NO_VALID_STRIP,
NO_VALID_SLOT,
CANNOT_RESOLVE_PATH,
/* Make sure to always keep this at the end of the enum. */
_KEYING_RESULT_MAX,
};
/**
* Add a message into the ReportList depending on which SingleKeyingResult is passed.
* This should only be used when a single keyframe is being added per user action. Otherwise use
* CombinedKeyingResult to avoid spamming the user with messages.
*/
void generate_single_keying_result_report(const SingleKeyingResult result, ReportList *reports);
/**
* Class for tracking the result of inserting keyframes. Tracks how often each of
* `SingleKeyingResult` has happened.
* */
class CombinedKeyingResult {
private:
/* The index to the array maps a `SingleKeyingResult` to the number of times this result has
* occurred. */
std::array<int, size_t(SingleKeyingResult::_KEYING_RESULT_MAX)> result_counter;
public:
CombinedKeyingResult();
/**
* Increase the count of the given `SingleKeyingResult` by `count`.
*/
void add(SingleKeyingResult result, int count = 1);
/* Add values of the given result to this result. */
void merge(const CombinedKeyingResult &other);
int get_count(const SingleKeyingResult result) const;
bool has_errors() const;
void generate_reports(ReportList *reports, eReportType report_level = RPT_ERROR);
};
/**
* Return the default channel group name for the given RNA pointer and property
* path, or none if it has no default.
*
* For example, for object location/rotation/scale this returns the standard
* "Object Transforms" channel group name.
*/
std::optional<StringRefNull> default_channel_group_for_path(const PointerRNA *animated_struct,
StringRef prop_rna_path);
/* -------------------------------------------------------------------- */
/**
* Return whether key insertion functions are allowed to create new fcurves,
* according to the given flags.
*
* Specifically, both `INSERTKEY_REPLACE` and `INSERTKEY_AVAILABLE` prohibit the
* creation of new F-Curves.
*/
bool key_insertion_may_create_fcurve(eInsertKeyFlags insert_key_flags);
/* -------------------------------------------------------------------- */
/** \name Key-Framing Management
* \{ */
/** Ensure FCurve flags are correct for the property type it animates. */
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyType prop_type);
/**
* Return all values of the given PropertyRNA.
* In case the property is an array, the length of the vector is the same as the length of the
* array. Otherwise the vector has just 1 element.
* All property types are cast to float.
*/
Vector<float> get_property_values(PointerRNA *ptr, PropertyRNA *prop, bool visual_key);
/**
* \brief Main key-frame insertion API.
*
* Insert keys for `struct_pointer`, for all paths in `rna_paths`. Any necessary
* animation data (AnimData, Action, ...) is created if it doesn't already
* exist.
*
* Note that this function was created as part of an ongoing refactor by merging
* two other functions that were *almost* identical to each other. There are
* still things left over from that which can and should be improved (such as
* the partially redundant `scene_frame` and `anim_eval_context`parameters).
* Additionally, it's a bit of a mega-function now, and can probably be stripped
* down to a clearer core functionality.
*
* \param struct_pointer: RNA pointer to the struct to be keyed. This is often
* an ID, but not necessarily. For example, pose bones are also common. Note
* that if you have an `ID` and want to pass it here for keying, you can create
* the `PointerRNA` for it with `RNA_id_pointer_create()`.
*
* \param channel_group: the channel group to put any newly created fcurves
* under. If not given, the standard groups are used.
*
* \param rna_paths: the RNA paths to key. These paths are relative to
* `struct_pointer`. Note that for paths to array properties, if the array index
* is specified then only that element is keyed, but if the index is not
* specified then *all* array elements are keyed.
*
* \param scene_frame: the frame to insert the keys at. This is in scene time,
* not NLA mapped (NLA mapping is already handled internally by this function).
* If not given, the evaluation time from `anim_eval_context` is used instead.
*
* \returns A summary of the successful and failed keyframe insertions, with
* reasons for the failures.
*/
CombinedKeyingResult insert_keyframes(Main *bmain,
PointerRNA *struct_pointer,
std::optional<StringRefNull> channel_group,
const Span<RNAPath> rna_paths,
std::optional<float> scene_frame,
const AnimationEvalContext &anim_eval_context,
eBezTriple_KeyframeType key_type,
eInsertKeyFlags insert_key_flags);
/**
* \brief Secondary Insert Key-framing API call.
*
* Retrieves the value of the PropertyRNA and sets a key at `fcurve_frame`. If the property is an
* array, the FCurve's array_index is used to find the element's value.
*
* \warning This bypasses all animation layer and strip logic. Use with caution. If unsure, use
* `insert_keyframes` instead.
*
* \param fcurve_frame: The frame at which to insert the keyframe. No time remapping is done on the
* frame.
*
* \param keytype: The "keyframe type" (eBezTriple_KeyframeType), as shown in the Dope Sheet.
*
* \param flag: Used for special settings that alter the behavior of the keyframe insertion.
* These include the 'visual' key-framing modes, quick refresh,
* and extra keyframe filtering.
*
* \note this function no longer deals with the NLA. For NLA support use
* animrig::nla::insert_keyframe_direct Other high level keyframing functions still work with the
* NLA. See `insert_keyframes`.
*
* \return Success.
*/
SingleKeyingResult insert_keyframe_direct(PointerRNA &ptr,
PropertyRNA &prop,
FCurve &fcu,
float fcurve_frame,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag);
/**
* \brief Main Delete Key-Framing API call.
*
* Use this to delete keyframe on current frame for relevant channel.
* Will perform checks just in case.
* \return The number of key-frames deleted.
*/
int delete_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path, float cfra);
/**
* Main Keyframing API call:
* Use this when validation of necessary animation data isn't necessary as it
* already exists. It will clear the current buttons fcurve(s).
*
* \return The number of f-curves removed.
*/
int clear_keyframe(Main *bmain, ReportList *reports, ID *id, const RNAPath &rna_path);
/** Check if a flag is set for keyframing (per scene takes precedence). */
bool is_keying_flag(const Scene *scene, eKeying_Flag flag);
/**
* Checks whether a keyframe exists for the given ID-block one the given frame.
*
* \param frame: The frame on which to check for a keyframe. This uses a threshold so the float
* doesn't need to match exactly.
*/
bool id_frame_has_keyframe(ID *id, float frame);
/**
* Get the settings for key-framing from the given scene.
*/
eInsertKeyFlags get_keyframing_flags(Scene *scene);
/** \} */
/* -------------------------------------------------------------------- */
/** \name Auto keyframing
* Notes:
* - All the defines for this (User-Pref settings and Per-Scene settings)
* are defined in DNA_userdef_types.h
* - Scene settings take precedence over those for user-preferences, with old files
* inheriting user-preferences settings for the scene settings
* - "On/Off + Mode" are stored per Scene, but "settings" are currently stored as user-preferences.
* \{ */
/** Check if auto-key-framing is enabled (per scene takes precedence). */
bool is_autokey_on(const Scene *scene);
/** Check the mode for auto-keyframing (per scene takes precedence). */
bool is_autokey_mode(const Scene *scene, eAutokey_Mode mode);
/**
* Auto-keyframing feature - checks for whether anything should be done for the current frame.
*/
bool autokeyframe_cfra_can_key(const Scene *scene, ID *id);
/**
* Insert keyframes on the given object `ob` based on the auto-keying settings.
*
* \param rna_paths: Only inserts keys on those RNA paths.
*/
void autokeyframe_object(bContext *C, const Scene *scene, Object *ob, Span<RNAPath> rna_paths);
/**
* Auto-keyframing feature - for objects
*
* \note Context may not always be available,
* so must check before using it as it's a luxury for a few cases.
*/
bool autokeyframe_object(bContext *C, Scene *scene, Object *ob, KeyingSet *ks);
bool autokeyframe_pchan(bContext *C, Scene *scene, Object *ob, bPoseChannel *pchan, KeyingSet *ks);
/**
* Auto-keyframing feature - for poses/pose-channels
*
* \param rna_paths: Only inserts keys on those RNA paths.
* \param targetless_ik: Has targetless ik been done on any channels?
*
* \note Context may not always be available,
* so must check before using it as it's a luxury for a few cases.
*/
void autokeyframe_pose_channel(bContext *C,
Scene *scene,
Object *ob,
bPoseChannel *pose_channel,
Span<RNAPath> rna_paths,
short targetless_ik);
/**
* Use for auto-key-framing.
* \param only_if_property_keyed: if true, auto-key-framing only creates keyframes on already keyed
* properties. This is by design when using buttons. For other callers such as gizmos or sequencer
* preview transform, creating new animation/keyframes also on non-keyed properties is desired.
*/
bool autokeyframe_property(bContext *C,
Scene *scene,
PointerRNA *ptr,
PropertyRNA *prop,
int rnaindex,
float cfra,
bool only_if_property_keyed);
/** \} */
} // namespace animrig
} // namespace blender