WIP: Rewrite Graph Editor drawing code #118662

Draft
Christoph Lendenfeld wants to merge 18 commits from ChrisLend/blender:ge_gpu_batch into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
288 changed files with 2961 additions and 854 deletions
Showing only changes of commit 17a5e2e76c - Show all commits

View File

@ -117,7 +117,7 @@ endif()
# Embree needs to be included after dpcpp as it uses it for compiling with GPU support
if(BLENDER_PLATFORM_WINDOWS_ARM)
# WoA needs embree to be built with the VS Generator + LLVM,
# put it in it's own file to avoid clutter.
# put it in its own file to avoid clutter.
include(cmake/embree_windows_arm.cmake)
else()
include(cmake/embree.cmake)

View File

@ -58,7 +58,7 @@ if(WIN32)
COMMAND ${CMAKE_COMMAND} -E copy
${LIBDIR}/opensubdiv/lib/osdCPU.lib
${HARVEST_TARGET}/opensubdiv/lib/osdCPU_d.lib
COMMAND ${CMAKE_COMMAND} -E copy
COMMAND ${CMAKE_COMMAND} -E copy
${LIBDIR}/opensubdiv/lib/osdGPU.lib
${HARVEST_TARGET}/opensubdiv/lib/osdGPU_d.lib

View File

@ -111,3 +111,5 @@ mark_as_advanced(
AUDASPACE_PY_INCLUDE_DIR
AUDASPACE_PY_INCLUDE_DIRS
)
unset(_audaspace_SEARCH_DIRS)

View File

@ -64,3 +64,5 @@ mark_as_advanced(
BLOSC_INCLUDE_DIR
BLOSC_LIBRARY
)
unset(_blosc_SEARCH_DIRS)

View File

@ -21,7 +21,7 @@ else()
set(BROTLI_ROOT_DIR "")
endif()
set(_BROTLI_SEARCH_DIRS
set(_brotli_SEARCH_DIRS
${BROTLI_ROOT_DIR}
)
@ -29,7 +29,7 @@ find_path(BROTLI_INCLUDE_DIR
NAMES
brotli/decode.h
HINTS
${_BROTLI_SEARCH_DIRS}
${_brotli_SEARCH_DIRS}
PATH_SUFFIXES
include
DOC "Brotli header files"
@ -41,7 +41,7 @@ find_library(BROTLI_LIBRARY_COMMON
brotlicommon-static
brotlicommon
HINTS
${_BROTLI_SEARCH_DIRS}
${_brotli_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib lib/static
DOC "Brotli static common library"
@ -52,7 +52,7 @@ find_library(BROTLI_LIBRARY_DEC
brotlidec-static
brotlidec
HINTS
${_BROTLI_SEARCH_DIRS}
${_brotli_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib lib/static
DOC "Brotli static decode library"
@ -81,4 +81,4 @@ mark_as_advanced(
BROTLI_LIBRARY_DIR
)
unset(_BROTLI_SEARCH_DIRS)
unset(_brotli_SEARCH_DIRS)

View File

@ -36,7 +36,7 @@ if(NOT LLVM_ROOT_DIR)
set(LLVM_ROOT_DIR ${LLVM_ROOT_DIR} CACHE PATH "Path to the LLVM installation")
endif()
set(_CLANG_SEARCH_DIRS
set(_clang_SEARCH_DIRS
${CLANG_ROOT_DIR}
${LLVM_ROOT_DIR}
/opt/lib/clang
@ -46,14 +46,14 @@ find_path(CLANG_INCLUDE_DIR
NAMES
AST/AST.h
HINTS
${_CLANG_SEARCH_DIRS}
${_clang_SEARCH_DIRS}
PATH_SUFFIXES
include
include/clang
)
set(_CLANG_FIND_COMPONENTS
set(_clang_FIND_COMPONENTS
clangDependencyScanning
clangDynamicASTMatchers
clangFrontendTool
@ -87,20 +87,20 @@ set(_CLANG_FIND_COMPONENTS
clangBasic
)
set(_CLANG_LIBRARIES)
foreach(COMPONENT ${_CLANG_FIND_COMPONENTS})
set(_clang_LIBRARIES)
foreach(COMPONENT ${_clang_FIND_COMPONENTS})
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
find_library(CLANG_${UPPERCOMPONENT}_LIBRARY
NAMES
${COMPONENT}
HINTS
${_CLANG_SEARCH_DIRS}
${_clang_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
if(CLANG_${UPPERCOMPONENT}_LIBRARY)
list(APPEND _CLANG_LIBRARIES "${CLANG_${UPPERCOMPONENT}_LIBRARY}")
list(APPEND _clang_LIBRARIES "${CLANG_${UPPERCOMPONENT}_LIBRARY}")
endif()
endforeach()
@ -109,10 +109,10 @@ endforeach()
# all listed variables are TRUE.
include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(Clang DEFAULT_MSG
_CLANG_LIBRARIES CLANG_INCLUDE_DIR)
_clang_LIBRARIES CLANG_INCLUDE_DIR)
if(CLANG_FOUND)
set(CLANG_LIBRARIES ${_CLANG_LIBRARIES})
set(CLANG_LIBRARIES ${_clang_LIBRARIES})
set(CLANG_INCLUDE_DIRS ${CLANG_INCLUDE_DIR})
endif()
@ -120,11 +120,11 @@ mark_as_advanced(
CLANG_INCLUDE_DIR
)
foreach(COMPONENT ${_CLANG_FIND_COMPONENTS})
foreach(COMPONENT ${_clang_FIND_COMPONENTS})
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
mark_as_advanced(CLANG_${UPPERCOMPONENT}_LIBRARY)
endforeach()
unset(_CLANG_SEARCH_DIRS)
unset(_CLANG_FIND_COMPONENTS)
unset(_CLANG_LIBRARIES)
unset(_clang_SEARCH_DIRS)
unset(_clang_FIND_COMPONENTS)
unset(_clang_LIBRARIES)

View File

@ -104,3 +104,5 @@ ${CLANG_TIDY_VERSION_PATCH}")
else()
set(CLANG_TIDY_FOUND FALSE)
endif()
unset(_clang_tidy_SEARCH_DIRS)

View File

@ -47,3 +47,5 @@ endif()
mark_as_advanced(
EIGEN3_INCLUDE_DIR
)
unset(_eigen3_SEARCH_DIRS)

View File

@ -66,6 +66,8 @@ foreach(_component ${FFMPEG_FIND_COMPONENTS})
list(APPEND _ffmpeg_LIBRARIES ${FFMPEG_${_upper_COMPONENT}_LIBRARY})
mark_as_advanced(FFMPEG_${_upper_COMPONENT}_LIBRARY)
endforeach()
unset(_component)
unset(_upper_COMPONENT)
# handle the QUIETLY and REQUIRED arguments and set FFMPEG_FOUND to TRUE if
# all listed variables are TRUE

View File

@ -72,10 +72,12 @@ if(FFTW3_FOUND)
set(FFTW3_INCLUDE_DIRS ${FFTW3_INCLUDE_DIR})
endif()
unset(_FFTW3_LIBRARIES)
mark_as_advanced(
FFTW3_INCLUDE_DIR
FFTW3_LIBRARY_F
FFTW3_LIBRARY_D
)
unset(_FFTW3_LIBRARIES)
unset(_fftw3_SEARCH_DIRS)

View File

@ -55,3 +55,5 @@ MARK_AS_ADVANCED(
LIBFRIBIDI_INCLUDE_DIR
LIBFRIBIDI_LIBRARY
)
unset(_fribidi_SEARCH_DIRS)

View File

@ -91,3 +91,5 @@ mark_as_advanced(
GMPXX_INCLUDE_DIR
GMPXX_LIBRARY
)
unset(_gmp_SEARCH_DIRS)

View File

@ -101,3 +101,5 @@ include(FindPackageHandleStandardArgs)
find_package_handle_standard_args(HIP
REQUIRED_VARS HIP_HIPCC_EXECUTABLE
VERSION_VAR HIP_VERSION)
unset(_hip_SEARCH_DIRS)

View File

@ -57,3 +57,5 @@ find_package_handle_standard_args(HIPRT DEFAULT_MSG
mark_as_advanced(
HIPRT_INCLUDE_DIR
)
unset(_hiprt_SEARCH_DIRS)

View File

@ -55,3 +55,5 @@ MARK_AS_ADVANCED(
LIBHARFBUZZ_INCLUDE_DIR
LIBHARFBUZZ_LIBRARY
)
unset(_harfbuzz_SEARCH_DIRS)

View File

@ -137,3 +137,5 @@ mark_as_advanced(
ICU_LIBRARY_TU
ICU_LIBRARY_UC
)
unset(_icu_SEARCH_DIRS)

View File

@ -61,3 +61,5 @@ mark_as_advanced(
JACK_INCLUDE_DIR
JACK_LIBRARY
)
unset(_jack_SEARCH_DIRS)

View File

@ -71,3 +71,5 @@ mark_as_advanced(
JEMALLOC_INCLUDE_DIR
JEMALLOC_LIBRARY
)
unset(_jemalloc_SEARCH_DIRS)

View File

@ -59,3 +59,5 @@ mark_as_advanced(
LZO_INCLUDE_DIR
LZO_LIBRARY
)
unset(_lzo_SEARCH_DIRS)

View File

@ -20,7 +20,7 @@ else()
set(LEVEL_ZERO_ROOT_DIR "")
endif()
set(_level_zero_search_dirs
set(_level_zero_SEARCH_DIRS
${LEVEL_ZERO_ROOT_DIR}
/usr/lib
/usr/local/lib
@ -30,7 +30,7 @@ find_library(LEVEL_ZERO_LIBRARY
NAMES
ze_loader
HINTS
${_level_zero_search_dirs}
${_level_zero_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
@ -39,7 +39,7 @@ find_path(LEVEL_ZERO_INCLUDE_DIR
NAMES
level_zero/ze_api.h
HINTS
${_level_zero_search_dirs}
${_level_zero_SEARCH_DIRS}
PATH_SUFFIXES
include
)
@ -60,3 +60,5 @@ mark_as_advanced(
LEVEL_ZERO_LIBRARY
LEVEL_ZERO_INCLUDE_DIR
)
unset(_level_zero_SEARCH_DIRS)

View File

@ -125,7 +125,15 @@ mark_as_advanced(
OSL_INCLUDE_DIR
OSL_SHADER_DIR
)
foreach(COMPONENT ${_osl_FIND_COMPONENTS})
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
mark_as_advanced(OSL_${UPPERCOMPONENT}_LIBRARY)
endforeach()
unset(COMPONENT)
unset(UPPERCOMPONENT)
unset(_osl_FIND_COMPONENTS)
unset(_osl_LIBRARIES)
unset(_osl_SEARCH_DIRS)

View File

@ -134,5 +134,9 @@ endif()
unset(COMPONENT)
unset(UPPERCOMPONENT)
unset(_opencollada_LIBRARIES)
unset(_opencollada_FIND_COMPONENTS)
unset(_opencollada_FIND_INCLUDES)
unset(_opencollada_FIND_STATIC_COMPONENTS)
unset(_opencollada_INCLUDES)
unset(_opencollada_LIBRARIES)
unset(_opencollada_SEARCH_DIRS)

View File

@ -72,6 +72,7 @@ if(EXISTS "${OPENCOLORIO_INCLUDE_DIR}/OpenColorIO/OpenColorABI.h")
REGEX "^#define OCIO_VERSION[ \t].*$")
endif()
string(REGEX MATCHALL "[0-9]+[.0-9]+" OPENCOLORIO_VERSION ${_opencolorio_version})
unset(_opencolorio_version)
endif()
# handle the QUIETLY and REQUIRED arguments and set OPENCOLORIO_FOUND to TRUE if

View File

@ -119,6 +119,10 @@ foreach(COMPONENT ${_openimagedenoise_FIND_COMPONENTS})
mark_as_advanced(OPENIMAGEDENOISE_${UPPERCOMPONENT}_LIBRARY)
endforeach()
unset(_openimagedenoise_SEARCH_DIRS)
unset(COMPONENT)
unset(UPPERCOMPONENT)
unset(_openimagedenoise_FIND_COMPONENTS)
unset(_openimagedenoise_FIND_STATIC_COMPONENTS)
unset(_openimagedenoise_LIBRARIES)
unset(_openimagedenoise_SEARCH_DIRS)

View File

@ -85,3 +85,10 @@ foreach(COMPONENT ${_opensubdiv_FIND_COMPONENTS})
string(TOUPPER ${COMPONENT} UPPERCOMPONENT)
mark_as_advanced(OPENSUBDIV_${UPPERCOMPONENT}_LIBRARY)
endforeach()
unset(COMPONENT)
unset(UPPERCOMPONENT)
unset(_opensubdiv_FIND_COMPONENTS)
unset(_opensubdiv_SEARCH_DIRS)
unset(_opensubdiv_LIBRARIES)

View File

@ -64,3 +64,5 @@ mark_as_advanced(
PCRE_INCLUDE_DIR
PCRE_LIBRARY
)
unset(_pcre_SEARCH_DIRS)

View File

@ -64,3 +64,5 @@ mark_as_advanced(
POTRACE_INCLUDE_DIR
POTRACE_LIBRARY
)
unset(_potrace_SEARCH_DIRS)

View File

@ -64,3 +64,5 @@ mark_as_advanced(
PUGIXML_INCLUDE_DIR
PUGIXML_LIBRARY
)
unset(_pugixml_SEARCH_DIRS)

View File

@ -59,3 +59,5 @@ mark_as_advanced(
LIBPULSE_INCLUDE_DIR
LIBPULSE_LIBRARY
)
unset(_pulse_SEARCH_DIRS)

View File

@ -256,10 +256,6 @@ if(PYTHONLIBSUNIX_FOUND)
)
endif()
unset(_PYTHON_ABI_FLAGS)
unset(_PYTHON_VERSION_SUPPORTED)
unset(_python_SEARCH_DIRS)
mark_as_advanced(
PYTHON_INCLUDE_DIR
PYTHON_INCLUDE_CONFIG_DIR
@ -268,3 +264,7 @@ mark_as_advanced(
PYTHON_SITE_PACKAGES
PYTHON_EXECUTABLE
)
unset(_PYTHON_ABI_FLAGS)
unset(_PYTHON_VERSION_SUPPORTED)
unset(_python_SEARCH_DIRS)

View File

@ -60,3 +60,5 @@ mark_as_advanced(
SDL2_INCLUDE_DIR
SDL2_LIBRARY
)
unset(_sdl2_SEARCH_DIRS)

View File

@ -22,7 +22,7 @@ elseif(DEFINED ENV{SYCL_ROOT_DIR} AND NOT $ENV{SYCL_ROOT_DIR} STREQUAL "")
set(SYCL_ROOT_DIR $ENV{SYCL_ROOT_DIR})
endif()
set(_sycl_search_dirs
set(_sycl_SEARCH_DIRS
${SYCL_ROOT_DIR}
/usr/lib
/usr/local/lib
@ -41,7 +41,7 @@ find_program(SYCL_COMPILER
dpcpp
clang++
HINTS
${_sycl_search_dirs}
${_sycl_SEARCH_DIRS}
PATH_SUFFIXES
bin
NO_CMAKE_FIND_ROOT_PATH
@ -56,7 +56,7 @@ if(NOT SYCL_COMPILER)
icpx
dpcpp
HINTS
${_sycl_search_dirs}
${_sycl_SEARCH_DIRS}
PATH_SUFFIXES
bin
)
@ -68,7 +68,7 @@ find_library(SYCL_LIBRARY
sycl6
sycl
HINTS
${_sycl_search_dirs}
${_sycl_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
@ -80,7 +80,7 @@ if(WIN32)
sycl6d
sycld
HINTS
${_sycl_search_dirs}
${_sycl_SEARCH_DIRS}
PATH_SUFFIXES
lib64 lib
)
@ -90,7 +90,7 @@ find_path(SYCL_INCLUDE_DIR
NAMES
sycl/sycl.hpp
HINTS
${_sycl_search_dirs}
${_sycl_SEARCH_DIRS}
PATH_SUFFIXES
include
)
@ -129,3 +129,5 @@ mark_as_advanced(
SYCL_INCLUDE_DIR
SYCL_LIBRARY
)
unset(_sycl_SEARCH_DIRS)

View File

@ -59,3 +59,5 @@ mark_as_advanced(
LIBSNDFILE_INCLUDE_DIR
LIBSNDFILE_LIBRARY
)
unset(_sndfile_SEARCH_DIRS)

View File

@ -61,3 +61,5 @@ mark_as_advanced(
SPACENAV_INCLUDE_DIR
SPACENAV_LIBRARY
)
unset(_spacenav_SEARCH_DIRS)

View File

@ -64,3 +64,5 @@ mark_as_advanced(
TBB_INCLUDE_DIR
TBB_LIBRARY
)
unset(_tbb_SEARCH_DIRS)

View File

@ -89,3 +89,7 @@ mark_as_advanced(
WEBP_WEBP_LIBRARY
WEBP_SHARPYUV_LIBRARY
)
unset(_webp_FIND_COMPONENTS)
unset(_webp_LIBRARIES)
unset(_webp_SEARCH_DIRS)

View File

@ -59,3 +59,5 @@ mark_as_advanced(
XML2_INCLUDE_DIR
XML2_LIBRARY
)
unset(_xml2_SEARCH_DIRS)

View File

@ -70,3 +70,5 @@ mark_as_advanced(
XR_OPENXR_SDK_INCLUDE_DIR
XR_OPENXR_SDK_LOADER_LIBRARY
)
unset(_xr_openxr_sdk_SEARCH_DIRS)

View File

@ -61,3 +61,5 @@ mark_as_advanced(
ZSTD_INCLUDE_DIR
ZSTD_LIBRARY
)
unset(_zstd_SEARCH_DIRS)

View File

@ -0,0 +1,74 @@
"""
Using Python Argument Parsing
-----------------------------
This example shows how the Python ``argparse`` module can be used with a custom command.
Using ``argparse`` is generally recommended as it has many useful utilities and
generates a ``--help`` message for your command.
"""
import os
import sys
import bpy
def argparse_create():
import argparse
parser = argparse.ArgumentParser(
prog=os.path.basename(sys.argv[0]) + " --command keyconfig_export",
description="Write key-configuration to a file.",
)
parser.add_argument(
"-o", "--output",
dest="output",
metavar='OUTPUT',
type=str,
help="The path to write the keymap to.",
required=True,
)
parser.add_argument(
"-a", "--all",
dest="all",
action="store_true",
help="Write all key-maps (not only customized key-maps).",
required=False,
)
return parser
def keyconfig_export(argv):
parser = argparse_create()
args = parser.parse_args(argv)
# Ensure the key configuration is loaded in background mode.
bpy.utils.keyconfig_init()
bpy.ops.preferences.keyconfig_export(
filepath=args.output,
all=args.all,
)
return 0
cli_commands = []
def register():
cli_commands.append(bpy.utils.register_cli_command("keyconfig_export", keyconfig_export))
def unregister():
for cmd in cli_commands:
bpy.utils.unregister_cli_command(cmd)
cli_commands.clear()
if __name__ == "__main__":
register()

View File

@ -0,0 +1,43 @@
"""
Custom Commands
---------------
Registering commands makes it possible to conveniently expose command line
functionality via commands passed to (``-c`` / ``--command``).
"""
import sys
import os
def sysinfo_command(argv):
import tempfile
import sys_info
if argv and argv[0] == "--help":
print("Print system information & exit!")
return 0
with tempfile.TemporaryDirectory() as tempdir:
filepath = os.path.join(tempdir, "system_info.txt")
sys_info.write_sysinfo(filepath)
with open(filepath, "r", encoding="utf-8") as fh:
sys.stdout.write(fh.read())
return 0
cli_commands = []
def register():
cli_commands.append(bpy.utils.register_cli_command("sysinfo", sysinfo_command))
def unregister():
for cmd in cli_commands:
bpy.utils.unregister_cli_command(cmd)
cli_commands.clear()
if __name__ == "__main__":
register()

View File

@ -21,6 +21,8 @@ __all__ = (
"refresh_script_paths",
"app_template_paths",
"register_class",
"register_cli_command",
"unregister_cli_command",
"register_manual_map",
"unregister_manual_map",
"register_classes_factory",
@ -49,9 +51,11 @@ from _bpy import (
flip_name,
unescape_identifier,
register_class,
register_cli_command,
resource_path,
script_paths as _bpy_script_paths,
unregister_class,
unregister_cli_command,
user_resource as _user_resource,
system_resource,
)

View File

@ -317,6 +317,8 @@ class ZoneOperator:
@classmethod
def get_node(cls, context):
node = context.active_node
if node is None:
return None
if node.bl_idname == cls.output_node_type:
return node
if node.bl_idname == cls.input_node_type:
@ -337,6 +339,8 @@ class NodeOperator:
@classmethod
def get_node(cls, context):
node = context.active_node
if node is None:
return None
if node.bl_idname == cls.node_type:
return node

View 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);
}

View File

@ -11,6 +11,7 @@ set(INC
../editors/include
../makesrna
../windowmanager
../../../extern/fmtlib/include
# RNA_prototypes.h
${CMAKE_BINARY_DIR}/source/blender/makesrna
)
@ -21,6 +22,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 +33,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 +53,7 @@ set(LIB
bf::dna
PRIVATE bf_editor_interface
PRIVATE bf::intern::guardedalloc
PRIVATE bf::intern::atomic
)

View 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 &copy->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

View File

@ -10,6 +10,8 @@
#include <cmath>
#include <string>
#include <fmt/format.h>
#include "ANIM_action.hh"
#include "ANIM_animdata.hh"
#include "ANIM_fcurve.hh"
@ -46,6 +48,45 @@
namespace blender::animrig {
enum class SingleKeyingResult {
SUCCESS = 0,
CANNOT_CREATE_FCURVE,
FCURVE_NOT_KEYFRAMEABLE,
NO_KEY_NEEDED,
/* Make sure to always keep this at the end of the enum. */
_KEYING_RESULT_MAX,
};
class CombinedKeyingResult {
private:
/* The index to the array maps a `SingleKeyingResult` to the number of times this result has
* occurred. */
std::array<int, int(SingleKeyingResult::_KEYING_RESULT_MAX)> result_counter{0};
public:
void add(const SingleKeyingResult result)
{
result_counter[int(result)]++;
}
int get_count(const SingleKeyingResult result) const
{
return result_counter[int(result)];
}
bool has_errors() const
{
/* For loop starts at 1 to skip the SUCCESS flag. Assumes that SUCCESS is 0 and the rest of the
* enum are sequential values. */
for (int i = 1; i < result_counter.size(); i++) {
if (result_counter[i] > 0) {
return true;
}
}
return false;
}
};
void update_autoflags_fcurve_direct(FCurve *fcu, PropertyRNA *prop)
{
/* Set additional flags for the F-Curve (i.e. only integer values). */
@ -309,11 +350,11 @@ static float nla_time_remap(const AnimationEvalContext *anim_eval_context,
}
/* Insert the specified keyframe value into a single F-Curve. */
static bool insert_keyframe_value(
static SingleKeyingResult insert_keyframe_value(
FCurve *fcu, float cfra, float curval, eBezTriple_KeyframeType keytype, eInsertKeyFlags flag)
{
if (!BKE_fcurve_is_keyframable(fcu)) {
return false;
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
}
/* Adjust coordinates for cycle aware insertion. */
@ -329,17 +370,19 @@ static bool insert_keyframe_value(
if (flag & INSERTKEY_NEEDED) {
if (!new_key_needed(fcu, cfra, curval)) {
return false;
return SingleKeyingResult::NO_KEY_NEEDED;
}
if (insert_vert_fcurve(fcu, {cfra, curval}, settings, flag) < 0) {
return false;
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
}
return true;
return SingleKeyingResult::SUCCESS;
}
return insert_vert_fcurve(fcu, {cfra, curval}, settings, flag) >= 0;
if (insert_vert_fcurve(fcu, {cfra, curval}, settings, flag) < 0) {
return SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE;
}
return SingleKeyingResult::SUCCESS;
}
bool insert_keyframe_direct(ReportList *reports,
@ -401,9 +444,9 @@ bool insert_keyframe_direct(ReportList *reports,
}
const float cfra = anim_eval_context->eval_time;
const bool success = insert_keyframe_value(fcu, cfra, current_value, keytype, flag);
const SingleKeyingResult result = insert_keyframe_value(fcu, cfra, current_value, keytype, flag);
if (!success) {
if (result != SingleKeyingResult::SUCCESS) {
BKE_reportf(reports,
RPT_ERROR,
"Failed to insert keys on F-Curve with path '%s[%d]', ensure that it is not "
@ -411,22 +454,21 @@ bool insert_keyframe_direct(ReportList *reports,
fcu->rna_path,
fcu->array_index);
}
return success;
return result == SingleKeyingResult::SUCCESS;
}
/** Find or create the FCurve based on the given path, and insert the specified value into it. */
static bool insert_keyframe_fcurve_value(Main *bmain,
ReportList *reports,
PointerRNA *ptr,
PropertyRNA *prop,
bAction *act,
const char group[],
const char rna_path[],
int array_index,
const float fcurve_frame,
float curval,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag)
static SingleKeyingResult insert_keyframe_fcurve_value(Main *bmain,
PointerRNA *ptr,
PropertyRNA *prop,
bAction *act,
const char group[],
const char rna_path[],
int array_index,
const float fcurve_frame,
float curval,
eBezTriple_KeyframeType keytype,
eInsertKeyFlags flag)
{
/* Make sure the F-Curve exists.
* - if we're replacing keyframes only, DO NOT create new F-Curves if they do not exist yet
@ -439,7 +481,7 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
/* We may not have a F-Curve when we're replacing only. */
if (!fcu) {
return false;
return SingleKeyingResult::CANNOT_CREATE_FCURVE;
}
const bool is_new_curve = (fcu->totvert == 0);
@ -454,23 +496,51 @@ static bool insert_keyframe_fcurve_value(Main *bmain,
/* Update F-Curve flags to ensure proper behavior for property type. */
update_autoflags_fcurve_direct(fcu, prop);
const bool success = insert_keyframe_value(fcu, fcurve_frame, curval, keytype, flag);
if (!success && reports != nullptr) {
BKE_reportf(reports,
RPT_ERROR,
"Failed to insert keys on F-Curve with path '%s[%d]', ensure that it is not "
"locked or sampled, and try removing F-Modifiers",
fcu->rna_path,
fcu->array_index);
}
const SingleKeyingResult result = insert_keyframe_value(
fcu, fcurve_frame, curval, keytype, flag);
/* If the curve is new, make it cyclic if appropriate. */
if (is_cyclic_action && is_new_curve) {
make_new_fcurve_cyclic(fcu, {act->frame_start, act->frame_end});
}
return success;
return result;
}
static void generate_keyframe_reports_from_result(ReportList *reports,
const CombinedKeyingResult &result)
{
std::string error = "Inserting keyframes failed due to the following reasons:";
if (result.get_count(SingleKeyingResult::CANNOT_CREATE_FCURVE) > 0) {
const int error_count = result.get_count(SingleKeyingResult::CANNOT_CREATE_FCURVE);
error.append(
fmt::format("\n- Could not create {} F-Curve{}. This can happen when only inserting to "
"available F-Curves.",
error_count,
error_count > 1 ? "s" : ""));
}
if (result.get_count(SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE) > 0) {
const int error_count = result.get_count(SingleKeyingResult::FCURVE_NOT_KEYFRAMEABLE);
if (error_count == 1) {
error.append("\n- One F-Curve is not keyframeable. It might be locked or sampled.");
}
else {
error.append(fmt::format(
"\n- {} F-Curves are not keyframeable. They might be locked or sampled.", error_count));
}
}
if (result.get_count(SingleKeyingResult::NO_KEY_NEEDED) > 0) {
const int error_count = result.get_count(SingleKeyingResult::NO_KEY_NEEDED);
error.append(fmt::format(
"\n- Due to the setting 'Only Insert Needed', {} keyframe{} not been inserted.",
error_count,
error_count > 1 ? "s have" : " has"));
}
BKE_reportf(reports, RPT_ERROR, "%s", error.c_str());
}
int insert_keyframe(Main *bmain,
@ -540,6 +610,8 @@ int insert_keyframe(Main *bmain,
&force_all,
successful_remaps);
CombinedKeyingResult combined_result;
/* Key the entire array. */
int key_count = 0;
if (array_index == -1 || force_all) {
@ -551,20 +623,19 @@ int insert_keyframe(Main *bmain,
if (!successful_remaps[array_index]) {
continue;
}
if (insert_keyframe_fcurve_value(bmain,
reports,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag))
{
const SingleKeyingResult result = insert_keyframe_fcurve_value(bmain,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
combined_result.add(result);
if (result == SingleKeyingResult::SUCCESS) {
key_count++;
exclude = array_index;
break;
@ -580,18 +651,21 @@ int insert_keyframe(Main *bmain,
}
if (array_index != exclude) {
key_count += insert_keyframe_fcurve_value(bmain,
reports,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
const SingleKeyingResult result = insert_keyframe_fcurve_value(bmain,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
combined_result.add(result);
if (result == SingleKeyingResult::SUCCESS) {
key_count++;
}
}
}
}
@ -603,36 +677,42 @@ int insert_keyframe(Main *bmain,
continue;
}
key_count += insert_keyframe_fcurve_value(bmain,
reports,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
const SingleKeyingResult result = insert_keyframe_fcurve_value(bmain,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
combined_result.add(result);
if (result == SingleKeyingResult::SUCCESS) {
key_count++;
}
}
}
}
/* Key a single index. */
else {
if (array_index >= 0 && array_index < values.size() && successful_remaps[array_index]) {
key_count += insert_keyframe_fcurve_value(bmain,
reports,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
const SingleKeyingResult result = insert_keyframe_fcurve_value(bmain,
&ptr,
prop,
act,
group,
rna_path,
array_index,
nla_mapped_frame,
values[array_index],
keytype,
flag);
combined_result.add(result);
if (result == SingleKeyingResult::SUCCESS) {
key_count++;
}
}
}
@ -647,6 +727,10 @@ int insert_keyframe(Main *bmain,
}
}
if (key_count == 0) {
generate_keyframe_reports_from_result(reports, combined_result);
}
return key_count;
}
@ -872,19 +956,18 @@ int insert_key_action(Main *bmain,
property_array_index++;
continue;
}
const bool inserted_key = insert_keyframe_fcurve_value(bmain,
nullptr,
ptr,
prop,
action,
group.c_str(),
rna_path.c_str(),
property_array_index,
frame,
value,
key_type,
insert_key_flag);
if (inserted_key) {
const SingleKeyingResult inserted_key = insert_keyframe_fcurve_value(bmain,
ptr,
prop,
action,
group.c_str(),
rna_path.c_str(),
property_array_index,
frame,
value,
key_type,
insert_key_flag);
if (inserted_key == SingleKeyingResult::SUCCESS) {
inserted_keys++;
}
property_array_index++;
@ -984,6 +1067,7 @@ void insert_key_rna(PointerRNA *rna_pointer,
key_type,
successful_remaps);
}
BKE_animsys_free_nla_keyframing_context_cache(&nla_cache);
if (insert_key_count == 0) {
BKE_reportf(reports, RPT_ERROR, "Failed to insert any keys");

View File

@ -176,7 +176,7 @@ AssetLibrary::AssetLibrary(eAssetLibraryType library_type, StringRef name, Strin
AssetLibrary::~AssetLibrary()
{
if (on_save_callback_store_.func) {
on_blend_save_handler_unregister();
this->on_blend_save_handler_unregister();
}
}

View File

@ -75,7 +75,7 @@ bool AllAssetLibrary::is_catalogs_dirty() const
void AllAssetLibrary::refresh_catalogs()
{
rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/true);
this->rebuild_catalogs_from_nested(/*reload_nested_catalogs=*/true);
}
} // namespace blender::asset_system

View File

@ -20,7 +20,7 @@ OnDiskAssetLibrary::OnDiskAssetLibrary(eAssetLibraryType library_type,
void OnDiskAssetLibrary::refresh_catalogs()
{
catalog_service().reload_catalogs();
this->catalog_service().reload_catalogs();
}
} // namespace blender::asset_system

View File

@ -43,20 +43,24 @@ class RuntimeAssetLibrary;
class AssetLibraryService {
static std::unique_ptr<AssetLibraryService> instance_;
/** Identify libraries with the library type, and the absolute path of the library's root path
/**
* Identify libraries with the library type, and the absolute path of the library's root path
* (normalize with #normalize_directory_path()!). The type is relevant since the current file
* library may point to the same path as a custom library. */
* library may point to the same path as a custom library.
*/
using OnDiskLibraryIdentifier = std::pair<eAssetLibraryType, std::string>;
/* Mapping of a (type, root path) pair to the AssetLibrary instance. */
/** Mapping of a (type, root path) pair to the AssetLibrary instance. */
Map<OnDiskLibraryIdentifier, std::unique_ptr<OnDiskAssetLibrary>> on_disk_libraries_;
/** Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If
/**
* Library without a known path, i.e. the "Current File" library if the file isn't saved yet. If
* the file was saved, a valid path for the library can be determined and #on_disk_libraries_
* above should be used. */
* above should be used.
*/
std::unique_ptr<RuntimeAssetLibrary> current_file_library_;
/** The "all" asset library, merging all other libraries into one. */
std::unique_ptr<AllAssetLibrary> all_library_;
/* Handlers for managing the life cycle of the AssetLibraryService instance. */
/** Handlers for managing the life cycle of the AssetLibraryService instance. */
bCallbackFuncStore on_load_callback_store_;
static bool atexit_handler_registered_;

View File

@ -45,7 +45,7 @@ bool AssetStorage::remove_asset(AssetRepresentation &asset)
void AssetStorage::remap_ids_and_remove_invalid(const blender::bke::id::IDRemapper &mappings)
{
Set<AssetRepresentation *> removed_assets{};
Set<AssetRepresentation *> removed_assets;
for (auto &asset_ptr : local_id_assets_) {
AssetRepresentation &asset = *asset_ptr;

View File

@ -49,7 +49,7 @@ static blender::Vector<uint8_t> filtered_rows_from_thumb(const Thumbnail *thumb)
/* In the image data sent to the compression step, each scan-line is preceded by a filter type
* byte containing the numeric code of the filter algorithm used for that scan-line. */
const size_t line_size = thumb->width * 4;
blender::Vector<uint8_t> filtered{};
blender::Vector<uint8_t> filtered;
size_t final_size = thumb->height * (line_size + 1);
filtered.reserve(final_size);
for (int i = 0; i < thumb->height; i++) {
@ -88,7 +88,7 @@ std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
}
/* Create `IDAT` chunk data. */
blender::Vector<uint8_t> image_data{};
blender::Vector<uint8_t> image_data;
{
auto image_data_opt = zlib_compress(filtered_rows_from_thumb(thumb));
if (image_data_opt == std::nullopt) {
@ -98,7 +98,7 @@ std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
}
/* Create the IHDR chunk data. */
blender::Vector<uint8_t> ihdr_data{};
blender::Vector<uint8_t> ihdr_data;
{
const size_t ihdr_data_final_size = 4 + 4 + 5;
ihdr_data.reserve(ihdr_data_final_size);
@ -115,7 +115,7 @@ std::optional<blender::Vector<uint8_t>> blendthumb_create_png_data_from_thumb(
}
/* Join it all together to create a PNG image. */
blender::Vector<uint8_t> png_buf{};
blender::Vector<uint8_t> png_buf;
{
const size_t png_buf_final_size = (
/* Header. */

View File

@ -950,7 +950,7 @@ char *BLF_display_name_from_file(const char *filepath)
{
/* While listing font directories this function can be called simultaneously from a greater
* number of threads than we want the FreeType cache to keep open at a time. Therefore open
* with own FT_Library object and use FreeType calls directly to avoid any contention. */
* with a separate FT_Library object and use FreeType calls directly to avoid any contention. */
char *name = nullptr;
FT_Library ft_library;
if (FT_Init_FreeType(&ft_library) == FT_Err_Ok) {

View File

@ -58,7 +58,6 @@ struct CCGElem;
struct CCGKey;
struct CustomData_MeshMasks;
struct Depsgraph;
struct MFace;
struct Mesh;
struct ModifierData;
struct Object;

View File

@ -14,7 +14,6 @@
struct AnimData;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct Library;

View 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[]);

View File

@ -18,7 +18,6 @@ extern "C" {
struct AnimData;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Depsgraph;
struct FCurve;

View File

@ -0,0 +1,67 @@
/* SPDX-FileCopyrightText: 2024 Blender Authors
*
* SPDX-License-Identifier: GPL-2.0-or-later */
#pragma once
/** \file
* \ingroup bke
* \brief Blender CLI Generic `--command` Support.
*
* \note all registered commands must print help to the STDOUT & exit with a zero exit-code
* when `--help` is passed in as the first argument to a command.
*/
#include "BLI_utility_mixins.hh"
#include <memory>
#include <string>
/**
* Each instance of this class can run the command with an argument list.
* The arguments begin at the first argument after the command identifier.
*/
class CommandHandler : blender::NonCopyable, blender::NonMovable {
public:
CommandHandler(const std::string &id) : id(id) {}
virtual ~CommandHandler() = default;
/** Matched against `--command {id}`. */
const std::string id;
/**
* The main execution function.
* The return value is used as the commands exit-code.
*/
virtual int exec(struct bContext *C, int argc, const char **argv) = 0;
/** True when one or more registered commands share an ID. */
bool is_duplicate = false;
};
/**
* \param cmd: The memory for a command type (ownership is transferred).
*/
void BKE_blender_cli_command_register(std::unique_ptr<CommandHandler> cmd);
/**
* Unregister a previously registered command.
*/
bool BKE_blender_cli_command_unregister(CommandHandler *cmd);
/**
* Run the command by `id`, passing in the argument list & context.
* The argument list must begin after the command identifier.
*/
int BKE_blender_cli_command_exec(struct bContext *C,
const char *id,
const int argc,
const char **argv);
/**
* Print all known commands (used for passing `--command help` in the command-line).
*/
void BKE_blender_cli_command_print_help();
/**
* Frees all commands (using their #CommandFreeFn call-backs).
*/
void BKE_blender_cli_command_free_all();

View File

@ -88,8 +88,8 @@ BlendFileData *BKE_blendfile_read(const char *filepath,
* \return Blend file data, this must be passed to
* #BKE_blendfile_read_setup_readfile/#BKE_blendfile_read_setup_undo when non-NULL.
*/
BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
BlendFileData *BKE_blendfile_read_from_memory(const void *file_buf,
int file_buf_size,
const BlendFileReadParams *params,
ReportList *reports);
@ -113,8 +113,8 @@ void BKE_blendfile_read_make_empty(bContext *C);
* Only read the #UserDef from a .blend.
*/
UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports);
UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
int filelength,
UserDef *BKE_blendfile_userdef_read_from_memory(const void *file_buf,
int file_buf_size,
ReportList *reports);
UserDef *BKE_blendfile_userdef_from_defaults();
@ -135,8 +135,8 @@ bool BKE_blendfile_userdef_write_app_template(const char *filepath, ReportList *
bool BKE_blendfile_userdef_write_all(ReportList *reports);
WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath,
const void *filebuf,
int filelength,
const void *file_buf,
int file_buf_size,
ReportList *reports);
bool BKE_blendfile_workspace_config_write(Main *bmain, const char *filepath, ReportList *reports);
void BKE_blendfile_workspace_config_data_free(WorkspaceConfigFileData *workspace_config);

View File

@ -173,8 +173,8 @@ struct CameraBGImage *BKE_camera_background_image_new(struct Camera *cam);
* \param copy_flag: The usual ID copying flags, see `LIB_ID_CREATE_`/`LIB_ID_COPY_` enums in
* `BKE_lib_id.hh`.
*/
struct CameraBGImage *BKE_camera_background_image_copy(struct CameraBGImage *bgpic_src,
const int copy_flag);
struct CameraBGImage *BKE_camera_background_image_copy(const struct CameraBGImage *bgpic_src,
int copy_flag);
void BKE_camera_background_image_remove(struct Camera *cam, struct CameraBGImage *bgpic);
void BKE_camera_background_image_clear(struct Camera *cam);

View File

@ -62,7 +62,7 @@ struct ClothSolverResult {
*
* The m and n members of this structure represent the assumed
* rectangular ordered grid for which the original paper is written.
* At some point they need to disappear and we need to determine out
* At some point they need to disappear and we need to determine our
* own connectivity of the mesh based on the actual edges in the mesh.
*/
struct Cloth {

View File

@ -20,12 +20,9 @@
struct BLI_Iterator;
struct Base;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Collection;
struct Depsgraph;
struct ID;
struct Library;
struct Main;
struct Object;
struct Scene;
@ -276,6 +273,11 @@ bool BKE_collection_cycles_fix(Main *bmain, Collection *collection);
bool BKE_collection_has_collection(const Collection *parent, const Collection *collection);
/**
* Return parent collection which is not linked.
*/
Collection *BKE_collection_parent_editable_find_recursive(const ViewLayer *view_layer,
Collection *collection);
/**
* Rebuild parent relationships from child ones, for all children of given \a collection.
*

View File

@ -9,7 +9,6 @@
*/
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Depsgraph;
struct ID;

View File

@ -19,7 +19,6 @@
struct BezTriple;
struct BezTriple;
struct BMEditMesh;
struct BoundBox;
struct BPoint;
struct Curve;
struct Depsgraph;

View File

@ -17,7 +17,6 @@ extern "C" {
struct Depsgraph;
struct Object;
struct ReportList;
struct Scene;
struct SpaceTransform;
/* Warning, those def are stored in files (TransferData modifier), *DO NOT* modify those values. */

View File

@ -21,7 +21,6 @@ struct AnimData;
struct AnimationEvalContext;
struct BezTriple;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct LibraryForeachIDData;
struct PathResolvedRNA;

View File

@ -16,6 +16,13 @@
struct Main;
/**
* Global data, typically accessed from #G.
* See: #BKE_blender_globals_init & #BKE_blender_globals_clear.
*
* \note This is run-time only but some global data is written
* to #FileGlobal which is used to initialize members of #Global.
*/
struct Global {
/**
@ -58,6 +65,14 @@ struct Global {
*/
bool background;
/**
* When true, suppress any non-error print messages such as files saves, loaded, quitting etc.
* This is used so command line tools can control output without unnecessary noise.
*
* \note This should only be used to suppress printing (not reports or other kinds of logging).
*/
bool quiet;
/**
* Skip reading the startup file and user preferences.
* Also disable saving the preferences on exit (see #G_FLAG_USERPREF_NO_SAVE_ON_EXIT),

View File

@ -16,7 +16,6 @@ extern "C" {
struct ARegionType;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Depsgraph;
struct GpencilModifierData;

View File

@ -74,8 +74,6 @@ struct Icon_Geom {
typedef struct Icon Icon;
struct BlendDataReader;
struct BlendWriter;
struct ID;
struct ImBuf;
struct PreviewImage;

View File

@ -16,13 +16,11 @@ extern "C" {
#endif
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct IDProperty;
struct IDPropertyUIData;
struct IDPropertyUIDataEnumItem;
struct Library;
typedef union IDPropertyTemplate {
int i;

View File

@ -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;

View File

@ -16,7 +16,6 @@
#include "BLI_sys_types.h"
struct BMEditMesh;
struct BoundBox;
struct BPoint;
struct Depsgraph;
struct Lattice;

View File

@ -21,6 +21,7 @@
*/
#include "BLI_compiler_attrs.h"
#include "BLI_function_ref.hh"
#include "BLI_map.hh"
#include "BLI_set.hh"
#include "BLI_span.hh"
@ -265,14 +266,14 @@ using IDTypeFilter = uint64_t;
namespace blender::bke::id {
class IDRemapper {
blender::Map<ID *, ID *> mappings_;
Map<ID *, ID *> mappings_;
IDTypeFilter source_types_ = 0;
/**
* Store all IDs using another ID with the 'NEVER_NULL' flag, which have (or
* should have been) remapped to `nullptr`.
*/
blender::Set<ID *> never_null_users_;
Set<ID *> never_null_users_;
public:
/**
@ -282,14 +283,14 @@ class IDRemapper {
bool allow_idtype_mismatch = false;
public:
void clear(void)
void clear()
{
mappings_.clear();
never_null_users_.clear();
source_types_ = 0;
}
bool is_empty(void) const
bool is_empty() const
{
return mappings_.is_empty();
}
@ -326,24 +327,24 @@ class IDRemapper {
never_null_users_.add(id);
}
const blender::Set<ID *> &never_null_users(void) const
const Set<ID *> &never_null_users() const
{
return never_null_users_;
}
/** Iterate over all remapping pairs in the remapper, and call the callback function on them. */
void iter(IDRemapperIterFunction func, void *user_data) const
void iter(FunctionRef<void(ID *old_id, ID *new_id)> func) const
{
for (auto item : mappings_.items()) {
func(item.key, item.value, user_data);
func(item.key, item.value);
}
}
/** Return a readable string for the given result. Can be used for debugging purposes. */
static const blender::StringRefNull result_to_string(const IDRemapperApplyResult result);
static const StringRefNull result_to_string(const IDRemapperApplyResult result);
/** Print out the rules inside the given id_remapper. Can be used for debugging purposes. */
void print(void) const;
void print() const;
};
} // namespace blender::bke::id

View File

@ -210,6 +210,7 @@ struct Main {
ListBase collections;
ListBase armatures;
ListBase actions;
ListBase animations;
ListBase nodetrees;
ListBase brushes;
ListBase particles;

View File

@ -15,8 +15,6 @@
#include "BKE_mesh_mapping.hh"
struct CustomData;
struct CustomData_MeshMasks;
struct MemArena;
struct Mesh;

View File

@ -28,7 +28,6 @@ struct Speaker;
struct bAction;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct PointerRNA;
struct PropertyRNA;
@ -432,11 +431,11 @@ void BKE_nlastrip_validate_name(struct AnimData *adt, struct NlaStrip *strip);
/* ............ */
/**
* Check if the given NLA-Track has any strips with own F-Curves.
* Check if the given NLA-Track has any strips with their own F-Curves.
*/
bool BKE_nlatrack_has_animated_strips(struct NlaTrack *nlt);
/**
* Check if given NLA-Tracks have any strips with own F-Curves.
* Check if given NLA-Tracks have any strips with their own F-Curves.
*/
bool BKE_nlatracks_have_animated_strips(ListBase *tracks);
/**

View File

@ -29,7 +29,6 @@
#define MAX_SOCKET 512
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct FreestyleLineStyle;
struct GPUMaterial;

View File

@ -30,7 +30,6 @@ struct FieldInferencingInterface;
class NodeDeclaration;
struct GeometryNodesLazyFunctionGraphInfo;
namespace anonymous_attribute_lifetime {
struct RelationsInNode;
}
namespace aal = anonymous_attribute_lifetime;
} // namespace blender::nodes

View File

@ -336,7 +336,7 @@ void BKE_object_where_is_calc_time(Depsgraph *depsgraph, Scene *scene, Object *o
*/
void BKE_object_where_is_calc_mat4(Object *ob, float r_obmat[4][4]);
/* Possibly belong in own module? */
/* Possibly belong in its own module? */
void BKE_boundbox_init_from_minmax(BoundBox *bb, const float min[3], const float max[3]);
void BKE_boundbox_minmax(const BoundBox *bb,

View File

@ -13,7 +13,6 @@
#include "DNA_customdata_types.h" /* #CustomData_MeshMasks. */
struct BoundBox;
struct bGPdata;
struct Curve;
struct CurveCache;

View File

@ -26,7 +26,6 @@ struct BMFace;
struct BMLog;
struct BMesh;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct Brush;
struct CustomDataLayer;
@ -53,7 +52,6 @@ struct Image;
struct ImagePool;
struct ImageUser;
struct KeyBlock;
struct ListBase;
struct Main;
struct Mesh;
struct MDeformVert;

View File

@ -225,7 +225,7 @@ struct ARegionType {
/* register operator types on startup */
void (*operatortypes)();
/* add own items to keymap */
/* add items to keymap */
void (*keymap)(wmKeyConfig *keyconf);
/* allows default cursor per region */
void (*cursor)(wmWindow *win, ScrArea *area, ARegion *region);

View File

@ -16,7 +16,6 @@ extern "C" {
struct ARegionType;
struct BlendDataReader;
struct BlendLibReader;
struct BlendWriter;
struct ID;
struct ListBase;

View File

@ -29,7 +29,6 @@
*/
struct BVHTree;
struct GreasePencilShrinkwrapModifierData;
struct MDeformVert;
struct Mesh;
struct ModifierEvalContext;

View File

@ -19,7 +19,6 @@
#include "BKE_DerivedMesh.hh"
struct CCGElem;
struct CCGFace;
struct CCGKey;
struct Mesh;
struct Subdiv;

View File

@ -26,9 +26,7 @@
struct BlendWriter;
struct BlendDataReader;
struct BlendLibReader;
struct LibraryForeachIDData;
struct Library;
namespace blender::bke::id {
class IDRemapper;

View File

@ -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
@ -75,6 +76,7 @@ set(SRC
intern/bake_items_serialize.cc
intern/bake_items_socket.cc
intern/blender.cc
intern/blender_cli_command.cc
intern/blender_copybuffer.cc
intern/blender_undo.cc
intern/blender_user_menu.cc
@ -327,6 +329,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
@ -343,6 +346,7 @@ set(SRC
BKE_bake_items_serialize.hh
BKE_bake_items_socket.hh
BKE_blender.hh
BKE_blender_cli_command.hh
BKE_blender_copybuffer.hh
BKE_blender_undo.hh
BKE_blender_user_menu.hh

View File

@ -82,9 +82,6 @@ CCGAllocatorIFC *ccg_getStandardAllocatorIFC(void);
* Catmull-Clark Gridding Subdivision Surface.
*/
/* TODO(sergey): Get rid of this, it's more or less a bad level call. */
struct DerivedMesh;
/* ** Data structures, constants. enums ** */
enum {
@ -256,8 +253,6 @@ void ccgSubSurf__effectedFaceNeighbors(CCGSubSurf *ss,
void ccgSubSurf__sync_legacy(CCGSubSurf *ss);
struct OpenSubdiv_Converter;
/* `CCGSubSurf_util.cc` */
#ifdef DUMP_RESULT_GRIDS

View File

@ -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);

View 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;
}

View File

@ -0,0 +1,181 @@
/* SPDX-FileCopyrightText: 2001-2002 NaN Holding BV. All rights reserved.
*
* SPDX-License-Identifier: GPL-2.0-or-later */
/** \file
* \ingroup bke
*
* Generic CLI "--command" declarations.
*
* Duplicate Commands
* ==================
*
* When two or more commands share the same identifier, a warning is printed and both are disabled.
*
* This is done because command-line actions may be destructive so the down-side of running the
* wrong command could be severe. The reason this is not considered an error is we can't prevent
* it so easily, unlike operator ID's which may be longer, commands are typically short terms
* which wont necessarily include an add-ons identifier as a prefix for e.g.
* Further, an error would break loading add-ons who's primary is *not*
* necessarily to provide command-line access.
* An alternative solution could be to generate unique names (number them for example)
* but this isn't reliable as it would depend on it the order add-ons are loaded which
* isn't under user control.
*/
#include <iostream>
#include "BLI_vector.hh"
#include "BKE_blender_cli_command.hh" /* own include */
#include "MEM_guardedalloc.h"
/* -------------------------------------------------------------------- */
/** \name Internal API
* \{ */
using CommandHandlerPtr = std::unique_ptr<CommandHandler>;
/**
* All registered command handlers.
* \note the order doesn't matter as duplicates are detected and prevented from running.
*/
blender::Vector<CommandHandlerPtr> g_command_handlers;
static CommandHandler *blender_cli_command_lookup(const std::string &id)
{
for (CommandHandlerPtr &cmd_iter : g_command_handlers) {
if (id == cmd_iter->id) {
return cmd_iter.get();
}
}
return nullptr;
}
static int blender_cli_command_index(const CommandHandler *cmd)
{
int index = 0;
for (CommandHandlerPtr &cmd_iter : g_command_handlers) {
if (cmd_iter.get() == cmd) {
return index;
}
index++;
}
return -1;
}
/** \} */
/* -------------------------------------------------------------------- */
/** \name Public API
* \{ */
void BKE_blender_cli_command_register(std::unique_ptr<CommandHandler> cmd)
{
bool is_duplicate = false;
if (CommandHandler *cmd_exists = blender_cli_command_lookup(cmd->id)) {
std::cerr << "warning: registered duplicate command \"" << cmd->id
<< "\", this will be inaccessible" << std::endl;
cmd_exists->is_duplicate = true;
is_duplicate = true;
}
cmd->is_duplicate = is_duplicate;
g_command_handlers.append(std::move(cmd));
}
bool BKE_blender_cli_command_unregister(CommandHandler *cmd)
{
const int cmd_index = blender_cli_command_index(cmd);
if (cmd_index == -1) {
std::cerr << "failed to unregister command handler" << std::endl;
return false;
}
/* Update duplicates after removal. */
if (cmd->is_duplicate) {
CommandHandler *cmd_other = nullptr;
for (CommandHandlerPtr &cmd_iter : g_command_handlers) {
/* Skip self. */
if (cmd == cmd_iter.get()) {
continue;
}
if (cmd_iter->is_duplicate && (cmd_iter->id == cmd->id)) {
if (cmd_other) {
/* Two or more found, clear and break. */
cmd_other = nullptr;
break;
}
cmd_other = cmd_iter.get();
}
}
if (cmd_other) {
cmd_other->is_duplicate = false;
}
}
g_command_handlers.remove_and_reorder(cmd_index);
return true;
}
int BKE_blender_cli_command_exec(bContext *C, const char *id, const int argc, const char **argv)
{
CommandHandler *cmd = blender_cli_command_lookup(id);
if (cmd == nullptr) {
std::cerr << "Unrecognized command: \"" << id << "\"" << std::endl;
return EXIT_FAILURE;
}
if (cmd->is_duplicate) {
std::cerr << "Command: \"" << id
<< "\" was registered multiple times, must be resolved, aborting!" << std::endl;
return EXIT_FAILURE;
}
return cmd->exec(C, argc, argv);
}
void BKE_blender_cli_command_print_help()
{
/* As this is isn't ordered sorting in-place is acceptable,
* sort alphabetically for display purposes only. */
std::sort(g_command_handlers.begin(),
g_command_handlers.end(),
[](const CommandHandlerPtr &a, const CommandHandlerPtr &b) { return a->id < b->id; });
for (int pass = 0; pass < 2; pass++) {
std::cout << ((pass == 0) ? "Blender Command Listing:" :
"Duplicate Command Listing (ignored):")
<< std::endl;
const bool is_duplicate = pass > 0;
bool found = false;
bool has_duplicate = false;
for (CommandHandlerPtr &cmd_iter : g_command_handlers) {
if (cmd_iter->is_duplicate) {
has_duplicate = true;
}
if (cmd_iter->is_duplicate != is_duplicate) {
continue;
}
std::cout << "\t" << cmd_iter->id << std::endl;
found = true;
}
if (!found) {
std::cout << "\tNone found" << std::endl;
}
/* Don't print that no duplicates are found as it's not helpful. */
if (pass == 0 && !has_duplicate) {
break;
}
}
}
void BKE_blender_cli_command_free_all()
{
g_command_handlers.clear();
}
/** \} */

View File

@ -1046,7 +1046,9 @@ BlendFileData *BKE_blendfile_read(const char *filepath,
{
/* Don't print startup file loading. */
if (params->is_startup == false) {
printf("Read blend: \"%s\"\n", filepath);
if (!G.quiet) {
printf("Read blend: \"%s\"\n", filepath);
}
}
BlendFileData *bfd = BLO_read_from_file(filepath, eBLOReadSkip(params->skip_flags), reports);
@ -1063,13 +1065,13 @@ BlendFileData *BKE_blendfile_read(const char *filepath,
return bfd;
}
BlendFileData *BKE_blendfile_read_from_memory(const void *filebuf,
int filelength,
BlendFileData *BKE_blendfile_read_from_memory(const void *file_buf,
int file_buf_size,
const BlendFileReadParams *params,
ReportList *reports)
{
BlendFileData *bfd = BLO_read_from_memory(
filebuf, filelength, eBLOReadSkip(params->skip_flags), reports);
file_buf, file_buf_size, eBLOReadSkip(params->skip_flags), reports);
if (bfd && bfd->main->is_read_invalid) {
BLO_blendfiledata_free(bfd);
bfd = nullptr;
@ -1167,15 +1169,15 @@ UserDef *BKE_blendfile_userdef_read(const char *filepath, ReportList *reports)
return userdef;
}
UserDef *BKE_blendfile_userdef_read_from_memory(const void *filebuf,
int filelength,
UserDef *BKE_blendfile_userdef_read_from_memory(const void *file_buf,
int file_buf_size,
ReportList *reports)
{
BlendFileData *bfd;
UserDef *userdef = nullptr;
bfd = BLO_read_from_memory(
filebuf, filelength, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
file_buf, file_buf_size, BLO_READ_SKIP_ALL & ~BLO_READ_SKIP_USERDEF, reports);
if (bfd) {
if (bfd->user) {
userdef = bfd->user;
@ -1332,12 +1334,18 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
/* Also save app-template preferences. */
BLI_path_join(filepath, sizeof(filepath), cfgdir->c_str(), BLENDER_USERPREF_FILE);
printf("Writing userprefs app-template: \"%s\" ", filepath);
if (!G.quiet) {
printf("Writing userprefs app-template: \"%s\" ", filepath);
}
if (BKE_blendfile_userdef_write(filepath, reports) != 0) {
printf("ok\n");
if (!G.quiet) {
printf("ok\n");
}
}
else {
printf("fail\n");
if (!G.quiet) {
printf("fail\n");
}
ok = false;
}
}
@ -1360,8 +1368,8 @@ bool BKE_blendfile_userdef_write_all(ReportList *reports)
* \{ */
WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepath,
const void *filebuf,
int filelength,
const void *file_buf,
int file_buf_size,
ReportList *reports)
{
BlendFileData *bfd;
@ -1373,7 +1381,7 @@ WorkspaceConfigFileData *BKE_blendfile_workspace_config_read(const char *filepat
bfd = BLO_read_from_file(filepath, BLO_READ_SKIP_USERDEF, &blend_file_read_reports);
}
else {
bfd = BLO_read_from_memory(filebuf, filelength, BLO_READ_SKIP_USERDEF, reports);
bfd = BLO_read_from_memory(file_buf, file_buf_size, BLO_READ_SKIP_USERDEF, reports);
}
if (bfd) {

View File

@ -520,11 +520,13 @@ static void loose_data_instantiate_ensure_active_collection(
Scene *scene = instantiate_context->lapp_context->params->context.scene;
ViewLayer *view_layer = instantiate_context->lapp_context->params->context.view_layer;
/* Find or add collection as needed. */
/* Find or add collection as needed. When `active_collection` is non-null, it is assumed to be
* editable. */
if (instantiate_context->active_collection == nullptr) {
if (lapp_context->params->flag & FILE_ACTIVE_COLLECTION) {
LayerCollection *lc = BKE_layer_collection_get_active(view_layer);
instantiate_context->active_collection = lc->collection;
instantiate_context->active_collection = BKE_collection_parent_editable_find_recursive(
view_layer, lc->collection);
}
else {
if (lapp_context->params->flag & FILE_LINK) {

View File

@ -282,7 +282,7 @@ static bool rule_avoid_collision(BoidRule *rule,
}
}
/* Check boids in own system. */
/* Check boids in their own system. */
if (acbr->options & BRULE_ACOLL_WITH_BOIDS) {
neighbors = BLI_kdtree_3d_range_search_with_len_squared_cb(bbd->sim->psys->tree,
pa->prev_state.co,
@ -690,7 +690,7 @@ static bool rule_fight(BoidRule *rule, BoidBrainData *bbd, BoidValues *val, Part
int n;
bool ret = false;
/* calculate own group strength */
/* calculate its own group strength */
int neighbors = BLI_kdtree_3d_range_search(
bbd->sim->psys->tree, pa->prev_state.co, &ptn, fbr->distance);
for (n = 0; n < neighbors; n++) {

View File

@ -78,7 +78,7 @@ static void camera_copy_data(Main * /*bmain*/,
Camera *cam_dst = (Camera *)id_dst;
const Camera *cam_src = (const Camera *)id_src;
/* We never handle user-count here for own data. */
/* We never handle user-count here for owned data. */
const int flag_subdata = flag | LIB_ID_CREATE_NO_USER_REFCOUNT;
BLI_listbase_clear(&cam_dst->bg_images);
@ -278,7 +278,7 @@ void *BKE_camera_add(Main *bmain, const char *name)
float BKE_camera_object_dof_distance(const Object *ob)
{
Camera *cam = (Camera *)ob->data;
const Camera *cam = (const Camera *)ob->data;
if (ob->type != OB_CAMERA) {
return 0.0f;
}
@ -355,7 +355,7 @@ void BKE_camera_params_from_object(CameraParams *params, const Object *cam_ob)
if (cam_ob->type == OB_CAMERA) {
/* camera object */
Camera *cam = static_cast<Camera *>(cam_ob->data);
const Camera *cam = static_cast<const Camera *>(cam_ob->data);
if (cam->type == CAM_ORTHO) {
params->is_ortho = true;
@ -899,7 +899,7 @@ static void camera_stereo3d_model_matrix(const Object *camera,
const bool is_left,
float r_modelmat[4][4])
{
Camera *data = (Camera *)camera->data;
const Camera *data = (const Camera *)camera->data;
float interocular_distance, convergence_distance;
short convergence_mode, pivot;
float sizemat[4][4];
@ -1060,7 +1060,6 @@ void BKE_camera_multiview_window_matrix(const RenderData *rd,
bool BKE_camera_multiview_spherical_stereo(const RenderData *rd, const Object *camera)
{
Camera *cam;
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
if (!is_multiview) {
@ -1071,7 +1070,7 @@ bool BKE_camera_multiview_spherical_stereo(const RenderData *rd, const Object *c
return false;
}
cam = static_cast<Camera *>(camera->data);
const Camera *cam = static_cast<const Camera *>(camera->data);
if ((rd->views_format == SCE_VIEWS_FORMAT_STEREO_3D) && ELEM(cam->type, CAM_PANO, CAM_PERSP) &&
((cam->stereo.flag & CAM_S3D_SPHERICAL) != 0))
@ -1132,7 +1131,7 @@ Object *BKE_camera_multiview_render(const Scene *scene, Object *camera, const ch
static float camera_stereo3d_shift_x(const Object *camera, const char *viewname)
{
Camera *data = static_cast<Camera *>(camera->data);
const Camera *data = static_cast<const Camera *>(camera->data);
float shift = data->shiftx;
float interocular_distance, convergence_distance;
short convergence_mode, pivot;
@ -1174,7 +1173,7 @@ float BKE_camera_multiview_shift_x(const RenderData *rd,
const char *viewname)
{
const bool is_multiview = (rd && rd->scemode & R_MULTIVIEW) != 0;
Camera *data = static_cast<Camera *>(camera->data);
const Camera *data = static_cast<const Camera *>(camera->data);
BLI_assert(camera->type == OB_CAMERA);
@ -1222,7 +1221,7 @@ CameraBGImage *BKE_camera_background_image_new(Camera *cam)
return bgpic;
}
CameraBGImage *BKE_camera_background_image_copy(CameraBGImage *bgpic_src, const int flag)
CameraBGImage *BKE_camera_background_image_copy(const CameraBGImage *bgpic_src, const int flag)
{
CameraBGImage *bgpic_dst = static_cast<CameraBGImage *>(MEM_dupallocN(bgpic_src));

View File

@ -1239,8 +1239,8 @@ static void collection_gobject_assert_internal_consistency(Collection *collectio
}
}
static Collection *collection_parent_editable_find_recursive(const ViewLayer *view_layer,
Collection *collection)
Collection *BKE_collection_parent_editable_find_recursive(const ViewLayer *view_layer,
Collection *collection)
{
if (!ID_IS_LINKED(collection) && !ID_IS_OVERRIDE_LIBRARY(collection) &&
(view_layer == nullptr || BKE_view_layer_has_collection(view_layer, collection)))
@ -1265,7 +1265,7 @@ static Collection *collection_parent_editable_find_recursive(const ViewLayer *vi
}
return collection_parent->collection;
}
Collection *editable_collection = collection_parent_editable_find_recursive(
Collection *editable_collection = BKE_collection_parent_editable_find_recursive(
view_layer, collection_parent->collection);
if (editable_collection != nullptr) {
return editable_collection;
@ -1393,7 +1393,7 @@ bool BKE_collection_viewlayer_object_add(Main *bmain,
return false;
}
collection = collection_parent_editable_find_recursive(view_layer, collection);
collection = BKE_collection_parent_editable_find_recursive(view_layer, collection);
if (collection == nullptr) {
return false;

View File

@ -474,7 +474,7 @@ static void build_mesh_positions(const CurvesInfo &curves_info,
}
const Span<float3> tangents = curves_info.main.evaluated_tangents();
const Span<float3> normals = curves_info.main.evaluated_normals();
Span<float> radii_eval = {};
Span<float> radii_eval;
if (const GVArray radii = *curves_info.main.attributes().lookup("radius", AttrDomain::Point)) {
radii_eval = evaluate_attribute(radii, curves_info.main, eval_buffer).typed<float>();
}

View File

@ -717,6 +717,13 @@ static ModifierData &legacy_object_modifier_common(Object &object,
/* Convert animation data if needed. */
AnimData *anim_data = BKE_animdata_from_id(&object.id);
if (anim_data) {
char legacy_name_esc[MAX_NAME * 2];
BLI_str_escape(legacy_name_esc, legacy_md.name, sizeof(legacy_name_esc));
const std::string legacy_root_path = fmt::format("grease_pencil_modifiers[\"{}\"]",
legacy_name_esc);
char new_name_esc[MAX_NAME * 2];
BLI_str_escape(new_name_esc, new_md.name, sizeof(new_name_esc));
auto modifier_path_update = [&](FCurve *fcurve) -> bool {
/* NOTE: This logic will likely need to be re-used in other similar conditions for other
* areas, should be put into its own util then. */
@ -724,15 +731,9 @@ static ModifierData &legacy_object_modifier_common(Object &object,
return false;
}
StringRefNull rna_path = fcurve->rna_path;
char legacy_name_esc[MAX_NAME * 2];
BLI_str_escape(legacy_name_esc, legacy_md.name, sizeof(legacy_name_esc));
const std::string legacy_root_path = fmt::format("grease_pencil_modifiers[\"{}\"]",
legacy_name_esc);
if (!rna_path.startswith(legacy_root_path)) {
return false;
}
char new_name_esc[MAX_NAME * 2];
BLI_str_escape(new_name_esc, new_md.name, sizeof(new_name_esc));
const std::string new_rna_path = fmt::format(
"modifiers[\"{}\"]{}", new_name_esc, rna_path.substr(int64_t(legacy_root_path.size())));
MEM_freeN(fcurve->rna_path);

View File

@ -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);

Some files were not shown because too many files have changed in this diff Show More