Anim: DNA for Animation data-block
Introduce new DNA for the `Animation` data-block and its sub-data. This includes the blenkernel code for reading & writing to blend files, and for memory management (freeing, duplicating). Minimal C++ wrappers are included, with just the functionality needed for blenkernel to do its job. The Outliner code is extended so that it knows about the new data-type, nothing more. For more info, see issue #113594. Pull Request: https://projects.blender.org/blender/blender/pulls/119077
This commit is contained in:
297
source/blender/animrig/ANIM_animation.hh
Normal file
297
source/blender/animrig/ANIM_animation.hh
Normal file
@@ -0,0 +1,297 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup animrig
|
||||
*
|
||||
* \brief Animation data-block functionality.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
|
||||
#include "BLI_math_vector.hh"
|
||||
#include "BLI_set.hh"
|
||||
#include "BLI_string_ref.hh"
|
||||
|
||||
struct AnimationEvalContext;
|
||||
struct FCurve;
|
||||
struct ID;
|
||||
struct Main;
|
||||
struct PointerRNA;
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
/* Forward declarations for the types defined later in this file. */
|
||||
class Layer;
|
||||
class Strip;
|
||||
class Binding;
|
||||
|
||||
/* Use an alias for the Binding handle type to help disambiguate function parameters. */
|
||||
using binding_handle_t = decltype(::AnimationBinding::handle);
|
||||
|
||||
/**
|
||||
* Container of animation data for one or more animated IDs.
|
||||
*
|
||||
* Broadly an Animation consists of Layers, each Layer has Strips, and it's the
|
||||
* Strips that eventually contain the animation data.
|
||||
*
|
||||
* Temporary limitation: each Animation can only contain one Layer.
|
||||
*
|
||||
* Which sub-set of that data drives the animation of which ID is determined by
|
||||
* which Binding is associated with that ID.
|
||||
*
|
||||
* \see AnimData::animation
|
||||
* \see AnimData::binding_handle
|
||||
*/
|
||||
class Animation : public ::Animation {
|
||||
public:
|
||||
Animation() = default;
|
||||
/**
|
||||
* Copy constructor is deleted, as code should use regular ID library
|
||||
* management functions to duplicate this data-block.
|
||||
*/
|
||||
Animation(const Animation &other) = delete;
|
||||
|
||||
/* Animation Layers access. */
|
||||
blender::Span<const Layer *> layers() const;
|
||||
blender::MutableSpan<Layer *> layers();
|
||||
const Layer *layer(int64_t index) const;
|
||||
Layer *layer(int64_t index);
|
||||
|
||||
/* Animation Binding access. */
|
||||
blender::Span<const Binding *> bindings() const;
|
||||
blender::MutableSpan<Binding *> bindings();
|
||||
const Binding *binding(int64_t index) const;
|
||||
Binding *binding(int64_t index);
|
||||
|
||||
/** Free all data in the `Animation`. Doesn't delete the `Animation` itself. */
|
||||
void free_data();
|
||||
};
|
||||
static_assert(sizeof(Animation) == sizeof(::Animation),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
/**
|
||||
* Strips contain the actual animation data.
|
||||
*
|
||||
* Although the data model allows for different strip types, currently only a
|
||||
* single type is implemented: keyframe strips.
|
||||
*/
|
||||
class Strip : public ::AnimationStrip {
|
||||
public:
|
||||
Strip() = default;
|
||||
/**
|
||||
* Strip cannot be duplicated via the copy constructor. Either use a concrete
|
||||
* strip type's copy constructor, or use Strip::duplicate().
|
||||
*
|
||||
* The reason why the copy constructor won't work is due to the double nature
|
||||
* of the inheritance at play here:
|
||||
*
|
||||
* C-style inheritance: `KeyframeAnimationStrip` "inherits" `AnimationStrip"
|
||||
* by embedding the latter. This means that any `KeyframeAnimationStrip *`
|
||||
* can be reinterpreted as `AnimationStrip *`.
|
||||
*
|
||||
* C++-style inheritance: the C++ wrappers inherit the DNA structs, so
|
||||
* `animrig::Strip` inherits `::AnimationStrip`, and
|
||||
* `animrig::KeyframeStrip` inherits `::KeyframeAnimationStrip`.
|
||||
*/
|
||||
Strip(const Strip &other) = delete;
|
||||
~Strip();
|
||||
|
||||
Strip *duplicate(StringRefNull allocation_name) const;
|
||||
|
||||
enum class Type : int8_t { Keyframe = 0 };
|
||||
|
||||
/**
|
||||
* Strip type, so it's known which subclass this can be wrapped in without
|
||||
* having to rely on C++ RTTI.
|
||||
*/
|
||||
Type type() const
|
||||
{
|
||||
return Type(this->strip_type);
|
||||
}
|
||||
|
||||
template<typename T> bool is() const;
|
||||
template<typename T> T &as();
|
||||
template<typename T> const T &as() const;
|
||||
};
|
||||
static_assert(sizeof(Strip) == sizeof(::AnimationStrip),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
/**
|
||||
* Layers can be stacked on top of each other to define the animation. Each
|
||||
* layer has a mix mode and an influence (0-1), which define how it is mixed
|
||||
* with the layers below it.
|
||||
*
|
||||
* Layers contain one or more Strips, which in turn contain the animation data
|
||||
* itself.
|
||||
*
|
||||
* Temporary limitation: at most one strip may exist on a layer, and it extends
|
||||
* from negative to positive infinity.
|
||||
*/
|
||||
class Layer : public ::AnimationLayer {
|
||||
public:
|
||||
Layer() = default;
|
||||
Layer(const Layer &other);
|
||||
~Layer();
|
||||
|
||||
enum class Flags : uint8_t {
|
||||
/* Set by default, cleared to mute. */
|
||||
Enabled = (1 << 0),
|
||||
/* When adding/removing a flag, also update the ENUM_OPERATORS() invocation below. */
|
||||
};
|
||||
|
||||
Flags flags() const
|
||||
{
|
||||
return static_cast<Flags>(this->layer_flags);
|
||||
}
|
||||
|
||||
enum class MixMode : int8_t {
|
||||
/** Channels in this layer override the same channels from underlying layers. */
|
||||
Replace = 0,
|
||||
/** Channels in this layer are added to underlying layers as sequential operations. */
|
||||
Offset = 1,
|
||||
/** Channels in this layer are added to underlying layers on a per-channel basis. */
|
||||
Add = 2,
|
||||
/** Channels in this layer are subtracted to underlying layers on a per-channel basis. */
|
||||
Subtract = 3,
|
||||
/** Channels in this layer are multiplied with underlying layers on a per-channel basis. */
|
||||
Multiply = 4,
|
||||
};
|
||||
|
||||
MixMode mix_mode() const
|
||||
{
|
||||
return static_cast<MixMode>(this->layer_mix_mode);
|
||||
}
|
||||
|
||||
/* Strip access. */
|
||||
blender::Span<const Strip *> strips() const;
|
||||
blender::MutableSpan<Strip *> strips();
|
||||
const Strip *strip(int64_t index) const;
|
||||
Strip *strip(int64_t index);
|
||||
};
|
||||
static_assert(sizeof(Layer) == sizeof(::AnimationLayer),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
ENUM_OPERATORS(Layer::Flags, Layer::Flags::Enabled);
|
||||
|
||||
/**
|
||||
* Identifier for a sub-set of the animation data inside an Animation data-block.
|
||||
*
|
||||
* An animatable ID specifies both an `Animation*` and an `AnimationBinding::handle`
|
||||
* to identify which F-Curves (and in the future other animation data) it will
|
||||
* be animated by.
|
||||
*
|
||||
* This is called an 'binding' because it acts like an binding socket of the
|
||||
* Animation data-block, into which an animatable ID can be noodled.
|
||||
*
|
||||
* \see AnimData::binding_handle
|
||||
*/
|
||||
class Binding : public ::AnimationBinding {
|
||||
public:
|
||||
Binding() = default;
|
||||
Binding(const Binding &other) = default;
|
||||
~Binding() = default;
|
||||
};
|
||||
static_assert(sizeof(Binding) == sizeof(::AnimationBinding),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
/**
|
||||
* KeyframeStrips effectively contain a bag of F-Curves for each Binding.
|
||||
*/
|
||||
class KeyframeStrip : public ::KeyframeAnimationStrip {
|
||||
public:
|
||||
KeyframeStrip() = default;
|
||||
KeyframeStrip(const KeyframeStrip &other);
|
||||
~KeyframeStrip();
|
||||
|
||||
/* ChannelBag array access. */
|
||||
blender::Span<const ChannelBag *> channelbags() const;
|
||||
blender::MutableSpan<ChannelBag *> channelbags();
|
||||
const ChannelBag *channelbag(int64_t index) const;
|
||||
ChannelBag *channelbag(int64_t index);
|
||||
};
|
||||
static_assert(sizeof(KeyframeStrip) == sizeof(::KeyframeAnimationStrip),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
template<> KeyframeStrip &Strip::as<KeyframeStrip>();
|
||||
template<> const KeyframeStrip &Strip::as<KeyframeStrip>() const;
|
||||
|
||||
/**
|
||||
* Collection of F-Curves, intended for a specific Binding handle.
|
||||
*/
|
||||
class ChannelBag : public ::AnimationChannelBag {
|
||||
public:
|
||||
ChannelBag() = default;
|
||||
ChannelBag(const ChannelBag &other);
|
||||
~ChannelBag();
|
||||
|
||||
/* FCurves access. */
|
||||
blender::Span<const FCurve *> fcurves() const;
|
||||
blender::MutableSpan<FCurve *> fcurves();
|
||||
const FCurve *fcurve(int64_t index) const;
|
||||
FCurve *fcurve(int64_t index);
|
||||
};
|
||||
static_assert(sizeof(ChannelBag) == sizeof(::AnimationChannelBag),
|
||||
"DNA struct and its C++ wrapper must have the same size");
|
||||
|
||||
} // namespace blender::animrig
|
||||
|
||||
/* Wrap functions for the DNA structs. */
|
||||
|
||||
inline blender::animrig::Animation &Animation::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::Animation *>(this);
|
||||
}
|
||||
inline const blender::animrig::Animation &Animation::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::Animation *>(this);
|
||||
}
|
||||
|
||||
inline blender::animrig::Layer &AnimationLayer::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::Layer *>(this);
|
||||
}
|
||||
inline const blender::animrig::Layer &AnimationLayer::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::Layer *>(this);
|
||||
}
|
||||
|
||||
inline blender::animrig::Binding &AnimationBinding::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::Binding *>(this);
|
||||
}
|
||||
inline const blender::animrig::Binding &AnimationBinding::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::Binding *>(this);
|
||||
}
|
||||
|
||||
inline blender::animrig::Strip &AnimationStrip::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::Strip *>(this);
|
||||
}
|
||||
inline const blender::animrig::Strip &AnimationStrip::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::Strip *>(this);
|
||||
}
|
||||
|
||||
inline blender::animrig::KeyframeStrip &KeyframeAnimationStrip::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::KeyframeStrip *>(this);
|
||||
}
|
||||
inline const blender::animrig::KeyframeStrip &KeyframeAnimationStrip::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::KeyframeStrip *>(this);
|
||||
}
|
||||
|
||||
inline blender::animrig::ChannelBag &AnimationChannelBag::wrap()
|
||||
{
|
||||
return *reinterpret_cast<blender::animrig::ChannelBag *>(this);
|
||||
}
|
||||
inline const blender::animrig::ChannelBag &AnimationChannelBag::wrap() const
|
||||
{
|
||||
return *reinterpret_cast<const blender::animrig::ChannelBag *>(this);
|
||||
}
|
||||
@@ -21,6 +21,7 @@ set(INC_SYS
|
||||
set(SRC
|
||||
intern/action.cc
|
||||
intern/anim_rna.cc
|
||||
intern/animation.cc
|
||||
intern/animdata.cc
|
||||
intern/bone_collections.cc
|
||||
intern/bonecolor.cc
|
||||
@@ -31,6 +32,7 @@ set(SRC
|
||||
intern/visualkey.cc
|
||||
|
||||
ANIM_action.hh
|
||||
ANIM_animation.hh
|
||||
ANIM_animdata.hh
|
||||
ANIM_armature_iter.hh
|
||||
ANIM_bone_collections.hh
|
||||
@@ -50,6 +52,7 @@ set(LIB
|
||||
bf::dna
|
||||
PRIVATE bf_editor_interface
|
||||
PRIVATE bf::intern::guardedalloc
|
||||
PRIVATE bf::intern::atomic
|
||||
)
|
||||
|
||||
|
||||
|
||||
260
source/blender/animrig/intern/animation.cc
Normal file
260
source/blender/animrig/intern/animation.cc
Normal file
@@ -0,0 +1,260 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
#include "DNA_anim_defaults.h"
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
|
||||
#include "BLI_listbase.h"
|
||||
#include "BLI_listbase_wrapper.hh"
|
||||
#include "BLI_math_base.h"
|
||||
#include "BLI_string.h"
|
||||
#include "BLI_string_utf8.h"
|
||||
#include "BLI_string_utils.hh"
|
||||
|
||||
#include "BKE_anim_data.hh"
|
||||
#include "BKE_animation.hh"
|
||||
#include "BKE_fcurve.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_main.hh"
|
||||
|
||||
#include "ED_keyframing.hh"
|
||||
|
||||
#include "MEM_guardedalloc.h"
|
||||
|
||||
#include "atomic_ops.h"
|
||||
|
||||
#include "ANIM_animation.hh"
|
||||
#include "ANIM_fcurve.hh"
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
namespace blender::animrig {
|
||||
|
||||
/* ----- Animation implementation ----------- */
|
||||
|
||||
blender::Span<const Layer *> Animation::layers() const
|
||||
{
|
||||
return blender::Span<Layer *>{reinterpret_cast<Layer **>(this->layer_array),
|
||||
this->layer_array_num};
|
||||
}
|
||||
blender::MutableSpan<Layer *> Animation::layers()
|
||||
{
|
||||
return blender::MutableSpan<Layer *>{reinterpret_cast<Layer **>(this->layer_array),
|
||||
this->layer_array_num};
|
||||
}
|
||||
const Layer *Animation::layer(const int64_t index) const
|
||||
{
|
||||
return &this->layer_array[index]->wrap();
|
||||
}
|
||||
Layer *Animation::layer(const int64_t index)
|
||||
{
|
||||
return &this->layer_array[index]->wrap();
|
||||
}
|
||||
|
||||
blender::Span<const Binding *> Animation::bindings() const
|
||||
{
|
||||
return blender::Span<Binding *>{reinterpret_cast<Binding **>(this->binding_array),
|
||||
this->binding_array_num};
|
||||
}
|
||||
blender::MutableSpan<Binding *> Animation::bindings()
|
||||
{
|
||||
return blender::MutableSpan<Binding *>{reinterpret_cast<Binding **>(this->binding_array),
|
||||
this->binding_array_num};
|
||||
}
|
||||
const Binding *Animation::binding(const int64_t index) const
|
||||
{
|
||||
return &this->binding_array[index]->wrap();
|
||||
}
|
||||
Binding *Animation::binding(const int64_t index)
|
||||
{
|
||||
return &this->binding_array[index]->wrap();
|
||||
}
|
||||
|
||||
void Animation::free_data()
|
||||
{
|
||||
/* Free layers. */
|
||||
for (Layer *layer : this->layers()) {
|
||||
MEM_delete(layer);
|
||||
}
|
||||
MEM_SAFE_FREE(this->layer_array);
|
||||
this->layer_array_num = 0;
|
||||
|
||||
/* Free bindings. */
|
||||
for (Binding *binding : this->bindings()) {
|
||||
MEM_delete(binding);
|
||||
}
|
||||
MEM_SAFE_FREE(this->binding_array);
|
||||
this->binding_array_num = 0;
|
||||
}
|
||||
|
||||
/* ----- AnimationLayer implementation ----------- */
|
||||
|
||||
Layer::Layer(const Layer &other)
|
||||
{
|
||||
memcpy(this, &other, sizeof(*this));
|
||||
|
||||
/* Strips. */
|
||||
this->strip_array = MEM_cnew_array<AnimationStrip *>(other.strip_array_num, __func__);
|
||||
for (int i : other.strips().index_range()) {
|
||||
this->strip_array[i] = other.strip(i)->duplicate(__func__);
|
||||
}
|
||||
}
|
||||
|
||||
Layer::~Layer()
|
||||
{
|
||||
for (Strip *strip : this->strips()) {
|
||||
MEM_delete(strip);
|
||||
}
|
||||
MEM_SAFE_FREE(this->strip_array);
|
||||
this->strip_array_num = 0;
|
||||
}
|
||||
|
||||
blender::Span<const Strip *> Layer::strips() const
|
||||
{
|
||||
return blender::Span<Strip *>{reinterpret_cast<Strip **>(this->strip_array),
|
||||
this->strip_array_num};
|
||||
}
|
||||
blender::MutableSpan<Strip *> Layer::strips()
|
||||
{
|
||||
return blender::MutableSpan<Strip *>{reinterpret_cast<Strip **>(this->strip_array),
|
||||
this->strip_array_num};
|
||||
}
|
||||
const Strip *Layer::strip(const int64_t index) const
|
||||
{
|
||||
return &this->strip_array[index]->wrap();
|
||||
}
|
||||
Strip *Layer::strip(const int64_t index)
|
||||
{
|
||||
return &this->strip_array[index]->wrap();
|
||||
}
|
||||
|
||||
/* ----- AnimationBinding implementation ----------- */
|
||||
|
||||
/* ----- AnimationStrip implementation ----------- */
|
||||
|
||||
Strip *Strip::duplicate(const StringRefNull allocation_name) const
|
||||
{
|
||||
switch (this->type()) {
|
||||
case Type::Keyframe: {
|
||||
const KeyframeStrip &source = this->as<KeyframeStrip>();
|
||||
KeyframeStrip *copy = MEM_new<KeyframeStrip>(allocation_name.c_str(), source);
|
||||
return ©->strip.wrap();
|
||||
}
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Strip::~Strip()
|
||||
{
|
||||
switch (this->type()) {
|
||||
case Type::Keyframe:
|
||||
this->as<KeyframeStrip>().~KeyframeStrip();
|
||||
return;
|
||||
}
|
||||
BLI_assert_unreachable();
|
||||
}
|
||||
|
||||
/* ----- KeyframeAnimationStrip implementation ----------- */
|
||||
|
||||
KeyframeStrip::KeyframeStrip(const KeyframeStrip &other)
|
||||
{
|
||||
memcpy(this, &other, sizeof(*this));
|
||||
|
||||
this->channelbags_array = MEM_cnew_array<AnimationChannelBag *>(other.channelbags_array_num,
|
||||
__func__);
|
||||
Span<const ChannelBag *> channelbags_src = other.channelbags();
|
||||
for (int i : channelbags_src.index_range()) {
|
||||
this->channelbags_array[i] = MEM_new<animrig::ChannelBag>(__func__, *other.channelbag(i));
|
||||
}
|
||||
}
|
||||
|
||||
KeyframeStrip::~KeyframeStrip()
|
||||
{
|
||||
for (ChannelBag *channelbag_for_binding : this->channelbags()) {
|
||||
MEM_delete(channelbag_for_binding);
|
||||
}
|
||||
MEM_SAFE_FREE(this->channelbags_array);
|
||||
this->channelbags_array_num = 0;
|
||||
}
|
||||
|
||||
template<> bool Strip::is<KeyframeStrip>() const
|
||||
{
|
||||
return this->type() == Type::Keyframe;
|
||||
}
|
||||
|
||||
template<> KeyframeStrip &Strip::as<KeyframeStrip>()
|
||||
{
|
||||
BLI_assert_msg(this->is<KeyframeStrip>(), "Strip is not a KeyframeStrip");
|
||||
return *reinterpret_cast<KeyframeStrip *>(this);
|
||||
}
|
||||
|
||||
template<> const KeyframeStrip &Strip::as<KeyframeStrip>() const
|
||||
{
|
||||
BLI_assert_msg(this->is<KeyframeStrip>(), "Strip is not a KeyframeStrip");
|
||||
return *reinterpret_cast<const KeyframeStrip *>(this);
|
||||
}
|
||||
|
||||
blender::Span<const ChannelBag *> KeyframeStrip::channelbags() const
|
||||
{
|
||||
return blender::Span<ChannelBag *>{reinterpret_cast<ChannelBag **>(this->channelbags_array),
|
||||
this->channelbags_array_num};
|
||||
}
|
||||
blender::MutableSpan<ChannelBag *> KeyframeStrip::channelbags()
|
||||
{
|
||||
return blender::MutableSpan<ChannelBag *>{
|
||||
reinterpret_cast<ChannelBag **>(this->channelbags_array), this->channelbags_array_num};
|
||||
}
|
||||
const ChannelBag *KeyframeStrip::channelbag(const int64_t index) const
|
||||
{
|
||||
return &this->channelbags_array[index]->wrap();
|
||||
}
|
||||
ChannelBag *KeyframeStrip::channelbag(const int64_t index)
|
||||
{
|
||||
return &this->channelbags_array[index]->wrap();
|
||||
}
|
||||
|
||||
/* AnimationChannelBag implementation. */
|
||||
|
||||
ChannelBag::ChannelBag(const ChannelBag &other)
|
||||
{
|
||||
this->binding_handle = other.binding_handle;
|
||||
this->fcurve_array_num = other.fcurve_array_num;
|
||||
|
||||
this->fcurve_array = MEM_cnew_array<FCurve *>(other.fcurve_array_num, __func__);
|
||||
for (int i = 0; i < other.fcurve_array_num; i++) {
|
||||
const FCurve *fcu_src = other.fcurve_array[i];
|
||||
this->fcurve_array[i] = BKE_fcurve_copy(fcu_src);
|
||||
}
|
||||
}
|
||||
|
||||
ChannelBag::~ChannelBag()
|
||||
{
|
||||
for (FCurve *fcu : this->fcurves()) {
|
||||
BKE_fcurve_free(fcu);
|
||||
}
|
||||
MEM_SAFE_FREE(this->fcurve_array);
|
||||
this->fcurve_array_num = 0;
|
||||
}
|
||||
|
||||
blender::Span<const FCurve *> ChannelBag::fcurves() const
|
||||
{
|
||||
return blender::Span<FCurve *>{this->fcurve_array, this->fcurve_array_num};
|
||||
}
|
||||
blender::MutableSpan<FCurve *> ChannelBag::fcurves()
|
||||
{
|
||||
return blender::MutableSpan<FCurve *>{this->fcurve_array, this->fcurve_array_num};
|
||||
}
|
||||
const FCurve *ChannelBag::fcurve(const int64_t index) const
|
||||
{
|
||||
return this->fcurve_array[index];
|
||||
}
|
||||
FCurve *ChannelBag::fcurve(const int64_t index)
|
||||
{
|
||||
return this->fcurve_array[index];
|
||||
}
|
||||
|
||||
} // namespace blender::animrig
|
||||
17
source/blender/blenkernel/BKE_animation.hh
Normal file
17
source/blender/blenkernel/BKE_animation.hh
Normal file
@@ -0,0 +1,17 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup bke
|
||||
*
|
||||
* This file only contains the memory management functions for the Animation
|
||||
* data-block. For all other functionality, see `source/blender/animrig`.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
struct Animation;
|
||||
struct Main;
|
||||
|
||||
Animation *BKE_animation_add(Main *bmain, const char name[]);
|
||||
@@ -273,6 +273,7 @@ extern IDTypeInfo IDType_ID_CV;
|
||||
extern IDTypeInfo IDType_ID_PT;
|
||||
extern IDTypeInfo IDType_ID_VO;
|
||||
extern IDTypeInfo IDType_ID_GP;
|
||||
extern IDTypeInfo IDType_ID_AN;
|
||||
|
||||
/** Empty shell mostly, but needed for read code. */
|
||||
extern IDTypeInfo IDType_ID_LINK_PLACEHOLDER;
|
||||
|
||||
@@ -210,6 +210,7 @@ struct Main {
|
||||
ListBase collections;
|
||||
ListBase armatures;
|
||||
ListBase actions;
|
||||
ListBase animations;
|
||||
ListBase nodetrees;
|
||||
ListBase brushes;
|
||||
ListBase particles;
|
||||
|
||||
@@ -55,6 +55,7 @@ set(SRC
|
||||
intern/anim_path.cc
|
||||
intern/anim_sys.cc
|
||||
intern/anim_visualization.cc
|
||||
intern/animation.cc
|
||||
intern/anonymous_attribute_id.cc
|
||||
intern/appdir.cc
|
||||
intern/armature.cc
|
||||
@@ -327,6 +328,7 @@ set(SRC
|
||||
BKE_anim_data.hh
|
||||
BKE_anim_path.h
|
||||
BKE_anim_visualization.h
|
||||
BKE_animation.hh
|
||||
BKE_animsys.h
|
||||
BKE_anonymous_attribute_id.hh
|
||||
BKE_appdir.hh
|
||||
|
||||
@@ -292,6 +292,7 @@ void BKE_animdata_foreach_id(AnimData *adt, LibraryForeachIDData *data)
|
||||
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcu, data));
|
||||
}
|
||||
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->animation, IDWALK_CB_USER);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->action, IDWALK_CB_USER);
|
||||
BKE_LIB_FOREACHID_PROCESS_IDSUPER(data, adt->tmpact, IDWALK_CB_USER);
|
||||
|
||||
|
||||
255
source/blender/blenkernel/intern/animation.cc
Normal file
255
source/blender/blenkernel/intern/animation.cc
Normal file
@@ -0,0 +1,255 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file Animation data-block.
|
||||
* \ingroup bke
|
||||
*/
|
||||
|
||||
#include "BLI_map.hh"
|
||||
#include "BLI_string_utf8.h"
|
||||
|
||||
#include "BLO_read_write.hh"
|
||||
|
||||
#include "BKE_animation.hh"
|
||||
#include "BKE_fcurve.hh"
|
||||
#include "BKE_idtype.hh"
|
||||
#include "BKE_lib_id.hh"
|
||||
#include "BKE_lib_query.hh"
|
||||
#include "BKE_main.hh"
|
||||
|
||||
#include "ANIM_animation.hh"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_defaults.h"
|
||||
|
||||
#include "BLT_translation.hh"
|
||||
|
||||
struct BlendWriter;
|
||||
struct BlendDataReader;
|
||||
|
||||
namespace blender::bke {
|
||||
|
||||
static void animation_copy_data(Main * /*bmain*/,
|
||||
std::optional<Library *> /*owner_library*/,
|
||||
ID *id_dst,
|
||||
const ID *id_src,
|
||||
const int /*flag*/)
|
||||
{
|
||||
Animation *dna_anim_dst = reinterpret_cast<Animation *>(id_dst);
|
||||
animrig::Animation &anim_dst = dna_anim_dst->wrap();
|
||||
|
||||
const Animation *dna_anim_src = reinterpret_cast<const Animation *>(id_src);
|
||||
const animrig::Animation &anim_src = dna_anim_src->wrap();
|
||||
|
||||
/* Copy all simple properties. */
|
||||
anim_dst.layer_array_num = anim_src.layer_array_num;
|
||||
anim_dst.layer_active_index = anim_src.layer_active_index;
|
||||
anim_dst.binding_array_num = anim_src.binding_array_num;
|
||||
anim_dst.last_binding_handle = anim_src.last_binding_handle;
|
||||
|
||||
/* Layers. */
|
||||
anim_dst.layer_array = MEM_cnew_array<AnimationLayer *>(anim_src.layer_array_num, __func__);
|
||||
for (int i : anim_src.layers().index_range()) {
|
||||
anim_dst.layer_array[i] = MEM_new<animrig::Layer>(__func__, *anim_src.layer(i));
|
||||
}
|
||||
|
||||
/* Bindings. */
|
||||
anim_dst.binding_array = MEM_cnew_array<AnimationBinding *>(anim_src.binding_array_num,
|
||||
__func__);
|
||||
for (int i : anim_src.bindings().index_range()) {
|
||||
anim_dst.binding_array[i] = MEM_new<animrig::Binding>(__func__, *anim_src.binding(i));
|
||||
}
|
||||
}
|
||||
|
||||
/** Free (or release) any data used by this animation (does not free the animation itself). */
|
||||
static void animation_free_data(ID *id)
|
||||
{
|
||||
reinterpret_cast<Animation *>(id)->wrap().free_data();
|
||||
}
|
||||
|
||||
static void animation_foreach_id(ID *id, LibraryForeachIDData *data)
|
||||
{
|
||||
animrig::Animation &anim = reinterpret_cast<Animation *>(id)->wrap();
|
||||
|
||||
for (animrig::Layer *layer : anim.layers()) {
|
||||
for (animrig::Strip *strip : layer->strips()) {
|
||||
switch (strip->type()) {
|
||||
case animrig::Strip::Type::Keyframe: {
|
||||
auto &key_strip = strip->as<animrig::KeyframeStrip>();
|
||||
for (animrig::ChannelBag *channelbag_for_binding : key_strip.channelbags()) {
|
||||
for (FCurve *fcurve : channelbag_for_binding->fcurves()) {
|
||||
BKE_LIB_FOREACHID_PROCESS_FUNCTION_CALL(data, BKE_fcurve_foreach_id(fcurve, data));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_channelbag(BlendWriter *writer, animrig::ChannelBag &channelbag)
|
||||
{
|
||||
BLO_write_struct(writer, AnimationChannelBag, &channelbag);
|
||||
|
||||
Span<FCurve *> fcurves = channelbag.fcurves();
|
||||
BLO_write_pointer_array(writer, fcurves.size(), fcurves.data());
|
||||
|
||||
for (FCurve *fcurve : fcurves) {
|
||||
BLO_write_struct(writer, FCurve, fcurve);
|
||||
BKE_fcurve_blend_write_data(writer, fcurve);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_keyframe_strip(BlendWriter *writer, animrig::KeyframeStrip &key_strip)
|
||||
{
|
||||
BLO_write_struct(writer, KeyframeAnimationStrip, &key_strip);
|
||||
|
||||
auto channelbags = key_strip.channelbags();
|
||||
BLO_write_pointer_array(writer, channelbags.size(), channelbags.data());
|
||||
|
||||
for (animrig::ChannelBag *channelbag : channelbags) {
|
||||
write_channelbag(writer, *channelbag);
|
||||
}
|
||||
}
|
||||
|
||||
static void write_strips(BlendWriter *writer, Span<animrig::Strip *> strips)
|
||||
{
|
||||
BLO_write_pointer_array(writer, strips.size(), strips.data());
|
||||
|
||||
for (animrig::Strip *strip : strips) {
|
||||
switch (strip->type()) {
|
||||
case animrig::Strip::Type::Keyframe: {
|
||||
auto &key_strip = strip->as<animrig::KeyframeStrip>();
|
||||
write_keyframe_strip(writer, key_strip);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void write_layers(BlendWriter *writer, Span<animrig::Layer *> layers)
|
||||
{
|
||||
BLO_write_pointer_array(writer, layers.size(), layers.data());
|
||||
|
||||
for (animrig::Layer *layer : layers) {
|
||||
BLO_write_struct(writer, AnimationLayer, layer);
|
||||
write_strips(writer, layer->strips());
|
||||
}
|
||||
}
|
||||
|
||||
static void write_bindings(BlendWriter *writer, Span<animrig::Binding *> bindings)
|
||||
{
|
||||
BLO_write_pointer_array(writer, bindings.size(), bindings.data());
|
||||
for (animrig::Binding *binding : bindings) {
|
||||
BLO_write_struct(writer, AnimationBinding, binding);
|
||||
}
|
||||
}
|
||||
|
||||
static void animation_blend_write(BlendWriter *writer, ID *id, const void *id_address)
|
||||
{
|
||||
animrig::Animation &anim = reinterpret_cast<Animation *>(id)->wrap();
|
||||
|
||||
BLO_write_id_struct(writer, Animation, id_address, &anim.id);
|
||||
BKE_id_blend_write(writer, &anim.id);
|
||||
|
||||
write_layers(writer, anim.layers());
|
||||
write_bindings(writer, anim.bindings());
|
||||
}
|
||||
|
||||
static void read_channelbag(BlendDataReader *reader, animrig::ChannelBag &channelbag)
|
||||
{
|
||||
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&channelbag.fcurve_array));
|
||||
|
||||
for (int i = 0; i < channelbag.fcurve_array_num; i++) {
|
||||
BLO_read_data_address(reader, &channelbag.fcurve_array[i]);
|
||||
BKE_fcurve_blend_read_data(reader, channelbag.fcurve_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void read_keyframe_strip(BlendDataReader *reader, animrig::KeyframeStrip &strip)
|
||||
{
|
||||
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&strip.channelbags_array));
|
||||
|
||||
for (int i = 0; i < strip.channelbags_array_num; i++) {
|
||||
BLO_read_data_address(reader, &strip.channelbags_array[i]);
|
||||
AnimationChannelBag *channelbag = strip.channelbags_array[i];
|
||||
read_channelbag(reader, channelbag->wrap());
|
||||
}
|
||||
}
|
||||
|
||||
static void read_animation_layers(BlendDataReader *reader, animrig::Animation &anim)
|
||||
{
|
||||
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&anim.layer_array));
|
||||
|
||||
for (int layer_idx = 0; layer_idx < anim.layer_array_num; layer_idx++) {
|
||||
BLO_read_data_address(reader, &anim.layer_array[layer_idx]);
|
||||
AnimationLayer *layer = anim.layer_array[layer_idx];
|
||||
|
||||
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&layer->strip_array));
|
||||
for (int strip_idx = 0; strip_idx < layer->strip_array_num; strip_idx++) {
|
||||
BLO_read_data_address(reader, &layer->strip_array[strip_idx]);
|
||||
AnimationStrip *dna_strip = layer->strip_array[strip_idx];
|
||||
animrig::Strip &strip = dna_strip->wrap();
|
||||
|
||||
switch (strip.type()) {
|
||||
case animrig::Strip::Type::Keyframe: {
|
||||
read_keyframe_strip(reader, strip.as<animrig::KeyframeStrip>());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void read_animation_bindings(BlendDataReader *reader, animrig::Animation &anim)
|
||||
{
|
||||
BLO_read_pointer_array(reader, reinterpret_cast<void **>(&anim.binding_array));
|
||||
|
||||
for (int i = 0; i < anim.binding_array_num; i++) {
|
||||
BLO_read_data_address(reader, &anim.binding_array[i]);
|
||||
}
|
||||
}
|
||||
|
||||
static void animation_blend_read_data(BlendDataReader *reader, ID *id)
|
||||
{
|
||||
animrig::Animation &animation = reinterpret_cast<Animation *>(id)->wrap();
|
||||
read_animation_layers(reader, animation);
|
||||
read_animation_bindings(reader, animation);
|
||||
}
|
||||
|
||||
} // namespace blender::bke
|
||||
|
||||
IDTypeInfo IDType_ID_AN = {
|
||||
/*id_code*/ ID_AN,
|
||||
/*id_filter*/ FILTER_ID_AN,
|
||||
/*dependencies_id_types*/ 0,
|
||||
/*main_listbase_index*/ INDEX_ID_AN,
|
||||
/*struct_size*/ sizeof(Animation),
|
||||
/*name*/ "Animation",
|
||||
/*name_plural*/ N_("animations"),
|
||||
/*translation_context*/ BLT_I18NCONTEXT_ID_ANIMATION,
|
||||
/*flags*/ IDTYPE_FLAGS_NO_ANIMDATA,
|
||||
/*asset_type_info*/ nullptr,
|
||||
|
||||
/*init_data*/ nullptr,
|
||||
/*copy_data*/ blender::bke::animation_copy_data,
|
||||
/*free_data*/ blender::bke::animation_free_data,
|
||||
/*make_local*/ nullptr,
|
||||
/*foreach_id*/ blender::bke::animation_foreach_id,
|
||||
/*foreach_cache*/ nullptr,
|
||||
/*foreach_path*/ nullptr,
|
||||
/*owner_pointer_get*/ nullptr,
|
||||
|
||||
/*blend_write*/ blender::bke::animation_blend_write,
|
||||
/*blend_read_data*/ blender::bke::animation_blend_read_data,
|
||||
/*blend_read_after_liblink*/ nullptr,
|
||||
|
||||
/*blend_read_undo_preserve*/ nullptr,
|
||||
|
||||
/*lib_override_apply_post*/ nullptr,
|
||||
};
|
||||
|
||||
Animation *BKE_animation_add(Main *bmain, const char name[])
|
||||
{
|
||||
Animation *anim = static_cast<Animation *>(BKE_id_new(bmain, ID_AN, name));
|
||||
return anim;
|
||||
}
|
||||
@@ -83,6 +83,7 @@ static void id_type_init()
|
||||
INIT_TYPE(ID_GR);
|
||||
INIT_TYPE(ID_AR);
|
||||
INIT_TYPE(ID_AC);
|
||||
INIT_TYPE(ID_AN);
|
||||
INIT_TYPE(ID_NT);
|
||||
INIT_TYPE(ID_BR);
|
||||
INIT_TYPE(ID_PA);
|
||||
@@ -225,6 +226,7 @@ int BKE_idtype_idcode_to_index(const short idcode)
|
||||
|
||||
switch ((ID_Type)idcode) {
|
||||
CASE_IDINDEX(AC);
|
||||
CASE_IDINDEX(AN);
|
||||
CASE_IDINDEX(AR);
|
||||
CASE_IDINDEX(BR);
|
||||
CASE_IDINDEX(CA);
|
||||
@@ -284,6 +286,7 @@ int BKE_idtype_idfilter_to_index(const uint64_t id_filter)
|
||||
|
||||
switch (id_filter) {
|
||||
CASE_IDINDEX(AC);
|
||||
CASE_IDINDEX(AN);
|
||||
CASE_IDINDEX(AR);
|
||||
CASE_IDINDEX(BR);
|
||||
CASE_IDINDEX(CA);
|
||||
|
||||
@@ -849,6 +849,8 @@ ListBase *which_libbase(Main *bmain, short type)
|
||||
return &(bmain->armatures);
|
||||
case ID_AC:
|
||||
return &(bmain->actions);
|
||||
case ID_AN:
|
||||
return &(bmain->animations);
|
||||
case ID_NT:
|
||||
return &(bmain->nodetrees);
|
||||
case ID_BR:
|
||||
@@ -894,6 +896,7 @@ int set_listbasepointers(Main *bmain, ListBase *lb[/*INDEX_ID_MAX*/])
|
||||
|
||||
/* Moved here to avoid problems when freeing with animato (aligorith). */
|
||||
lb[INDEX_ID_AC] = &(bmain->actions);
|
||||
lb[INDEX_ID_AN] = &(bmain->animations);
|
||||
|
||||
lb[INDEX_ID_KE] = &(bmain->shapekeys);
|
||||
|
||||
|
||||
@@ -86,6 +86,7 @@ const char *BLT_translate_do_new_dataname(const char *msgctxt, const char *msgid
|
||||
/* ID-types contexts. */
|
||||
/* WARNING! Keep it in sync with ID-types in `blenkernel/intern/idtype.cc`. */
|
||||
#define BLT_I18NCONTEXT_ID_ACTION "Action"
|
||||
#define BLT_I18NCONTEXT_ID_ANIMATION "Animation"
|
||||
#define BLT_I18NCONTEXT_ID_ARMATURE "Armature"
|
||||
#define BLT_I18NCONTEXT_ID_BRUSH "Brush"
|
||||
#define BLT_I18NCONTEXT_ID_CACHEFILE "CacheFile"
|
||||
|
||||
@@ -557,6 +557,10 @@ void DepsgraphNodeBuilder::build_id(ID *id, const bool force_be_visible)
|
||||
case ID_AC:
|
||||
build_action((bAction *)id);
|
||||
break;
|
||||
case ID_AN:
|
||||
/* TODO: actually handle this ID type properly, will be done in a followup commit. */
|
||||
build_generic_id(id);
|
||||
break;
|
||||
case ID_AR:
|
||||
build_armature((bArmature *)id);
|
||||
break;
|
||||
|
||||
@@ -525,6 +525,10 @@ void DepsgraphRelationBuilder::build_id(ID *id)
|
||||
case ID_AC:
|
||||
build_action((bAction *)id);
|
||||
break;
|
||||
case ID_AN:
|
||||
/* TODO: actually handle this ID type properly, will be done in a followup commit. */
|
||||
build_generic_id(id);
|
||||
break;
|
||||
case ID_AR:
|
||||
build_armature((bArmature *)id);
|
||||
break;
|
||||
|
||||
@@ -2392,6 +2392,8 @@ int UI_icon_from_idcode(const int idcode)
|
||||
switch ((ID_Type)idcode) {
|
||||
case ID_AC:
|
||||
return ICON_ACTION;
|
||||
case ID_AN:
|
||||
return ICON_ACTION; /* TODO: give Animation its own icon. */
|
||||
case ID_AR:
|
||||
return ICON_ARMATURE_DATA;
|
||||
case ID_BR:
|
||||
|
||||
@@ -1118,6 +1118,8 @@ static const char *template_id_browse_tip(const StructRNA *type)
|
||||
return N_("Browse Armature data to be linked");
|
||||
case ID_AC:
|
||||
return N_("Browse Action to be linked");
|
||||
case ID_AN:
|
||||
return N_("Browse Animation to be linked");
|
||||
case ID_NT:
|
||||
return N_("Browse Node Tree to be linked");
|
||||
case ID_BR:
|
||||
|
||||
@@ -616,6 +616,7 @@ static int gather_frames_to_render_for_id(LibraryIDLinkCallbackData *cb_data)
|
||||
case ID_SCR: /* Screen */
|
||||
case ID_GR: /* Group */
|
||||
case ID_AC: /* bAction */
|
||||
case ID_AN: /* Animation */
|
||||
case ID_BR: /* Brush */
|
||||
case ID_WM: /* WindowManager */
|
||||
case ID_LS: /* FreestyleLineStyle */
|
||||
|
||||
@@ -2433,6 +2433,8 @@ static BIFIconID tree_element_get_icon_from_id(const ID *id)
|
||||
return ICON_WORLD_DATA;
|
||||
case ID_AC:
|
||||
return ICON_ACTION;
|
||||
case ID_AN:
|
||||
return ICON_ACTION; /* TODO: give Animation its own icon. */
|
||||
case ID_NLA:
|
||||
return ICON_NLA;
|
||||
case ID_TXT: {
|
||||
|
||||
@@ -139,6 +139,7 @@ struct TreeElementIcon {
|
||||
ID_GR, \
|
||||
ID_AR, \
|
||||
ID_AC, \
|
||||
ID_AN, \
|
||||
ID_BR, \
|
||||
ID_PA, \
|
||||
ID_GD_LEGACY, \
|
||||
|
||||
@@ -147,6 +147,7 @@ static void get_element_operation_type(
|
||||
case ID_KE:
|
||||
case ID_WO:
|
||||
case ID_AC:
|
||||
case ID_AN:
|
||||
case ID_TXT:
|
||||
case ID_GR:
|
||||
case ID_LS:
|
||||
|
||||
@@ -88,6 +88,7 @@ std::unique_ptr<TreeElementID> TreeElementID::create_from_id(TreeElement &legacy
|
||||
case ID_TXT:
|
||||
case ID_SO:
|
||||
case ID_AC:
|
||||
case ID_AN:
|
||||
case ID_PAL:
|
||||
case ID_PC:
|
||||
case ID_CF:
|
||||
|
||||
@@ -1210,6 +1210,7 @@ typedef enum IDRecalcFlag {
|
||||
#define FILTER_ID_LI (1ULL << 39)
|
||||
#define FILTER_ID_GP (1ULL << 40)
|
||||
#define FILTER_ID_IP (1ULL << 41)
|
||||
#define FILTER_ID_AN (1ULL << 42)
|
||||
|
||||
#define FILTER_ID_ALL \
|
||||
(FILTER_ID_AC | FILTER_ID_AR | FILTER_ID_BR | FILTER_ID_CA | FILTER_ID_CU_LEGACY | \
|
||||
@@ -1219,7 +1220,7 @@ typedef enum IDRecalcFlag {
|
||||
FILTER_ID_SPK | FILTER_ID_SO | FILTER_ID_TE | FILTER_ID_TXT | FILTER_ID_VF | FILTER_ID_WO | \
|
||||
FILTER_ID_CF | FILTER_ID_WS | FILTER_ID_LP | FILTER_ID_CV | FILTER_ID_PT | FILTER_ID_VO | \
|
||||
FILTER_ID_SIM | FILTER_ID_KE | FILTER_ID_SCR | FILTER_ID_WM | FILTER_ID_LI | FILTER_ID_GP | \
|
||||
FILTER_ID_IP)
|
||||
FILTER_ID_IP | FILTER_ID_AN)
|
||||
|
||||
/**
|
||||
* This enum defines the index assigned to each type of IDs in the array returned by
|
||||
@@ -1258,6 +1259,7 @@ typedef enum eID_Index {
|
||||
/* Animation types, might be used by almost all other types. */
|
||||
INDEX_ID_IP, /* Deprecated. */
|
||||
INDEX_ID_AC,
|
||||
INDEX_ID_AN,
|
||||
|
||||
/* Grease Pencil, special case, should be with the other obdata, but it can also be used by many
|
||||
* other ID types, including node trees e.g.
|
||||
|
||||
@@ -84,6 +84,7 @@ typedef enum ID_Type {
|
||||
ID_PT = MAKE_ID2('P', 'T'), /* PointCloud */
|
||||
ID_VO = MAKE_ID2('V', 'O'), /* Volume */
|
||||
ID_GP = MAKE_ID2('G', 'P'), /* Grease Pencil */
|
||||
ID_AN = MAKE_ID2('A', 'N'), /* Animation */
|
||||
} ID_Type;
|
||||
|
||||
/* Only used as 'placeholder' in .blend files for directly linked data-blocks. */
|
||||
|
||||
39
source/blender/makesdna/DNA_anim_defaults.h
Normal file
39
source/blender/makesdna/DNA_anim_defaults.h
Normal file
@@ -0,0 +1,39 @@
|
||||
/* SPDX-FileCopyrightText: 2024 Blender Authors
|
||||
*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later */
|
||||
|
||||
/** \file
|
||||
* \ingroup DNA
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <math.h>
|
||||
|
||||
/* Struct members on own line. */
|
||||
/* clang-format off */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name AnimationLayer Struct
|
||||
* \{ */
|
||||
|
||||
#define _DNA_DEFAULT_AnimationLayer \
|
||||
{ \
|
||||
.influence = 1.0f, \
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/** \name AnimationStrip Struct
|
||||
* \{ */
|
||||
|
||||
#define _DNA_DEFAULT_AnimationStrip \
|
||||
{ \
|
||||
.frame_start = -INFINITY, \
|
||||
.frame_end = INFINITY, \
|
||||
}
|
||||
|
||||
/** \} */
|
||||
|
||||
/* clang-format on */
|
||||
@@ -15,6 +15,19 @@
|
||||
#include "DNA_curve_types.h"
|
||||
#include "DNA_listBase.h"
|
||||
|
||||
#ifdef __cplusplus
|
||||
# include "BLI_span.hh"
|
||||
|
||||
# include <type_traits>
|
||||
#endif
|
||||
|
||||
/* Forward declarations so the actual declarations can happen top-down. */
|
||||
struct Animation;
|
||||
struct AnimationLayer;
|
||||
struct AnimationBinding;
|
||||
struct AnimationStrip;
|
||||
struct AnimationChannelBag;
|
||||
|
||||
/* ************************************************ */
|
||||
/* F-Curve DataTypes */
|
||||
|
||||
@@ -1146,10 +1159,32 @@ typedef struct AnimData {
|
||||
/** Runtime data, for depsgraph evaluation. */
|
||||
FCurve **driver_array;
|
||||
|
||||
/**
|
||||
* Active Animation data-block. If this is set, `action` and NLA-related
|
||||
* properties should be ignored. Note that there is plenty of code in Blender
|
||||
* that doesn't check this pointer yet.
|
||||
*/
|
||||
struct Animation *animation;
|
||||
|
||||
/**
|
||||
* Identifier for which AnimationBinding of the above Animation is actually animating this
|
||||
* data-block.
|
||||
*
|
||||
* Do not set this directly, use one of the assignment functions in ANIM_animation.hh instead.
|
||||
*/
|
||||
int32_t binding_handle;
|
||||
/**
|
||||
* Binding name, primarily used for mapping to the right binding when assigning
|
||||
* another Animation data-block. Should be the same type as #AnimationBinding::name.
|
||||
*
|
||||
* \see AnimationBinding::name
|
||||
*/
|
||||
char binding_name[66];
|
||||
uint8_t _pad0[6];
|
||||
|
||||
/* settings for animation evaluation */
|
||||
/** User-defined settings. */
|
||||
int flag;
|
||||
char _pad[4];
|
||||
|
||||
/* settings for active action evaluation (based on NLA strip settings) */
|
||||
/** Accumulation mode for active action. */
|
||||
@@ -1208,3 +1243,183 @@ typedef struct IdAdtTemplate {
|
||||
#define SELECT 1
|
||||
|
||||
/* ************************************************ */
|
||||
/* Layered Animation data-types. */
|
||||
|
||||
/* Declarations of C++ wrappers. See ANIM_animation.hh for the actual classes. */
|
||||
#ifdef __cplusplus
|
||||
namespace blender::animrig {
|
||||
class Animation;
|
||||
class ChannelBag;
|
||||
class KeyframeStrip;
|
||||
class Layer;
|
||||
class Binding;
|
||||
class Strip;
|
||||
} // namespace blender::animrig
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Container of layered animation data.
|
||||
*
|
||||
* \see blender::animrig::Animation
|
||||
*/
|
||||
typedef struct Animation {
|
||||
ID id;
|
||||
|
||||
struct AnimationLayer **layer_array; /* Array of 'layer_array_num' layers. */
|
||||
int layer_array_num;
|
||||
int layer_active_index; /* Index into layer_array, -1 means 'no active'. */
|
||||
|
||||
struct AnimationBinding **binding_array; /* Array of 'binding_array_num` bindings. */
|
||||
int binding_array_num;
|
||||
int32_t last_binding_handle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::Animation &wrap();
|
||||
const blender::animrig::Animation &wrap() const;
|
||||
#endif
|
||||
} Animation;
|
||||
|
||||
/**
|
||||
* \see blender::animrig::Layer
|
||||
*/
|
||||
typedef struct AnimationLayer {
|
||||
/** User-Visible identifier, unique within the Animation. */
|
||||
char name[64]; /* MAX_NAME. */
|
||||
|
||||
float influence; /* [0-1] */
|
||||
|
||||
/** \see blender::animrig::Layer::flags() */
|
||||
uint8_t layer_flags;
|
||||
|
||||
/** \see blender::animrig::Layer::mixmode() */
|
||||
int8_t layer_mix_mode;
|
||||
|
||||
uint8_t _pad0[2];
|
||||
|
||||
/**
|
||||
* There is always at least one strip.
|
||||
* If there is only one, it can be infinite. This is the default for new layers.
|
||||
*/
|
||||
struct AnimationStrip **strip_array; /* Array of 'strip_array_num' strips. */
|
||||
int strip_array_num;
|
||||
|
||||
uint8_t _pad1[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::Layer &wrap();
|
||||
const blender::animrig::Layer &wrap() const;
|
||||
#endif
|
||||
} AnimationLayer;
|
||||
|
||||
/**
|
||||
* \see blender::animrig::Binding
|
||||
*/
|
||||
typedef struct AnimationBinding {
|
||||
/**
|
||||
* Typically the ID name this binding was created for, including the two
|
||||
* letters indicating the ID type.
|
||||
*
|
||||
* \see AnimData::binding_name
|
||||
*/
|
||||
char name[66]; /* MAX_ID_NAME */
|
||||
uint8_t _pad0[2];
|
||||
|
||||
/**
|
||||
* Type of ID-blocks that this binding can be assigned to.
|
||||
* If 0, will be set to whatever ID is first assigned.
|
||||
*/
|
||||
int idtype;
|
||||
|
||||
/**
|
||||
* Identifier of this Binding within the Animation data-block.
|
||||
*
|
||||
* This number allows reorganisation of the Animation::bindings_array without
|
||||
* invalidating references. Also these remain valid when copy-on-evaluate
|
||||
* copies are made.
|
||||
*
|
||||
* Only valid within the Animation data-block that owns this Binding.
|
||||
*
|
||||
* \see blender::animrig::Animation::binding_for_handle()
|
||||
*/
|
||||
int32_t handle;
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::Binding &wrap();
|
||||
const blender::animrig::Binding &wrap() const;
|
||||
#endif
|
||||
} AnimationBinding;
|
||||
|
||||
/**
|
||||
* \see blender::animrig::Strip
|
||||
*/
|
||||
typedef struct AnimationStrip {
|
||||
/**
|
||||
* \see blender::animrig::Strip::type()
|
||||
*/
|
||||
int8_t strip_type;
|
||||
uint8_t _pad0[3];
|
||||
|
||||
float frame_start; /** Start frame of the strip, in Animation time. */
|
||||
float frame_end; /** End frame of the strip, in Animation time. */
|
||||
|
||||
/**
|
||||
* Offset applied to the contents of the strip, in frames.
|
||||
*
|
||||
* This offset determines the difference between "Animation time" (which would
|
||||
* typically be the same as the scene time, until the animation system
|
||||
* supports strips referencing other Animation data-blocks).
|
||||
*/
|
||||
float frame_offset;
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::Strip &wrap();
|
||||
const blender::animrig::Strip &wrap() const;
|
||||
#endif
|
||||
} AnimationStrip;
|
||||
|
||||
/**
|
||||
* AnimationStrip::type = Strip::Type::Keyframe.
|
||||
*
|
||||
* \see blender::animrig::KeyframeStrip
|
||||
*/
|
||||
typedef struct KeyframeAnimationStrip {
|
||||
AnimationStrip strip;
|
||||
|
||||
struct AnimationChannelBag **channelbags_array;
|
||||
int channelbags_array_num;
|
||||
|
||||
uint8_t _pad[4];
|
||||
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::KeyframeStrip &wrap();
|
||||
const blender::animrig::KeyframeStrip &wrap() const;
|
||||
#endif
|
||||
} KeyframeAnimationStrip;
|
||||
|
||||
/**
|
||||
* \see blender::animrig::ChannelBag
|
||||
*/
|
||||
typedef struct AnimationChannelBag {
|
||||
int32_t binding_handle;
|
||||
|
||||
int fcurve_array_num;
|
||||
FCurve **fcurve_array; /* Array of 'fcurve_array_num' FCurves. */
|
||||
|
||||
/* TODO: Design & implement a way to integrate other channel types as well,
|
||||
* and still have them map to a certain binding */
|
||||
#ifdef __cplusplus
|
||||
blender::animrig::ChannelBag &wrap();
|
||||
const blender::animrig::ChannelBag &wrap() const;
|
||||
#endif
|
||||
} ChannelBag;
|
||||
|
||||
#ifdef __cplusplus
|
||||
/* Some static assertions that things that should have the same type actually do. */
|
||||
static_assert(
|
||||
std::is_same_v<decltype(AnimationBinding::handle), decltype(AnimData::binding_handle)>);
|
||||
static_assert(
|
||||
std::is_same_v<decltype(AnimationBinding::handle), decltype(Animation::last_binding_handle)>);
|
||||
static_assert(std::is_same_v<decltype(AnimationBinding::handle),
|
||||
decltype(AnimationChannelBag::binding_handle)>);
|
||||
static_assert(std::is_same_v<decltype(AnimationBinding::name), decltype(AnimData::binding_name)>);
|
||||
#endif
|
||||
|
||||
@@ -75,6 +75,7 @@
|
||||
|
||||
#include "DNA_defaults.h"
|
||||
|
||||
#include "DNA_anim_types.h"
|
||||
#include "DNA_armature_types.h"
|
||||
#include "DNA_asset_types.h"
|
||||
#include "DNA_brush_types.h"
|
||||
@@ -108,6 +109,7 @@
|
||||
#include "DNA_volume_types.h"
|
||||
#include "DNA_world_types.h"
|
||||
|
||||
#include "DNA_anim_defaults.h"
|
||||
#include "DNA_armature_defaults.h"
|
||||
#include "DNA_asset_defaults.h"
|
||||
#include "DNA_brush_defaults.h"
|
||||
@@ -142,6 +144,10 @@
|
||||
#define SDNA_DEFAULT_DECL_STRUCT(struct_name) \
|
||||
static const struct_name DNA_DEFAULT_##struct_name = _DNA_DEFAULT_##struct_name
|
||||
|
||||
/* DNA_anim_defaults.h */
|
||||
SDNA_DEFAULT_DECL_STRUCT(AnimationLayer);
|
||||
SDNA_DEFAULT_DECL_STRUCT(AnimationStrip);
|
||||
|
||||
/* DNA_asset_defaults.h */
|
||||
SDNA_DEFAULT_DECL_STRUCT(AssetMetaData);
|
||||
SDNA_DEFAULT_DECL_STRUCT(AssetLibraryReference);
|
||||
@@ -381,6 +387,10 @@ extern const bTheme U_theme_default;
|
||||
|
||||
const void *DNA_default_table[SDNA_TYPE_MAX] = {
|
||||
|
||||
/* DNA_anim_defaults.h */
|
||||
SDNA_DEFAULT_DECL(AnimationLayer),
|
||||
SDNA_DEFAULT_DECL(AnimationStrip),
|
||||
|
||||
/* DNA_asset_defaults.h */
|
||||
SDNA_DEFAULT_DECL(AssetMetaData),
|
||||
SDNA_DEFAULT_DECL(AssetLibraryReference),
|
||||
|
||||
@@ -34,6 +34,7 @@
|
||||
*/
|
||||
const EnumPropertyItem rna_enum_id_type_items[] = {
|
||||
{ID_AC, "ACTION", ICON_ACTION, "Action", ""},
|
||||
{ID_AN, "ANIMATION", ICON_ACTION, "Animation", ""}, /* TODO: give Animation its own icon. */
|
||||
{ID_AR, "ARMATURE", ICON_ARMATURE_DATA, "Armature", ""},
|
||||
{ID_BR, "BRUSH", ICON_BRUSH_DATA, "Brush", ""},
|
||||
{ID_CF, "CACHEFILE", ICON_FILE, "Cache File", ""},
|
||||
@@ -498,6 +499,8 @@ StructRNA *ID_code_to_RNA_type(short idcode)
|
||||
switch ((ID_Type)idcode) {
|
||||
case ID_AC:
|
||||
return &RNA_Action;
|
||||
case ID_AN:
|
||||
break;
|
||||
case ID_AR:
|
||||
return &RNA_Armature;
|
||||
case ID_BR:
|
||||
@@ -1057,7 +1060,8 @@ static void rna_ID_update_tag(ID *id, Main *bmain, ReportList *reports, int flag
|
||||
allow_flag = OB_RECALC_ALL | PSYS_RECALC;
|
||||
break;
|
||||
# endif
|
||||
case ID_AC:
|
||||
case ID_AC: /* Fallthrough. */
|
||||
case ID_AN:
|
||||
allow_flag = ID_RECALC_ANIMATION;
|
||||
break;
|
||||
default:
|
||||
|
||||
Reference in New Issue
Block a user