#ifndef ANIMATION_SYSTEM_H #define ANIMATION_SYSTEM_H class AnimationNode; namespace ECS { struct AnimationPlayer; enum AnimationProcessMode { ANIMATION_PROCESS_PHYSICS, ANIMATION_PROCESS_IDLE, ANIMATION_PROCESS_MANUAL, }; enum AnimationMethodCallMode { ANIMATION_METHOD_CALL_DEFERRED, ANIMATION_METHOD_CALL_IMMEDIATE, }; enum SpecialProperty { SP_NONE, SP_NODE2D_POS, SP_NODE2D_ROT, SP_NODE2D_SCALE, }; struct TrackNodeCache { bool used; NodePath path; flecs::entity_t id; Ref resource; flecs::entity_t bone_idx; // accumulated transforms Vector3 loc_accum; Quat rot_accum; Vector3 scale_accum; uint64_t accum_pass; bool audio_playing; float audio_start; float audio_len; bool animation_playing; TrackNodeCache() : used(false), id(-1), bone_idx(-1), accum_pass(0), audio_playing(false), audio_start(0.0), audio_len(0.0), animation_playing(false) { } }; struct Track { Animation::TrackType type; Animation::InterpolationType interpolation; bool loop_wrap; NodePath path; // path to something bool imported; bool enabled; Track() { interpolation = Animation::INTERPOLATION_LINEAR; imported = false; loop_wrap = true; enabled = true; } virtual ~Track() {} }; struct Key { float transition; float time; // time in secs Key() { transition = 1; } }; // transform key holds either Vector3 or Quaternion template struct TKey : public Key { T value; }; struct TransformKey { Vector3 loc; Quat rot; Vector3 scale; }; struct TransformTrack : public Track { Vector> transforms; TransformTrack() { type = Animation::TYPE_TRANSFORM; } }; struct ValueTrack : public Track { Animation::UpdateMode update_mode; bool update_on_seek; Vector> values; ValueTrack() { type = Animation::TYPE_VALUE; update_mode = Animation::UPDATE_CONTINUOUS; } }; struct MethodKey : public Key { StringName method; Vector params; }; struct MethodTrack : public Track { Vector methods; MethodTrack() { type = Animation::TYPE_METHOD; } }; struct BezierKey { Vector2 in_handle; //relative (x always <0) Vector2 out_handle; //relative (x always >0) float value; }; struct BezierTrack : public Track { Vector> values; BezierTrack() { type = Animation::TYPE_BEZIER; } }; struct AudioKey { RES stream; float start_offset; //offset from start float end_offset; //offset from end, if 0 then full length or infinite AudioKey() { start_offset = 0; end_offset = 0; } }; struct AudioTrack : public Track { Vector> values; AudioTrack() { type = Animation::TYPE_AUDIO; } }; struct BasicTrack : public Track { uint8_t data[256]; BasicTrack() { type = Animation::TYPE_TRANSFORM; } }; struct AnimationData { String name; StringName next; int node_cache_size; struct TrackNodeCache *node_cache[128]; AnimationData(const Animation *anim) : animation(anim), node_cache_size(0) { assert(animation); animation = anim; } AnimationData() : animation(nullptr), node_cache_size(0) {} AnimationData(const AnimationData &d) { int i; name = d.name; next = d.next; assert(d.animation); node_cache_size = d.node_cache_size; for (i = 0; i < 128; i++) node_cache[i] = d.node_cache[i]; animation = d.animation; assert(animation); } AnimationData(AnimationData &&d) { int i; name = d.name; next = d.next; assert(d.animation); node_cache_size = d.node_cache_size; for (i = 0; i < 128; i++) node_cache[i] = d.node_cache[i]; animation = d.animation; assert(animation.is_valid()); d.node_cache_size = 0; d.name = ""; d.next = ""; d.animation = nullptr; } AnimationData &operator=(const AnimationData &d) { memnew_placement(this, AnimationData(d)); return *this; } const Animation *get_animation() const { return animation; } ~AnimationData() { animation = nullptr; } private: const Animation *animation; }; struct PlaybackData { AnimationData *from; float pos; float speed_scale; }; struct Blend { PlaybackData data; float blend_time; float blend_left; }; struct Playback { List blend; PlaybackData current; StringName assigned; bool seeked; bool started; Playback() { blend.clear(); seeked = false; started = false; } }; struct BlendKey { StringName from; StringName to; bool operator<(const BlendKey &bk) const { return from == bk.from ? String(to) < String(bk.to) : String(from) < String(bk.from); } }; struct TrackNodeCacheKey { flecs::entity_t id, bone_idx; inline bool operator<(const TrackNodeCacheKey &p_right) const { if (id < p_right.id) { return true; } else if (id > p_right.id) { return false; } else { return bone_idx < p_right.bone_idx; } } }; enum { NODE_CACHE_UPDATE_MAX = 1024, BLEND_FROM_MAX = 3 }; struct AnimationCache { Map node_cache_map; TrackNodeCache node_cache_data[NODE_CACHE_UPDATE_MAX]; }; struct AnimationPlayerData { int type_id; TrackNodeCache *cache_update[NODE_CACHE_UPDATE_MAX]; int cache_update_size; Set playing_caches; uint64_t accum_pass; float speed_scale; float default_blend_time; static Map animation_set[2]; Map blend_times; Playback playback; List queued; bool end_reached; bool end_notify; String autoplay; bool reset_on_save; AnimationProcessMode animation_process_mode; bool processing; bool active; bool playing; AnimationPlayerData(int id) { type_id = id; processing = false; playing = false; active = false; cache_update_size = 0; playing_caches.clear(); accum_pass = 0; speed_scale = 1.0f; default_blend_time = 0; animation_set[id].clear(); blend_times.clear(); queued.clear(); end_reached = false; end_notify = false; autoplay = ""; reset_on_save = false; animation_process_mode = AnimationProcessMode::ANIMATION_PROCESS_MANUAL; processing = false; active = false; } AnimationPlayerData(const AnimationPlayerData &d) { int i; type_id = d.type_id; for (i = 0; i < NODE_CACHE_UPDATE_MAX; i++) cache_update[i] = d.cache_update[i]; cache_update_size = d.cache_update_size; playing_caches = d.playing_caches; accum_pass = d.accum_pass; speed_scale = d.speed_scale; default_blend_time = d.default_blend_time; blend_times = d.blend_times; playback = d.playback; queued = d.queued; end_reached = d.end_reached; end_notify = d.end_notify; autoplay = d.autoplay; reset_on_save = d.reset_on_save; animation_process_mode = d.animation_process_mode; processing = d.processing; active = d.active; playing = d.playing; } AnimationPlayerData(AnimationPlayerData &&d) { memnew_placement(this, AnimationPlayerData(d)); d.playing = playing; d.cache_update_size = 0; d.active = false; } AnimationPlayerData &operator=(const AnimationPlayerData &d) { memnew_placement(this, AnimationPlayerData(d)); return *this; } AnimationPlayerData &operator=(AnimationPlayerData &&d) { int i; type_id = d.type_id; for (i = 0; i < NODE_CACHE_UPDATE_MAX; i++) cache_update[i] = d.cache_update[i]; cache_update_size = d.cache_update_size; playing_caches = d.playing_caches; accum_pass = d.accum_pass; speed_scale = d.speed_scale; default_blend_time = d.default_blend_time; blend_times = d.blend_times; playback = d.playback; queued = d.queued; end_reached = d.end_reached; end_notify = d.end_notify; autoplay = d.autoplay; reset_on_save = d.reset_on_save; animation_process_mode = d.animation_process_mode; processing = d.processing; active = d.active; playing = d.playing; d.playing = playing; d.cache_update_size = 0; d.active = false; return *this; } ~AnimationPlayerData() { playing = false; } }; /* AnimationPlayer */ /* public functions */ StringName find_animation( struct AnimationPlayerData *player, const Ref &p_animation); Error add_animation(flecs::entity_t entity, flecs::world &ecs, struct AnimationPlayerData *player, const StringName &p_name, const Animation *p_animation); void remove_animation(flecs::entity_t entity, flecs::world &ecs, struct AnimationPlayerData *player, const StringName &p_name); void rename_animation(struct AnimationPlayerData *player, const StringName &p_name, const StringName &p_new_name); bool has_animation( struct AnimationPlayerData *player, const StringName &p_name); Ref get_animation( struct AnimationPlayerData *player, const StringName &p_name); void get_animation_list( struct AnimationPlayerData *player, List *p_animations); void set_blend_time(struct AnimationPlayerData *player, const StringName &p_animation1, const StringName &p_animation2, float p_time); float get_blend_time(struct AnimationPlayerData *player, const StringName &p_animation1, const StringName &p_animation2); void animation_set_next(struct AnimationPlayerData *player, const StringName &p_animation, const StringName &p_next); StringName animation_get_next( struct AnimationPlayerData *player, const StringName &p_animation); void set_default_blend_time( struct AnimationPlayerData *player, float p_default); float get_default_blend_time(struct AnimationPlayerData *player); void play(struct AnimationPlayerData *player, const StringName &p_name = StringName(), float p_custom_blend = -1, float p_custom_scale = 1.0, bool p_from_end = false); void play_backwards(struct AnimationPlayerData *player, const StringName &p_name = StringName(), float p_custom_blend = -1); void queue(struct AnimationPlayerData *player, const StringName &p_name); PoolVector get_queue(struct AnimationPlayerData *player); void clear_queue(struct AnimationPlayerData *player); void stop(struct AnimationPlayerData *player, bool p_reset = true); bool is_playing(struct AnimationPlayerData *player); String get_current_animation(struct AnimationPlayerData *player); void set_current_animation( struct AnimationPlayerData *player, const String &p_anim); String get_assigned_animation(struct AnimationPlayerData *player); void set_assigned_animation( struct AnimationPlayerData *player, const String &p_anim); void set_active(struct AnimationPlayerData *player, bool p_active); bool is_active(struct AnimationPlayerData *player); bool is_valid(struct AnimationPlayerData *player); void set_speed_scale(struct AnimationPlayerData *player, float p_speed); float get_speed_scale(struct AnimationPlayerData *player); float get_playing_speed(struct AnimationPlayerData *player); void set_autoplay(struct AnimationPlayerData *player, const String &p_name); String get_autoplay(struct AnimationPlayerData *player); void set_reset_on_save_enabled( struct AnimationPlayerData *player, bool p_enabled); bool is_reset_on_save_enabled(struct AnimationPlayerData *player); void set_animation_process_mode( struct AnimationPlayerData *player, AnimationProcessMode p_mode); AnimationProcessMode get_animation_process_mode( struct AnimationPlayerData *player); void set_method_call_mode( struct AnimationPlayerData *player, AnimationMethodCallMode p_mode); AnimationMethodCallMode get_method_call_mode( struct AnimationPlayerData *player); void seek(struct AnimationPlayerData *player, float p_time, bool p_update = false); void seek_delta( struct AnimationPlayerData *player, float p_time, float p_delta); float get_current_animation_position(struct AnimationPlayerData *player); float get_current_animation_length(struct AnimationPlayerData *player); void advance(flecs::entity_t entity, flecs::world &ecs, AnimationPlayerData *player, float p_time); void set_root(struct AnimationPlayerData *player, const NodePath &p_root); NodePath get_root(struct AnimationPlayerData *player); void clear_caches(flecs::entity_t entity, flecs::world &ecs, struct AnimationPlayerData *player); void get_argument_options(struct AnimationPlayerData *player, const StringName &p_function, int p_idx, List *r_options); } //namespace ECS #endif