| 1 | /**************************************************************************/ |
| 2 | /* animation.h */ |
| 3 | /**************************************************************************/ |
| 4 | /* This file is part of: */ |
| 5 | /* GODOT ENGINE */ |
| 6 | /* https://godotengine.org */ |
| 7 | /**************************************************************************/ |
| 8 | /* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */ |
| 9 | /* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */ |
| 10 | /* */ |
| 11 | /* Permission is hereby granted, free of charge, to any person obtaining */ |
| 12 | /* a copy of this software and associated documentation files (the */ |
| 13 | /* "Software"), to deal in the Software without restriction, including */ |
| 14 | /* without limitation the rights to use, copy, modify, merge, publish, */ |
| 15 | /* distribute, sublicense, and/or sell copies of the Software, and to */ |
| 16 | /* permit persons to whom the Software is furnished to do so, subject to */ |
| 17 | /* the following conditions: */ |
| 18 | /* */ |
| 19 | /* The above copyright notice and this permission notice shall be */ |
| 20 | /* included in all copies or substantial portions of the Software. */ |
| 21 | /* */ |
| 22 | /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */ |
| 23 | /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */ |
| 24 | /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. */ |
| 25 | /* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */ |
| 26 | /* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */ |
| 27 | /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */ |
| 28 | /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ |
| 29 | /**************************************************************************/ |
| 30 | |
| 31 | #ifndef ANIMATION_H |
| 32 | #define ANIMATION_H |
| 33 | |
| 34 | #include "core/io/resource.h" |
| 35 | #include "core/templates/local_vector.h" |
| 36 | |
| 37 | #define ANIM_MIN_LENGTH 0.001 |
| 38 | |
| 39 | class Animation : public Resource { |
| 40 | GDCLASS(Animation, Resource); |
| 41 | RES_BASE_EXTENSION("anim" ); |
| 42 | |
| 43 | public: |
| 44 | enum TrackType { |
| 45 | TYPE_VALUE, ///< Set a value in a property, can be interpolated. |
| 46 | TYPE_POSITION_3D, ///< Position 3D track |
| 47 | TYPE_ROTATION_3D, ///< Rotation 3D track |
| 48 | TYPE_SCALE_3D, ///< Scale 3D track |
| 49 | TYPE_BLEND_SHAPE, ///< Blend Shape track |
| 50 | TYPE_METHOD, ///< Call any method on a specific node. |
| 51 | TYPE_BEZIER, ///< Bezier curve |
| 52 | TYPE_AUDIO, |
| 53 | TYPE_ANIMATION, |
| 54 | }; |
| 55 | |
| 56 | enum InterpolationType { |
| 57 | INTERPOLATION_NEAREST, |
| 58 | INTERPOLATION_LINEAR, |
| 59 | INTERPOLATION_CUBIC, |
| 60 | INTERPOLATION_LINEAR_ANGLE, |
| 61 | INTERPOLATION_CUBIC_ANGLE, |
| 62 | }; |
| 63 | |
| 64 | enum UpdateMode { |
| 65 | UPDATE_CONTINUOUS, |
| 66 | UPDATE_DISCRETE, |
| 67 | UPDATE_CAPTURE, |
| 68 | }; |
| 69 | |
| 70 | enum LoopMode { |
| 71 | LOOP_NONE, |
| 72 | LOOP_LINEAR, |
| 73 | LOOP_PINGPONG, |
| 74 | }; |
| 75 | |
| 76 | enum LoopedFlag { |
| 77 | LOOPED_FLAG_NONE, |
| 78 | LOOPED_FLAG_END, |
| 79 | LOOPED_FLAG_START, |
| 80 | }; |
| 81 | |
| 82 | enum FindMode { |
| 83 | FIND_MODE_NEAREST, |
| 84 | FIND_MODE_APPROX, |
| 85 | FIND_MODE_EXACT, |
| 86 | }; |
| 87 | |
| 88 | #ifdef TOOLS_ENABLED |
| 89 | enum HandleMode { |
| 90 | HANDLE_MODE_FREE, |
| 91 | HANDLE_MODE_LINEAR, |
| 92 | HANDLE_MODE_BALANCED, |
| 93 | HANDLE_MODE_MIRRORED, |
| 94 | }; |
| 95 | enum HandleSetMode { |
| 96 | HANDLE_SET_MODE_NONE, |
| 97 | HANDLE_SET_MODE_RESET, |
| 98 | HANDLE_SET_MODE_AUTO, |
| 99 | }; |
| 100 | #endif // TOOLS_ENABLED |
| 101 | |
| 102 | private: |
| 103 | struct Track { |
| 104 | TrackType type = TrackType::TYPE_ANIMATION; |
| 105 | InterpolationType interpolation = INTERPOLATION_LINEAR; |
| 106 | bool loop_wrap = true; |
| 107 | NodePath path; // path to something |
| 108 | bool imported = false; |
| 109 | bool enabled = true; |
| 110 | Track() {} |
| 111 | virtual ~Track() {} |
| 112 | }; |
| 113 | |
| 114 | struct Key { |
| 115 | real_t transition = 1.0; |
| 116 | double time = 0.0; // time in secs |
| 117 | }; |
| 118 | |
| 119 | // transform key holds either Vector3 or Quaternion |
| 120 | template <class T> |
| 121 | struct TKey : public Key { |
| 122 | T value; |
| 123 | }; |
| 124 | |
| 125 | const int32_t POSITION_TRACK_SIZE = 5; |
| 126 | const int32_t ROTATION_TRACK_SIZE = 6; |
| 127 | const int32_t SCALE_TRACK_SIZE = 5; |
| 128 | const int32_t BLEND_SHAPE_TRACK_SIZE = 3; |
| 129 | |
| 130 | /* POSITION TRACK */ |
| 131 | |
| 132 | struct PositionTrack : public Track { |
| 133 | Vector<TKey<Vector3>> positions; |
| 134 | int32_t compressed_track = -1; |
| 135 | PositionTrack() { type = TYPE_POSITION_3D; } |
| 136 | }; |
| 137 | |
| 138 | /* ROTATION TRACK */ |
| 139 | |
| 140 | struct RotationTrack : public Track { |
| 141 | Vector<TKey<Quaternion>> rotations; |
| 142 | int32_t compressed_track = -1; |
| 143 | RotationTrack() { type = TYPE_ROTATION_3D; } |
| 144 | }; |
| 145 | |
| 146 | /* SCALE TRACK */ |
| 147 | |
| 148 | struct ScaleTrack : public Track { |
| 149 | Vector<TKey<Vector3>> scales; |
| 150 | int32_t compressed_track = -1; |
| 151 | ScaleTrack() { type = TYPE_SCALE_3D; } |
| 152 | }; |
| 153 | |
| 154 | /* BLEND SHAPE TRACK */ |
| 155 | |
| 156 | struct BlendShapeTrack : public Track { |
| 157 | Vector<TKey<float>> blend_shapes; |
| 158 | int32_t compressed_track = -1; |
| 159 | BlendShapeTrack() { type = TYPE_BLEND_SHAPE; } |
| 160 | }; |
| 161 | |
| 162 | /* PROPERTY VALUE TRACK */ |
| 163 | |
| 164 | struct ValueTrack : public Track { |
| 165 | UpdateMode update_mode = UPDATE_CONTINUOUS; |
| 166 | bool update_on_seek = false; |
| 167 | Vector<TKey<Variant>> values; |
| 168 | |
| 169 | ValueTrack() { |
| 170 | type = TYPE_VALUE; |
| 171 | } |
| 172 | }; |
| 173 | |
| 174 | /* METHOD TRACK */ |
| 175 | |
| 176 | struct MethodKey : public Key { |
| 177 | StringName method; |
| 178 | Vector<Variant> params; |
| 179 | }; |
| 180 | |
| 181 | struct MethodTrack : public Track { |
| 182 | Vector<MethodKey> methods; |
| 183 | MethodTrack() { type = TYPE_METHOD; } |
| 184 | }; |
| 185 | |
| 186 | /* BEZIER TRACK */ |
| 187 | struct BezierKey { |
| 188 | Vector2 in_handle; //relative (x always <0) |
| 189 | Vector2 out_handle; //relative (x always >0) |
| 190 | real_t value = 0.0; |
| 191 | #ifdef TOOLS_ENABLED |
| 192 | HandleMode handle_mode = HANDLE_MODE_FREE; |
| 193 | #endif // TOOLS_ENABLED |
| 194 | }; |
| 195 | |
| 196 | struct BezierTrack : public Track { |
| 197 | Vector<TKey<BezierKey>> values; |
| 198 | |
| 199 | BezierTrack() { |
| 200 | type = TYPE_BEZIER; |
| 201 | } |
| 202 | }; |
| 203 | |
| 204 | /* AUDIO TRACK */ |
| 205 | |
| 206 | struct AudioKey { |
| 207 | Ref<Resource> stream; |
| 208 | real_t start_offset = 0.0; //offset from start |
| 209 | real_t end_offset = 0.0; //offset from end, if 0 then full length or infinite |
| 210 | AudioKey() { |
| 211 | } |
| 212 | }; |
| 213 | |
| 214 | struct AudioTrack : public Track { |
| 215 | Vector<TKey<AudioKey>> values; |
| 216 | bool use_blend = true; |
| 217 | |
| 218 | AudioTrack() { |
| 219 | type = TYPE_AUDIO; |
| 220 | } |
| 221 | }; |
| 222 | |
| 223 | /* AUDIO TRACK */ |
| 224 | |
| 225 | struct AnimationTrack : public Track { |
| 226 | Vector<TKey<StringName>> values; |
| 227 | |
| 228 | AnimationTrack() { |
| 229 | type = TYPE_ANIMATION; |
| 230 | } |
| 231 | }; |
| 232 | |
| 233 | Vector<Track *> tracks; |
| 234 | |
| 235 | /* |
| 236 | template<class T> |
| 237 | int _insert_pos(double p_time, T& p_keys);*/ |
| 238 | |
| 239 | template <class T> |
| 240 | void _clear(T &p_keys); |
| 241 | |
| 242 | template <class T, class V> |
| 243 | int _insert(double p_time, T &p_keys, const V &p_value); |
| 244 | |
| 245 | template <class K> |
| 246 | |
| 247 | inline int _find(const Vector<K> &p_keys, double p_time, bool p_backward = false) const; |
| 248 | |
| 249 | _FORCE_INLINE_ Vector3 _interpolate(const Vector3 &p_a, const Vector3 &p_b, real_t p_c) const; |
| 250 | _FORCE_INLINE_ Quaternion _interpolate(const Quaternion &p_a, const Quaternion &p_b, real_t p_c) const; |
| 251 | _FORCE_INLINE_ Variant _interpolate(const Variant &p_a, const Variant &p_b, real_t p_c) const; |
| 252 | _FORCE_INLINE_ real_t _interpolate(const real_t &p_a, const real_t &p_b, real_t p_c) const; |
| 253 | _FORCE_INLINE_ Variant _interpolate_angle(const Variant &p_a, const Variant &p_b, real_t p_c) const; |
| 254 | |
| 255 | _FORCE_INLINE_ Vector3 _cubic_interpolate_in_time(const Vector3 &p_pre_a, const Vector3 &p_a, const Vector3 &p_b, const Vector3 &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; |
| 256 | _FORCE_INLINE_ Quaternion _cubic_interpolate_in_time(const Quaternion &p_pre_a, const Quaternion &p_a, const Quaternion &p_b, const Quaternion &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; |
| 257 | _FORCE_INLINE_ Variant _cubic_interpolate_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; |
| 258 | _FORCE_INLINE_ real_t _cubic_interpolate_in_time(const real_t &p_pre_a, const real_t &p_a, const real_t &p_b, const real_t &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; |
| 259 | _FORCE_INLINE_ Variant _cubic_interpolate_angle_in_time(const Variant &p_pre_a, const Variant &p_a, const Variant &p_b, const Variant &p_post_b, real_t p_c, real_t p_pre_a_t, real_t p_b_t, real_t p_post_b_t) const; |
| 260 | |
| 261 | template <class T> |
| 262 | _FORCE_INLINE_ T _interpolate(const Vector<TKey<T>> &p_keys, double p_time, InterpolationType p_interp, bool p_loop_wrap, bool *p_ok, bool p_backward = false) const; |
| 263 | |
| 264 | template <class T> |
| 265 | _FORCE_INLINE_ void _track_get_key_indices_in_range(const Vector<T> &p_array, double from_time, double to_time, List<int> *p_indices, bool p_is_backward) const; |
| 266 | |
| 267 | double length = 1.0; |
| 268 | real_t step = 0.1; |
| 269 | LoopMode loop_mode = LOOP_NONE; |
| 270 | |
| 271 | /* Animation compression page format (version 1): |
| 272 | * |
| 273 | * Animation uses bitwidth based compression separated into small pages. The intention is that pages fit easily in the cache, so decoding is cache efficient. |
| 274 | * The page-based nature also makes future animation streaming from disk possible. |
| 275 | * |
| 276 | * Actual format: |
| 277 | * |
| 278 | * num_compressed_tracks = bounds.size() |
| 279 | * header : (x num_compressed_tracks) |
| 280 | * ------- |
| 281 | * timeline_keys_offset : uint32_t - offset to time keys |
| 282 | * timeline_size : uint32_t - amount of time keys |
| 283 | * data_keys_offset : uint32_t offset to key data |
| 284 | * |
| 285 | * time key (uint32_t): |
| 286 | * ------------------ |
| 287 | * frame : bits 0-15 - time offset of key, computed as: page.time_offset + frame * (1.0/fps) |
| 288 | * data_key_offset : bits 16-27 - offset to key data, computed as: data_keys_offset * 4 + data_key_offset |
| 289 | * data_key_count : bits 28-31 - amount of data keys pointed to, computed as: data_key_count+1 (max 16) |
| 290 | * |
| 291 | * data key: |
| 292 | * --------- |
| 293 | * X / Blend Shape : uint16_t - X coordinate of XYZ vector key, or Blend Shape value. If Blend shape, Y and Z are not present and can be ignored. |
| 294 | * Y : uint16_t |
| 295 | * Z : uint16_t |
| 296 | * If data_key_count+1 > 1 (if more than 1 key is stored): |
| 297 | * data_bitwidth : uint16_t - This is only present if data_key_count > 1. Contains delta bitwidth information. |
| 298 | * X / Blend Shape delta bitwidth: bits 0-3 - |
| 299 | * if 0, nothing is present for X (use the first key-value for subsequent keys), |
| 300 | * else assume the number of bits present for each element (+ 1 for sign). Assumed always 16 bits, delta max signed 15 bits, with underflow and overflow supported. |
| 301 | * Y delta bitwidth : bits 4-7 |
| 302 | * Z delta bitwidth : bits 8-11 |
| 303 | * FRAME delta bitwidth : 12-15 bits - always present (obviously), actual bitwidth is FRAME+1 |
| 304 | * Data key is 4 bytes long for Blend Shapes, 8 bytes long for pos/rot/scale. |
| 305 | * |
| 306 | * delta keys: |
| 307 | * ----------- |
| 308 | * Compressed format is packed in the following format after the data key, containing delta keys one after the next in a tightly bit packed fashion. |
| 309 | * FRAME bits -> X / Blend Shape Bits (if bitwidth > 0) -> Y Bits (if not Blend Shape and Y Bitwidth > 0) -> Z Bits (if not Blend Shape and Z Bitwidth > 0) |
| 310 | * |
| 311 | * data key format: |
| 312 | * ---------------- |
| 313 | * Decoding keys means starting from the base key and going key by key applying deltas until the proper position is reached needed for interpolation. |
| 314 | * Resulting values are uint32_t |
| 315 | * data for X / Blend Shape, Y and Z must be normalized first: unorm = float(data) / 65535.0 |
| 316 | * **Blend Shape**: (unorm * 2.0 - 1.0) * Compression::BLEND_SHAPE_RANGE |
| 317 | * **Pos/Scale**: unorm_vec3 * bounds[track].size + bounds[track].position |
| 318 | * **Rotation**: Quaternion(Vector3::octahedron_decode(unorm_vec3.xy),unorm_vec3.z * Math_PI * 2.0) |
| 319 | * **Frame**: page.time_offset + frame * (1.0/fps) |
| 320 | */ |
| 321 | |
| 322 | struct Compression { |
| 323 | enum { |
| 324 | MAX_DATA_TRACK_SIZE = 16384, |
| 325 | BLEND_SHAPE_RANGE = 8, // - 8.0 to 8.0 |
| 326 | FORMAT_VERSION = 1 |
| 327 | }; |
| 328 | struct Page { |
| 329 | Vector<uint8_t> data; |
| 330 | double time_offset; |
| 331 | }; |
| 332 | |
| 333 | uint32_t fps = 120; |
| 334 | LocalVector<Page> pages; |
| 335 | LocalVector<AABB> bounds; //used by position and scale tracks (which contain index to track and index to bounds). |
| 336 | bool enabled = false; |
| 337 | } compression; |
| 338 | |
| 339 | Vector3i _compress_key(uint32_t p_track, const AABB &p_bounds, int32_t p_key = -1, float p_time = 0.0); |
| 340 | bool _rotation_interpolate_compressed(uint32_t p_compressed_track, double p_time, Quaternion &r_ret) const; |
| 341 | bool _pos_scale_interpolate_compressed(uint32_t p_compressed_track, double p_time, Vector3 &r_ret) const; |
| 342 | bool _blend_shape_interpolate_compressed(uint32_t p_compressed_track, double p_time, float &r_ret) const; |
| 343 | template <uint32_t COMPONENTS> |
| 344 | bool _fetch_compressed(uint32_t p_compressed_track, double p_time, Vector3i &r_current_value, double &r_current_time, Vector3i &r_next_value, double &r_next_time, uint32_t *key_index = nullptr) const; |
| 345 | template <uint32_t COMPONENTS> |
| 346 | bool _fetch_compressed_by_index(uint32_t p_compressed_track, int p_index, Vector3i &r_value, double &r_time) const; |
| 347 | int _get_compressed_key_count(uint32_t p_compressed_track) const; |
| 348 | template <uint32_t COMPONENTS> |
| 349 | void _get_compressed_key_indices_in_range(uint32_t p_compressed_track, double p_time, double p_delta, List<int> *r_indices) const; |
| 350 | _FORCE_INLINE_ Quaternion _uncompress_quaternion(const Vector3i &p_value) const; |
| 351 | _FORCE_INLINE_ Vector3 _uncompress_pos_scale(uint32_t p_compressed_track, const Vector3i &p_value) const; |
| 352 | _FORCE_INLINE_ float _uncompress_blend_shape(const Vector3i &p_value) const; |
| 353 | |
| 354 | // bind helpers |
| 355 | private: |
| 356 | bool _float_track_optimize_key(const TKey<float> t0, const TKey<float> t1, const TKey<float> t2, real_t p_allowed_velocity_err, real_t p_allowed_precision_error); |
| 357 | bool _vector2_track_optimize_key(const TKey<Vector2> t0, const TKey<Vector2> t1, const TKey<Vector2> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); |
| 358 | bool _vector3_track_optimize_key(const TKey<Vector3> t0, const TKey<Vector3> t1, const TKey<Vector3> t2, real_t p_alowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); |
| 359 | bool _quaternion_track_optimize_key(const TKey<Quaternion> t0, const TKey<Quaternion> t1, const TKey<Quaternion> t2, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); |
| 360 | |
| 361 | void _position_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); |
| 362 | void _rotation_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_error, real_t p_allowed_precision_error); |
| 363 | void _scale_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); |
| 364 | void _blend_shape_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_precision_error); |
| 365 | void _value_track_optimize(int p_idx, real_t p_allowed_velocity_err, real_t p_allowed_angular_err, real_t p_allowed_precision_error); |
| 366 | |
| 367 | protected: |
| 368 | bool _set(const StringName &p_name, const Variant &p_value); |
| 369 | bool _get(const StringName &p_name, Variant &r_ret) const; |
| 370 | void _get_property_list(List<PropertyInfo> *p_list) const; |
| 371 | |
| 372 | virtual void reset_state() override; |
| 373 | |
| 374 | static void _bind_methods(); |
| 375 | |
| 376 | public: |
| 377 | int add_track(TrackType p_type, int p_at_pos = -1); |
| 378 | void remove_track(int p_track); |
| 379 | |
| 380 | int get_track_count() const; |
| 381 | TrackType track_get_type(int p_track) const; |
| 382 | |
| 383 | void track_set_path(int p_track, const NodePath &p_path); |
| 384 | NodePath track_get_path(int p_track) const; |
| 385 | int find_track(const NodePath &p_path, const TrackType p_type) const; |
| 386 | |
| 387 | void track_move_up(int p_track); |
| 388 | void track_move_down(int p_track); |
| 389 | void track_move_to(int p_track, int p_to_index); |
| 390 | void track_swap(int p_track, int p_with_track); |
| 391 | |
| 392 | void track_set_imported(int p_track, bool p_imported); |
| 393 | bool track_is_imported(int p_track) const; |
| 394 | |
| 395 | void track_set_enabled(int p_track, bool p_enabled); |
| 396 | bool track_is_enabled(int p_track) const; |
| 397 | |
| 398 | int track_insert_key(int p_track, double p_time, const Variant &p_key, real_t p_transition = 1); |
| 399 | void track_set_key_transition(int p_track, int p_key_idx, real_t p_transition); |
| 400 | void track_set_key_value(int p_track, int p_key_idx, const Variant &p_value); |
| 401 | void track_set_key_time(int p_track, int p_key_idx, double p_time); |
| 402 | int track_find_key(int p_track, double p_time, FindMode p_find_mode = FIND_MODE_NEAREST) const; |
| 403 | void track_remove_key(int p_track, int p_idx); |
| 404 | void track_remove_key_at_time(int p_track, double p_time); |
| 405 | int track_get_key_count(int p_track) const; |
| 406 | Variant track_get_key_value(int p_track, int p_key_idx) const; |
| 407 | double track_get_key_time(int p_track, int p_key_idx) const; |
| 408 | real_t track_get_key_transition(int p_track, int p_key_idx) const; |
| 409 | bool track_is_compressed(int p_track) const; |
| 410 | |
| 411 | int position_track_insert_key(int p_track, double p_time, const Vector3 &p_position); |
| 412 | Error position_track_get_key(int p_track, int p_key, Vector3 *r_position) const; |
| 413 | Error try_position_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const; |
| 414 | Vector3 position_track_interpolate(int p_track, double p_time) const; |
| 415 | |
| 416 | int rotation_track_insert_key(int p_track, double p_time, const Quaternion &p_rotation); |
| 417 | Error rotation_track_get_key(int p_track, int p_key, Quaternion *r_rotation) const; |
| 418 | Error try_rotation_track_interpolate(int p_track, double p_time, Quaternion *r_interpolation) const; |
| 419 | Quaternion rotation_track_interpolate(int p_track, double p_time) const; |
| 420 | |
| 421 | int scale_track_insert_key(int p_track, double p_time, const Vector3 &p_scale); |
| 422 | Error scale_track_get_key(int p_track, int p_key, Vector3 *r_scale) const; |
| 423 | Error try_scale_track_interpolate(int p_track, double p_time, Vector3 *r_interpolation) const; |
| 424 | Vector3 scale_track_interpolate(int p_track, double p_time) const; |
| 425 | |
| 426 | int blend_shape_track_insert_key(int p_track, double p_time, float p_blend); |
| 427 | Error blend_shape_track_get_key(int p_track, int p_key, float *r_blend) const; |
| 428 | Error try_blend_shape_track_interpolate(int p_track, double p_time, float *r_blend) const; |
| 429 | float blend_shape_track_interpolate(int p_track, double p_time) const; |
| 430 | |
| 431 | void track_set_interpolation_type(int p_track, InterpolationType p_interp); |
| 432 | InterpolationType track_get_interpolation_type(int p_track) const; |
| 433 | |
| 434 | int bezier_track_insert_key(int p_track, double p_time, real_t p_value, const Vector2 &p_in_handle, const Vector2 &p_out_handle); |
| 435 | void bezier_track_set_key_value(int p_track, int p_index, real_t p_value); |
| 436 | void bezier_track_set_key_in_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0); |
| 437 | void bezier_track_set_key_out_handle(int p_track, int p_index, const Vector2 &p_handle, real_t p_balanced_value_time_ratio = 1.0); |
| 438 | real_t bezier_track_get_key_value(int p_track, int p_index) const; |
| 439 | Vector2 bezier_track_get_key_in_handle(int p_track, int p_index) const; |
| 440 | Vector2 bezier_track_get_key_out_handle(int p_track, int p_index) const; |
| 441 | #ifdef TOOLS_ENABLED |
| 442 | void bezier_track_set_key_handle_mode(int p_track, int p_index, HandleMode p_mode, HandleSetMode p_set_mode = HANDLE_SET_MODE_NONE); |
| 443 | HandleMode bezier_track_get_key_handle_mode(int p_track, int p_index) const; |
| 444 | #endif // TOOLS_ENABLED |
| 445 | |
| 446 | real_t bezier_track_interpolate(int p_track, double p_time) const; |
| 447 | |
| 448 | int audio_track_insert_key(int p_track, double p_time, const Ref<Resource> &p_stream, real_t p_start_offset = 0, real_t p_end_offset = 0); |
| 449 | void audio_track_set_key_stream(int p_track, int p_key, const Ref<Resource> &p_stream); |
| 450 | void audio_track_set_key_start_offset(int p_track, int p_key, real_t p_offset); |
| 451 | void audio_track_set_key_end_offset(int p_track, int p_key, real_t p_offset); |
| 452 | Ref<Resource> audio_track_get_key_stream(int p_track, int p_key) const; |
| 453 | real_t audio_track_get_key_start_offset(int p_track, int p_key) const; |
| 454 | real_t audio_track_get_key_end_offset(int p_track, int p_key) const; |
| 455 | void audio_track_set_use_blend(int p_track, bool p_enable); |
| 456 | bool audio_track_is_use_blend(int p_track) const; |
| 457 | |
| 458 | int animation_track_insert_key(int p_track, double p_time, const StringName &p_animation); |
| 459 | void animation_track_set_key_animation(int p_track, int p_key, const StringName &p_animation); |
| 460 | StringName animation_track_get_key_animation(int p_track, int p_key) const; |
| 461 | |
| 462 | void track_set_interpolation_loop_wrap(int p_track, bool p_enable); |
| 463 | bool track_get_interpolation_loop_wrap(int p_track) const; |
| 464 | |
| 465 | Variant value_track_interpolate(int p_track, double p_time) const; |
| 466 | void value_track_set_update_mode(int p_track, UpdateMode p_mode); |
| 467 | UpdateMode value_track_get_update_mode(int p_track) const; |
| 468 | |
| 469 | Vector<Variant> method_track_get_params(int p_track, int p_key_idx) const; |
| 470 | StringName method_track_get_name(int p_track, int p_key_idx) const; |
| 471 | |
| 472 | void copy_track(int p_track, Ref<Animation> p_to_animation); |
| 473 | |
| 474 | void track_get_key_indices_in_range(int p_track, double p_time, double p_delta, List<int> *p_indices, Animation::LoopedFlag p_looped_flag = Animation::LOOPED_FLAG_NONE) const; |
| 475 | |
| 476 | void set_length(real_t p_length); |
| 477 | real_t get_length() const; |
| 478 | |
| 479 | void set_loop_mode(LoopMode p_loop_mode); |
| 480 | LoopMode get_loop_mode() const; |
| 481 | |
| 482 | void set_step(real_t p_step); |
| 483 | real_t get_step() const; |
| 484 | |
| 485 | void clear(); |
| 486 | |
| 487 | void optimize(real_t p_allowed_velocity_err = 0.01, real_t p_allowed_angular_err = 0.01, int p_precision = 3); |
| 488 | void compress(uint32_t p_page_size = 8192, uint32_t p_fps = 120, float p_split_tolerance = 4.0); // 4.0 seems to be the split tolerance sweet spot from many tests |
| 489 | |
| 490 | // Helper math functions for Variant. |
| 491 | static Variant add_variant(const Variant &a, const Variant &b); |
| 492 | static Variant subtract_variant(const Variant &a, const Variant &b); |
| 493 | static Variant blend_variant(const Variant &a, const Variant &b, float c); |
| 494 | static Variant interpolate_variant(const Variant &a, const Variant &b, float c); |
| 495 | |
| 496 | Animation(); |
| 497 | ~Animation(); |
| 498 | }; |
| 499 | |
| 500 | VARIANT_ENUM_CAST(Animation::TrackType); |
| 501 | VARIANT_ENUM_CAST(Animation::InterpolationType); |
| 502 | VARIANT_ENUM_CAST(Animation::UpdateMode); |
| 503 | VARIANT_ENUM_CAST(Animation::LoopMode); |
| 504 | VARIANT_ENUM_CAST(Animation::LoopedFlag); |
| 505 | VARIANT_ENUM_CAST(Animation::FindMode); |
| 506 | #ifdef TOOLS_ENABLED |
| 507 | VARIANT_ENUM_CAST(Animation::HandleMode); |
| 508 | VARIANT_ENUM_CAST(Animation::HandleSetMode); |
| 509 | #endif // TOOLS_ENABLED |
| 510 | |
| 511 | #endif // ANIMATION_H |
| 512 | |