Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSergey Sharybin <sergey.vfx@gmail.com>2015-05-12 13:05:57 +0300
committerSergey Sharybin <sergey.vfx@gmail.com>2015-05-12 14:06:37 +0300
commitbac735380189c63d2b8824cba8e0398bb35e9af2 (patch)
treed9bc3e73a89520ef7e23782419d880964d1a4fb7
parenta09341469ee3874a0874492a7dcad79c2b99179a (diff)
Depsgraph: New dependency graph integration commit
This commit integrates the work done so far on the new dependency graph system, where goal was to replace legacy depsgraph with the new one, supporting loads of neat features like: - More granular dependency relation nature, which solves issues with fake cycles in the dependencies. - Move towards all-animatable, by better integration of drivers into the system. - Lay down some basis for upcoming copy-on-write, overrides and so on. The new system is living side-by-side with the previous one and disabled by default, so nothing will become suddenly broken. The way to enable new depsgraph is to pass `--new-depsgraph` command line argument. It's a bit early to consider the system production-ready, there are some TODOs and issues were discovered during the merge period, they'll be addressed ASAP. But it's important to merge, because it's the only way to attract artists to really start testing this system. There are number of assorted documents related on the design of the new system: * http://wiki.blender.org/index.php/User:Aligorith/GSoC2013_Depsgraph#Design_Documents * http://wiki.blender.org/index.php/User:Nazg-gul/DependencyGraph There are also some user-related information online: * http://code.blender.org/2015/02/blender-dependency-graph-branch-for-users/ * http://code.blender.org/2015/03/more-dependency-graph-tricks/ Kudos to everyone who was involved into the project: - Joshua "Aligorith" Leung -- design specification, initial code - Lukas "lukas_t" Toenne -- integrating code into blender, with further fixes - Sergey "Sergey" "Sharybin" -- some mocking around, trying to wrap up the project and so - Bassam "slikdigit" Kurdali -- stressing the new system, reporting all the issues and recording/writing documentation. - Everyone else who i forgot to mention here :)
-rw-r--r--CMakeLists.txt3
-rw-r--r--build_files/cmake/macros.cmake1
-rw-r--r--build_files/scons/tools/Blender.py2
-rw-r--r--build_files/scons/tools/btools.py4
-rw-r--r--source/blender/CMakeLists.txt1
-rw-r--r--source/blender/SConscript1
-rw-r--r--source/blender/blenkernel/BKE_depsgraph.h1
-rw-r--r--source/blender/blenkernel/BKE_modifier.h12
-rw-r--r--source/blender/blenkernel/CMakeLists.txt5
-rw-r--r--source/blender/blenkernel/SConscript4
-rw-r--r--source/blender/blenkernel/intern/action.c7
-rw-r--r--source/blender/blenkernel/intern/armature_update.c2
-rw-r--r--source/blender/blenkernel/intern/depsgraph.c405
-rw-r--r--source/blender/blenkernel/intern/library.c7
-rw-r--r--source/blender/blenkernel/intern/mesh.c5
-rw-r--r--source/blender/blenkernel/intern/object_update.c2
-rw-r--r--source/blender/blenkernel/intern/scene.c120
-rw-r--r--source/blender/blenloader/intern/readfile.c1
-rw-r--r--source/blender/depsgraph/CMakeLists.txt116
-rw-r--r--source/blender/depsgraph/DEG_depsgraph.h210
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_build.h117
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_debug.h107
-rw-r--r--source/blender/depsgraph/DEG_depsgraph_query.h191
-rw-r--r--source/blender/depsgraph/SConscript74
-rw-r--r--source/blender/depsgraph/intern/depsgraph.cc469
-rw-r--r--source/blender/depsgraph/intern/depsgraph.h220
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.cc365
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build.h404
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_nodes.cc1199
-rw-r--r--source/blender/depsgraph/intern/depsgraph_build_relations.cc1815
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.cc1187
-rw-r--r--source/blender/depsgraph/intern/depsgraph_debug.h83
-rw-r--r--source/blender/depsgraph/intern/depsgraph_eval.cc386
-rw-r--r--source/blender/depsgraph/intern/depsgraph_intern.h164
-rw-r--r--source/blender/depsgraph/intern/depsgraph_query.cc213
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.cc173
-rw-r--r--source/blender/depsgraph/intern/depsgraph_queue.h87
-rw-r--r--source/blender/depsgraph/intern/depsgraph_tag.cc490
-rw-r--r--source/blender/depsgraph/intern/depsgraph_type_defines.cc98
-rw-r--r--source/blender/depsgraph/intern/depsgraph_types.h169
-rw-r--r--source/blender/depsgraph/intern/depsnode.cc308
-rw-r--r--source/blender/depsgraph/intern/depsnode.h243
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.cc314
-rw-r--r--source/blender/depsgraph/intern/depsnode_component.h197
-rw-r--r--source/blender/depsgraph/intern/depsnode_opcodes.h141
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.cc100
-rw-r--r--source/blender/depsgraph/intern/depsnode_operation.h86
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.cc134
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_cycle.h31
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_function.h106
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_hash.h66
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_map.h61
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.cc132
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_pchanmap.h55
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_set.h60
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.cc133
-rw-r--r--source/blender/depsgraph/util/depsgraph_util_transitive.h32
-rw-r--r--source/blender/editors/space_view3d/CMakeLists.txt1
-rw-r--r--source/blender/editors/space_view3d/SConscript1
-rw-r--r--source/blender/editors/space_view3d/space_view3d.c8
-rw-r--r--source/blender/editors/transform/CMakeLists.txt4
-rw-r--r--source/blender/editors/transform/SConscript3
-rw-r--r--source/blender/editors/transform/transform_conversions.c4
-rw-r--r--source/blender/makesdna/DNA_scene_types.h1
-rw-r--r--source/blender/makesrna/SConscript1
-rw-r--r--source/blender/makesrna/intern/CMakeLists.txt2
-rw-r--r--source/blender/makesrna/intern/SConscript1
-rw-r--r--source/blender/makesrna/intern/makesrna.c1
-rw-r--r--source/blender/makesrna/intern/rna_depsgraph.c112
-rw-r--r--source/blender/makesrna/intern/rna_internal.h1
-rw-r--r--source/blender/makesrna/intern/rna_object_api.c6
-rw-r--r--source/blender/makesrna/intern/rna_scene.c5
-rw-r--r--source/blender/modifiers/CMakeLists.txt1
-rw-r--r--source/blender/modifiers/SConscript1
-rw-r--r--source/blender/modifiers/intern/MOD_armature.c13
-rw-r--r--source/blender/modifiers/intern/MOD_array.c23
-rw-r--r--source/blender/modifiers/intern/MOD_bevel.c1
-rw-r--r--source/blender/modifiers/intern/MOD_boolean.c16
-rw-r--r--source/blender/modifiers/intern/MOD_build.c1
-rw-r--r--source/blender/modifiers/intern/MOD_cast.c13
-rw-r--r--source/blender/modifiers/intern/MOD_cloth.c22
-rw-r--r--source/blender/modifiers/intern/MOD_collision.c1
-rw-r--r--source/blender/modifiers/intern/MOD_correctivesmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_curve.c21
-rw-r--r--source/blender/modifiers/intern/MOD_datatransfer.c13
-rw-r--r--source/blender/modifiers/intern/MOD_decimate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_displace.c16
-rw-r--r--source/blender/modifiers/intern/MOD_dynamicpaint.c22
-rw-r--r--source/blender/modifiers/intern/MOD_edgesplit.c1
-rw-r--r--source/blender/modifiers/intern/MOD_explode.c1
-rw-r--r--source/blender/modifiers/intern/MOD_fluidsim.c28
-rw-r--r--source/blender/modifiers/intern/MOD_hook.c20
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciandeform.c1
-rw-r--r--source/blender/modifiers/intern/MOD_laplaciansmooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_lattice.c13
-rw-r--r--source/blender/modifiers/intern/MOD_mask.c18
-rw-r--r--source/blender/modifiers/intern/MOD_meshcache.c1
-rw-r--r--source/blender/modifiers/intern/MOD_meshdeform.c14
-rw-r--r--source/blender/modifiers/intern/MOD_mirror.c15
-rw-r--r--source/blender/modifiers/intern/MOD_multires.c1
-rw-r--r--source/blender/modifiers/intern/MOD_none.c1
-rw-r--r--source/blender/modifiers/intern/MOD_normal_edit.c13
-rw-r--r--source/blender/modifiers/intern/MOD_ocean.c1
-rw-r--r--source/blender/modifiers/intern/MOD_particleinstance.c15
-rw-r--r--source/blender/modifiers/intern/MOD_particlesystem.c1
-rw-r--r--source/blender/modifiers/intern/MOD_remesh.c1
-rw-r--r--source/blender/modifiers/intern/MOD_screw.c15
-rw-r--r--source/blender/modifiers/intern/MOD_shapekey.c1
-rw-r--r--source/blender/modifiers/intern/MOD_shrinkwrap.c18
-rw-r--r--source/blender/modifiers/intern/MOD_simpledeform.c13
-rw-r--r--source/blender/modifiers/intern/MOD_skin.c1
-rw-r--r--source/blender/modifiers/intern/MOD_smoke.c107
-rw-r--r--source/blender/modifiers/intern/MOD_smooth.c1
-rw-r--r--source/blender/modifiers/intern/MOD_softbody.c1
-rw-r--r--source/blender/modifiers/intern/MOD_solidify.c1
-rw-r--r--source/blender/modifiers/intern/MOD_subsurf.c1
-rw-r--r--source/blender/modifiers/intern/MOD_surface.c1
-rw-r--r--source/blender/modifiers/intern/MOD_triangulate.c1
-rw-r--r--source/blender/modifiers/intern/MOD_util.h2
-rw-r--r--source/blender/modifiers/intern/MOD_uvproject.c18
-rw-r--r--source/blender/modifiers/intern/MOD_uvwarp.c25
-rw-r--r--source/blender/modifiers/intern/MOD_warp.c17
-rw-r--r--source/blender/modifiers/intern/MOD_wave.c16
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgedit.c18
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgmix.c18
-rw-r--r--source/blender/modifiers/intern/MOD_weightvgproximity.c21
-rw-r--r--source/blender/modifiers/intern/MOD_wireframe.c1
-rw-r--r--source/blender/render/CMakeLists.txt1
-rw-r--r--source/blender/render/SConscript1
-rw-r--r--source/blender/render/intern/source/pipeline.c5
-rw-r--r--source/blenderplayer/CMakeLists.txt1
-rw-r--r--source/creator/CMakeLists.txt1
-rw-r--r--source/creator/creator.c14
133 files changed, 11844 insertions, 58 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt
index ae2c67b59bf..a8b32b4dc0f 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -449,6 +449,9 @@ endif()
option(WITH_CPP11 "Build with C++11 standard enabled, for development use only!" OFF)
mark_as_advanced(WITH_CPP11)
+# Dependency graph
+option(WITH_LEGACY_DEPSGRAPH "Build Blender with legacy dependency graph" ON)
+
# avoid using again
option_defaults_clear()
diff --git a/build_files/cmake/macros.cmake b/build_files/cmake/macros.cmake
index 8b2f3f18215..7de2b25f321 100644
--- a/build_files/cmake/macros.cmake
+++ b/build_files/cmake/macros.cmake
@@ -524,6 +524,7 @@ macro(SETUP_BLENDER_SORTED_LIBS)
bf_blenloader
bf_imbuf
bf_blenlib
+ bf_depsgraph
bf_intern_ghost
bf_intern_string
bf_avi
diff --git a/build_files/scons/tools/Blender.py b/build_files/scons/tools/Blender.py
index 6e7417c76ec..ecf34759033 100644
--- a/build_files/scons/tools/Blender.py
+++ b/build_files/scons/tools/Blender.py
@@ -372,7 +372,7 @@ def propose_priorities():
def creator(env):
sources = ['creator.c']# + Blender.buildinfo(env, "dynamic") + Blender.resources
- incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
+ incs = ['#/intern/guardedalloc', '#/source/blender/blenlib', '#/source/blender/blenkernel', '#/source/blender/depsgraph', '#/source/blender/editors/include', '#/source/blender/blenloader', '#/source/blender/imbuf', '#/source/blender/renderconverter', '#/source/blender/render/extern/include', '#/source/blender/windowmanager', '#/source/blender/makesdna', '#/source/blender/makesrna', '#/source/gameengine/BlenderRoutines', '#/extern/glew/include', '#/source/blender/gpu', env['BF_OPENGL_INC']]
defs = []
diff --git a/build_files/scons/tools/btools.py b/build_files/scons/tools/btools.py
index c5342d6f349..76450fbd223 100644
--- a/build_files/scons/tools/btools.py
+++ b/build_files/scons/tools/btools.py
@@ -199,7 +199,7 @@ def validate_arguments(args, bc):
'LLIBS', 'PLATFORM_LINKFLAGS', 'MACOSX_ARCHITECTURE', 'MACOSX_SDK', 'XCODE_CUR_VER', 'C_COMPILER_ID',
'BF_CYCLES_CUDA_BINARIES_ARCH', 'BF_PROGRAM_LINKFLAGS', 'MACOSX_DEPLOYMENT_TARGET',
'WITH_BF_CYCLES_DEBUG', 'WITH_BF_CYCLES_LOGGING',
- 'WITH_BF_CPP11'
+ 'WITH_BF_CPP11', 'WITH_BF_LEGACY_DEPSGRAPH',
]
@@ -657,6 +657,8 @@ def read_opts(env, cfg, args):
('BF_PROGRAM_LINKFLAGS', 'Link flags applied only to final binaries (blender and blenderplayer, not makesrna/makesdna)', ''),
(BoolVariable('WITH_BF_CPP11', '"Build with C++11 standard enabled, for development use only!', False)),
+
+ (BoolVariable('WITH_BF_LEGACY_DEPSGRAPH', 'Build Blender with legacy dependency graph', True)),
) # end of opts.AddOptions()
return localopts
diff --git a/source/blender/CMakeLists.txt b/source/blender/CMakeLists.txt
index d87d5dfc2cc..9a73921bbc7 100644
--- a/source/blender/CMakeLists.txt
+++ b/source/blender/CMakeLists.txt
@@ -102,6 +102,7 @@ add_subdirectory(bmesh)
add_subdirectory(render)
add_subdirectory(blenfont)
add_subdirectory(blenloader)
+add_subdirectory(depsgraph)
add_subdirectory(ikplugin)
add_subdirectory(physics)
add_subdirectory(gpu)
diff --git a/source/blender/SConscript b/source/blender/SConscript
index 64eca6a62db..e987b6be779 100644
--- a/source/blender/SConscript
+++ b/source/blender/SConscript
@@ -33,6 +33,7 @@ SConscript(['avi/SConscript',
'blenkernel/SConscript',
'blenlib/SConscript',
'blenloader/SConscript',
+ 'depsgraph/SConscript',
'gpu/SConscript',
'editors/SConscript',
'imbuf/SConscript',
diff --git a/source/blender/blenkernel/BKE_depsgraph.h b/source/blender/blenkernel/BKE_depsgraph.h
index f3a483fd0d8..862f91f567e 100644
--- a/source/blender/blenkernel/BKE_depsgraph.h
+++ b/source/blender/blenkernel/BKE_depsgraph.h
@@ -92,6 +92,7 @@ void DAG_exit(void);
*/
void DAG_scene_relations_update(struct Main *bmain, struct Scene *sce);
+void DAG_scene_relations_validate(struct Main *bmain, struct Scene *sce);
void DAG_relations_tag_update(struct Main *bmain);
void DAG_scene_relations_rebuild(struct Main *bmain, struct Scene *scene);
void DAG_scene_free(struct Scene *sce);
diff --git a/source/blender/blenkernel/BKE_modifier.h b/source/blender/blenkernel/BKE_modifier.h
index 9c5261c1583..cc53f9409fd 100644
--- a/source/blender/blenkernel/BKE_modifier.h
+++ b/source/blender/blenkernel/BKE_modifier.h
@@ -43,6 +43,7 @@ struct bArmature;
struct Main;
struct ModifierData;
struct BMEditMesh;
+struct DepsNodeHandle;
typedef enum {
/* Should not be used, only for None modifier type */
@@ -260,6 +261,17 @@ typedef struct ModifierTypeInfo {
struct Main *bmain, struct Scene *scene,
struct Object *ob, struct DagNode *obNode);
+ /* Add the appropriate relations to the dependency graph.
+ *
+ * This function is optional.
+ */
+ /* TODO(sergey): Remove once we finalyl switched to the new depsgraph. */
+ void (*updateDepsgraph)(struct ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ struct Object *ob,
+ struct DepsNodeHandle *node);
+
/* Should return true if the modifier needs to be recalculated on time
* changes.
*
diff --git a/source/blender/blenkernel/CMakeLists.txt b/source/blender/blenkernel/CMakeLists.txt
index fe713e64c64..37e5b36779f 100644
--- a/source/blender/blenkernel/CMakeLists.txt
+++ b/source/blender/blenkernel/CMakeLists.txt
@@ -28,6 +28,7 @@ set(INC
../blenfont
../blenlib
../blenloader
+ ../depsgraph
../gpu
../ikplugin
../imbuf
@@ -482,4 +483,8 @@ endif()
# set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} /WX")
#endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
blender_add_lib(bf_blenkernel "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/blenkernel/SConscript b/source/blender/blenkernel/SConscript
index 47bba5f5537..9d19e1c29b4 100644
--- a/source/blender/blenkernel/SConscript
+++ b/source/blender/blenkernel/SConscript
@@ -58,6 +58,7 @@ incs = [
'../blenlib',
'../blenloader',
'../bmesh',
+ '../depsgraph',
'../gpu',
'../ikplugin',
'../imbuf',
@@ -175,6 +176,9 @@ if env['WITH_BF_BINRELOC']:
incs += ' #extern/binreloc/include'
defs.append('WITH_BINRELOC')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
if env['OURPLATFORM'] in ('win32-vc', 'win64-vc'):
env.BlenderLib ( libname = 'bf_blenkernel', sources = sources, includes = Split(incs), defines = defs, libtype=['core','player'], priority = [166,25]) #, cc_compileflags = env['CCFLAGS'].append('/WX') )
else:
diff --git a/source/blender/blenkernel/intern/action.c b/source/blender/blenkernel/intern/action.c
index 708c64f8ffc..7e09ad355a7 100644
--- a/source/blender/blenkernel/intern/action.c
+++ b/source/blender/blenkernel/intern/action.c
@@ -54,6 +54,7 @@
#include "BKE_animsys.h"
#include "BKE_constraint.h"
#include "BKE_deform.h"
+#include "BKE_depsgraph.h"
#include "BKE_fcurve.h"
#include "BKE_global.h"
#include "BKE_idprop.h"
@@ -1318,9 +1319,13 @@ bool BKE_pose_copy_result(bPose *to, bPose *from)
}
/* Tag pose for recalc. Also tag all related data to be recalc. */
-void BKE_pose_tag_recalc(Main *UNUSED(bmain), bPose *pose)
+void BKE_pose_tag_recalc(Main *bmain, bPose *pose)
{
pose->flag |= POSE_RECALC;
+ /* Depsgraph components depends on actual pose state,
+ * if pose was changed depsgraph is to be updated as well.
+ */
+ DAG_relations_tag_update(bmain);
}
/* For the calculation of the effects of an Action at the given frame on an object
diff --git a/source/blender/blenkernel/intern/armature_update.c b/source/blender/blenkernel/intern/armature_update.c
index 44ffb6a6697..aa36036ed6a 100644
--- a/source/blender/blenkernel/intern/armature_update.c
+++ b/source/blender/blenkernel/intern/armature_update.c
@@ -51,6 +51,8 @@
#include "BKE_global.h"
#include "BKE_main.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_LEGACY_DEPSGRAPH
# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
#else
diff --git a/source/blender/blenkernel/intern/depsgraph.c b/source/blender/blenkernel/intern/depsgraph.c
index 869404ae4a6..9ee9f3d57af 100644
--- a/source/blender/blenkernel/intern/depsgraph.c
+++ b/source/blender/blenkernel/intern/depsgraph.c
@@ -88,16 +88,25 @@
#include "depsgraph_private.h"
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_query.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+
static SpinLock threaded_update_lock;
void DAG_init(void)
{
BLI_spin_init(&threaded_update_lock);
+ DEG_register_node_types();
}
void DAG_exit(void)
{
BLI_spin_end(&threaded_update_lock);
+ DEG_free_node_types();
}
/* Queue and stack operations for dag traversal
@@ -1329,8 +1338,14 @@ static void (*EditorsUpdateSceneCb)(Main *bmain, Scene *scene, int updated) = NU
void DAG_editors_update_cb(void (*id_func)(Main *bmain, ID *id), void (*scene_func)(Main *bmain, Scene *scene, int updated))
{
- EditorsUpdateIDCb = id_func;
- EditorsUpdateSceneCb = scene_func;
+ if (DEG_depsgraph_use_legacy()) {
+ EditorsUpdateIDCb = id_func;
+ EditorsUpdateSceneCb = scene_func;
+ }
+ else {
+ /* New dependency graph. */
+ DEG_editors_set_update_cb(id_func, scene_func);
+ }
}
static void dag_editors_id_update(Main *bmain, ID *id)
@@ -1529,7 +1544,7 @@ static void dag_scene_build(Main *bmain, Scene *sce)
Base *base;
BLI_listbase_clear(&tempbase);
-
+
build_dag(bmain, sce, DAG_RL_ALL_BUT_DATA);
dag_check_cycle(sce->theDag);
@@ -1621,32 +1636,65 @@ static void dag_scene_build(Main *bmain, Scene *sce)
/* clear all dependency graphs */
void DAG_relations_tag_update(Main *bmain)
{
- Scene *sce;
-
- for (sce = bmain->scene.first; sce; sce = sce->id.next)
- dag_scene_free(sce);
+ if (DEG_depsgraph_use_legacy()) {
+ Scene *sce;
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ dag_scene_free(sce);
+ }
+ }
+ else {
+ /* New dependency graph. */
+ DEG_relations_tag_update(bmain);
+ }
}
/* rebuild dependency graph only for a given scene */
void DAG_scene_relations_rebuild(Main *bmain, Scene *sce)
{
- dag_scene_free(sce);
- DAG_scene_relations_update(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ dag_scene_free(sce);
+ DAG_scene_relations_update(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_rebuild(bmain, sce);
+ }
}
/* create dependency graph if it was cleared or didn't exist yet */
void DAG_scene_relations_update(Main *bmain, Scene *sce)
{
- if (!sce->theDag)
- dag_scene_build(bmain, sce);
+ if (DEG_depsgraph_use_legacy()) {
+ if (!sce->theDag)
+ dag_scene_build(bmain, sce);
+ }
+ else {
+ /* New dependency graph. */
+ DEG_scene_relations_update(bmain, sce);
+ }
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *sce)
+{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_debug_scene_relations_validate(bmain, sce);
+ }
}
void DAG_scene_free(Scene *sce)
{
- if (sce->theDag) {
- free_forest(sce->theDag);
- MEM_freeN(sce->theDag);
- sce->theDag = NULL;
+ if (DEG_depsgraph_use_legacy()) {
+ if (sce->theDag) {
+ free_forest(sce->theDag);
+ MEM_freeN(sce->theDag);
+ sce->theDag = NULL;
+ }
+ }
+ else {
+ if (sce->depsgraph) {
+ DEG_graph_free(sce->depsgraph);
+ sce->depsgraph = NULL;
+ }
}
}
@@ -1889,7 +1937,11 @@ void DAG_scene_flush_update(Main *bmain, Scene *sce, unsigned int lay, const sho
DagAdjList *itA;
Object *ob;
int lasttime;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ return;
+ }
+
if (sce->theDag == NULL) {
printf("DAG zero... not allowed to happen!\n");
DAG_scene_relations_update(bmain, sce);
@@ -2300,7 +2352,7 @@ static void dag_current_scene_layers(Main *bmain, ListBase *lb)
}
}
-static void dag_group_on_visible_update(Group *group)
+static void dag_group_on_visible_update(Scene *scene, Group *group)
{
GroupObject *go;
@@ -2322,7 +2374,7 @@ static void dag_group_on_visible_update(Group *group)
}
if (go->ob->dup_group)
- dag_group_on_visible_update(go->ob->dup_group);
+ dag_group_on_visible_update(scene, go->ob->dup_group);
}
}
@@ -2330,7 +2382,13 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
{
ListBase listbase;
DagSceneLayer *dsl;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ /* Inform new dependnecy graphs about visibility changes. */
+ DEG_on_visible_update(bmain, do_time);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2357,7 +2415,8 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
oblay = (node) ? node->lay : ob->lay;
if ((oblay & lay) & ~scene->lay_updated) {
- if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE)) {
+ /* TODO(sergey): Why do we need armature here now but didn't need before? */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_SURF, OB_FONT, OB_MBALL, OB_LATTICE, OB_ARMATURE)) {
ob->recalc |= OB_RECALC_DATA;
lib_id_recalc_tag(bmain, &ob->id);
}
@@ -2375,7 +2434,7 @@ void DAG_on_visible_update(Main *bmain, const bool do_time)
lib_id_recalc_tag(bmain, &ob->id);
}
if (ob->dup_group)
- dag_group_on_visible_update(ob->dup_group);
+ dag_group_on_visible_update(scene, ob->dup_group);
}
}
@@ -2609,7 +2668,12 @@ void DAG_ids_flush_tagged(Main *bmain)
ListBase *lbarray[MAX_LIBARRAY];
int a;
bool do_flush = false;
-
+
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_flush_tagged(bmain);
+ return;
+ }
+
/* get list of visible scenes and layers */
dag_current_scene_layers(bmain, &listbase);
@@ -2653,6 +2717,11 @@ void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
int a;
bool updated = false;
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_ids_check_recalc(bmain, scene, time);
+ return;
+ }
+
/* loop over all ID types */
a = set_listbasepointers(bmain, lbarray);
@@ -2769,6 +2838,11 @@ void DAG_ids_clear_recalc(Main *bmain)
void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
{
+ if (!DEG_depsgraph_use_legacy()) {
+ DEG_id_tag_update_ex(bmain, id, flag);
+ return;
+ }
+
if (id == NULL) return;
if (G.debug & G_DEBUG_DEPSGRAPH) {
@@ -3160,6 +3234,10 @@ short DAG_get_eval_flags_for_object(Scene *scene, void *object)
{
DagNode *node;
+ if (!DEG_depsgraph_use_legacy()) {
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID*)object);
+ }
+
if (scene->theDag == NULL) {
/* Happens when converting objects to mesh from a python script
* after modifying scene graph.
@@ -3198,3 +3276,286 @@ bool DAG_is_acyclic(Scene *scene)
{
return scene->theDag->is_acyclic;
}
+
+#else
+
+/* *********************************************************************
+ * Stubs to avoid linking issues and make sure legacy crap is not used *
+ * *********************************************************************
+ */
+
+DagNodeQueue *queue_create(int UNUSED(slots))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void queue_raz(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void queue_delete(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_queue(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void push_stack(DagNodeQueue *UNUSED(queue), DagNode *UNUSED(node))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *pop_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *get_top_node_queue(DagNodeQueue *UNUSED(queue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *dag_init(void)
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagForest *build_dag(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ short UNUSED(mask))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void free_forest(DagForest *UNUSED(Dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+DagNode *dag_find_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_add_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+DagNode *dag_get_sub_node(DagForest *UNUSED(forest), void *UNUSED(fob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+void dag_add_relation(DagForest *UNUSED(forest),
+ DagNode *UNUSED(fob1),
+ DagNode *UNUSED(fob2),
+ short UNUSED(rel),
+ const char *UNUSED(name))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* debug test functions */
+
+void graph_print_queue(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_queue_dist(DagNodeQueue *UNUSED(nqueue))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void graph_print_adj_list(DagForest *UNUSED(dag))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_flush_update(Main *UNUSED(bmain),
+ Scene *UNUSED(sce),
+ unsigned int UNUSED(lay),
+ const short UNUSED(time))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+void DAG_scene_update_flags(Main *UNUSED(bmain),
+ Scene *UNUSED(scene),
+ unsigned int UNUSED(lay),
+ const bool UNUSED(do_time),
+ const bool UNUSED(do_invisible_flush))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ******************* DAG FOR ARMATURE POSE ***************** */
+
+void DAG_pose_sort(Object *UNUSED(ob))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+}
+
+/* ************************ DAG FOR THREADED UPDATE ********************* */
+
+void DAG_threaded_update_begin(Scene *UNUSED(scene),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+void DAG_threaded_update_handle_node_updated(void *UNUSED(node_v),
+ void (*func)(void *node, void *user_data),
+ void *UNUSED(user_data))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ (void)func;
+}
+
+/* ************************ DAG querying ********************* */
+
+Object *DAG_get_node_object(void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return NULL;
+}
+
+const char *DAG_get_node_name(Scene *UNUSED(scene), void *UNUSED(node_v))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return "INVALID";
+}
+
+bool DAG_is_acyclic(Scene *UNUSED(scene))
+{
+ BLI_assert(!"Should not be used with new dependnecy graph");
+ return false;
+}
+
+/* ************************************
+ * This functions are to be supported *
+ * ************************************
+ */
+
+void DAG_init(void)
+{
+ DEG_register_node_types();
+}
+
+void DAG_exit(void)
+{
+ DEG_free_node_types();
+}
+
+/* ************************ API *********************** */
+
+void DAG_editors_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ DEG_editors_set_update_cb(id_func, scene_func);
+}
+
+/* Tag all relations for update. */
+void DAG_relations_tag_update(Main *bmain)
+{
+ DEG_relations_tag_update(bmain);
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DAG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_rebuild(bmain, scene);
+}
+
+/* Create dependency graph if it was cleared or didn't exist yet. */
+void DAG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DAG_scene_relations_validate(Main *bmain, Scene *scene)
+{
+ DEG_debug_scene_relations_validate(bmain, scene);
+}
+
+void DAG_scene_free(Scene *scene)
+{
+ DEG_scene_graph_free(scene);
+}
+
+void DAG_on_visible_update(Main *bmain, const bool do_time)
+{
+ DEG_on_visible_update(bmain, do_time);
+}
+
+void DAG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ DEG_ids_check_recalc(bmain, scene, time);
+}
+
+void DAG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DAG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ DEG_id_tag_update_ex(bmain, id, flag);
+}
+
+void DAG_id_type_tag(Main *bmain, short idtype)
+{
+ DEG_id_type_tag(bmain, idtype);
+}
+
+int DAG_id_type_tagged(Main *bmain, short idtype)
+{
+ return DEG_id_type_tagged(bmain, idtype);
+}
+
+void DAG_ids_clear_recalc(Main *bmain)
+{
+ DEG_ids_clear_recalc(bmain);
+}
+
+short DAG_get_eval_flags_for_object(Scene *scene, void *object)
+{
+ return DEG_get_eval_flags_for_id(scene->depsgraph, (ID*)object);
+}
+
+void DAG_ids_flush_tagged(Main *bmain)
+{
+ DEG_ids_flush_tagged(bmain);
+}
+
+/* ************************ DAG DEBUGGING ********************* */
+
+void DAG_print_dependencies(Main *UNUSED(bmain),
+ Scene *scene,
+ Object *UNUSED(ob))
+{
+ DEG_debug_graphviz(scene->depsgraph, stdout, "Depsgraph", false);
+}
+
+#endif
diff --git a/source/blender/blenkernel/intern/library.c b/source/blender/blenkernel/intern/library.c
index ce118fe9fde..543d2de939a 100644
--- a/source/blender/blenkernel/intern/library.c
+++ b/source/blender/blenkernel/intern/library.c
@@ -115,6 +115,8 @@
#include "BKE_texture.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RNA_access.h"
#ifdef WITH_PYTHON
@@ -1081,8 +1083,7 @@ void BKE_libblock_free_us(Main *bmain, void *idv) /* test users */
Main *BKE_main_new(void)
{
Main *bmain = MEM_callocN(sizeof(Main), "new main");
- bmain->eval_ctx = MEM_callocN(sizeof(EvaluationContext),
- "EvaluationContext");
+ bmain->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_VIEWPORT);
bmain->lock = MEM_mallocN(sizeof(SpinLock), "main lock");
BLI_spin_init((SpinLock *)bmain->lock);
return bmain;
@@ -1149,7 +1150,7 @@ void BKE_main_free(Main *mainvar)
BLI_spin_end((SpinLock *)mainvar->lock);
MEM_freeN(mainvar->lock);
- MEM_freeN(mainvar->eval_ctx);
+ DEG_evaluation_context_free(mainvar->eval_ctx);
MEM_freeN(mainvar);
}
diff --git a/source/blender/blenkernel/intern/mesh.c b/source/blender/blenkernel/intern/mesh.c
index 735e4358cb8..37a98eae58b 100644
--- a/source/blender/blenkernel/intern/mesh.c
+++ b/source/blender/blenkernel/intern/mesh.c
@@ -61,6 +61,7 @@
#include "BKE_object.h"
#include "BKE_editmesh.h"
+#include "DEG_depsgraph.h"
enum {
MESHCMP_DVERT_WEIGHTMISMATCH = 1,
@@ -2397,8 +2398,8 @@ Mesh *BKE_mesh_new_from_object(
* only contains for_render flag. As soon as CoW is
* implemented, this is to be rethinked.
*/
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = DAG_EVAL_RENDER;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, DAG_EVAL_RENDER);
BKE_displist_make_mball_forRender(&eval_ctx, sce, ob, &disp);
BKE_mesh_from_metaball(&disp, tmpmesh);
BKE_displist_free(&disp);
diff --git a/source/blender/blenkernel/intern/object_update.c b/source/blender/blenkernel/intern/object_update.c
index 76c20adf8c5..972a93b4a35 100644
--- a/source/blender/blenkernel/intern/object_update.c
+++ b/source/blender/blenkernel/intern/object_update.c
@@ -57,6 +57,8 @@
#include "BKE_material.h"
#include "BKE_image.h"
+#include "DEG_depsgraph.h"
+
#ifdef WITH_LEGACY_DEPSGRAPH
# define DEBUG_PRINT if (!DEG_depsgraph_use_legacy() && G.debug & G_DEBUG_DEPSGRAPH) printf
#else
diff --git a/source/blender/blenkernel/intern/scene.c b/source/blender/blenkernel/intern/scene.c
index f810630c83b..3d87279e054 100644
--- a/source/blender/blenkernel/intern/scene.c
+++ b/source/blender/blenkernel/intern/scene.c
@@ -89,6 +89,8 @@
#include "BKE_unit.h"
#include "BKE_world.h"
+#include "DEG_depsgraph.h"
+
#include "RE_engine.h"
#include "PIL_time.h"
@@ -193,6 +195,7 @@ Scene *BKE_scene_copy(Scene *sce, int type)
scen->ed = NULL;
scen->theDag = NULL;
+ scen->depsgraph = NULL;
scen->obedit = NULL;
scen->stats = NULL;
scen->fps_info = NULL;
@@ -431,6 +434,8 @@ void BKE_scene_free(Scene *sce)
}
DAG_scene_free(sce);
+ if (sce->depsgraph)
+ DEG_graph_free(sce->depsgraph);
if (sce->nodetree) {
ntreeFreeTree(sce->nodetree);
@@ -1167,6 +1172,7 @@ void BKE_scene_frame_set(struct Scene *scene, double cfra)
scene->r.cfra = (int)intpart;
}
+#ifdef WITH_LEGACY_DEPSGRAPH
/* drivers support/hacks
* - this method is called from scene_update_tagged_recursive(), so gets included in viewport + render
* - these are always run since the depsgraph can't handle non-object data
@@ -1267,6 +1273,7 @@ static void scene_depsgraph_hack(EvaluationContext *eval_ctx, Scene *scene, Scen
}
}
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
/* That's like really a bummer, because currently animation data for armatures
* might want to use pose, and pose might be missing on the object.
@@ -1318,7 +1325,12 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
* would pollute STDERR with whole bunch of timing information which then
* could be parsed and nicely visualized.
*/
-#undef DETAILED_ANALYSIS_OUTPUT
+#ifdef WITH_LEGACY_DEPSGRAPH
+# undef DETAILED_ANALYSIS_OUTPUT
+#else
+/* ALWAYS KEEY DISABLED! */
+# undef DETAILED_ANALYSIS_OUTPUT
+#endif
/* Mballs evaluation uses BKE_scene_base_iter_next which calls
* duplilist for all objects in the scene. This leads to conflict
@@ -1330,6 +1342,7 @@ static void scene_do_rb_simulation_recursive(Scene *scene, float ctime)
*/
#define MBALL_SINGLETHREAD_HACK
+#ifdef WITH_LEGACY_DEPSGRAPH
typedef struct StatisicsEntry {
struct StatisicsEntry *next, *prev;
Object *object;
@@ -1619,6 +1632,7 @@ static void scene_update_tagged_recursive(EvaluationContext *eval_ctx, Main *bma
BKE_mask_update_scene(bmain, scene);
}
+#endif /* WITH_LEGACY_DEPSGRAPH */
static bool check_rendered_viewport_visible(Main *bmain)
{
@@ -1670,13 +1684,26 @@ static void prepare_mesh_for_viewport_render(Main *bmain, Scene *scene)
void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *scene)
{
Scene *sce_iter;
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#endif
+
/* keep this first */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_PRE);
/* (re-)build dependency graph if needed */
- for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set)
+ for (sce_iter = scene; sce_iter; sce_iter = sce_iter->set) {
DAG_scene_relations_update(bmain, sce_iter);
+ /* Uncomment this to check if graph was properly tagged for update. */
+#if 0
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval)
+#endif
+ {
+ DAG_scene_relations_validate(bmain, sce_iter);
+ }
+#endif
+ }
/* flush editing data if needed */
prepare_mesh_for_viewport_render(bmain, scene);
@@ -1697,7 +1724,17 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
*
* in the future this should handle updates for all datablocks, not
* only objects and scenes. - brecht */
- scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_refresh(eval_ctx, scene->depsgraph, scene);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, scene, scene);
+ }
+#else
+ DEG_evaluate_on_refresh(eval_ctx, bmain, scene->depsgraph, scene);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, scene);
@@ -1715,7 +1752,8 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
* Need to do this so changing material settings from the graph/dopesheet
* will update stuff in the viewport.
*/
- if (DAG_id_type_tagged(bmain, ID_MA)) {
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_MA)) {
Material *material;
float ctime = BKE_scene_frame_get(scene);
@@ -1730,7 +1768,7 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
/* Also do the same for node trees. */
- if (DAG_id_type_tagged(bmain, ID_NT)) {
+ if (!use_new_eval && DAG_id_type_tagged(bmain, ID_NT)) {
float ctime = BKE_scene_frame_get(scene);
FOREACH_NODETREE(bmain, ntree, id)
@@ -1741,9 +1779,12 @@ void BKE_scene_update_tagged(EvaluationContext *eval_ctx, Main *bmain, Scene *sc
}
FOREACH_NODETREE_END
}
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &scene->id, BLI_CB_EVT_SCENE_UPDATE_POST);
+
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, scene, false);
/* clear recalc flags */
@@ -1763,6 +1804,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
#ifdef DETAILED_ANALYSIS_OUTPUT
double start_time = PIL_check_seconds_timer();
#endif
+#ifdef WITH_LEGACY_DEPSGRAPH
+ bool use_new_eval = !DEG_depsgraph_use_legacy();
+#else
+ /* TODO(sergey): Pass to evaluation routines instead of storing layer in the graph? */
+ (void) do_invisible_flush;
+#endif
/* keep this first */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_PRE);
@@ -1772,12 +1819,16 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* call this at the start so modifiers with textures don't lag 1 frame */
BKE_image_update_frame(bmain, sce->r.cfra);
+#ifdef WITH_LEGACY_DEPSGRAPH
/* rebuild rigid body worlds before doing the actual frame update
* this needs to be done on start frame but animation playback usually starts one frame later
* we need to do it here to avoid rebuilding the world on every simulation change, which can be very expensive
*/
- scene_rebuild_rbw_recursive(sce, ctime);
-
+ if (!use_new_eval) {
+ scene_rebuild_rbw_recursive(sce, ctime);
+ }
+#endif
+
BKE_sound_set_cfra(sce->r.cfra);
/* clear animation overrides */
@@ -1786,14 +1837,18 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
for (sce_iter = sce; sce_iter; sce_iter = sce_iter->set)
DAG_scene_relations_update(bmain, sce_iter);
- /* flush recalc flags to dependencies, if we were only changing a frame
- * this would not be necessary, but if a user or a script has modified
- * some datablock before BKE_scene_update_tagged was called, we need the flush */
- DAG_ids_flush_tagged(bmain);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ /* flush recalc flags to dependencies, if we were only changing a frame
+ * this would not be necessary, but if a user or a script has modified
+ * some datablock before BKE_scene_update_tagged was called, we need the flush */
+ DAG_ids_flush_tagged(bmain);
- /* Following 2 functions are recursive
- * so don't call within 'scene_update_tagged_recursive' */
- DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ /* Following 2 functions are recursive
+ * so don't call within 'scene_update_tagged_recursive' */
+ DAG_scene_update_flags(bmain, sce, lay, true, do_invisible_flush); // only stuff that moves or needs display still
+ }
+#endif
BKE_mask_evaluate_all_masks(bmain, ctime, true);
@@ -1807,8 +1862,12 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
* can be overridden by settings from Scene, which owns the Texture through a hierarchy
* such as Scene->World->MTex/Texture) can still get correctly overridden.
*/
- BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
- /*...done with recursive funcs */
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ BKE_animsys_evaluate_all_animation(bmain, sce, ctime);
+ /*...done with recursive funcs */
+ }
+#endif
/* clear "LIB_DOIT" flag from all materials, to prevent infinite recursion problems later
* when trying to find materials with drivers that need evaluating [#32017]
@@ -1818,19 +1877,38 @@ void BKE_scene_update_for_newframe_ex(EvaluationContext *eval_ctx, Main *bmain,
/* run rigidbody sim */
/* NOTE: current position is so that rigidbody sim affects other objects, might change in the future */
- scene_do_rb_simulation_recursive(sce, ctime);
-
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_do_rb_simulation_recursive(sce, ctime);
+ }
+#endif
+
/* BKE_object_handle_update() on all objects, groups and sets */
- scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (use_new_eval) {
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+ }
+ else {
+ scene_update_tagged_recursive(eval_ctx, bmain, sce, sce);
+ }
+#else
+ DEG_evaluate_on_framechange(eval_ctx, bmain, sce->depsgraph, ctime, lay);
+#endif
+
/* update sound system animation (TODO, move to depsgraph) */
BKE_sound_update_scene(bmain, sce);
- scene_depsgraph_hack(eval_ctx, sce, sce);
+#ifdef WITH_LEGACY_DEPSGRAPH
+ if (!use_new_eval) {
+ scene_depsgraph_hack(eval_ctx, sce, sce);
+ }
+#endif
/* notify editors and python about recalc */
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_SCENE_UPDATE_POST);
BLI_callback_exec(bmain, &sce->id, BLI_CB_EVT_FRAME_CHANGE_POST);
+ /* Inform editors about possible changes. */
DAG_ids_check_recalc(bmain, sce, true);
/* clear recalc flags */
diff --git a/source/blender/blenloader/intern/readfile.c b/source/blender/blenloader/intern/readfile.c
index 6634767d412..c736e54c4e9 100644
--- a/source/blender/blenloader/intern/readfile.c
+++ b/source/blender/blenloader/intern/readfile.c
@@ -5567,6 +5567,7 @@ static void direct_link_scene(FileData *fd, Scene *sce)
SceneRenderLayer *srl;
sce->theDag = NULL;
+ sce->depsgraph = NULL;
sce->obedit = NULL;
sce->stats = NULL;
sce->fps_info = NULL;
diff --git a/source/blender/depsgraph/CMakeLists.txt b/source/blender/depsgraph/CMakeLists.txt
new file mode 100644
index 00000000000..014bcb40163
--- /dev/null
+++ b/source/blender/depsgraph/CMakeLists.txt
@@ -0,0 +1,116 @@
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2014, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Joshua Leung, Lukas Toenne
+#
+# ***** END GPL LICENSE BLOCK *****
+
+set(INC
+ .
+ ./intern
+ ./util
+ ../blenkernel
+ ../blenlib
+ ../bmesh
+ ../makesdna
+ ../makesrna
+ ../modifiers
+ ../windowmanager
+ ../../../intern/atomic
+ ../../../intern/guardedalloc
+)
+
+set(INC_SYS
+)
+
+set(SRC
+ intern/depsgraph.cc
+ intern/depsnode.cc
+ intern/depsnode_component.cc
+ intern/depsnode_operation.cc
+ intern/depsgraph_build.cc
+ intern/depsgraph_build_nodes.cc
+ intern/depsgraph_build_relations.cc
+ intern/depsgraph_debug.cc
+ intern/depsgraph_eval.cc
+ intern/depsgraph_query.cc
+ intern/depsgraph_queue.cc
+ intern/depsgraph_tag.cc
+ intern/depsgraph_type_defines.cc
+ util/depsgraph_util_cycle.cc
+ util/depsgraph_util_pchanmap.cc
+ util/depsgraph_util_transitive.cc
+
+ DEG_depsgraph.h
+ DEG_depsgraph_build.h
+ DEG_depsgraph_debug.h
+ DEG_depsgraph_query.h
+ intern/depsgraph.h
+ intern/depsnode.h
+ intern/depsnode_component.h
+ intern/depsnode_operation.h
+ intern/depsnode_opcodes.h
+ intern/depsgraph_build.h
+ intern/depsgraph_debug.h
+ intern/depsgraph_intern.h
+ intern/depsgraph_queue.h
+ intern/depsgraph_types.h
+
+ util/depsgraph_util_cycle.h
+ util/depsgraph_util_function.h
+ util/depsgraph_util_hash.h
+ util/depsgraph_util_map.h
+ util/depsgraph_util_pchanmap.h
+ util/depsgraph_util_set.h
+ util/depsgraph_util_transitive.h
+)
+
+TEST_UNORDERED_MAP_SUPPORT()
+if(HAVE_STD_UNORDERED_MAP_HEADER)
+ if(HAVE_UNORDERED_MAP_IN_STD_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP)
+ else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+ endif()
+else()
+ if(HAVE_UNORDERED_MAP_IN_TR1_NAMESPACE)
+ add_definitions(-DDEG_TR1_UNORDERED_MAP)
+ else()
+ add_definitions(-DDEG_NO_UNORDERED_MAP)
+ message(STATUS "Replacing unordered_map/set with map/set (warning: slower!)")
+ endif()
+endif()
+
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
+if(WITH_BOOST)
+ list(APPEND INC_SYS ${BOOST_INCLUDE_DIR})
+ add_definitions(-DHAVE_BOOST_FUNCTION_BINDINGS)
+endif()
+
+blender_add_lib(bf_depsgraph "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/depsgraph/DEG_depsgraph.h b/source/blender/depsgraph/DEG_depsgraph.h
new file mode 100644
index 00000000000..9fc50476e47
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph.h
@@ -0,0 +1,210 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Public API for Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_H__
+#define __DEG_DEPSGRAPH_H__
+
+/* Dependency Graph
+ *
+ * The dependency graph tracks relations between various pieces of data in
+ * a Blender file, but mainly just those which make up scene data. It is used
+ * to determine the set of operations need to ensure that all data has been
+ * correctly evaluated in response to changes, based on dependencies and visibility
+ * of affected data.
+ *
+ *
+ * Evaluation Engine
+ *
+ * The evaluation takes the operation-nodes the Depsgraph has tagged for updating,
+ * and schedules them up for being evaluated/executed such that the all dependency
+ * relationship constraints are satisfied.
+ */
+
+/* ************************************************* */
+/* Forward-defined typedefs for core types
+ * - These are used in all depsgraph code and by all callers of Depsgraph API...
+ */
+
+/* Dependency Graph */
+typedef struct Depsgraph Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct EvaluationContext;
+struct Main;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+bool DEG_depsgraph_use_legacy(void);
+void DEG_depsgraph_switch_to_legacy(void);
+void DEG_depsgraph_switch_to_new(void);
+
+/* ************************************************ */
+/* Depsgraph API */
+
+/* CRUD ------------------------------------------- */
+
+// Get main depsgraph instance from context!
+
+/* Create new Depsgraph instance */
+// TODO: what args are needed here? What's the building-graph entry point?
+Depsgraph *DEG_graph_new(void);
+
+/* Free Depsgraph itself and all its data */
+void DEG_graph_free(Depsgraph *graph);
+
+/* Node Types Registry ---------------------------- */
+
+/* Register all node types */
+void DEG_register_node_types(void);
+
+/* Free node type registry on exit */
+void DEG_free_node_types(void);
+
+/* Update Tagging -------------------------------- */
+
+/* Tag node(s) associated with states such as time and visibility */
+void DEG_scene_update_flags(Depsgraph *graph, const bool do_time);
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(struct Main *bmain, struct Scene *scene);
+
+/* Update all dependency graphs when visible scenes/layers changes. */
+void DEG_on_visible_update(struct Main *bmain, const bool do_time);
+
+/* Tag node(s) associated with changed data for later updates */
+void DEG_graph_id_tag_update(struct Main *bmain,
+ Depsgraph *graph,
+ struct ID *id);
+void DEG_graph_data_tag_update(Depsgraph *graph, const struct PointerRNA *ptr);
+void DEG_graph_property_tag_update(Depsgraph *graph, const struct PointerRNA *ptr, const struct PropertyRNA *prop);
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(struct ID *id, short flag);
+void DEG_id_tag_update_ex(struct Main *bmain,
+ struct ID *id,
+ short flag);
+
+/* Tag given ID type for update.
+ *
+ * Used by all sort of render engines to quickly check if
+ * IDs of a given type need to be checked for update.
+ */
+void DEG_id_type_tag(struct Main *bmain, short idtype);
+
+void DEG_ids_clear_recalc(struct Main *bmain);
+
+/* Update Flushing ------------------------------- */
+
+/* Flush updates */
+void DEG_graph_flush_updates(struct Main *bmain, Depsgraph *graph);
+
+/* Flush updates for all IDs */
+void DEG_ids_flush_tagged(struct Main *bmain);
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(struct Main *bmain,
+ struct Scene *scene,
+ bool time);
+
+/* Clear all update tags
+ * - For aborted updates, or after successful evaluation
+ */
+void DEG_graph_clear_tags(Depsgraph *graph);
+
+/* ************************************************ */
+/* Evaluation Engine API */
+
+/* Evaluation Context ---------------------------- */
+
+/* Create new evaluation context. */
+struct EvaluationContext *DEG_evaluation_context_new(int mode);
+
+/* Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(struct EvaluationContext *eval_ctx, int mode);
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(struct EvaluationContext *eval_ctx);
+
+/* Graph Evaluation ----------------------------- */
+
+/* Frame changed recalculation entry point
+ * < context_type: context to perform evaluation for
+ * < ctime: (frame) new frame to evaluate values on
+ */
+void DEG_evaluate_on_framechange(struct EvaluationContext *eval_ctx,
+ struct Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layer);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ * < layers: visible layers bitmask to update the graph for
+ */
+void DEG_evaluate_on_refresh_ex(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers);
+
+/* Data changed recalculation entry point.
+ * < context_type: context to perform evaluation for
+ */
+void DEG_evaluate_on_refresh(struct EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ struct Scene *scene);
+
+/* Editors Integration -------------------------- */
+
+/* Mechanism to allow editors to be informed of depsgraph updates,
+ * to do their own updates based on changes.
+ */
+
+typedef void (*DEG_EditorUpdateIDCb)(struct Main *bmain, struct ID *id);
+typedef void (*DEG_EditorUpdateSceneCb)(struct Main *bmain,
+ struct Scene *scene,
+ int updated);
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_build.h b/source/blender/depsgraph/DEG_depsgraph_build.h
new file mode 100644
index 00000000000..08b83ac2ea1
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_build.h
@@ -0,0 +1,117 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Lukas Toenne
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Public API for Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_BUILD_H__
+#define __DEG_DEPSGRAPH_BUILD_H__
+
+/* ************************************************* */
+
+/* Dependency Graph */
+struct Depsgraph;
+
+/* ------------------------------------------------ */
+
+struct Main;
+struct Scene;
+
+struct PointerRNA;
+struct PropertyRNA;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* Graph Building -------------------------------- */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+void DEG_graph_build_from_scene(struct Depsgraph *graph, struct Main *bmain, struct Scene *scene);
+
+/* Tag relations from the given graph for update. */
+void DEG_graph_tag_relations_update(struct Depsgraph *graph);
+
+/* Tag all relations in the database for update.*/
+void DEG_relations_tag_update(struct Main *bmain);
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(struct Main *bmain, struct Scene *scene);
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(struct Main *bmain,
+ struct Scene *scene);
+
+/* Delete scene graph. */
+void DEG_scene_graph_free(struct Scene *scene);
+
+/* Add Dependencies ----------------------------- */
+
+/* Handle for components to define their dependencies from callbacks.
+ * This is generated by the depsgraph and passed to dependency callbacks
+ * as a symbolic reference to the current DepsNode.
+ * All relations will be defined in reference to that node.
+ */
+struct DepsNodeHandle;
+
+struct Object;
+
+typedef enum eDepsSceneComponentType {
+ DEG_SCENE_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_SCENE_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_SCENE_COMP_SEQUENCER, /* Sequencer Component (Scene Only) */
+} eDepsSceneComponentType;
+
+typedef enum eDepsObjectComponentType {
+ DEG_OB_COMP_PARAMETERS, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEG_OB_COMP_PROXY, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEG_OB_COMP_ANIMATION, /* Animation Component */ // XXX: merge in with parameters?
+ DEG_OB_COMP_TRANSFORM, /* Transform Component (Parenting/Constraints) */
+ DEG_OB_COMP_GEOMETRY, /* Geometry Component (DerivedMesh/Displist) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEG_OB_COMP_EVAL_POSE, /* Pose Component - Owner/Container of Bones Eval */
+ DEG_OB_COMP_BONE, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEG_OB_COMP_EVAL_PARTICLES, /* Particle Systems Component */
+ DEG_OB_COMP_SHADING, /* Material Shading Component */
+} eDepsObjectComponentType;
+
+void DEG_add_scene_relation(struct DepsNodeHandle *node, struct Scene *scene, eDepsSceneComponentType component, const char *description);
+void DEG_add_object_relation(struct DepsNodeHandle *node, struct Object *ob, eDepsObjectComponentType component, const char *description);
+void DEG_add_bone_relation(struct DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description);
+
+/* TODO(sergey): Remove once all geometry update is granular. */
+void DEG_add_special_eval_flag(struct Depsgraph *graph, struct ID *id, short flag);
+
+/* ************************************************ */
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_debug.h b/source/blender/depsgraph/DEG_depsgraph_debug.h
new file mode 100644
index 00000000000..60e9a021854
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_debug.h
@@ -0,0 +1,107 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Public API for Querying and Filtering Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_DEBUG_H__
+#define __DEG_DEPSGRAPH_DEBUG_H__
+
+#include <stdio.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+struct DepsgraphSettings;
+struct GHash;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+/* ************************************************ */
+/* Statistics */
+
+typedef struct DepsgraphStatsTimes {
+ float duration_last;
+} DepsgraphStatsTimes;
+
+typedef struct DepsgraphStatsComponent {
+ struct DepsgraphStatsComponent *next, *prev;
+
+ char name[64];
+ DepsgraphStatsTimes times;
+} DepsgraphStatsComponent;
+
+typedef struct DepsgraphStatsID {
+ struct ID *id;
+
+ DepsgraphStatsTimes times;
+ ListBase components;
+} DepsgraphStatsID;
+
+typedef struct DepsgraphStats {
+ struct GHash *id_stats;
+} DepsgraphStats;
+
+struct DepsgraphStats *DEG_stats(void);
+
+void DEG_stats_verify(void);
+
+struct DepsgraphStatsID *DEG_stats_id(struct ID *id);
+
+/* ------------------------------------------------ */
+
+void DEG_stats_simple(const struct Depsgraph *graph,
+ size_t *r_outer,
+ size_t *r_operations,
+ size_t *r_relations);
+
+/* ************************************************ */
+/* Diagram-Based Graph Debugging */
+
+void DEG_debug_graphviz(const struct Depsgraph *graph, FILE *stream, const char *label, bool show_eval);
+
+/* ************************************************ */
+
+/* Compare two dependency graphs. */
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2);
+
+/* Check that dependnecies in the graph are really up to date. */
+bool DEG_debug_scene_relations_validate(struct Main *bmain,
+ struct Scene *scene);
+
+
+/* Perform consistency check on the graph. */
+bool DEG_debug_consistency_check(struct Depsgraph *graph);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/DEG_depsgraph_query.h b/source/blender/depsgraph/DEG_depsgraph_query.h
new file mode 100644
index 00000000000..000497cfac9
--- /dev/null
+++ b/source/blender/depsgraph/DEG_depsgraph_query.h
@@ -0,0 +1,191 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Public API for Querying and Filtering Depsgraph
+ */
+
+#ifndef __DEG_DEPSGRAPH_QUERY_H__
+#define __DEG_DEPSGRAPH_QUERY_H__
+
+struct ListBase;
+struct ID;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsRelation;
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* ************************************************ */
+/* Type Defines */
+
+/* FilterPredicate Callback
+ *
+ * Defines a callback function which can be supplied to check whether a
+ * node is relevant or not.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to check
+ * < userdata: FilterPredicate state data (as needed)
+ * > returns: True if node is relevant
+ */
+typedef bool (*DEG_FilterPredicate)(const struct Depsgraph *graph, const struct DepsNode *node, void *userdata);
+
+
+/* Node Operation
+ *
+ * Performs some action on the given node, provided that the node was
+ * deemed to be relevant to operate on.
+ *
+ * < graph: Depsgraph that we're traversing
+ * < node: The node to perform operation on/with
+ * < userdata: Node Operation's state data (as needed)
+ * > returns: True if traversal should be aborted at this point
+ */
+typedef bool (*DEG_NodeOperation)(const struct Depsgraph *graph, struct DepsNode *node, void *userdata);
+
+/* ************************************************ */
+/* Low-Level Filtering API */
+
+/* Create a filtered copy of the given graph which contains only the
+ * nodes which fulfill the criteria specified using the FilterPredicate
+ * passed in.
+ *
+ * < graph: The graph to be copied and filtered
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, full graph is copied as-is)
+ * < userdata: State data for filter (as necessary)
+ *
+ * > returns: a full copy of all the relevant nodes - the matching subgraph
+ */
+// XXX: is there any need for extra settings/options for how the filtering goes?
+Depsgraph *DEG_graph_filter(const struct Depsgraph *graph, DEG_FilterPredicate *filter, void *userdata);
+
+
+/* Traverse nodes in graph which are deemed relevant,
+ * performing the provided operation on the nodes.
+ *
+ * < graph: The graph to perform operations on
+ * < filter: FilterPredicate used to check which nodes should be included
+ * (If null, all nodes are considered valid targets)
+ * < filter_data: Custom state data for FilterPredicate
+ * (Note: This can be the same as op_data, where appropriate)
+ * < op: NodeOperation to perform on each node
+ * (If null, no graph traversal is performed for efficiency)
+ * < op_data: Custom state data for NodeOperation
+ * (Note: This can be the same as filter_data, where appropriate)
+ */
+void DEG_graph_traverse(const struct Depsgraph *graph,
+ DEG_FilterPredicate *filter, void *filter_data,
+ DEG_NodeOperation *op, void *op_data);
+
+/* ************************************************ */
+/* Node-Based Operations */
+// XXX: do we want to be able to attach conditional requirements here?
+
+/* Find an (outer) node matching given conditions
+ * ! Assumes that there will only be one such node, or that only the first one matters
+ *
+ * < graph: a dependency graph which may or may not contain a node matching these requirements
+ * < query: query conditions for the criteria that the node must satisfy
+ */
+//DepsNode *DEG_node_find(const Depsgraph *graph, DEG_QueryConditions *query);
+
+/* Topology Queries (Direct) ---------------------- */
+
+/* Get list of nodes which directly depend on given node
+ *
+ * > result: list to write results to
+ * < node: the node to find the children/dependents of
+ */
+void DEG_node_get_children(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Get list of nodes which given node directly depends on
+ *
+ * > result: list to write results to
+ * < node: the node to find the dependencies of
+ */
+void DEG_node_get_dependencies(struct ListBase *result, const struct DepsNode *node);
+
+
+/* Topology Queries (Subgraph) -------------------- */
+// XXX: given that subgraphs potentially involve many interconnected nodes, we currently
+// just spit out a copy of the subgraph which matches. This works well for the cases
+// where these are used - mostly for efficient updating of subsets of the nodes.
+
+// XXX: allow supplying a filter predicate to provide further filtering/pruning?
+
+
+/* Get all descendants of a node
+ *
+ * That is, get the subgraph / subset of nodes which are dependent
+ * on the results of the given node.
+ */
+Depsgraph *DEG_node_get_descendants(const struct Depsgraph *graph, const struct DepsNode *node);
+
+
+/* Get all ancestors of a node
+ *
+ * That is, get the subgraph / subset of nodes which the given node
+ * is dependent on in order to be evaluated.
+ */
+Depsgraph *DEG_node_get_ancestors(const struct Depsgraph *graph, const struct DepsNode *node);
+
+/* ************************************************ */
+/* Higher-Level Queries */
+
+/* Get ID-blocks which would be affected if specified ID is modified
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_affected_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+
+/* Get ID-blocks which are needed to update/evaluate specified ID
+ * < only_direct: True = Only ID-blocks with direct relationships to ID-block will be returned
+ *
+ * > result: (LinkData : ID) a list of ID-blocks matching the specified criteria
+ * > returns: number of matching ID-blocks
+ */
+size_t DEG_query_required_ids(struct ListBase *result, const struct ID *id, const bool only_direct);
+
+/* ************************************************ */
+
+/* Check if given ID type was tagged for update. */
+bool DEG_id_type_tagged(struct Main *bmain, short idtype);
+
+/* Get additional evaluation flags for the given ID. */
+short DEG_get_eval_flags_for_id(struct Depsgraph *graph, struct ID *id);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif
+
+#endif /* __DEG_DEPSGRAPH_QUERY_H__ */
diff --git a/source/blender/depsgraph/SConscript b/source/blender/depsgraph/SConscript
new file mode 100644
index 00000000000..dd0552e19a2
--- /dev/null
+++ b/source/blender/depsgraph/SConscript
@@ -0,0 +1,74 @@
+#!/usr/bin/env python
+#
+# ***** BEGIN GPL LICENSE BLOCK *****
+#
+# This program is free software; you can redistribute it and/or
+# modify it under the terms of the GNU General Public License
+# as published by the Free Software Foundation; either version 2
+# of the License, or (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+#
+# The Original Code is Copyright (C) 2013, Blender Foundation
+# All rights reserved.
+#
+# The Original Code is: all of this file.
+#
+# Contributor(s): Nathan Letwory, Joshua Leung.
+#
+# ***** END GPL LICENSE BLOCK *****
+
+Import('env')
+
+sources = env.Glob('intern/*.cc') + env.Glob('util/*.cc')
+
+incs = [
+ '.',
+ './intern',
+ './util',
+ '#/intern/atomic',
+ '#/intern/guardedalloc',
+ '../bmesh',
+ '../blenlib',
+ '../blenkernel',
+ '../makesdna',
+ '../makesrna',
+ '../modifiers',
+ '../windowmanager',
+ ]
+
+defs = []
+
+if env['WITH_BF_BOOST']:
+ incs.append(env['BF_BOOST_INC'])
+ defs.append('HAVE_BOOST_FUNCTION_BINDINGS')
+
+if env['OURPLATFORM'] in ('win32-vc', 'win32-mingw', 'linuxcross', 'win64-vc', 'win64-mingw'):
+ incs.append(env['BF_PTHREADS_INC'])
+
+
+if env['WITH_UNORDERED_MAP_SUPPORT']:
+ if env['UNORDERED_MAP_HEADER'] == 'unordered_map':
+ if env['UNORDERED_MAP_NAMESPACE'] == 'std':
+ defs.append('DEG_STD_UNORDERED_MAP')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE')
+ elif env['UNORDERED_MAP_NAMESPACE'] == 'std::tr1':
+ defs.append('DEG_TR1_UNORDERED_MAP')
+else:
+ print("-- Replacing unordered_map/set with map/set (warning: slower!)")
+ defs.append('DEG_NO_UNORDERED_MAP')
+
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
+env.BlenderLib(libname='bf_depsgraph', sources=sources,
+ includes=incs, defines=defs,
+ libtype=['core', 'player'], priority=[200, 40])
diff --git a/source/blender/depsgraph/intern/depsgraph.cc b/source/blender/depsgraph/intern/depsgraph.cc
new file mode 100644
index 00000000000..c519f1d498e
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.cc
@@ -0,0 +1,469 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Core routines for how the Depsgraph works
+ */
+
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+#include "BLI_listbase.h"
+
+extern "C" {
+#include "DNA_action_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_key_types.h"
+#include "DNA_object_types.h"
+#include "DNA_sequence_types.h"
+
+#include "RNA_access.h"
+}
+
+#include "DEG_depsgraph.h"
+#include "depsgraph.h" /* own include */
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsnode_component.h"
+#include "depsgraph_intern.h"
+
+static DEG_EditorUpdateIDCb deg_editor_update_id_cb = NULL;
+static DEG_EditorUpdateSceneCb deg_editor_update_scene_cb = NULL;
+
+Depsgraph::Depsgraph()
+ : root_node(NULL),
+ need_update(false),
+ layers((1 << 20) - 1)
+{
+ BLI_spin_init(&lock);
+}
+
+Depsgraph::~Depsgraph()
+{
+ /* Free root node - it won't have been freed yet... */
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ if (this->root_node != NULL) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ }
+ BLI_spin_end(&lock);
+}
+
+/* Query Conditions from RNA ----------------------- */
+
+static bool pointer_to_id_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id)
+{
+ if (!ptr->type)
+ return false;
+
+ if (!prop) {
+ if (RNA_struct_is_ID(ptr->type)) {
+ *id = (ID *)ptr->data;
+ return true;
+ }
+ }
+
+ return false;
+}
+
+static bool pointer_to_component_node_criteria(const PointerRNA *ptr,
+ const PropertyRNA *prop,
+ ID **id,
+ eDepsNode_Type *type,
+ string *subdata)
+{
+ if (!ptr->type)
+ return false;
+
+ /* Set default values for returns. */
+ *id = (ID *)ptr->id.data; /* For obvious reasons... */
+ *subdata = ""; /* Default to no subdata (e.g. bone) name
+ * lookup in most cases. */
+
+ /* Handling of commonly known scenarios... */
+ if (ptr->type == &RNA_PoseBone) {
+ bPoseChannel *pchan = (bPoseChannel *)ptr->data;
+
+ /* Bone - generally, we just want the bone component... */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Bone) {
+ Bone *bone = (Bone *)ptr->data;
+
+ /* armature-level bone, but it ends up going to bone component anyway */
+ // TODO: the ID in thise case will end up being bArmature, not Object as needed!
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = bone->name;
+ //*id = ...
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Constraint)) {
+ Object *ob = (Object *)ptr->id.data;
+ bConstraint *con = (bConstraint *)ptr->data;
+
+ /* object or bone? */
+ if (BLI_findindex(&ob->constraints, con) != -1) {
+ /* object transform */
+ // XXX: for now, we can't address the specific constraint or the constraint stack...
+ *type = DEPSNODE_TYPE_TRANSFORM;
+ return true;
+ }
+ else if (ob->pose) {
+ bPoseChannel *pchan;
+ for (pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ if (BLI_findindex(&pchan->constraints, con) != -1) {
+ /* bone transforms */
+ *type = DEPSNODE_TYPE_BONE;
+ *subdata = pchan->name;
+ return true;
+ }
+ }
+ }
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Modifier)) {
+ //ModifierData *md = (ModifierData *)ptr->data;
+
+ /* Modifier */
+ /* NOTE: subdata is not the same as "operation name",
+ * so although we have unique ops for modifiers,
+ * we can't lump them together
+ */
+ *type = DEPSNODE_TYPE_BONE;
+ //*subdata = md->name;
+
+ return true;
+ }
+ else if (ptr->type == &RNA_Object) {
+ //Object *ob = (Object *)ptr->data;
+
+ /* Transforms props? */
+ if (prop) {
+ const char *prop_identifier = RNA_property_identifier((PropertyRNA *)prop);
+
+ if (strstr(prop_identifier, "location") ||
+ strstr(prop_identifier, "rotation") ||
+ strstr(prop_identifier, "scale"))
+ {
+ *type = DEPSNODE_TYPE_TRANSFORM;
+ return true;
+ }
+ }
+ // ...
+ }
+ else if (ptr->type == &RNA_ShapeKey) {
+ Key *key = (Key *)ptr->id.data;
+
+ /* ShapeKeys are currently handled as geometry on the geometry that owns it */
+ *id = key->from; // XXX
+ *type = DEPSNODE_TYPE_PARAMETERS;
+
+ return true;
+ }
+ else if (RNA_struct_is_a(ptr->type, &RNA_Sequence)) {
+ Sequence *seq = (Sequence *)ptr->data;
+ /* Sequencer strip */
+ *type = DEPSNODE_TYPE_SEQUENCER;
+ *subdata = seq->name; // xxx?
+ return true;
+ }
+
+ if (prop) {
+ /* All unknown data effectively falls under "parameter evaluation" */
+ *type = DEPSNODE_TYPE_PARAMETERS;
+ return true;
+ }
+
+ return false;
+}
+
+/* Convenience wrapper to find node given just pointer + property. */
+DepsNode *Depsgraph::find_node_from_pointer(const PointerRNA *ptr,
+ const PropertyRNA *prop) const
+{
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+
+ /* Get querying conditions. */
+ if (pointer_to_id_node_criteria(ptr, prop, &id)) {
+ return find_id_node(id);
+ }
+ else if (pointer_to_component_node_criteria(ptr, prop, &id, &type, &name)) {
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node)
+ return id_node->find_component(type, name);
+ }
+
+ return NULL;
+}
+
+/* Node Management ---------------------------- */
+
+RootDepsNode *Depsgraph::add_root_node()
+{
+ if (!root_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ROOT);
+ root_node = (RootDepsNode *)factory->create_node(NULL, "", "Root (Scene)");
+ }
+ return root_node;
+}
+
+TimeSourceDepsNode *Depsgraph::find_time_source(const ID *id) const
+{
+ /* Search for one attached to a particular ID? */
+ if (id) {
+ /* Check if it was added as a component
+ * (as may be done for subgraphs needing timeoffset).
+ */
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node) {
+ // XXX: review this
+// return id_node->find_component(DEPSNODE_TYPE_TIMESOURCE);
+ }
+ BLI_assert(!"Not implemented yet");
+ }
+ else {
+ /* Use "official" timesource. */
+ return root_node->time_source;
+ }
+ return NULL;
+}
+
+SubgraphDepsNode *Depsgraph::add_subgraph_node(const ID *id)
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_SUBGRAPH);
+ SubgraphDepsNode *subgraph_node =
+ (SubgraphDepsNode *)factory->create_node(id, "", id->name + 2);
+
+ /* Add to subnodes list. */
+ this->subgraphs.insert(subgraph_node);
+
+ /* if there's an ID associated, add to ID-nodes lookup too */
+ if (id) {
+#if 0
+ /* XXX subgraph node is NOT a true IDDepsNode - what is this supposed to do? */
+ // TODO: what to do if subgraph's ID has already been added?
+ BLI_assert(!graph->find_id_node(id));
+ graph->id_hash[id] = this;
+#endif
+ }
+
+ return subgraph_node;
+}
+
+void Depsgraph::remove_subgraph_node(SubgraphDepsNode *subgraph_node)
+{
+ subgraphs.erase(subgraph_node);
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+}
+
+void Depsgraph::clear_subgraph_nodes()
+{
+ for (Subgraphs::iterator it = subgraphs.begin();
+ it != subgraphs.end();
+ ++it)
+ {
+ SubgraphDepsNode *subgraph_node = *it;
+ OBJECT_GUARDED_DELETE(subgraph_node, SubgraphDepsNode);
+ }
+ subgraphs.clear();
+}
+
+IDDepsNode *Depsgraph::find_id_node(const ID *id) const
+{
+ IDNodeMap::const_iterator it = this->id_hash.find(id);
+ return it != this->id_hash.end() ? it->second : NULL;
+}
+
+IDDepsNode *Depsgraph::add_id_node(ID *id, const string &name)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (!id_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_ID_REF);
+ id_node = (IDDepsNode *)factory->create_node(id, "", name);
+ id->flag |= LIB_DOIT;
+ /* register */
+ this->id_hash[id] = id_node;
+ }
+ return id_node;
+}
+
+void Depsgraph::remove_id_node(const ID *id)
+{
+ IDDepsNode *id_node = find_id_node(id);
+ if (id_node) {
+ /* unregister */
+ this->id_hash.erase(id);
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+}
+
+void Depsgraph::clear_id_nodes()
+{
+ for (IDNodeMap::const_iterator it = id_hash.begin();
+ it != id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ OBJECT_GUARDED_DELETE(id_node, IDDepsNode);
+ }
+ id_hash.clear();
+}
+
+/* Add new relationship between two nodes. */
+DepsRelation *Depsgraph::add_new_relation(OperationDepsNode *from,
+ OperationDepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ /* Create new relation, and add it to the graph. */
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ return rel;
+}
+
+/* Add new relation between two nodes */
+DepsRelation *Depsgraph::add_new_relation(DepsNode *from, DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ /* Create new relation, and add it to the graph. */
+ DepsRelation *rel = OBJECT_GUARDED_NEW(DepsRelation, from, to, type, description);
+ return rel;
+}
+
+/* ************************ */
+/* Relationships Management */
+
+DepsRelation::DepsRelation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description)
+ : from(from),
+ to(to),
+ name(description),
+ type(type),
+ flag(0)
+{
+#ifndef NDEBUG
+/*
+ for (OperationDepsNode::Relations::const_iterator it = from->outlinks.begin();
+ it != from->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ if (rel->from == from &&
+ rel->to == to &&
+ rel->type == type &&
+ rel->name == description)
+ {
+ BLI_assert(!"Duplicated relation, should not happen!");
+ }
+ }
+*/
+#endif
+
+ /* Hook it up to the nodes which use it. */
+ from->outlinks.insert(this);
+ to->inlinks.insert(this);
+}
+
+DepsRelation::~DepsRelation()
+{
+ /* Sanity check. */
+ BLI_assert(this->from && this->to);
+ /* Remove it from the nodes that use it. */
+ this->from->outlinks.erase(this);
+ this->to->inlinks.erase(this);
+}
+
+/* Low level tagging -------------------------------------- */
+
+/* Tag a specific node as needing updates. */
+void Depsgraph::add_entry_tag(OperationDepsNode *node)
+{
+ /* Sanity check. */
+ if (!node)
+ return;
+
+ /* Add to graph-level set of directly modified nodes to start searching from.
+ * NOTE: this is necessary since we have several thousand nodes to play with...
+ */
+ this->entry_tags.insert(node);
+}
+
+void Depsgraph::clear_all_nodes()
+{
+ clear_id_nodes();
+ clear_subgraph_nodes();
+ id_hash.clear();
+ if (this->root_node) {
+ OBJECT_GUARDED_DELETE(this->root_node, RootDepsNode);
+ root_node = NULL;
+ }
+}
+
+/* **************** */
+/* Public Graph API */
+
+/* Initialize a new Depsgraph */
+Depsgraph *DEG_graph_new()
+{
+ return OBJECT_GUARDED_NEW(Depsgraph);
+}
+
+/* Free graph's contents and graph itself */
+void DEG_graph_free(Depsgraph *graph)
+{
+ OBJECT_GUARDED_DELETE(graph, Depsgraph);
+}
+
+/* Set callbacks which are being called when depsgraph changes. */
+void DEG_editors_set_update_cb(DEG_EditorUpdateIDCb id_func,
+ DEG_EditorUpdateSceneCb scene_func)
+{
+ deg_editor_update_id_cb = id_func;
+ deg_editor_update_scene_cb = scene_func;
+}
+
+void deg_editors_id_update(Main *bmain, ID *id)
+{
+ if (deg_editor_update_id_cb != NULL) {
+ deg_editor_update_id_cb(bmain, id);
+ }
+}
+
+void deg_editors_scene_update(Main *bmain, Scene *scene, bool updated)
+{
+ if (deg_editor_update_scene_cb != NULL) {
+ deg_editor_update_scene_cb(bmain, scene, updated);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph.h b/source/blender/depsgraph/intern/depsgraph.h
new file mode 100644
index 00000000000..8ce73626c13
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph.h
@@ -0,0 +1,220 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Sergey Sharybin
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_H__
+#define __DEPSGRAPH_H__
+
+#include "BLI_threads.h" /* for SpinLock */
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct PointerRNA;
+struct PropertyRNA;
+
+struct DepsNode;
+struct RootDepsNode;
+struct TimeSourceDepsNode;
+struct IDDepsNode;
+struct SubgraphDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+
+/* *************************** */
+/* Relationships Between Nodes */
+
+/* Settings/Tags on Relationship */
+typedef enum eDepsRelation_Flag {
+ /* "touched" tag is used when filtering, to know which to collect */
+ DEPSREL_FLAG_TEMP_TAG = (1 << 0),
+
+ /* "cyclic" link - when detecting cycles, this relationship was the one
+ * which triggers a cyclic relationship to exist in the graph
+ */
+ DEPSREL_FLAG_CYCLIC = (1 << 1),
+} eDepsRelation_Flag;
+
+/* B depends on A (A -> B) */
+struct DepsRelation {
+ /* the nodes in the relationship (since this is shared between the nodes) */
+ DepsNode *from; /* A */
+ DepsNode *to; /* B */
+
+ /* relationship attributes */
+ const char* name; /* label for debugging */
+
+ eDepsRelation_Type type; /* type */
+ int flag; /* (eDepsRelation_Flag) */
+
+ DepsRelation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ ~DepsRelation();
+};
+
+/* ********* */
+/* Depsgraph */
+
+/* Dependency Graph object */
+struct Depsgraph {
+ typedef unordered_map<const ID *, IDDepsNode *> IDNodeMap;
+ typedef unordered_set<SubgraphDepsNode *> Subgraphs;
+ typedef unordered_set<OperationDepsNode *> EntryTags;
+ typedef vector<OperationDepsNode *> OperationNodes;
+
+ Depsgraph();
+ ~Depsgraph();
+
+ /**
+ * Find node which matches the specified description.
+ *
+ * \param id: ID block that is associated with this
+ * \param subdata: identifier used for sub-ID data (e.g. bone)
+ * \param type: type of node we're dealing with
+ * \param name: custom identifier assigned to node
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph.
+ */
+ DepsNode *find_node(const ID *id,
+ eDepsNode_Type type,
+ const string &subdata,
+ const string &name);
+
+ /**
+ * Convenience wrapper to find node given just pointer + property.
+ *
+ * \param ptr: pointer to the data that node will represent
+ * \param prop: optional property affected - providing this effectively results in inner nodes being returned
+ *
+ * \return A node matching the required characteristics if it exists
+ * or NULL if no such node exists in the graph
+ */
+ DepsNode *find_node_from_pointer(const PointerRNA *ptr, const PropertyRNA *prop) const;
+
+ RootDepsNode *add_root_node();
+
+ TimeSourceDepsNode *find_time_source(const ID *id = NULL) const;
+
+ SubgraphDepsNode *add_subgraph_node(const ID *id);
+ void remove_subgraph_node(SubgraphDepsNode *subgraph_node);
+ void clear_subgraph_nodes();
+
+ IDDepsNode *find_id_node(const ID *id) const;
+ IDDepsNode *add_id_node(ID *id, const string &name = "");
+ void remove_id_node(const ID *id);
+ void clear_id_nodes();
+
+ /* Add new relationship between two nodes. */
+ DepsRelation *add_new_relation(OperationDepsNode *from,
+ OperationDepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ DepsRelation *add_new_relation(DepsNode *from,
+ DepsNode *to,
+ eDepsRelation_Type type,
+ const char *description);
+
+ /* Tag a specific node as needing updates. */
+ void add_entry_tag(OperationDepsNode *node);
+
+ /* Clear storage used by all nodes. */
+ void clear_all_nodes();
+
+ /* Core Graph Functionality ........... */
+
+ /* <ID : IDDepsNode> mapping from ID blocks to nodes representing these blocks
+ * (for quick lookups). */
+ IDNodeMap id_hash;
+
+ /* "root" node - the one where all evaluation enters from. */
+ RootDepsNode *root_node;
+
+ /* Subgraphs referenced in tree. */
+ Subgraphs subgraphs;
+
+ /* Indicates whether relations needs to be updated. */
+ bool need_update;
+
+ /* Quick-Access Temp Data ............. */
+
+ /* Nodes which have been tagged as "directly modified". */
+ EntryTags entry_tags;
+
+ /* Convenience Data ................... */
+
+ /* XXX: should be collected after building (if actually needed?) */
+ /* All operation nodes, sorted in order of single-thread traversal order. */
+ OperationNodes operations;
+
+ /* Spin lock for threading-critical operations.
+ * Mainly used by graph evaluation.
+ */
+ SpinLock lock;
+
+ /* Layers Visibility .................. */
+
+ /* Visible layers bitfield, used for skipping invisible objects updates. */
+ int layers;
+
+ // XXX: additional stuff like eval contexts, mempools for allocating nodes from, etc.
+};
+
+/**
+ * Helper macros for interating over set of relationship links
+ * incident on each node.
+ *
+ * \note it is safe to perform removal operations here...
+ *
+ * relations_set[in]: (DepsNode::Relations) set of relationships (in/out links)
+ * relation[out]: (DepsRelation *) identifier where DepsRelation that we're
+ * currently accessing comes up
+ */
+#define DEPSNODE_RELATIONS_ITER_BEGIN(relations_set_, relation_) \
+ { \
+ OperationDepsNode::Relations::const_iterator __rel_iter = relations_set_.begin(); \
+ while (__rel_iter != relations_set_.end()) { \
+ DepsRelation *relation_ = *__rel_iter; \
+ ++__rel_iter; \
+
+ /* ... code for iterator body can be written here ... */
+
+#define DEPSNODE_RELATIONS_ITER_END \
+ } \
+ } ((void)0)
+
+#endif /* __DEPSGRAPH_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build.cc b/source/blender/depsgraph/intern/depsgraph_build.cc
new file mode 100644
index 00000000000..b5e09db6507
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.cc
@@ -0,0 +1,365 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include <stack>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsgraph_debug.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph_util_transitive.h"
+
+/* ****************** */
+/* External Build API */
+
+static eDepsNode_Type deg_build_scene_component_type(eDepsSceneComponentType component)
+{
+ switch (component) {
+ case DEG_SCENE_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_SCENE_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_SCENE_COMP_SEQUENCER: return DEPSNODE_TYPE_SEQUENCER;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+static eDepsNode_Type deg_build_object_component_type(eDepsObjectComponentType component)
+{
+ switch (component) {
+ case DEG_OB_COMP_PARAMETERS: return DEPSNODE_TYPE_PARAMETERS;
+ case DEG_OB_COMP_PROXY: return DEPSNODE_TYPE_PROXY;
+ case DEG_OB_COMP_ANIMATION: return DEPSNODE_TYPE_ANIMATION;
+ case DEG_OB_COMP_TRANSFORM: return DEPSNODE_TYPE_TRANSFORM;
+ case DEG_OB_COMP_GEOMETRY: return DEPSNODE_TYPE_GEOMETRY;
+ case DEG_OB_COMP_EVAL_POSE: return DEPSNODE_TYPE_EVAL_POSE;
+ case DEG_OB_COMP_BONE: return DEPSNODE_TYPE_BONE;
+ case DEG_OB_COMP_EVAL_PARTICLES: return DEPSNODE_TYPE_EVAL_PARTICLES;
+ case DEG_OB_COMP_SHADING: return DEPSNODE_TYPE_SHADING;
+ }
+ return DEPSNODE_TYPE_UNDEFINED;
+}
+
+void DEG_add_scene_relation(DepsNodeHandle *handle, struct Scene *scene, eDepsSceneComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_scene_component_type(component);
+ ComponentKey comp_key(&scene->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_object_relation(DepsNodeHandle *handle, struct Object *ob, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type);
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_bone_relation(DepsNodeHandle *handle, struct Object *ob, const char *bone_name, eDepsObjectComponentType component, const char *description)
+{
+ eDepsNode_Type type = deg_build_object_component_type(component);
+ ComponentKey comp_key(&ob->id, type, bone_name);
+
+ // XXX: "Geometry Eval" might not always be true, but this only gets called from modifier building now
+ handle->builder->add_node_handle_relation(comp_key, handle, DEPSREL_TYPE_GEOMETRY_EVAL, description);
+}
+
+void DEG_add_special_eval_flag(Depsgraph *graph, ID *id, short flag)
+{
+ if (graph == NULL) {
+ BLI_assert(!"Graph should always be valid");
+ return;
+ }
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ BLI_assert(!"ID should always be valid");
+ return;
+ }
+ id_node->eval_flags |= flag;
+}
+
+/* ********************** */
+/* Utilities for Builders */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu)
+{
+ char index_buf[32];
+ sprintf(index_buf, "[%d]", fcu->array_index);
+
+ return string(fcu->rna_path) + index_buf;
+}
+
+static void deg_graph_build_finalize(Depsgraph *graph)
+{
+ std::stack<OperationDepsNode*> stack;
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->done = 0;
+ node->num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ ++node->num_links_pending;
+ }
+ }
+ if (node->num_links_pending == 0) {
+ stack.push(node);
+ }
+ IDDepsNode *id_node = node->owner->owner;
+ id_node->id->flag |= LIB_DOIT;
+ }
+
+ while (!stack.empty()) {
+ OperationDepsNode *node = stack.top();
+ if (node->done == 0 && node->outlinks.size() != 0) {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(to->num_links_pending > 0);
+ --to->num_links_pending;
+ }
+ if (to->num_links_pending == 0) {
+ stack.push(to);
+ }
+ }
+ }
+ node->done = 1;
+ }
+ else {
+ stack.pop();
+ IDDepsNode *id_node = node->owner->owner;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ IDDepsNode *id_to = to->owner->owner;
+ id_node->layers |= id_to->layers;
+ }
+ }
+
+ /* Re-tag ID for update if it was tagged before the relations
+ * update tag.
+ */
+ ID *id = id_node->id;
+ if (id->flag & LIB_ID_RECALC_ALL &&
+ id->flag & LIB_DOIT)
+ {
+ id_node->tag_update(graph);
+ id->flag &= ~LIB_DOIT;
+ }
+ }
+ }
+}
+
+/* ******************** */
+/* Graph Building API's */
+
+/* Build depsgraph for the given scene, and dump results in given graph container */
+// XXX: assume that this is called from outside, given the current scene as the "main" scene
+void DEG_graph_build_from_scene(Depsgraph *graph, Main *bmain, Scene *scene)
+{
+ /* 1) Generate all the nodes in the graph first */
+ DepsgraphNodeBuilder node_builder(bmain, graph);
+ /* create root node for scene first
+ * - this way it should be the first in the graph,
+ * reflecting its role as the entrypoint
+ */
+ node_builder.add_root_node();
+ node_builder.build_scene(bmain, scene);
+
+ /* 2) Hook up relationships between operations - to determine evaluation order */
+ DepsgraphRelationBuilder relation_builder(graph);
+ /* hook scene up to the root node as entrypoint to graph */
+ /* XXX what does this relation actually mean?
+ * it doesnt add any operations anyway and is not clear what part of the scene is to be connected.
+ */
+ //relation_builder.add_relation(RootKey(), IDKey(scene), DEPSREL_TYPE_ROOT_TO_ACTIVE, "Root to Active Scene");
+ relation_builder.build_scene(bmain, scene);
+
+ /* Detect and solve cycles. */
+ deg_graph_detect_cycles(graph);
+
+ /* 3) Simplify the graph by removing redundant relations (to optimise traversal later) */
+ // TODO: it would be useful to have an option to disable this in cases where it is causing trouble
+ if (G.debug_value == 799) {
+ deg_graph_transitive_reduction(graph);
+ }
+
+ /* 4) Flush visibility layer and re-schedule nodes for update. */
+ deg_graph_build_finalize(graph);
+
+#if 0
+ if (!DEG_debug_consistency_check(graph)) {
+ printf("Consistency validation failed, ABORTING!\n");
+ abort();
+ }
+#endif
+}
+
+/* Tag graph relations for update. */
+void DEG_graph_tag_relations_update(Depsgraph *graph)
+{
+ graph->need_update = true;
+}
+
+/* Tag all relations for update. */
+void DEG_relations_tag_update(Main *bmain)
+{
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ }
+}
+
+/* Create new graph if didn't exist yet,
+ * or update relations if graph was tagged for update.
+ */
+void DEG_scene_relations_update(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph == NULL) {
+ /* Rebuild graph from scratch and exit. */
+ scene->depsgraph = DEG_graph_new();
+ DEG_graph_build_from_scene(scene->depsgraph, bmain, scene);
+ return;
+ }
+
+ Depsgraph *graph = scene->depsgraph;
+ if (!graph->need_update) {
+ /* Graph is up to date, nothing to do. */
+ return;
+ }
+
+ /* Clear all previous nodes and operations. */
+ graph->clear_all_nodes();
+ graph->operations.clear();
+ graph->entry_tags.clear();
+
+ /* Build new nodes and relations. */
+ DEG_graph_build_from_scene(graph, bmain, scene);
+
+ graph->need_update = false;
+}
+
+/* Rebuild dependency graph only for a given scene. */
+void DEG_scene_relations_rebuild(Main *bmain, Scene *scene)
+{
+ if (scene->depsgraph != NULL) {
+ DEG_graph_tag_relations_update(scene->depsgraph);
+ }
+ DEG_scene_relations_update(bmain, scene);
+}
+
+void DEG_scene_graph_free(Scene *scene)
+{
+ if (scene->depsgraph) {
+ DEG_graph_free(scene->depsgraph);
+ scene->depsgraph = NULL;
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build.h b/source/blender/depsgraph/intern/depsgraph_build.h
new file mode 100644
index 00000000000..84c09b81508
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build.h
@@ -0,0 +1,404 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DEPSGRAPH_BUILD_H__
+#define __DEPSGRAPH_BUILD_H__
+
+struct Base;
+struct bGPdata;
+struct ListBase;
+struct GHash;
+struct ID;
+struct FCurve;
+struct Group;
+struct Key;
+struct Main;
+struct Material;
+struct MTex;
+struct bNodeTree;
+struct Object;
+struct bPoseChannel;
+struct bConstraint;
+struct Scene;
+struct Tex;
+struct World;
+
+struct PropertyRNA;
+
+struct Depsgraph;
+struct DepsNode;
+struct DepsNodeHandle;
+struct RootDepsNode;
+struct SubgraphDepsNode;
+struct IDDepsNode;
+struct TimeSourceDepsNode;
+struct ComponentDepsNode;
+struct OperationDepsNode;
+struct RootPChanMap;
+
+struct DepsgraphNodeBuilder {
+ DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph);
+ ~DepsgraphNodeBuilder();
+
+ RootDepsNode *add_root_node();
+ IDDepsNode *add_id_node(ID *id);
+ TimeSourceDepsNode *add_time_source(ID *id);
+
+ ComponentDepsNode *add_component_node(ID *id, eDepsNode_Type comp_type, const string &comp_name = "");
+
+ OperationDepsNode *add_operation_node(ComponentDepsNode *comp_node, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "");
+ OperationDepsNode *add_operation_node(ID *id, eDepsNode_Type comp_type, eDepsOperation_Type optype,
+ DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &description = "")
+ {
+ return add_operation_node(id, comp_type, "", optype, op, opcode, description);
+ }
+
+ bool has_operation_node(ID *id, eDepsNode_Type comp_type, const string &comp_name,
+ eDepsOperation_Code opcode, const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description = "");
+
+ OperationDepsNode *find_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ eDepsOperation_Code opcode,
+ const string &description = "")
+ {
+ return find_operation_node(id, comp_type, "", opcode, description);
+ }
+
+ void build_scene(Main *bmain, Scene *scene);
+ SubgraphDepsNode *build_subgraph(Group *group);
+ void build_group(Scene *scene, Base *base, Group *group);
+ void build_object(Scene *scene, Base *base, Object *ob);
+ void build_object_transform(Scene *scene, Object *ob);
+ void build_object_constraints(Scene *scene, Object *ob);
+ void build_pose_constraints(Object *ob, bPoseChannel *pchan);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Object *ob);
+ void build_animdata(ID *id);
+ OperationDepsNode *build_driver(ID *id, FCurve *fcurve);
+ void build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(Key *key);
+ void build_obdata_geom(Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(DepsNode *owner_node, bNodeTree *ntree);
+ void build_material(DepsNode *owner_node, Material *ma);
+ void build_texture(DepsNode *owner_node, Tex *tex);
+ void build_texture_stack(DepsNode *owner_node, MTex **texture_stack);
+ void build_world(World *world);
+ void build_compositor(Scene *scene);
+ void build_gpencil(bGPdata *gpd);
+
+private:
+ Main *m_bmain;
+ Depsgraph *m_graph;
+};
+
+struct RootKey
+{
+ RootKey() {}
+};
+
+struct TimeSourceKey
+{
+ TimeSourceKey() : id(NULL) {}
+ TimeSourceKey(ID *id) : id(id) {}
+
+ string identifier() const
+ {
+ return string("TimeSourceKey");
+ }
+
+ ID *id;
+};
+
+struct ComponentKey
+{
+ ComponentKey() :
+ id(NULL), type(DEPSNODE_TYPE_UNDEFINED), name("")
+ {}
+ ComponentKey(ID *id, eDepsNode_Type type, const string &name = "") :
+ id(id), type(type), name(name)
+ {}
+
+ string identifier() const
+ {
+ const char *idname = (id) ? id->name : "<None>";
+
+ char typebuf[5];
+ sprintf(typebuf, "%d", type);
+
+ return string("ComponentKey(") + idname + ", " + typebuf + ", '" + name + "')";
+ }
+
+ ID *id;
+ eDepsNode_Type type;
+ string name;
+};
+
+struct OperationKey
+{
+ OperationKey() :
+ id(NULL), component_type(DEPSNODE_TYPE_UNDEFINED), component_name(""), opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(DEG_OPCODE_OPERATION), name(name)
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name("")
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name("")
+ {}
+
+ OperationKey(ID *id, eDepsNode_Type component_type, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(""), opcode(opcode), name(name)
+ {}
+ OperationKey(ID *id, eDepsNode_Type component_type, const string &component_name, eDepsOperation_Code opcode, const string &name) :
+ id(id), component_type(component_type), component_name(component_name), opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char typebuf[5];
+ sprintf(typebuf, "%d", component_type);
+
+ return string("OperationKey(") + "t: " + typebuf + ", cn: '" + component_name + "', c: " + DEG_OPNAMES[opcode] + ", n: '" + name + "')";
+ }
+
+
+ ID *id;
+ eDepsNode_Type component_type;
+ string component_name;
+ eDepsOperation_Code opcode;
+ string name;
+};
+
+struct RNAPathKey
+{
+ // Note: see depsgraph_build.cpp for implementation
+ RNAPathKey(ID *id, const string &path);
+
+ RNAPathKey(ID *id, const PointerRNA &ptr, PropertyRNA *prop) :
+ id(id), ptr(ptr), prop(prop)
+ {}
+
+ string identifier() const
+ {
+ const char *id_name = (id) ? id->name : "<No ID>";
+ const char *prop_name = (prop) ? RNA_property_identifier(prop) : "<No Prop>";
+
+ return string("RnaPathKey(") + "id: " + id_name + ", prop: " + prop_name + "')";
+ }
+
+
+ ID *id;
+ PointerRNA ptr;
+ PropertyRNA *prop;
+};
+
+struct DepsgraphRelationBuilder
+{
+ DepsgraphRelationBuilder(Depsgraph *graph);
+
+ template <typename KeyFrom, typename KeyTo>
+ void add_relation(const KeyFrom &key_from, const KeyTo &key_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyTo>
+ void add_relation(const TimeSourceKey &key_from, const KeyTo &key_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyType>
+ void add_node_handle_relation(const KeyType &key_from, const DepsNodeHandle *handle,
+ eDepsRelation_Type type, const char *description);
+
+ void build_scene(Main *bmain, Scene *scene);
+ void build_group(Main *bmain, Scene *scene, Object *object, Group *group);
+ void build_object(Main *bmain, Scene *scene, Object *ob);
+ void build_object_parent(Object *ob);
+ void build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
+ ListBase *constraints, RootPChanMap *root_map);
+ void build_animdata(ID *id);
+ void build_driver(ID *id, FCurve *fcurve);
+ void build_world(World *world);
+ void build_rigidbody(Scene *scene);
+ void build_particles(Scene *scene, Object *ob);
+ void build_ik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_splineik_pose(Object *ob, bPoseChannel *pchan, bConstraint *con, RootPChanMap *root_map);
+ void build_rig(Scene *scene, Object *ob);
+ void build_proxy_rig(Object *ob);
+ void build_shapekeys(ID *obdata, Key *key);
+ void build_obdata_geom(Main *bmain, Scene *scene, Object *ob);
+ void build_camera(Object *ob);
+ void build_lamp(Object *ob);
+ void build_nodetree(ID *owner, bNodeTree *ntree);
+ void build_material(ID *owner, Material *ma);
+ void build_texture(ID *owner, Tex *tex);
+ void build_texture_stack(ID *owner, MTex **texture_stack);
+ void build_compositor(Scene *scene);
+ void build_gpencil(ID *owner, bGPdata *gpd);
+
+protected:
+ RootDepsNode *find_node(const RootKey &key) const;
+ TimeSourceDepsNode *find_node(const TimeSourceKey &key) const;
+ ComponentDepsNode *find_node(const ComponentKey &key) const;
+ OperationDepsNode *find_node(const OperationKey &key) const;
+ DepsNode *find_node(const RNAPathKey &key) const;
+ OperationDepsNode *has_node(const OperationKey &key) const;
+
+ void add_time_relation(TimeSourceDepsNode *timesrc, DepsNode *node_to, const char *description);
+ void add_operation_relation(OperationDepsNode *node_from, OperationDepsNode *node_to,
+ eDepsRelation_Type type, const char *description);
+
+ template <typename KeyType>
+ DepsNodeHandle create_node_handle(const KeyType &key, const string &default_name = "");
+
+ bool needs_animdata_node(ID *id);
+
+private:
+ Depsgraph *m_graph;
+};
+
+struct DepsNodeHandle
+{
+ DepsNodeHandle(DepsgraphRelationBuilder *builder, OperationDepsNode *node, const string &default_name = "") :
+ builder(builder),
+ node(node),
+ default_name(default_name)
+ {
+ BLI_assert(node != NULL);
+ }
+
+ DepsgraphRelationBuilder *builder;
+ OperationDepsNode *node;
+ const string &default_name;
+};
+
+/* Utilities for Builders ----------------------------------------------------- */
+
+/* Get unique identifier for FCurves and Drivers */
+string deg_fcurve_id_name(const FCurve *fcu);
+
+template <typename KeyFrom, typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const KeyFrom &key_from,
+ const KeyTo &key_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ DepsNode *node_from = find_node(key_from);
+ DepsNode *node_to = find_node(key_to);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, type, description);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%d, %s) - Could not find op_from (%s)\n",
+ type, description, key_from.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%d, %s) - Failed, but op_from (%s) was ok\n",
+ type, description, key_from.identifier().c_str());
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ fprintf(stderr, "add_relation(%d, %s) - Could not find op_to (%s)\n",
+ type, description, key_to.identifier().c_str());
+ }
+ else {
+ fprintf(stderr, "add_relation(%d, %s) - Failed, but op_to (%s) was ok\n",
+ type, description, key_to.identifier().c_str());
+ }
+ }
+}
+
+template <typename KeyTo>
+void DepsgraphRelationBuilder::add_relation(const TimeSourceKey &key_from,
+ const KeyTo &key_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ (void)type; /* Ignored in release builds. */
+ BLI_assert(type == DEPSREL_TYPE_TIME);
+ TimeSourceDepsNode *time_from = find_node(key_from);
+ DepsNode *node_to = find_node(key_to);
+ OperationDepsNode *op_to = node_to ? node_to->get_entry_operation() : NULL;
+ if (time_from && op_to) {
+ add_time_relation(time_from, op_to, description);
+ }
+ else {
+ }
+}
+
+template <typename KeyType>
+void DepsgraphRelationBuilder::add_node_handle_relation(const KeyType &key_from,
+ const DepsNodeHandle *handle,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ DepsNode *node_from = find_node(key_from);
+ OperationDepsNode *op_from = node_from ? node_from->get_exit_operation() : NULL;
+ OperationDepsNode *op_to = handle->node->get_entry_operation();
+ if (op_from && op_to) {
+ add_operation_relation(op_from, op_to, type, description);
+ }
+ else {
+ if (!op_from) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ if (!op_to) {
+ /* XXX TODO handle as error or report if needed */
+ }
+ }
+}
+
+template <typename KeyType>
+DepsNodeHandle DepsgraphRelationBuilder::create_node_handle(const KeyType &key,
+ const string &default_name)
+{
+ return DepsNodeHandle(this, find_node(key), default_name);
+}
+
+#endif /* __DEPSGRAPH_BUILD_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_build_nodes.cc b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
new file mode 100644
index 00000000000..a55fb900551
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_nodes.cc
@@ -0,0 +1,1199 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Methods for constructing depsgraph's nodes
+ */
+
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_depsgraph.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_idcode.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_lattice.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mesh.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_types.h"
+#include "depsgraph_build.h"
+#include "depsgraph_intern.h"
+
+/* ************ */
+/* Node Builder */
+
+/* **** General purpose functions **** */
+
+DepsgraphNodeBuilder::DepsgraphNodeBuilder(Main *bmain, Depsgraph *graph) :
+ m_bmain(bmain),
+ m_graph(graph)
+{
+}
+
+DepsgraphNodeBuilder::~DepsgraphNodeBuilder()
+{
+}
+
+RootDepsNode *DepsgraphNodeBuilder::add_root_node()
+{
+ return m_graph->add_root_node();
+}
+
+IDDepsNode *DepsgraphNodeBuilder::add_id_node(ID *id)
+{
+ const char *idtype_name = BKE_idcode_to_name(GS(id->name));
+ return m_graph->add_id_node(id, string(id->name+2) + "[" + idtype_name + "]");
+}
+
+TimeSourceDepsNode *DepsgraphNodeBuilder::add_time_source(ID *id)
+{
+ /* determine which node to attach timesource to */
+ if (id) {
+#if 0 /* XXX TODO */
+ /* get ID node */
+ IDDepsNode id_node = m_graph->find_id_node(id);
+
+ /* depends on what this is... */
+ switch (GS(id->name)) {
+ case ID_SCE: /* Scene - Usually sequencer strip causing time remapping... */
+ {
+ // TODO...
+ }
+ break;
+
+ case ID_GR: /* Group */
+ {
+ // TODO...
+ }
+ break;
+
+ // XXX: time source...
+
+ default: /* Unhandled */
+ printf("%s(): Unhandled ID - %s \n", __func__, id->name);
+ break;
+ }
+#endif
+ }
+ else {
+ /* root-node */
+ RootDepsNode *root_node = m_graph->root_node;
+ if (root_node) {
+ return root_node->add_time_source("Time Source");
+ }
+ }
+
+ return NULL;
+}
+
+ComponentDepsNode *DepsgraphNodeBuilder::add_component_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name)
+{
+ IDDepsNode *id_node = add_id_node(id);
+ ComponentDepsNode *comp_node = id_node->add_component(comp_type, comp_name);
+ comp_node->owner = id_node;
+ return comp_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ComponentDepsNode *comp_node,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ OperationDepsNode *op_node = comp_node->has_operation(opcode, description);
+ if (op_node == NULL) {
+ op_node = comp_node->add_operation(optype, op, opcode, description);
+ m_graph->operations.push_back(op_node);
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ comp_node->identifier().c_str(),
+ op_node->identifier().c_str(),
+ op_node);
+ BLI_assert(!"Should not happen!");
+ }
+ return op_node;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::add_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Type optype,
+ DepsEvalOperationCb op,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return add_operation_node(comp_node, optype, op, opcode, description);
+}
+
+bool DepsgraphNodeBuilder::has_operation_node(ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ return find_operation_node(id, comp_type, comp_name, opcode, description) != NULL;
+}
+
+OperationDepsNode *DepsgraphNodeBuilder::find_operation_node(
+ ID *id,
+ eDepsNode_Type comp_type,
+ const string &comp_name,
+ eDepsOperation_Code opcode,
+ const string &description)
+{
+ ComponentDepsNode *comp_node = add_component_node(id, comp_type, comp_name);
+ return comp_node->has_operation(opcode, description);
+}
+
+
+/* **** Build functions for entity nodes **** */
+
+void DepsgraphNodeBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_DOIT is used to indicate whether node for given ID was already
+ * created or not. This flag is being set in add_id_node(), so functions
+ * shouldn't bother with setting it, they only might query this flag when
+ * needed.
+ */
+ BKE_main_id_tag_all(bmain, false);
+
+ /* scene ID block */
+ add_id_node(&scene->id);
+
+ /* timesource */
+ add_time_source(NULL);
+
+ /* build subgraph for set, and link this in... */
+ // XXX: depending on how this goes, that scene itself could probably store its
+ // own little partial depsgraph?
+ if (scene->set) {
+ build_scene(bmain, scene->set);
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(scene, base, ob);
+
+ /* object that this is a proxy for */
+ // XXX: the way that proxies work needs to be completely reviewed!
+ if (ob->proxy) {
+ build_object(scene, base, ob->proxy);
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group) {
+ build_group(scene, base, ob->dup_group);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* sequencer */
+ // XXX...
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(scene->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_group(Scene *scene,
+ Base *base,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ if (group_id->flag & LIB_DOIT) {
+ return;
+ }
+ group_id->flag |= LIB_DOIT;
+
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ build_object(scene, base, go->ob);
+ }
+}
+
+SubgraphDepsNode *DepsgraphNodeBuilder::build_subgraph(Group *group)
+{
+ /* sanity checks */
+ if (!group)
+ return NULL;
+
+ /* create new subgraph's data */
+ Depsgraph *subgraph = DEG_graph_new();
+
+ DepsgraphNodeBuilder subgraph_builder(m_bmain, subgraph);
+
+ /* add group objects */
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ /*Object *ob = go->ob;*/
+
+ /* Each "group object" is effectively a separate instance of the underlying
+ * object data. When the group is evaluated, the transform results and/or
+ * some other attributes end up getting overridden by the group
+ */
+ }
+
+ /* create a node for representing subgraph */
+ SubgraphDepsNode *subgraph_node = m_graph->add_subgraph_node(&group->id);
+ subgraph_node->graph = subgraph;
+
+ /* make a copy of the data this node will need? */
+ // XXX: do we do this now, or later?
+ // TODO: need API function which queries graph's ID's hash, and duplicates those blocks thoroughly with all outside links removed...
+
+ return subgraph_node;
+}
+
+void DepsgraphNodeBuilder::build_object(Scene *scene, Base *base, Object *ob)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ IDDepsNode *id_node = m_graph->find_id_node(&ob->id);
+ id_node->layers = base->lay;
+ return;
+ }
+
+ IDDepsNode *id_node = add_id_node(&ob->id);
+ id_node->layers = base->lay;
+
+ /* standard components */
+ build_object_transform(scene, ob);
+
+
+ /* object data */
+ if (ob->data) {
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ /* TODO(sergey): This way using this object's
+ * properties as driver target works fine.
+ *
+ * Does this depend on other nodes?
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ build_obdata_geom(scene, ob);
+ /* TODO(sergey): Only for until we support granular
+ * update of curves.
+ */
+ if (ob->type == OB_FONT) {
+ Curve *curve = (Curve *)ob->data;
+ if (curve->textoncurve) {
+ id_node->eval_flags |= DAG_EVAL_NEED_CURVE_PATH;
+ }
+ }
+ }
+ break;
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+
+ default:
+ {
+ ID *obdata = (ID *)ob->data;
+ if ((obdata->flag & LIB_DOIT) == 0) {
+ build_animdata(obdata);
+ }
+ break;
+ }
+ }
+ }
+
+ /* Build animation data,
+ *
+ * Do it now because it's possible object data will affect
+ * on object's level animation, for example in case of rebuilding
+ * pose for proxy.
+ */
+ build_animdata(&ob->id);
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(ob->gpd);
+ }
+}
+
+void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
+{
+ /* local transforms (from transform channels - loc/rot/scale + deltas) */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_INIT, function_bind(BKE_object_eval_local_transform, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_LOCAL);
+
+ /* object parent */
+ if (ob->parent) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_parent, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_PARENT);
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ build_object_constraints(scene, ob);
+ }
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
+ DEG_OPCODE_OBJECT_UBEREVAL);
+
+ /* object transform is done */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_POST, function_bind(BKE_object_eval_done, _1, ob),
+ DEG_OPCODE_TRANSFORM_FINAL);
+}
+
+/**
+ * Constraints Graph Notes
+ *
+ * For constraints, we currently only add a operation node to the Transform
+ * or Bone components (depending on whichever type of owner we have).
+ * This represents the entire constraints stack, which is for now just
+ * executed as a single monolithic block. At least initially, this should
+ * be sufficient for ensuring that the porting/refactoring process remains
+ * manageable.
+ *
+ * However, when the time comes for developing "node-based" constraints,
+ * we'll need to split this up into pre/post nodes for "constraint stack
+ * evaluation" + operation nodes for each constraint (i.e. the contents
+ * of the loop body used in the current "solve_constraints()" operation).
+ *
+ * -- Aligorith, August 2013
+ */
+void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
+{
+ /* create node for constraint stack */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_constraints, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+}
+
+void DepsgraphNodeBuilder::build_pose_constraints(Object *ob, bPoseChannel *pchan)
+{
+ /* create node for constraint stack */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_pose_constraints_evaluate, _1, ob, pchan),
+ DEG_OPCODE_BONE_CONSTRAINTS);
+}
+
+/**
+ * Build graph nodes for AnimData block
+ * \param scene_node: Scene that ID-block this lives on belongs to
+ * \param id: ID-Block which hosts the AnimData
+ */
+void DepsgraphNodeBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ /* animation */
+ if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ /* actions and NLA - as a single unit for now, as it gets complicated to schedule otherwise */
+ if ((adt->action) || (adt->nla_tracks.first)) {
+ /* create the node */
+ add_operation_node(id, DEPSNODE_TYPE_ANIMATION,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_animdata, _1, id),
+ DEG_OPCODE_ANIMATION, id->name);
+
+ // TODO: for each channel affected, we might also want to add some support for running RNA update callbacks on them
+ // (which will be needed for proper handling of drivers later)
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ /* create driver */
+ build_driver(id, fcu);
+ }
+ }
+}
+
+/**
+ * Build graph node(s) for Driver
+ * \param id: ID-Block that driver is attached to
+ * \param fcu: Driver-FCurve
+ */
+OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+
+ /* Create data node for this driver */
+ /* TODO(sergey): Avoid creating same operation multiple times,
+ * in the future we need to avoid lookup of the operation as well
+ * and use some tagging magic instead.
+ */
+ OperationDepsNode *driver_op = find_operation_node(id,
+ DEPSNODE_TYPE_PARAMETERS,
+ DEG_OPCODE_DRIVER,
+ deg_fcurve_id_name(fcu));
+
+ if (driver_op == NULL) {
+ driver_op = add_operation_node(id, DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_animsys_eval_driver, _1, id, fcu),
+ DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ }
+
+ /* tag "scripted expression" drivers as needing Python (due to GIL issues, etc.) */
+ if (driver->type == DRIVER_TYPE_PYTHON) {
+ driver_op->flag |= DEPSOP_FLAG_USES_PYTHON;
+ }
+
+ /* return driver node created */
+ return driver_op;
+}
+
+/* Recursively build graph for world */
+void DepsgraphNodeBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* world itself */
+ IDDepsNode *world_node = add_id_node(world_id); /* world shading/params? */
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_node, world->mtex);
+
+ /* world's nodetree */
+ if (world->nodetree) {
+ build_nodetree(world_node, world->nodetree);
+ }
+}
+
+/* Rigidbody Simulation - Scene Level */
+void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ /**
+ * Rigidbody Simulation Nodes
+ * ==========================
+ *
+ * There are 3 nodes related to Rigidbody Simulation:
+ * 1) "Initialize/Rebuild World" - this is called sparingly, only when the simulation
+ * needs to be rebuilt (mainly after file reload, or moving back to start frame)
+ * 2) "Do Simulation" - perform a simulation step - interleaved between the evaluation
+ * steps for clusters of objects (i.e. between those affected and/or not affected by
+ * the sim for instance)
+ *
+ * 3) "Pull Results" - grab the specific transforms applied for a specific object -
+ * performed as part of object's transform-stack building
+ */
+
+ /* create nodes ------------------------------------------------------------------------ */
+ /* XXX: is this the right component, or do we want to use another one instead? */
+
+ /* init/rebuild operation */
+ /*OperationDepsNode *init_node =*/ add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_REBUILD, function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
+ DEG_OPCODE_RIGIDBODY_REBUILD);
+
+ /* do-sim operation */
+ // XXX: what happens if we need to split into several groups?
+ OperationDepsNode *sim_node = add_operation_node(&scene->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_SIM, function_bind(BKE_rigidbody_eval_simulation, _1, scene),
+ DEG_OPCODE_RIGIDBODY_SIM);
+
+ /* XXX: For now, the sim node is the only one that really matters here. If any other
+ * sims get added later, we may have to remove these hacks...
+ */
+ sim_node->owner->entry_operation = sim_node;
+ sim_node->owner->exit_operation = sim_node;
+
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+
+ if (!ob || (ob->type != OB_MESH))
+ continue;
+
+ /* 2) create operation for flushing results */
+ /* object's transform component - where the rigidbody operation lives */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_TRANSFORM,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
+ DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_particles(Object *ob)
+{
+ /**
+ * Particle Systems Nodes
+ * ======================
+ *
+ * There are two types of nodes associated with representing
+ * particle systems:
+ * 1) Component (EVAL_PARTICLES) - This is the particle-system
+ * evaluation context for an object. It acts as the container
+ * for all the nodes associated with a particular set of particle
+ * systems.
+ * 2) Particle System Eval Operation - This operation node acts as a
+ * blackbox evaluation step for one particle system referenced by
+ * the particle systems stack. All dependencies link to this operation.
+ */
+
+ /* component for all particle systems */
+ ComponentDepsNode *psys_comp = add_component_node(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES);
+
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ // XXX: what if this is used more than once!
+ build_animdata(&part->id);
+
+ /* this particle system */
+ // TODO: for now, this will just be a placeholder "ubereval" node
+ add_operation_node(psys_comp,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_particle_system_eval, _1, ob, psys),
+ DEG_OPCODE_PSYS_EVAL,
+ psys->name);
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+
+ if (has_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEG_OPCODE_POSE_IK_SOLVER))
+ {
+ return;
+ }
+
+ /* Operation node for evaluating/running IK Solver. */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEPSOP_TYPE_SIM, function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
+ DEG_OPCODE_POSE_IK_SOLVER);
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+
+ /* Find the chain's root. */
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+
+ /* Operation node for evaluating/running Spline IK Solver.
+ * Store the "root bone" of this chain in the solver, so it knows where to start.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name,
+ DEPSOP_TYPE_SIM, function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
+ DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
+{
+ bArmature *arm = (bArmature *)ob->data;
+
+ /* animation and/or drivers linking posebones to base-armature used to define them
+ * NOTE: AnimData here is really used to control animated deform properties,
+ * which ideally should be able to be unique across different instances.
+ * Eventually, we need some type of proxy/isolation mechanism in-between here
+ * to ensure that we can use same rig multiple times in same scene...
+ */
+ build_animdata(&arm->id);
+
+ /* Rebuild pose if not up to date. */
+ if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
+ BKE_pose_rebuild(ob, arm);
+ /* XXX: Without this animation gets lost in certain circumstances
+ * after loading file. Need to investigate further since it does
+ * not happen with simple scenes..
+ */
+ if (ob->adt) {
+ ob->adt->recalc |= ADT_RECALC_ANIM;
+ }
+ }
+
+ /**
+ * Pose Rig Graph
+ * ==============
+ *
+ * Pose Component:
+ * - Mainly used for referencing Bone components.
+ * - This is where the evaluation operations for init/exec/cleanup
+ * (ik) solvers live, and are later hooked up (so that they can be
+ * interleaved during runtime) with bone-operations they depend on/affect.
+ * - init_pose_eval() and cleanup_pose_eval() are absolute first and last
+ * steps of pose eval process. ALL bone operations must be performed
+ * between these two...
+ *
+ * Bone Component:
+ * - Used for representing each bone within the rig
+ * - Acts to encapsulate the evaluation operations (base matrix + parenting,
+ * and constraint stack) so that they can be easily found.
+ * - Everything else which depends on bone-results hook up to the component only
+ * so that we can redirect those to point at either the the post-IK/
+ * post-constraint/post-matrix steps, as needed.
+ */
+
+ /* pose eval context */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_INIT, function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_INIT);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_POST, function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose), DEG_OPCODE_POSE_DONE);
+
+ /* bones */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ /* node for bone eval */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_INIT, NULL, // XXX: BKE_pose_eval_bone_local
+ DEG_OPCODE_BONE_LOCAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan), // XXX: BKE_pose_eval_bone_pose
+ DEG_OPCODE_BONE_POSE_PARENT);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_OUT, NULL, /* NOTE: dedicated noop for easier relationship construction */
+ DEG_OPCODE_BONE_READY);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_POST, function_bind(BKE_pose_bone_done, _1, pchan),
+ DEG_OPCODE_BONE_DONE);
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ build_pose_constraints(ob, pchan);
+ }
+
+ /**
+ * IK Solvers...
+ *
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(scene, ob, pchan, con);
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(scene, ob, pchan, con);
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+}
+
+void DepsgraphNodeBuilder::build_proxy_rig(Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+ build_animdata(obdata);
+
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_INIT,
+ function_bind(BKE_pose_eval_proxy_copy, _1, ob),
+ DEG_OPCODE_POSE_INIT);
+
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_INIT, NULL,
+ DEG_OPCODE_BONE_LOCAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_BONE_READY);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_BONE, pchan->name,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_BONE_DONE);
+ }
+
+ add_operation_node(&ob->id,
+ DEPSNODE_TYPE_EVAL_POSE,
+ DEPSOP_TYPE_POST,
+ NULL,
+ DEG_OPCODE_POSE_DONE);
+}
+
+/* Shapekeys */
+void DepsgraphNodeBuilder::build_shapekeys(Key *key)
+{
+ build_animdata(&key->id);
+}
+
+/* ObData Geometry Evaluation */
+// XXX: what happens if the datablock is shared!
+void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+
+ /* Temporary uber-update node, which does everything.
+ * It is for the being we're porting old dependencies into the new system.
+ * We'll get rid of this node as soon as all the granular update functions
+ * are filled in.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST, function_bind(BKE_object_eval_uber_data, _1, scene, ob),
+ DEG_OPCODE_GEOMETRY_UBEREVAL);
+
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Init");
+
+ // TODO: "Done" operation
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key)
+ build_shapekeys(key);
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ add_operation_node(&ob->id, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_object_eval_modifier, _1, scene, ob, md),
+ DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma) {
+ // XXX?!
+ ComponentDepsNode *geom_node = add_component_node(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+ build_material(geom_node, ma);
+ }
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(obdata);
+
+ /* nodes for result of obdata's evaluation, and geometry evaluation on object */
+ switch (ob->type) {
+ case OB_MESH:
+ {
+ //Mesh *me = (Mesh *)ob->data;
+
+ /* evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_mesh_eval_geometry, _1, (Mesh *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ }
+ break;
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ if (mom == ob) {
+ /* metaball evaluation operations */
+ /* NOTE: only the motherball gets evaluated! */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_mball_eval_geometry, _1, (MetaBall *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ }
+ }
+ break;
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ /* curve evaluation operations */
+ /* - calculate curve geometry (including path) */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+
+ /* - calculate curve path - this is used by constraints, etc. */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_EXEC, function_bind(BKE_curve_eval_path, _1, (Curve *)obdata),
+ DEG_OPCODE_GEOMETRY_PATH, "Path");
+ }
+ break;
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ /* nurbs evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_curve_eval_geometry, _1, (Curve *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ }
+ break;
+
+ case OB_LATTICE: /* Lattice */
+ {
+ /* lattice evaluation operations */
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_INIT, function_bind(BKE_lattice_eval_geometry, _1, (Lattice *)obdata),
+ DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ }
+ break;
+ }
+
+ add_operation_node(obdata, DEPSNODE_TYPE_GEOMETRY,
+ DEPSOP_TYPE_POST, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Eval Done");
+
+ /* Parameters for driver sources. */
+ add_operation_node(obdata, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+}
+
+/* Cameras */
+void DepsgraphNodeBuilder::build_camera(Object *ob)
+{
+ /* TODO: Link scene-camera links in somehow... */
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&cam->id);
+
+ add_operation_node(camera_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ if (cam->dof_ob != NULL) {
+ /* TODO(sergey): For now parametrs are on object level. */
+ add_operation_node(&ob->id, DEPSNODE_TYPE_PARAMETERS,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER,
+ "Camera DOF");
+ }
+}
+
+/* Lamps */
+void DepsgraphNodeBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ build_animdata(&la->id);
+
+ /* node for obdata */
+ ComponentDepsNode *param_node = add_component_node(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+
+ /* TODO(sergey): Is it really how we're supposed to work with drivers? */
+ add_operation_node(lamp_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* lamp's nodetree */
+ if (la->nodetree) {
+ build_nodetree(param_node, la->nodetree);
+ }
+
+ /* textures */
+ build_texture_stack(param_node, la->mtex);
+}
+
+void DepsgraphNodeBuilder::build_nodetree(DepsNode *owner_node, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ /* nodetree itself */
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* Parameters for drivers. */
+ add_operation_node(ntree_id, DEPSNODE_TYPE_PARAMETERS, DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Parameters Eval");
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner_node, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner_node, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner_node, ntree);
+ }
+ }
+ }
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphNodeBuilder::build_material(DepsNode *owner_node, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+
+ /* material itself */
+ add_id_node(ma_id);
+
+ add_operation_node(ma_id, DEPSNODE_TYPE_SHADING,
+ DEPSOP_TYPE_EXEC, NULL,
+ DEG_OPCODE_PLACEHOLDER, "Material Update");
+
+ /* material animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner_node, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner_node, ma->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphNodeBuilder::build_texture_stack(DepsNode *owner_node, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner_node, mtex->tex);
+ }
+}
+
+/* Recursively build graph for texture */
+void DepsgraphNodeBuilder::build_texture(DepsNode *owner_node, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+ /* texture itself */
+ build_animdata(tex_id);
+ /* texture's nodetree */
+ build_nodetree(owner_node, tex->nodetree);
+}
+
+void DepsgraphNodeBuilder::build_compositor(Scene *scene)
+{
+ /* For now, just a plain wrapper? */
+ // TODO: create compositing component?
+ // XXX: component type undefined!
+ //graph->get_node(&scene->id, NULL, DEPSNODE_TYPE_COMPOSITING, NULL);
+
+ /* for now, nodetrees are just parameters; compositing occurs in internals of renderer... */
+ ComponentDepsNode *owner_node = add_component_node(&scene->id, DEPSNODE_TYPE_PARAMETERS);
+ build_nodetree(owner_node, scene->nodetree);
+}
+
+void DepsgraphNodeBuilder::build_gpencil(bGPdata *gpd)
+{
+ ID *gpd_id = &gpd->id;
+
+ /* gpencil itself */
+ // XXX: what about multiple users of same datablock? This should only get added once
+ add_id_node(gpd_id);
+
+ /* The main reason Grease Pencil is included here is because the animation (and drivers)
+ * need to be hosted somewhere...
+ */
+ build_animdata(gpd_id);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_build_relations.cc b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
new file mode 100644
index 00000000000..300ed07de56
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_build_relations.cc
@@ -0,0 +1,1815 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): Based on original depsgraph.c code - Blender Foundation (2005-2013)
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Methods for constructing depsgraph
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_blenlib.h"
+#include "BLI_string.h"
+#include "BLI_utildefines.h"
+
+#include "DNA_action_types.h"
+#include "DNA_anim_types.h"
+#include "DNA_armature_types.h"
+#include "DNA_camera_types.h"
+#include "DNA_constraint_types.h"
+#include "DNA_curve_types.h"
+#include "DNA_effect_types.h"
+#include "DNA_gpencil_types.h"
+#include "DNA_group_types.h"
+#include "DNA_key_types.h"
+#include "DNA_lamp_types.h"
+#include "DNA_material_types.h"
+#include "DNA_mesh_types.h"
+#include "DNA_meta_types.h"
+#include "DNA_node_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_object_types.h"
+#include "DNA_rigidbody_types.h"
+#include "DNA_scene_types.h"
+#include "DNA_texture_types.h"
+#include "DNA_world_types.h"
+
+#include "BKE_action.h"
+#include "BKE_armature.h"
+#include "BKE_animsys.h"
+#include "BKE_constraint.h"
+#include "BKE_curve.h"
+#include "BKE_effect.h"
+#include "BKE_fcurve.h"
+#include "BKE_group.h"
+#include "BKE_key.h"
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_material.h"
+#include "BKE_mball.h"
+#include "BKE_modifier.h"
+#include "BKE_node.h"
+#include "BKE_object.h"
+#include "BKE_particle.h"
+#include "BKE_rigidbody.h"
+#include "BKE_sound.h"
+#include "BKE_texture.h"
+#include "BKE_tracking.h"
+#include "BKE_world.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_build.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+} /* extern "C" */
+
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_build.h"
+#include "depsgraph_debug.h"
+#include "depsgraph_intern.h"
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_pchanmap.h"
+
+/* ***************** */
+/* Relations Builder */
+
+/* **** General purpose functions **** */
+
+RNAPathKey::RNAPathKey(ID *id, const string &path) :
+ id(id)
+{
+ /* create ID pointer for root of path lookup */
+ PointerRNA id_ptr;
+ RNA_id_pointer_create(id, &id_ptr);
+ /* try to resolve path... */
+ if (!RNA_path_resolve(&id_ptr, path.c_str(), &this->ptr, &this->prop)) {
+ this->ptr = PointerRNA_NULL;
+ this->prop = NULL;
+ }
+}
+
+DepsgraphRelationBuilder::DepsgraphRelationBuilder(Depsgraph *graph) :
+ m_graph(graph)
+{
+}
+
+RootDepsNode *DepsgraphRelationBuilder::find_node(const RootKey &key) const
+{
+ (void)key;
+ BLI_assert(!"Doesn't seem to be correct");
+ return m_graph->root_node;
+}
+
+TimeSourceDepsNode *DepsgraphRelationBuilder::find_node(
+ const TimeSourceKey &key) const
+{
+ if (key.id) {
+ /* XXX TODO */
+ return NULL;
+ }
+ else {
+ return m_graph->root_node->time_source;
+ }
+}
+
+ComponentDepsNode *DepsgraphRelationBuilder::find_node(
+ const ComponentKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node component: Could not find ID %s\n",
+ (key.id != NULL) ? key.id->name : "<null>");
+ return NULL;
+ }
+
+ ComponentDepsNode *node = id_node->find_component(key.type, key.name);
+ return node;
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::find_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ fprintf(stderr, "find_node operation: Could not find ID\n");
+ return NULL;
+ }
+
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ fprintf(stderr, "find_node operation: Could not find component\n");
+ return NULL;
+ }
+
+ OperationDepsNode *op_node = comp_node->find_operation(key.opcode, key.name);
+ if (!op_node) {
+ fprintf(stderr, "find_node_operation: Failed for (%s, '%s')\n",
+ DEG_OPNAMES[key.opcode], key.name.c_str());
+ }
+ return op_node;
+}
+
+DepsNode *DepsgraphRelationBuilder::find_node(const RNAPathKey &key) const
+{
+ return m_graph->find_node_from_pointer(&key.ptr, key.prop);
+}
+
+OperationDepsNode *DepsgraphRelationBuilder::has_node(
+ const OperationKey &key) const
+{
+ IDDepsNode *id_node = m_graph->find_id_node(key.id);
+ if (!id_node) {
+ return NULL;
+ }
+ ComponentDepsNode *comp_node = id_node->find_component(key.component_type,
+ key.component_name);
+ if (!comp_node) {
+ return NULL;
+ }
+ return comp_node->has_operation(key.opcode, key.name);
+}
+
+void DepsgraphRelationBuilder::add_time_relation(TimeSourceDepsNode *timesrc,
+ DepsNode *node_to,
+ const char *description)
+{
+ if (timesrc && node_to) {
+ m_graph->add_new_relation(timesrc, node_to, DEPSREL_TYPE_TIME, description);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_time_relation(%p = %s, %p = %s, %s) Failed\n",
+ timesrc, (timesrc) ? timesrc->identifier().c_str() : "<None>",
+ node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
+ description);
+ }
+}
+
+void DepsgraphRelationBuilder::add_operation_relation(
+ OperationDepsNode *node_from,
+ OperationDepsNode *node_to,
+ eDepsRelation_Type type,
+ const char *description)
+{
+ if (node_from && node_to) {
+ m_graph->add_new_relation(node_from, node_to, type, description);
+ }
+ else {
+ DEG_DEBUG_PRINTF("add_operation_relation(%p = %s, %p = %s, %d, %s) Failed\n",
+ node_from, (node_from) ? node_from->identifier().c_str() : "<None>",
+ node_to, (node_to) ? node_to->identifier().c_str() : "<None>",
+ type, description);
+ }
+}
+
+/* **** Functions to build relations between entities **** */
+
+void DepsgraphRelationBuilder::build_scene(Main *bmain, Scene *scene)
+{
+ /* LIB_DOIT is used to indicate whether node for given ID was already
+ * created or not.
+ */
+ BKE_main_id_tag_all(bmain, false);
+
+ if (scene->set) {
+ // TODO: link set to scene, especially our timesource...
+ }
+
+ /* scene objects */
+ for (Base *base = (Base *)scene->base.first; base; base = base->next) {
+ Object *ob = base->object;
+
+ /* object itself */
+ build_object(bmain, scene, ob);
+
+ /* object that this is a proxy for */
+ if (ob->proxy) {
+ build_object(bmain, scene, ob->proxy);
+ /* TODO(sergey): This is an inverted relation, matches old depsgraph
+ * behavior and need to be investigated if it still need to be inverted.
+ */
+ ComponentKey ob_pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ ComponentKey proxy_pose_key(&ob->proxy->id, DEPSNODE_TYPE_EVAL_POSE);
+ add_relation(ob_pose_key, proxy_pose_key, DEPSREL_TYPE_TRANSFORM, "Proxy");
+ }
+
+ /* Object dupligroup. */
+ if (ob->dup_group) {
+ build_group(bmain, scene, ob, ob->dup_group);
+ }
+ }
+
+ /* rigidbody */
+ if (scene->rigidbody_world) {
+ build_rigidbody(scene);
+ }
+
+ /* scene's animation and drivers */
+ if (scene->adt) {
+ build_animdata(&scene->id);
+ }
+
+ /* world */
+ if (scene->world) {
+ build_world(scene->world);
+ }
+
+ /* compo nodes */
+ if (scene->nodetree) {
+ build_compositor(scene);
+ }
+
+ /* grease pencil */
+ if (scene->gpd) {
+ build_gpencil(&scene->id, scene->gpd);
+ }
+}
+
+void DepsgraphRelationBuilder::build_group(Main *bmain,
+ Scene *scene,
+ Object *object,
+ Group *group)
+{
+ ID *group_id = &group->id;
+ bool group_done = (group_id->flag & LIB_DOIT) != 0;
+ OperationKey object_local_transform_key(&object->id,
+ DEPSNODE_TYPE_TRANSFORM,
+ DEG_OPCODE_TRANSFORM_LOCAL);
+ for (GroupObject *go = (GroupObject *)group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (!group_done) {
+ build_object(bmain, scene, go->ob);
+ }
+ ComponentKey dupli_transform_key(&go->ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(dupli_transform_key,
+ object_local_transform_key,
+ DEPSREL_TYPE_TRANSFORM,
+ "Dupligroup");
+ }
+ group_id->flag |= LIB_DOIT;
+}
+
+void DepsgraphRelationBuilder::build_object(Main *bmain, Scene *scene, Object *ob)
+{
+ if (ob->id.flag & LIB_DOIT) {
+ return;
+ }
+
+ /* Object Transforms */
+ eDepsOperation_Code base_op = (ob->parent) ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
+ OperationKey base_op_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, base_op);
+
+ OperationKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ OperationKey parent_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ OperationKey final_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+
+ OperationKey ob_ubereval_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+
+ /* parenting */
+ if (ob->parent) {
+ /* parent relationship */
+ build_object_parent(ob);
+
+ /* local -> parent */
+ add_relation(local_transform_key, parent_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObLocal -> ObParent]");
+ }
+
+ /* object constraints */
+ if (ob->constraints.first) {
+ OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+
+ /* constraint relations */
+ // TODO: provide base op
+ // XXX: this is broken
+ build_constraints(scene, &ob->id, DEPSNODE_TYPE_TRANSFORM, "", &ob->constraints, NULL);
+
+ /* operation order */
+ add_relation(base_op_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObBase-> Constraint Stack]");
+ add_relation(constraint_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "[ObConstraints -> Done]");
+
+ // XXX
+ add_relation(constraint_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ }
+ else {
+ /* operation order */
+ add_relation(base_op_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Object Transform");
+
+ // XXX
+ add_relation(base_op_key, ob_ubereval_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ add_relation(ob_ubereval_key, final_transform_key, DEPSREL_TYPE_COMPONENT_ORDER, "Temp Ubereval");
+ }
+
+
+ /* AnimData */
+ build_animdata(&ob->id);
+
+ // XXX: This should be hooked up by the build_animdata code
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey adt_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(adt_key, local_transform_key, DEPSREL_TYPE_OPERATION, "Object Animation");
+ }
+
+
+ /* object data */
+ if (ob->data) {
+ ID *obdata_id = (ID *)ob->data;
+
+ /* ob data animation */
+ build_animdata(obdata_id);
+
+ /* type-specific data... */
+ switch (ob->type) {
+ case OB_MESH: /* Geometry */
+ case OB_CURVE:
+ case OB_FONT:
+ case OB_SURF:
+ case OB_MBALL:
+ case OB_LATTICE:
+ {
+ build_obdata_geom(bmain, scene, ob);
+ }
+ break;
+
+
+ case OB_ARMATURE: /* Pose */
+ if (ob->id.lib != NULL && ob->proxy_from != NULL) {
+ build_proxy_rig(ob);
+ }
+ else {
+ build_rig(scene, ob);
+ }
+ break;
+
+ case OB_LAMP: /* Lamp */
+ build_lamp(ob);
+ break;
+
+ case OB_CAMERA: /* Camera */
+ build_camera(ob);
+ break;
+ }
+ }
+
+ /* particle systems */
+ if (ob->particlesystem.first) {
+ build_particles(scene, ob);
+ }
+
+ /* grease pencil */
+ if (ob->gpd) {
+ build_gpencil(&ob->id, ob->gpd);
+ }
+}
+
+void DepsgraphRelationBuilder::build_object_parent(Object *ob)
+{
+ /* XXX: for now, need to use the component key (not just direct to the parent op), or else the matrix doesn't get reset */
+ // XXX: @sergey - it would be good if we got that backwards flushing working when tagging for updates
+ //OperationKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_PARENT);
+ ComponentKey ob_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+
+ /* type-specific links */
+ switch (ob->partype) {
+ case PARSKEL: /* Armature Deform (Virtual Modifier) */
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Armature Deform Parent");
+ }
+ break;
+
+ case PARVERT1: /* Vertex Parent */
+ case PARVERT3:
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Vertex Parent");
+ /* XXX not sure what this is for or how you could be done properly - lukas */
+ //parent_node->customdata_mask |= CD_MASK_ORIGINDEX;
+
+ ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Vertex Parent TFM");
+ }
+ break;
+
+ case PARBONE: /* Bone Parent */
+ {
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_BONE, ob->parsubstr);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Bone Parent");
+ }
+ break;
+
+ default:
+ {
+ if (ob->parent->type == OB_LATTICE) {
+ /* Lattice Deform Parent - Virtual Modifier */
+ // XXX: no virtual modifiers should be left!
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ ComponentKey geom_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent");
+ add_relation(geom_key, ob_key, DEPSREL_TYPE_STANDARD, "Lattice Deform Parent Geom");
+ }
+ else if (ob->parent->type == OB_CURVE) {
+ Curve *cu = (Curve *)ob->parent->data;
+
+ if (cu->flag & CU_PATH) {
+ /* Follow Path */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow Parent");
+
+ ComponentKey transform_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(transform_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Follow TFM");
+ }
+ else {
+ /* Standard Parent */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Curve Parent");
+ }
+ }
+ else {
+ /* Standard Parent */
+ ComponentKey parent_key(&ob->parent->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(parent_key, ob_key, DEPSREL_TYPE_TRANSFORM, "Parent");
+ }
+ }
+ break;
+ }
+
+ /* exception case: parent is duplivert */
+ if ((ob->type == OB_MBALL) && (ob->parent->transflag & OB_DUPLIVERTS)) {
+ //dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_OB, "Duplivert");
+ }
+}
+
+void DepsgraphRelationBuilder::build_constraints(Scene *scene, ID *id, eDepsNode_Type component_type, const char *component_subdata,
+ ListBase *constraints, RootPChanMap *root_map)
+{
+ OperationKey constraint_op_key(id, component_type, component_subdata,
+ (component_type == DEPSNODE_TYPE_BONE) ? DEG_OPCODE_BONE_CONSTRAINTS : DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+
+ /* add dependencies for each constraint in turn */
+ for (bConstraint *con = (bConstraint *)constraints->first; con; con = con->next) {
+ const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
+
+ /* invalid constraint type... */
+ if (cti == NULL)
+ continue;
+
+ /* special case for camera tracking -- it doesn't use targets to define relations */
+ // TODO: we can now represent dependencies in a much richer manner, so review how this is done...
+ if (ELEM(cti->type, CONSTRAINT_TYPE_FOLLOWTRACK, CONSTRAINT_TYPE_CAMERASOLVER, CONSTRAINT_TYPE_OBJECTSOLVER)) {
+ bool depends_on_camera = false;
+
+ if (cti->type == CONSTRAINT_TYPE_FOLLOWTRACK) {
+ bFollowTrackConstraint *data = (bFollowTrackConstraint *)con->data;
+
+ if (((data->clip) || (data->flag & FOLLOWTRACK_ACTIVECLIP)) && data->track[0])
+ depends_on_camera = true;
+
+ if (data->depth_ob) {
+ // DAG_RL_DATA_OB | DAG_RL_OB_OB
+ ComponentKey depth_key(&data->depth_ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(depth_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
+ depends_on_camera = true;
+ }
+
+ if (depends_on_camera && scene->camera) {
+ // DAG_RL_DATA_OB | DAG_RL_OB_OB
+ ComponentKey camera_key(&scene->camera->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(camera_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+
+ /* tracker <-> constraints */
+ // FIXME: actually motionclip dependency on results of motionclip block here...
+ //dag_add_relation(dag, scenenode, node, DAG_RL_SCENE, "Scene Relation");
+ }
+ else if (cti->get_constraint_targets) {
+ ListBase targets = {NULL, NULL};
+ cti->get_constraint_targets(con, &targets);
+
+ for (bConstraintTarget *ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
+ if (!ct->tar)
+ continue;
+
+ if (ELEM(con->type, CONSTRAINT_TYPE_KINEMATIC, CONSTRAINT_TYPE_SPLINEIK)) {
+ /* ignore IK constraints - these are handled separately (on pose level) */
+ }
+ else if (ELEM(con->type, CONSTRAINT_TYPE_FOLLOWPATH, CONSTRAINT_TYPE_CLAMPTO)) {
+ /* these constraints require path geometry data... */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name); // XXX: type = geom_transform
+ // TODO: path dependency
+ }
+ else if ((ct->tar->type == OB_ARMATURE) && (ct->subtarget[0])) {
+ /* bone */
+ if (&ct->tar->id == id) {
+ /* same armature */
+ eDepsOperation_Code target_key_opcode;
+
+ /* Using "done" here breaks in-chain deps, while using "ready" here breaks most production rigs instead...
+ * So, we do a compromise here, and only do this when an IK chain conflict may occur
+ */
+ if (root_map->has_common_root(component_subdata, ct->subtarget)) {
+ target_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ target_key_opcode = DEG_OPCODE_BONE_DONE;
+ }
+
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, target_key_opcode);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ /* different armature - we can safely use the result of that */
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_BONE, ct->subtarget, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else if (ELEM(ct->tar->type, OB_MESH, OB_LATTICE) && (ct->subtarget[0])) {
+ /* vertex group */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_GEOMETRY_EVAL, cti->name);
+
+ if (ct->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else if (con->type == CONSTRAINT_TYPE_SHRINKWRAP) {
+ /* Constraints which requires the target object surface. */
+ ComponentKey target_key(&ct->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+
+ /* NOTE: obdata eval now doesn't necessarily depend on the object's transform... */
+ ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ /* standard object relation */
+ // TODO: loc vs rot vs scale?
+ if (&ct->tar->id == id) {
+ /* Constraint targetting own object:
+ * - This case is fine IFF we're dealing with a bone constraint pointing to
+ * its own armature. In that case, it's just transform -> bone.
+ * - If however it is a real self targetting case, just make it depend on the
+ * previous constraint (or the pre-constraint state)...
+ */
+ if ((ct->tar->type == OB_ARMATURE) && (component_type == DEPSNODE_TYPE_BONE)) {
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ else {
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+ else {
+ /* normal object dependency */
+ OperationKey target_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+ }
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ if (ELEM(con->type,
+ CONSTRAINT_TYPE_ROTLIKE,
+ CONSTRAINT_TYPE_SIZELIKE,
+ CONSTRAINT_TYPE_LOCLIKE,
+ CONSTRAINT_TYPE_TRANSLIKE))
+ {
+ /* TODO(sergey): Add used space check. */
+ ComponentKey target_transform_key(&ct->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_transform_key, constraint_op_key, DEPSREL_TYPE_TRANSFORM, cti->name);
+ }
+
+ }
+
+ if (cti->flush_constraint_targets)
+ cti->flush_constraint_targets(con, &targets, 1);
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_animdata(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+
+ if (adt == NULL)
+ return;
+
+ ComponentKey adt_key(id, DEPSNODE_TYPE_ANIMATION);
+
+ /* animation */
+ if (adt->action || adt->nla_tracks.first) {
+ /* wire up dependency to time source */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, adt_key, DEPSREL_TYPE_TIME, "[TimeSrc -> Animation]");
+
+ // XXX: Hook up specific update callbacks for special properties which may need it...
+
+ // XXX: animdata "hierarchy" - top-level overrides need to go after lower-down
+ }
+
+ /* drivers */
+ for (FCurve *fcu = (FCurve *)adt->drivers.first; fcu; fcu = fcu->next) {
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+
+ /* create the driver's relations to targets */
+ build_driver(id, fcu);
+
+ /* prevent driver from occurring before own animation... */
+ if (adt->action || adt->nla_tracks.first) {
+ add_relation(adt_key, driver_key, DEPSREL_TYPE_OPERATION,
+ "[AnimData Before Drivers]");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_driver(ID *id, FCurve *fcu)
+{
+ ChannelDriver *driver = fcu->driver;
+ OperationKey driver_key(id, DEPSNODE_TYPE_PARAMETERS, DEG_OPCODE_DRIVER, deg_fcurve_id_name(fcu));
+ bPoseChannel *pchan = NULL;
+
+ /* create dependency between driver and data affected by it */
+ /* - direct property relationship... */
+ //RNAPathKey affected_key(id, fcu->rna_path);
+ //add_relation(driver_key, affected_key, DEPSREL_TYPE_DRIVER, "[Driver -> Data] DepsRel");
+
+ /* driver -> data components (for interleaved evaluation - bones/constraints/modifiers) */
+ // XXX: this probably should probably be moved out into a separate function
+ if (strstr(fcu->rna_path, "pose.bones[") != NULL) {
+ /* interleaved drivers during bone eval */
+ // TODO: ideally, if this is for a constraint, it goes to said constraint
+ Object *ob = (Object *)id;
+ char *bone_name;
+
+ bone_name = BLI_str_quoted_substrN(fcu->rna_path, "pose.bones[");
+ pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+
+ if (bone_name) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+
+ if (pchan) {
+ OperationKey bone_key(id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Driver -> Bone]");
+ }
+ else {
+ fprintf(stderr,
+ "Couldn't find bone name for driver path - '%s'\n",
+ fcu->rna_path);
+ }
+ }
+ else if (GS(id->name) == ID_AR && strstr(fcu->rna_path, "bones[")) {
+ /* drivers on armature-level bone settings (i.e. bbone stuff),
+ * which will affect the evaluation of corresponding pose bones
+ */
+ IDDepsNode *arm_node = m_graph->find_id_node(id);
+ char *bone_name = BLI_str_quoted_substrN(fcu->rna_path, "bones[");
+
+ if (arm_node && bone_name) {
+ /* find objects which use this, and make their eval callbacks depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(arm_node->outlinks, rel)
+ {
+ IDDepsNode *to_node = (IDDepsNode *)rel->to;
+
+ /* we only care about objects with pose data which use this... */
+ if (GS(to_node->id->name) == ID_OB) {
+ Object *ob = (Object *)to_node->id;
+ bPoseChannel *pchan = BKE_pose_channel_find_name(ob->pose, bone_name); // NOTE: ob->pose may be NULL
+
+ if (pchan) {
+ OperationKey bone_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(driver_key, bone_key, DEPSREL_TYPE_DRIVER, "[Arm Bone -> Driver -> Bone]");
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ /* free temp data */
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+ else {
+ fprintf(stderr,
+ "Couldn't find armature bone name for driver path - '%s'\n",
+ fcu->rna_path);
+ }
+ }
+ else if (GS(id->name) == ID_OB && strstr(fcu->rna_path, "modifiers[")) {
+ /* modifier driver - connect directly to the modifier */
+ char *modifier_name = BLI_str_quoted_substrN(fcu->rna_path, "modifiers[");
+ if (modifier_name) {
+ OperationKey modifier_key(id,
+ DEPSNODE_TYPE_GEOMETRY,
+ DEG_OPCODE_GEOMETRY_MODIFIER,
+ modifier_name);
+ if (has_node(modifier_key)) {
+ add_relation(driver_key, modifier_key, DEPSREL_TYPE_DRIVER, "[Driver -> Modifier]");
+ }
+ else {
+ printf("Unexisting driver RNA path: %s\n", fcu->rna_path);
+ }
+
+ MEM_freeN(modifier_name);
+ }
+ }
+ else if (GS(id->name) == ID_KE && strstr(fcu->rna_path, "key_blocks[")) {
+ /* shape key driver - hook into the base geometry operation */
+ // XXX: double check where this points
+ Key *shape_key = (Key *)id;
+
+ ComponentKey geometry_key(shape_key->from, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(driver_key, geometry_key, DEPSREL_TYPE_DRIVER, "[Driver -> ShapeKey Geom]");
+ }
+ else {
+ if (GS(id->name) == ID_OB) {
+ /* assume that driver affects a transform... */
+ OperationKey local_transform_key(id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_LOCAL);
+ add_relation(driver_key, local_transform_key, DEPSREL_TYPE_OPERATION, "[Driver -> Transform]");
+ }
+ }
+
+ /* ensure that affected prop's update callbacks will be triggered once done */
+ // TODO: implement this once the functionality to add these links exists in RNA
+ // XXX: the data itself could also set this, if it were to be truly initialised later?
+
+ /* loop over variables to get the target relationships */
+ for (DriverVar *dvar = (DriverVar *)driver->variables.first; dvar; dvar = dvar->next) {
+ /* only used targets */
+ DRIVER_TARGETS_USED_LOOPER(dvar)
+ {
+ if (dtar->id == NULL)
+ continue;
+
+ /* special handling for directly-named bones */
+ if ((dtar->flag & DTAR_FLAG_STRUCT_REF) && (dtar->pchan_name[0])) {
+ Object *ob = (Object *)dtar->id;
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, dtar->pchan_name);
+ if (target_pchan != NULL) {
+ /* get node associated with bone */
+ // XXX: watch the space!
+ /* Some cases can't use final bone transform, for example:
+ * - Driving the bone with itself (addressed here)
+ * - Relations inside an IK chain (TODO?)
+ */
+ if (dtar->id == id &&
+ pchan != NULL &&
+ STREQ(pchan->name, target_pchan->name))
+ {
+ continue;
+ }
+ OperationKey target_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Bone Target -> Driver]");
+ }
+ }
+ else if (dtar->flag & DTAR_FLAG_STRUCT_REF) {
+ /* get node associated with the object's transforms */
+ OperationKey target_key(dtar->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[Target -> Driver]");
+ }
+ else if (dtar->rna_path && strstr(dtar->rna_path, "pose.bones[")) {
+ /* workaround for ensuring that local bone transforms don't end up
+ * having to wait for pose eval to finish (to prevent cycles)
+ */
+ Object *ob = (Object *)dtar->id;
+ char *bone_name = BLI_str_quoted_substrN(dtar->rna_path, "pose.bones[");
+ bPoseChannel *target_pchan = BKE_pose_channel_find_name(ob->pose, bone_name);
+ if (bone_name) {
+ MEM_freeN(bone_name);
+ bone_name = NULL;
+ }
+ if (target_pchan) {
+ if (dtar->id == id &&
+ pchan != NULL &&
+ STREQ(pchan->name, target_pchan->name))
+ {
+ continue;
+ }
+ OperationKey bone_key(dtar->id, DEPSNODE_TYPE_BONE, target_pchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(bone_key, driver_key, DEPSREL_TYPE_DRIVER, "[RNA Bone -> Driver]");
+ }
+ }
+ else {
+ /* resolve path to get node */
+ RNAPathKey target_key(dtar->id, dtar->rna_path ? dtar->rna_path : "");
+ add_relation(target_key, driver_key, DEPSREL_TYPE_DRIVER_TARGET, "[RNA Target -> Driver]");
+ }
+ }
+ DRIVER_TARGETS_LOOPER_END
+ }
+}
+
+void DepsgraphRelationBuilder::build_world(World *world)
+{
+ ID *world_id = &world->id;
+ if (world_id->flag & LIB_DOIT) {
+ return;
+ }
+ world_id->flag |= LIB_DOIT;
+
+ build_animdata(world_id);
+
+ /* TODO: other settings? */
+
+ /* textures */
+ build_texture_stack(world_id, world->mtex);
+
+ /* world's nodetree */
+ build_nodetree(world_id, world->nodetree);
+}
+
+void DepsgraphRelationBuilder::build_rigidbody(Scene *scene)
+{
+ RigidBodyWorld *rbw = scene->rigidbody_world;
+
+ OperationKey init_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_REBUILD);
+ OperationKey sim_key(&scene->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_RIGIDBODY_SIM);
+
+ /* rel between the two sim-nodes */
+ add_relation(init_key, sim_key, DEPSREL_TYPE_OPERATION, "Rigidbody [Init -> SimStep]");
+
+ /* set up dependencies between these operations and other builtin nodes --------------- */
+
+ /* time dependency */
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, init_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Reset/Rebuild (Optional)");
+ add_relation(time_src_key, sim_key, DEPSREL_TYPE_TIME, "TimeSrc -> Rigidbody Sim Step");
+
+ /* objects - simulation participants */
+ if (rbw->group) {
+ for (GroupObject *go = (GroupObject *)rbw->group->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || ob->type != OB_MESH)
+ continue;
+
+ /* hook up evaluation order...
+ * 1) flushing rigidbody results follows base transforms being applied
+ * 2) rigidbody flushing can only be performed after simulation has been run
+ *
+ * 3) simulation needs to know base transforms to figure out what to do
+ * XXX: there's probably a difference between passive and active
+ * - passive don't change, so may need to know full transform...
+ */
+ OperationKey rbo_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+
+ eDepsOperation_Code trans_opcode = ob->parent ? DEG_OPCODE_TRANSFORM_PARENT : DEG_OPCODE_TRANSFORM_LOCAL;
+ OperationKey trans_op(&ob->id, DEPSNODE_TYPE_TRANSFORM, trans_opcode);
+
+ add_relation(trans_op, rbo_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> RBO Sync");
+ add_relation(sim_key, rbo_key, DEPSREL_TYPE_COMPONENT_ORDER, "Rigidbody Sim Eval -> RBO Sync");
+
+ /* if constraints exist, those depend on the result of the rigidbody sim
+ * - This allows constraints to modify the result of the sim (i.e. clamping)
+ * while still allowing the sim to depend on some changes to the objects.
+ * Also, since constraints are hooked up to the final nodes, this link
+ * means that we can also fit in there too...
+ * - Later, it might be good to include a constraint in the stack allowing us
+ * to control whether rigidbody eval gets interleaved into the constraint stack
+ */
+ if (ob->constraints.first) {
+ OperationKey constraint_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_CONSTRAINTS);
+ add_relation(rbo_key, constraint_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Ob Constraints");
+ }
+ else {
+ /* final object transform depends on rigidbody */
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_FINAL);
+ add_relation(rbo_key, done_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Done");
+
+ // XXX: ubereval will be removed eventually, but we still need it in the meantime
+ OperationKey uber_key(&ob->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_OBJECT_UBEREVAL);
+ add_relation(rbo_key, uber_key, DEPSREL_TYPE_COMPONENT_ORDER, "RBO Sync -> Uber (Temp)");
+ }
+
+
+ /* needed to get correct base values */
+ add_relation(trans_op, sim_key, DEPSREL_TYPE_OPERATION, "Base Ob Transform -> Rigidbody Sim Eval");
+ }
+ }
+
+ /* constraints */
+ if (rbw->constraints) {
+ for (GroupObject *go = (GroupObject *)rbw->constraints->gobject.first; go; go = go->next) {
+ Object *ob = go->ob;
+ if (!ob || !ob->rigidbody_constraint)
+ continue;
+
+ RigidBodyCon *rbc = ob->rigidbody_constraint;
+
+ /* final result of the constraint object's transform controls how the
+ * constraint affects the physics sim for these objects
+ */
+ ComponentKey trans_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ OperationKey ob1_key(&rbc->ob1->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+ OperationKey ob2_key(&rbc->ob2->id, DEPSNODE_TYPE_TRANSFORM, DEG_OPCODE_TRANSFORM_RIGIDBODY);
+
+ /* - constrained-objects sync depends on the constraint-holder */
+ add_relation(trans_key, ob1_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_1");
+ add_relation(trans_key, ob2_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint -> RBC.Object_2");
+
+ /* - ensure that sim depends on this constraint's transform */
+ add_relation(trans_key, sim_key, DEPSREL_TYPE_TRANSFORM, "RigidBodyConstraint Transform -> RB Simulation");
+ }
+ }
+}
+
+void DepsgraphRelationBuilder::build_particles(Scene *scene, Object *ob)
+{
+ /* particle systems */
+ for (ParticleSystem *psys = (ParticleSystem *)ob->particlesystem.first; psys; psys = psys->next) {
+ ParticleSettings *part = psys->part;
+
+ /* particle settings */
+ build_animdata(&part->id);
+
+ /* this particle system */
+ OperationKey psys_key(&ob->id, DEPSNODE_TYPE_EVAL_PARTICLES, DEG_OPCODE_PSYS_EVAL, psys->name);
+
+ /* XXX: if particle system is later re-enabled, we must do full rebuild? */
+ if (!psys_check_enabled(ob, psys))
+ continue;
+
+#if 0
+ if (ELEM(part->phystype, PART_PHYS_KEYED, PART_PHYS_BOIDS)) {
+ ParticleTarget *pt;
+
+ for (pt = psys->targets.first; pt; pt = pt->next) {
+ if (pt->ob && BLI_findlink(&pt->ob->particlesystem, pt->psys - 1)) {
+ node2 = dag_get_node(dag, pt->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_DATA_DATA | DAG_RL_OB_DATA, "Particle Targets");
+ }
+ }
+ }
+
+ if (part->ren_as == PART_DRAW_OB && part->dup_ob) {
+ node2 = dag_get_node(dag, part->dup_ob);
+ /* note that this relation actually runs in the wrong direction, the problem
+ * is that dupli system all have this (due to parenting), and the render
+ * engine instancing assumes particular ordering of objects in list */
+ dag_add_relation(dag, node, node2, DAG_RL_OB_OB, "Particle Object Visualization");
+ if (part->dup_ob->type == OB_MBALL)
+ dag_add_relation(dag, node, node2, DAG_RL_DATA_DATA, "Particle Object Visualization");
+ }
+
+ if (part->ren_as == PART_DRAW_GR && part->dup_group) {
+ for (go = part->dup_group->gobject.first; go; go = go->next) {
+ node2 = dag_get_node(dag, go->ob);
+ dag_add_relation(dag, node2, node, DAG_RL_OB_OB, "Particle Group Visualization");
+ }
+ }
+#endif
+
+ /* effectors */
+ ListBase *effectors = pdInitEffectors(scene, ob, psys, part->effector_weights, false);
+
+ if (effectors) {
+ for (EffectorCache *eff = (EffectorCache *)effectors->first; eff; eff = eff->next) {
+ if (eff->psys) {
+ // XXX: DAG_RL_DATA_DATA | DAG_RL_OB_DATA
+ ComponentKey eff_key(&eff->ob->id, DEPSNODE_TYPE_GEOMETRY); // xxx: particles instead?
+ add_relation(eff_key, psys_key, DEPSREL_TYPE_STANDARD, "Particle Field");
+ }
+ }
+ }
+
+ pdEndEffectors(&effectors);
+
+ /* boids */
+ if (part->boids) {
+ BoidRule *rule = NULL;
+ BoidState *state = NULL;
+
+ for (state = (BoidState *)part->boids->states.first; state; state = state->next) {
+ for (rule = (BoidRule *)state->rules.first; rule; rule = rule->next) {
+ Object *ruleob = NULL;
+ if (rule->type == eBoidRuleType_Avoid)
+ ruleob = ((BoidRuleGoalAvoid *)rule)->ob;
+ else if (rule->type == eBoidRuleType_FollowLeader)
+ ruleob = ((BoidRuleFollowLeader *)rule)->ob;
+
+ if (ruleob) {
+ ComponentKey ruleob_key(&ruleob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(ruleob_key, psys_key, DEPSREL_TYPE_TRANSFORM, "Boid Rule");
+ }
+ }
+ }
+ }
+ }
+
+ /* pointcache */
+ // TODO...
+}
+
+/* IK Solver Eval Steps */
+void DepsgraphRelationBuilder::build_ik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bKinematicConstraint *data = (bKinematicConstraint *)con->data;
+
+ /* attach owner to IK Solver too
+ * - assume that owner is always part of chain
+ * - see notes on direction of rel below...
+ */
+ bPoseChannel *rootchan = BKE_armature_ik_solver_find_root(pchan, data);
+ OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_IK_SOLVER);
+
+ /* IK target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->tar != NULL) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ *
+ * This way we ensuring the whole subtree is updated from scratch without
+ * need of intermediate matricies. This is an overkill, but good enough for
+ * testing IK solver.
+ */
+ // FIXME: geometry targets...
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+ /* TODO(sergey): This is only for until granular update stores intermediate result. */
+ if (data->tar != ob) {
+ /* different armature - can just read the results */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ else {
+ /* same armature - we'll use the ready state only, just in case this bone is in the chain we're solving */
+ OperationKey target_key(&data->tar->id, DEPSNODE_TYPE_BONE, data->subtarget, DEG_OPCODE_BONE_DONE);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ }
+ else if (ELEM(data->tar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ /* vertex group target */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+ if (data->tar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ /* Standard Object Target */
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+
+ if ((data->tar == ob) && (data->subtarget[0])) {
+ /* Prevent target's constraints from linking to anything from same
+ * chain that it controls.
+ */
+ root_map->add_bone(data->subtarget, rootchan->name);
+ }
+ }
+
+ /* Pole Target */
+ // XXX: this should get handled as part of the constraint code
+ if (data->poletar != NULL) {
+ if ((data->tar->type == OB_ARMATURE) && (data->subtarget[0])) {
+ // XXX: same armature issues - ready vs done?
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_BONE, data->subtarget);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ else if (ELEM(data->poletar->type, OB_MESH, OB_LATTICE) && (data->subtarget[0])) {
+ /* vertex group target */
+ /* NOTE: for now, we don't need to represent vertex groups separately... */
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_GEOMETRY_EVAL, con->name);
+
+ if (data->poletar->type == OB_MESH) {
+ //node2->customdata_mask |= CD_MASK_MDEFORMVERT;
+ }
+ }
+ else {
+ ComponentKey target_key(&data->poletar->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(target_key, solver_key, DEPSREL_TYPE_TRANSFORM, con->name);
+ }
+ }
+
+ DEG_DEBUG_PRINTF("\nStarting IK Build: pchan = %s, target = (%s, %s), segcount = %d\n",
+ pchan->name, data->tar->id.name, data->subtarget, data->rootbone);
+
+ bPoseChannel *parchan = pchan;
+ /* exclude tip from chain? */
+ if (!(data->flag & CONSTRAINT_IK_TIP)) {
+ OperationKey tip_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_LOCAL);
+ add_relation(solver_key, tip_transforms_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+ parchan = pchan->parent;
+ }
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ OperationKey parchan_transforms_key(&ob->id, DEPSNODE_TYPE_BONE,
+ parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parchan_transforms_key, solver_key,
+ DEPSREL_TYPE_TRANSFORM, "IK Solver Owner");
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ while (parchan) {
+ /* Make IK-solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * grab the result with IK solver results...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Parent");
+
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "IK Solver Result");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ DEG_DEBUG_PRINTF(" %d = %s\n", segcount, parchan->name);
+ segcount++;
+ if ((segcount == data->rootbone) || (segcount > 255)) break; /* 255 is weak */
+
+ parchan = parchan->parent;
+ }
+
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Spline IK Eval Steps */
+void DepsgraphRelationBuilder::build_splineik_pose(Object *ob,
+ bPoseChannel *pchan,
+ bConstraint *con,
+ RootPChanMap *root_map)
+{
+ bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
+ bPoseChannel *rootchan = BKE_armature_splineik_solver_find_root(pchan, data);
+ OperationKey transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey solver_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, rootchan->name, DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
+
+ /* attach owner to IK Solver too
+ * - assume that owner is always part of chain
+ * - see notes on direction of rel below...
+ */
+ add_relation(transforms_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Owner");
+
+ /* attach path dependency to solver */
+ if (data->tar) {
+ /* TODO(sergey): For until we'll store partial matricies in the depsgraph,
+ * we create dependency between target object and pose eval component.
+ * See IK pose for a bit more information.
+ */
+ // TODO: the bigggest point here is that we need the curve PATH and not just the general geometry...
+ ComponentKey target_key(&data->tar->id, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ add_relation(target_key, pose_key, DEPSREL_TYPE_TRANSFORM,"[Curve.Path -> Spline IK] DepsRel");
+ }
+
+ pchan->flag |= POSE_DONE;
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Result");
+
+ root_map->add_bone(pchan->name, rootchan->name);
+
+ /* Walk to the chain's root */
+ //size_t segcount = 0;
+ int segcount = 0;
+
+ for (bPoseChannel *parchan = pchan->parent; parchan; parchan = parchan->parent) {
+ /* Make Spline IK solver dependent on this bone's result,
+ * since it can only run after the standard results
+ * of the bone are know. Validate links step on the
+ * bone will ensure that users of this bone only
+ * grab the result with IK solver results...
+ */
+ if (parchan != pchan) {
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_READY);
+ add_relation(parent_key, solver_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Update");
+
+ OperationKey done_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, done_key, DEPSREL_TYPE_TRANSFORM, "IK Chain Result");
+ }
+ parchan->flag |= POSE_DONE;
+
+ OperationKey final_transforms_key(&ob->id, DEPSNODE_TYPE_BONE, parchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(solver_key, final_transforms_key, DEPSREL_TYPE_TRANSFORM, "Spline IK Solver Result");
+
+ root_map->add_bone(parchan->name, rootchan->name);
+
+ /* continue up chain, until we reach target number of items... */
+ segcount++;
+ if ((segcount == data->chainlen) || (segcount > 255)) break; /* 255 is weak */
+ }
+
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ add_relation(solver_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+}
+
+/* Pose/Armature Bones Graph */
+void DepsgraphRelationBuilder::build_rig(Scene *scene, Object *ob)
+{
+ /* Armature-Data */
+ // TODO: selection status?
+
+ /* attach links between pose operations */
+ OperationKey init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey flush_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+
+ add_relation(init_key, flush_key, DEPSREL_TYPE_COMPONENT_ORDER, "[Pose Init -> Pose Cleanup]");
+
+ if (ob->adt && (ob->adt->action || ob->adt->nla_tracks.first)) {
+ ComponentKey animation_key(&ob->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, init_key, DEPSREL_TYPE_OPERATION, "Rig Animation");
+ }
+
+ /* IK Solvers...
+ * - These require separate processing steps are pose-level
+ * to be executed between chains of bones (i.e. once the
+ * base transforms of a bunch of bones is done)
+ *
+ * - We build relations for these before the dependencies
+ * between ops in the same component as it is necessary
+ * to check whether such bones are in the same IK chain
+ * (or else we get weird issues with either in-chain
+ * references, or with bones being parented to IK'd bones)
+ *
+ * Unsolved Issues:
+ * - Care is needed to ensure that multi-headed trees work out the same as in ik-tree building
+ * - Animated chain-lengths are a problem...
+ */
+ RootPChanMap root_map;
+ bool pose_depends_on_local_transform = false;
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ for (bConstraint *con = (bConstraint *)pchan->constraints.first; con; con = con->next) {
+ switch (con->type) {
+ case CONSTRAINT_TYPE_KINEMATIC:
+ build_ik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ case CONSTRAINT_TYPE_SPLINEIK:
+ build_splineik_pose(ob, pchan, con, &root_map);
+ pose_depends_on_local_transform = true;
+ break;
+
+ /* Constraints which needs world's matrix for transform.
+ * TODO(sergey): More constraints here?
+ */
+ case CONSTRAINT_TYPE_ROTLIKE:
+ case CONSTRAINT_TYPE_SIZELIKE:
+ case CONSTRAINT_TYPE_LOCLIKE:
+ case CONSTRAINT_TYPE_TRANSLIKE:
+ /* TODO(sergey): Add used space check. */
+ pose_depends_on_local_transform = true;
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ //root_map.print_debug();
+
+ if (pose_depends_on_local_transform) {
+ /* TODO(sergey): Once partial updates are possible use relation between
+ * object transform and solver itself in it's build function.
+ */
+ ComponentKey pose_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE);
+ ComponentKey local_transform_key(&ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(local_transform_key, pose_key, DEPSREL_TYPE_TRANSFORM, "Local Transforms");
+ }
+
+
+ /* links between operations for each bone */
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first; pchan; pchan = pchan->next) {
+ OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_pose_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_POSE_PARENT);
+ OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+
+ pchan->flag &= ~POSE_DONE;
+
+ /* pose init to bone local */
+ add_relation(init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "PoseEval Source-Bone Link");
+
+ /* local to pose parenting operation */
+ add_relation(bone_local_key, bone_pose_key, DEPSREL_TYPE_OPERATION, "Bone Local - PoseSpace Link");
+
+ /* parent relation */
+ if (pchan->parent != NULL) {
+ eDepsOperation_Code parent_key_opcode;
+
+ /* NOTE: this difference in handling allows us to prevent lockups while ensuring correct poses for separate chains */
+ if (root_map.has_common_root(pchan->name, pchan->parent->name)) {
+ parent_key_opcode = DEG_OPCODE_BONE_READY;
+ }
+ else {
+ parent_key_opcode = DEG_OPCODE_BONE_DONE;
+ }
+
+ OperationKey parent_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->parent->name, parent_key_opcode);
+ add_relation(parent_key, bone_pose_key, DEPSREL_TYPE_TRANSFORM, "[Parent Bone -> Child Bone]");
+ }
+
+ /* constraints */
+ if (pchan->constraints.first != NULL) {
+ /* constraints stack and constraint dependencies */
+ build_constraints(scene, &ob->id, DEPSNODE_TYPE_BONE, pchan->name, &pchan->constraints, &root_map);
+
+ /* pose -> constraints */
+ OperationKey constraints_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_CONSTRAINTS);
+ add_relation(bone_pose_key, constraints_key, DEPSREL_TYPE_OPERATION, "Constraints Stack");
+
+ /* constraints -> ready */
+ // TODO: when constraint stack is exploded, this step should occur before the first IK solver
+ add_relation(constraints_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Constraints -> Ready");
+ }
+ else {
+ /* pose -> ready */
+ add_relation(bone_pose_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Pose -> Ready");
+ }
+
+ /* bone ready -> done
+ * NOTE: For bones without IK, this is all that's needed.
+ * For IK chains however, an additional rel is created from IK to done,
+ * with transitive reduction removing this one...
+ */
+ add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+
+ /* assume that all bones must be done for the pose to be ready (for deformers) */
+ add_relation(bone_done_key, flush_key, DEPSREL_TYPE_OPERATION, "PoseEval Result-Bone Link");
+ }
+}
+
+void DepsgraphRelationBuilder::build_proxy_rig(Object *ob)
+{
+ OperationKey pose_init_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_INIT);
+ OperationKey pose_done_key(&ob->id, DEPSNODE_TYPE_EVAL_POSE, DEG_OPCODE_POSE_DONE);
+ for (bPoseChannel *pchan = (bPoseChannel *)ob->pose->chanbase.first;
+ pchan != NULL;
+ pchan = pchan->next)
+ {
+ OperationKey bone_local_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_LOCAL);
+ OperationKey bone_ready_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_READY);
+ OperationKey bone_done_key(&ob->id, DEPSNODE_TYPE_BONE, pchan->name, DEG_OPCODE_BONE_DONE);
+ add_relation(pose_init_key, bone_local_key, DEPSREL_TYPE_OPERATION, "Pose Init -> Bone Local");
+ add_relation(bone_local_key, bone_ready_key, DEPSREL_TYPE_OPERATION, "Local -> Ready");
+ add_relation(bone_ready_key, bone_done_key, DEPSREL_TYPE_OPERATION, "Ready -> Done");
+ add_relation(bone_done_key, pose_done_key, DEPSREL_TYPE_OPERATION, "Bone Done -> Pose Done");
+ }
+}
+
+/* Shapekeys */
+void DepsgraphRelationBuilder::build_shapekeys(ID *obdata, Key *key)
+{
+ ComponentKey obdata_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+
+ /* attach animdata to geometry */
+ build_animdata(&key->id);
+
+ if (key->adt) {
+ // TODO: this should really be handled in build_animdata, since many of these cases will need it
+ if (key->adt->action || key->adt->nla_tracks.first) {
+ ComponentKey adt_key(&key->id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(adt_key, obdata_key, DEPSREL_TYPE_OPERATION, "Animation");
+ }
+
+ /* NOTE: individual shapekey drivers are handled above already */
+ }
+
+ /* attach to geometry */
+ // XXX: aren't shapekeys now done as a pseudo-modifier on object?
+ //ComponentKey key_key(&key->id, DEPSNODE_TYPE_GEOMETRY); // FIXME: this doesn't exist
+ //add_relation(key_key, obdata_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Shapekeys");
+}
+
+/**
+ * ObData Geometry Evaluation
+ * ==========================
+ *
+ * The evaluation of geometry on objects is as follows:
+ * - The actual evaluated of the derived geometry (e.g. DerivedMesh, DispList, etc.)
+ * occurs in the Geometry component of the object which references this. This includes
+ * modifiers, and the temporary "ubereval" for geometry.
+ * - Therefore, each user of a piece of shared geometry data ends up evaluating its own
+ * version of the stuff, complete with whatever modifiers it may use.
+ *
+ * - The datablocks for the geometry data - "obdata" (e.g. ID_ME, ID_CU, ID_LT, etc.) are used for
+ * 1) calculating the bounding boxes of the geometry data,
+ * 2) aggregating inward links from other objects (e.g. for text on curve, etc.)
+ * and also for the links coming from the shapekey datablocks
+ * - Animation/Drivers affecting the parameters of the geometry are made to trigger
+ * updates on the obdata geometry component, which then trigger downstream
+ * re-evaluation of the individual instances of this geometry.
+ */
+// TODO: Materials and lighting should probably get their own component, instead of being lumped under geometry?
+void DepsgraphRelationBuilder::build_obdata_geom(Main *bmain, Scene *scene, Object *ob)
+{
+ ID *obdata = (ID *)ob->data;
+
+ /* Init operation of object-level geometry evaluation. */
+ OperationKey geom_init_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Init");
+
+ /* get nodes for result of obdata's evaluation, and geometry evaluation on object */
+ ComponentKey obdata_geom_key(obdata, DEPSNODE_TYPE_GEOMETRY);
+ ComponentKey geom_key(&ob->id, DEPSNODE_TYPE_GEOMETRY);
+
+ /* link components to each other */
+ add_relation(obdata_geom_key, geom_key, DEPSREL_TYPE_DATABLOCK, "Object Geometry Base Data");
+
+ /* Modifiers */
+ if (ob->modifiers.first) {
+ ModifierData *md;
+ OperationKey prev_mod_key;
+
+ for (md = (ModifierData *)ob->modifiers.first; md; md = md->next) {
+ const ModifierTypeInfo *mti = modifierType_getInfo((ModifierType)md->type);
+ OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+
+ if (md->prev) {
+ /* Stack relation: modifier depends on previous modifier in the stack */
+ add_relation(prev_mod_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
+ }
+ else {
+ /* Stack relation: first modifier depends on the geometry. */
+ add_relation(geom_init_key, mod_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Modifier Stack");
+ }
+
+ if (mti->updateDepsgraph) {
+ DepsNodeHandle handle = create_node_handle(mod_key);
+ mti->updateDepsgraph(md, bmain, scene, ob, &handle);
+ }
+
+ if (BKE_object_modifier_use_time(ob, md)) {
+ TimeSourceKey time_src_key;
+ add_relation(time_src_key, mod_key, DEPSREL_TYPE_TIME, "Time Source");
+ }
+
+ prev_mod_key = mod_key;
+ }
+ }
+
+ /* materials */
+ if (ob->totcol) {
+ int a;
+
+ for (a = 1; a <= ob->totcol; a++) {
+ Material *ma = give_current_material(ob, a);
+
+ if (ma)
+ build_material(&ob->id, ma);
+ }
+ }
+
+ /* geometry collision */
+ if (ELEM(ob->type, OB_MESH, OB_CURVE, OB_LATTICE)) {
+ // add geometry collider relations
+ }
+
+ /* Make sure uber update is the last in the dependencies.
+ *
+ * TODO(sergey): Get rid of this node.
+ */
+ if (ob->type != OB_ARMATURE) {
+ /* Armatures does no longer require uber node. */
+ OperationKey obdata_ubereval_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_UBEREVAL);
+ if (ob->modifiers.last) {
+ ModifierData *md = (ModifierData *)ob->modifiers.last;
+ OperationKey mod_key(&ob->id, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_GEOMETRY_MODIFIER, md->name);
+ add_relation(mod_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
+ }
+ else {
+ add_relation(geom_init_key, obdata_ubereval_key, DEPSREL_TYPE_OPERATION, "Object Geometry UberEval");
+ }
+ }
+
+ if (obdata->flag & LIB_DOIT) {
+ return;
+ }
+ obdata->flag |= LIB_DOIT;
+
+ /* Link object data evaluation node to exit operation. */
+ OperationKey obdata_geom_eval_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Geometry Eval");
+ OperationKey obdata_geom_done_key(obdata, DEPSNODE_TYPE_GEOMETRY, DEG_OPCODE_PLACEHOLDER, "Eval Done");
+ add_relation(obdata_geom_eval_key, obdata_geom_done_key, DEPSREL_TYPE_DATABLOCK, "ObData Geom Eval Done");
+
+ /* type-specific node/links */
+ switch (ob->type) {
+ case OB_MESH:
+ break;
+
+ case OB_MBALL:
+ {
+ Object *mom = BKE_mball_basis_find(scene, ob);
+
+ /* motherball - mom depends on children! */
+ if (mom != ob) {
+ /* non-motherball -> cannot be directly evaluated! */
+ ComponentKey mom_key(&mom->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(geom_key, mom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Metaball Motherball");
+ }
+ }
+ break;
+
+ case OB_CURVE:
+ case OB_FONT:
+ {
+ Curve *cu = (Curve *)obdata;
+
+ /* curve's dependencies */
+ // XXX: these needs geom data, but where is geom stored?
+ if (cu->bevobj) {
+ ComponentKey bevob_key(&cu->bevobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(bevob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Bevel");
+ }
+ if (cu->taperobj) {
+ ComponentKey taperob_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(taperob_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Curve Taper");
+ }
+ if (ob->type == OB_FONT) {
+ if (cu->textoncurve) {
+ ComponentKey textoncurve_key(&cu->taperobj->id, DEPSNODE_TYPE_GEOMETRY);
+ add_relation(textoncurve_key, geom_key, DEPSREL_TYPE_GEOMETRY_EVAL, "Text on Curve");
+ }
+ }
+ }
+ break;
+
+ case OB_SURF: /* Nurbs Surface */
+ {
+ }
+ break;
+
+ case OB_LATTICE: /* Lattice */
+ {
+ }
+ break;
+ }
+
+ /* ShapeKeys */
+ Key *key = BKE_key_from_object(ob);
+ if (key) {
+ build_shapekeys(obdata, key);
+ }
+
+ if (needs_animdata_node(obdata)) {
+ ComponentKey animation_key(obdata, DEPSNODE_TYPE_ANIMATION);
+ ComponentKey parameters_key(obdata, DEPSNODE_TYPE_PARAMETERS);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Geom Parameters");
+ }
+}
+
+/* Cameras */
+// TODO: Link scene-camera links in somehow...
+void DepsgraphRelationBuilder::build_camera(Object *ob)
+{
+ Camera *cam = (Camera *)ob->data;
+ ID *camera_id = &cam->id;
+ if (camera_id->flag & LIB_DOIT) {
+ return;
+ }
+ camera_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(camera_id, DEPSNODE_TYPE_PARAMETERS);
+
+ if (needs_animdata_node(camera_id)) {
+ ComponentKey animation_key(camera_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Camera Parameters");
+ }
+
+ /* DOF */
+ if (cam->dof_ob) {
+ ComponentKey ob_param_key(&ob->id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey dof_ob_key(&cam->dof_ob->id, DEPSNODE_TYPE_TRANSFORM);
+ add_relation(dof_ob_key, ob_param_key, DEPSREL_TYPE_TRANSFORM, "Camera DOF");
+ }
+}
+
+/* Lamps */
+void DepsgraphRelationBuilder::build_lamp(Object *ob)
+{
+ Lamp *la = (Lamp *)ob->data;
+ ID *lamp_id = &la->id;
+ if (lamp_id->flag & LIB_DOIT) {
+ return;
+ }
+ lamp_id->flag |= LIB_DOIT;
+
+ ComponentKey parameters_key(lamp_id, DEPSNODE_TYPE_PARAMETERS);
+
+ if (needs_animdata_node(lamp_id)) {
+ ComponentKey animation_key(lamp_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "Lamp Parameters");
+ }
+
+ /* lamp's nodetree */
+ if (la->nodetree) {
+ build_nodetree(lamp_id, la->nodetree);
+ ComponentKey nodetree_key(&la->nodetree->id, DEPSNODE_TYPE_PARAMETERS);
+ add_relation(nodetree_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "NTree->Lamp Parameters");
+ }
+
+ /* textures */
+ build_texture_stack(lamp_id, la->mtex);
+}
+
+void DepsgraphRelationBuilder::build_nodetree(ID *owner, bNodeTree *ntree)
+{
+ if (!ntree)
+ return;
+
+ ID *ntree_id = &ntree->id;
+
+ build_animdata(ntree_id);
+
+ /* nodetree's nodes... */
+ for (bNode *bnode = (bNode *)ntree->nodes.first; bnode; bnode = bnode->next) {
+ if (bnode->id) {
+ if (GS(bnode->id->name) == ID_MA) {
+ build_material(owner, (Material *)bnode->id);
+ }
+ else if (bnode->type == ID_TE) {
+ build_texture(owner, (Tex *)bnode->id);
+ }
+ else if (bnode->type == NODE_GROUP) {
+ bNodeTree *ntree = (bNodeTree *)bnode->id;
+ if ((ntree_id->flag & LIB_DOIT) == 0) {
+ build_nodetree(owner, ntree);
+ ntree_id->flag |= LIB_DOIT;
+ }
+ }
+ }
+ }
+
+ if (needs_animdata_node(ntree_id)) {
+ ComponentKey parameters_key(ntree_id, DEPSNODE_TYPE_PARAMETERS);
+ ComponentKey animation_key(ntree_id, DEPSNODE_TYPE_ANIMATION);
+ add_relation(animation_key, parameters_key,
+ DEPSREL_TYPE_COMPONENT_ORDER, "NTree Parameters");
+ }
+
+ // TODO: link from nodetree to owner_component?
+}
+
+/* Recursively build graph for material */
+void DepsgraphRelationBuilder::build_material(ID *owner, Material *ma)
+{
+ ID *ma_id = &ma->id;
+ if (ma_id->flag & LIB_DOIT) {
+ return;
+ }
+ ma_id->flag |= LIB_DOIT;
+
+ /* animation */
+ build_animdata(ma_id);
+
+ /* textures */
+ build_texture_stack(owner, ma->mtex);
+
+ /* material's nodetree */
+ build_nodetree(owner, ma->nodetree);
+}
+
+/* Recursively build graph for texture */
+void DepsgraphRelationBuilder::build_texture(ID *owner, Tex *tex)
+{
+ ID *tex_id = &tex->id;
+ if (tex_id->flag & LIB_DOIT) {
+ return;
+ }
+ tex_id->flag |= LIB_DOIT;
+
+ /* texture itself */
+ build_animdata(tex_id);
+
+ /* texture's nodetree */
+ build_nodetree(owner, tex->nodetree);
+}
+
+/* Texture-stack attached to some shading datablock */
+void DepsgraphRelationBuilder::build_texture_stack(ID *owner, MTex **texture_stack)
+{
+ int i;
+
+ /* for now assume that all texture-stacks have same number of max items */
+ for (i = 0; i < MAX_MTEX; i++) {
+ MTex *mtex = texture_stack[i];
+ if (mtex && mtex->tex)
+ build_texture(owner, mtex->tex);
+ }
+}
+
+void DepsgraphRelationBuilder::build_compositor(Scene *scene)
+{
+ /* For now, just a plain wrapper? */
+ build_nodetree(&scene->id, scene->nodetree);
+}
+
+void DepsgraphRelationBuilder::build_gpencil(ID *UNUSED(owner), bGPdata *gpd)
+{
+ /* animation */
+ build_animdata(&gpd->id);
+
+ // TODO: parent object (when that feature is implemented)
+}
+
+bool DepsgraphRelationBuilder::needs_animdata_node(ID *id)
+{
+ AnimData *adt = BKE_animdata_from_id(id);
+ if (adt != NULL) {
+ return adt->action != NULL;
+ }
+ return false;
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.cc b/source/blender/depsgraph/intern/depsgraph_debug.cc
new file mode 100644
index 00000000000..c876640b462
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.cc
@@ -0,0 +1,1187 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of tools for debugging the depsgraph
+ */
+
+//#include <stdlib.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_listbase.h"
+#include "BLI_ghash.h"
+#include "BLI_string.h"
+
+#include "DNA_scene_types.h"
+#include "DNA_userdef_types.h"
+
+#include "DEG_depsgraph.h"
+#include "DEG_depsgraph_debug.h"
+#include "DEG_depsgraph_build.h"
+
+#include "WM_api.h"
+#include "WM_types.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ****************** */
+/* Graphviz Debugging */
+
+static SpinLock lock;
+
+#define NL "\r\n"
+
+/* Only one should be enabled, defines whether graphviz nodes
+ * get colored by individual types or classes.
+ */
+#define COLOR_SCHEME_NODE_CLASS 1
+//#define COLOR_SCHEME_NODE_TYPE 2
+
+static const char *deg_debug_graphviz_fontname = "helvetica";
+static float deg_debug_graphviz_graph_label_size = 20.0f;
+static float deg_debug_graphviz_node_label_size = 14.0f;
+static const int deg_debug_max_colors = 12;
+#if 0
+static const char *deg_debug_colors_dark[] = {
+ "#6e8997", "#144f77", "#76945b",
+ "#216a1d", "#a76665", "#971112",
+ "#a87f49", "#0a9540", "#86768e",
+ "#462866", "#a9a965", "#753b1a",
+};
+#endif
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const char *deg_debug_colors[] = {
+ "#a6cee3", "#1f78b4", "#b2df8a",
+ "#33a02c", "#fb9a99", "#e31a1c",
+ "#fdbf6f", "#ff7f00", "#cab2d6",
+ "#6a3d9a", "#ffff99", "#b15928",
+};
+#endif
+static const char *deg_debug_colors_light[] = {
+ "#8dd3c7", "#ffffb3", "#bebada",
+ "#fb8072", "#80b1d3", "#fdb462",
+ "#b3de69", "#fccde5", "#d9d9d9",
+ "#bc80bd", "#ccebc5", "#ffed6f",
+};
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+static const int deg_debug_node_type_color_map[][2] = {
+ {DEPSNODE_TYPE_ROOT, 0},
+ {DEPSNODE_TYPE_TIMESOURCE, 1},
+ {DEPSNODE_TYPE_ID_REF, 2},
+ {DEPSNODE_TYPE_SUBGRAPH, 3},
+
+ /* Outer Types */
+ {DEPSNODE_TYPE_PARAMETERS, 4},
+ {DEPSNODE_TYPE_PROXY, 5},
+ {DEPSNODE_TYPE_ANIMATION, 6},
+ {DEPSNODE_TYPE_TRANSFORM, 7},
+ {DEPSNODE_TYPE_GEOMETRY, 8},
+ {DEPSNODE_TYPE_SEQUENCER, 9},
+ {DEPSNODE_TYPE_SHADING, 10},
+ {-1, 0}
+};
+#endif
+
+#if 0 /* unused */
+static const int deg_debug_relation_type_color_map[][2] = {
+ {DEPSREL_TYPE_STANDARD, 0},
+ {DEPSREL_TYPE_ROOT_TO_ACTIVE, 1},
+ {DEPSREL_TYPE_DATABLOCK, 2},
+ {DEPSREL_TYPE_TIME, 3},
+ {DEPSREL_TYPE_COMPONENT_ORDER, 4},
+ {DEPSREL_TYPE_OPERATION, 5},
+ {DEPSREL_TYPE_DRIVER, 6},
+ {DEPSREL_TYPE_DRIVER_TARGET, 7},
+ {DEPSREL_TYPE_TRANSFORM, 8},
+ {DEPSREL_TYPE_GEOMETRY_EVAL, 9},
+ {DEPSREL_TYPE_UPDATE, 10},
+ {DEPSREL_TYPE_UPDATE_UI, 11},
+ {-1, 0}
+};
+#endif
+
+static int deg_debug_node_color_index(const DepsNode *node)
+{
+#ifdef COLOR_SCHEME_NODE_CLASS
+ /* Some special types. */
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ return 5;
+ case DEPSNODE_TYPE_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->is_noop())
+ return 8;
+ }
+
+ default:
+ break;
+ }
+ /* Do others based on class. */
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_OPERATION:
+ return 4;
+ case DEPSNODE_CLASS_COMPONENT:
+ return 1;
+ default:
+ return 9;
+ }
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == node->type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+#endif
+}
+
+struct DebugContext {
+ FILE *file;
+ bool show_tags;
+ bool show_eval_priority;
+};
+
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...) ATTR_PRINTF_FORMAT(2, 3);
+static void deg_debug_fprintf(const DebugContext &ctx, const char *fmt, ...)
+{
+ va_list args;
+ va_start(args, fmt);
+ vfprintf(ctx.file, fmt, args);
+ va_end(args);
+}
+
+static void deg_debug_graphviz_legend_color(const DebugContext &ctx,
+ const char *name,
+ const char *color)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD BGCOLOR=\"%s\"></TD>", color);
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+
+#if 0
+static void deg_debug_graphviz_legend_line(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ /* XXX TODO */
+ deg_debug_fprintf(ctx, "" NL);
+}
+
+static void deg_debug_graphviz_legend_cluster(const DebugContext &ctx,
+ const char *name,
+ const char *color,
+ const char *style)
+{
+ deg_debug_fprintf(ctx, "<TR>");
+ deg_debug_fprintf(ctx, "<TD>%s</TD>", name);
+ deg_debug_fprintf(ctx, "<TD CELLPADDING=\"4\"><TABLE BORDER=\"1\" CELLBORDER=\"0\" CELLSPACING=\"0\" CELLPADDING=\"0\">");
+ deg_debug_fprintf(ctx, "<TR><TD BGCOLOR=\"%s\"></TD></TR>", color);
+ deg_debug_fprintf(ctx, "</TABLE></TD>");
+ deg_debug_fprintf(ctx, "</TR>" NL);
+}
+#endif
+
+static void deg_debug_graphviz_legend(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "{" NL);
+ deg_debug_fprintf(ctx, "rank = sink;" NL);
+ deg_debug_fprintf(ctx, "Legend [shape=none, margin=0, label=<" NL);
+ deg_debug_fprintf(ctx, " <TABLE BORDER=\"0\" CELLBORDER=\"1\" CELLSPACING=\"0\" CELLPADDING=\"4\">" NL);
+ deg_debug_fprintf(ctx, "<TR><TD COLSPAN=\"2\"><B>Legend</B></TD></TR>" NL);
+
+#ifdef COLOR_SCHEME_NODE_CLASS
+ const char **colors = deg_debug_colors_light;
+ deg_debug_graphviz_legend_color(ctx, "Operation", colors[4]);
+ deg_debug_graphviz_legend_color(ctx, "Component", colors[1]);
+ deg_debug_graphviz_legend_color(ctx, "ID Node", colors[5]);
+ deg_debug_graphviz_legend_color(ctx, "NOOP", colors[8]);
+#endif
+
+#ifdef COLOR_SCHEME_NODE_TYPE
+ const int (*pair)[2];
+ for (pair = deg_debug_node_type_color_map; (*pair)[0] >= 0; ++pair) {
+ DepsNodeFactory *nti = DEG_get_node_factory((eDepsNode_Type)(*pair)[0]);
+ deg_debug_graphviz_legend_color(ctx,
+ nti->tname().c_str(),
+ deg_debug_colors_light[(*pair)[1] % deg_debug_max_colors]);
+ }
+#endif
+
+ deg_debug_fprintf(ctx, "</TABLE>" NL);
+ deg_debug_fprintf(ctx, ">" NL);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#if 0 /* unused */
+static int deg_debug_relation_type_color_index(eDepsRelation_Type type)
+{
+ const int (*pair)[2];
+ for (pair = deg_debug_relation_type_color_map; (*pair)[0] >= 0; ++pair) {
+ if ((*pair)[0] == type) {
+ return (*pair)[1];
+ }
+ }
+ return -1;
+}
+#endif
+
+static void deg_debug_graphviz_node_color(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *color_default = "black";
+ const char *color_modified = "orangered4";
+ const char *color_update = "dodgerblue3";
+ const char *color = color_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ color = color_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ color = color_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%s\"", color);
+}
+
+static void deg_debug_graphviz_node_penwidth(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ float penwidth_default = 1.0f;
+ float penwidth_modified = 4.0f;
+ float penwidth_update = 4.0f;
+ float penwidth = penwidth_default;
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & DEPSOP_FLAG_DIRECTLY_MODIFIED) {
+ penwidth = penwidth_modified;
+ }
+ else if (op_node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ penwidth = penwidth_update;
+ }
+ }
+ }
+ deg_debug_fprintf(ctx, "\"%f\"", penwidth);
+}
+
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ int color_index = deg_debug_node_color_index(node);
+ const char *fillcolor = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ deg_debug_fprintf(ctx, "\"%s\"", fillcolor);
+}
+
+#if 0 /* implementation using stripes, a bit too noisy ... */
+static void deg_debug_graphviz_node_fillcolor(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *defaultcolor = "gainsboro";
+ const char *color_needs_update = "orange";
+ const int num_stripes = 10;
+ int color_index = deg_debug_node_color_index(node);
+ const char *base_color = color_index < 0 ? defaultcolor : deg_debug_colors_light[color_index % deg_debug_max_colors];
+ if (ctx.show_tags &&
+ (node->flag & (DEPSNODE_FLAG_DIRECTLY_MODIFIED | DEPSNODE_FLAG_NEEDS_UPDATE))) {
+ deg_debug_fprintf(ctx, "\"");
+ for (int i = 0; i < num_stripes; ++i) {
+ if (i > 0) {
+ deg_debug_fprintf(ctx, ":");
+ }
+ deg_debug_fprintf(ctx, "%s:%s", base_color, color_needs_update);
+ }
+ deg_debug_fprintf(ctx, "\"");
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", base_color);
+ }
+}
+#endif
+
+static void deg_debug_graphviz_relation_color(const DebugContext &ctx,
+ const DepsRelation *UNUSED(rel))
+{
+ const char *defaultcolor = "black";
+#if 0 /* disabled for now, edge colors are hardly distinguishable */
+ int color = deg_debug_relation_type_color_index(rel->type);
+ if (color < 0) {
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+ }
+ else {
+ deg_debug_fprintf(ctx, "\"%s\"", deg_debug_colors_dark[color % deg_debug_max_colors]);
+ }
+#else
+ deg_debug_fprintf(ctx, "%s", defaultcolor);
+#endif
+}
+
+static void deg_debug_graphviz_node_style(const DebugContext &ctx, const DepsNode *node)
+{
+ const char *base_style = "filled"; /* default style */
+ if (ctx.show_tags) {
+ if (node->tclass == DEPSNODE_CLASS_OPERATION) {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->flag & (DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE)) {
+ base_style = "striped";
+ }
+ }
+ }
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_GENERIC:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_COMPONENT:
+ deg_debug_fprintf(ctx, "\"%s\"", base_style);
+ break;
+ case DEPSNODE_CLASS_OPERATION:
+ deg_debug_fprintf(ctx, "\"%s,rounded\"", base_style);
+ break;
+ }
+}
+
+static void deg_debug_graphviz_node_single(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ const char *shape = "box";
+ string name = node->identifier();
+ float priority = -1.0f;
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ if (ctx.show_eval_priority && node->tclass == DEPSNODE_CLASS_OPERATION) {
+ priority = ((OperationDepsNode *)node)->eval_priority;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>", name);
+ if (priority >= 0.0f) {
+ deg_debug_fprintf(ctx, "label=<%s<BR/>(<I>%.2f</I>)>",
+ name.c_str(),
+ priority);
+ }
+ else {
+ deg_debug_fprintf(ctx, "label=<%s>", name.c_str());
+ }
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, ",shape=%s", shape);
+ deg_debug_fprintf(ctx, ",style="); deg_debug_graphviz_node_style(ctx, node);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_node_color(ctx, node);
+ deg_debug_fprintf(ctx, ",fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node);
+ deg_debug_fprintf(ctx, ",penwidth="); deg_debug_graphviz_node_penwidth(ctx, node);
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_begin(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ string name = node->identifier().c_str();
+ if (node->type == DEPSNODE_TYPE_ID_REF) {
+ IDDepsNode *id_node = (IDDepsNode *)node;
+ char buf[256];
+ BLI_snprintf(buf, sizeof(buf), " (Layers: %d)", id_node->layers);
+ name += buf;
+ }
+ deg_debug_fprintf(ctx, "// %s\n", name.c_str());
+ deg_debug_fprintf(ctx, "subgraph \"cluster_%p\" {" NL, node);
+// deg_debug_fprintf(ctx, "label=<<B>%s</B>>;" NL, name);
+ deg_debug_fprintf(ctx, "label=<%s>;" NL, name.c_str());
+ deg_debug_fprintf(ctx, "fontname=\"%s\";" NL, deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, "fontsize=%f;" NL, deg_debug_graphviz_node_label_size);
+ deg_debug_fprintf(ctx, "style="); deg_debug_graphviz_node_style(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "color="); deg_debug_graphviz_node_color(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "fillcolor="); deg_debug_graphviz_node_fillcolor(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ deg_debug_fprintf(ctx, "penwidth="); deg_debug_graphviz_node_penwidth(ctx, node); deg_debug_fprintf(ctx, ";" NL);
+ /* dummy node, so we can add edges between clusters */
+ deg_debug_fprintf(ctx, "\"node_%p\"", node);
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "shape=%s", "point");
+ deg_debug_fprintf(ctx, ",style=%s", "invis");
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_node_cluster_end(const DebugContext &ctx)
+{
+ deg_debug_fprintf(ctx, "}" NL);
+ deg_debug_fprintf(ctx, NL);
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph);
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph);
+
+static void deg_debug_graphviz_node(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ if (id_node->components.empty()) {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ else {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node(ctx, comp);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ deg_debug_graphviz_graph_nodes(ctx, sub_node->graph);
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ case DEPSNODE_TYPE_SHADING:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (!comp_node->operations.empty()) {
+ deg_debug_graphviz_node_cluster_begin(ctx, node);
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ const DepsNode *op_node = it->second;
+ deg_debug_graphviz_node(ctx, op_node);
+ }
+ deg_debug_graphviz_node_cluster_end(ctx);
+ }
+ else {
+ deg_debug_graphviz_node_single(ctx, node);
+ }
+ break;
+ }
+ default:
+ deg_debug_graphviz_node_single(ctx, node);
+ break;
+ }
+}
+
+static bool deg_debug_graphviz_is_cluster(const DepsNode *node)
+{
+ switch (node->type) {
+ case DEPSNODE_TYPE_ID_REF:
+ {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ return !id_node->components.empty();
+ }
+ case DEPSNODE_TYPE_SUBGRAPH:
+ {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ return sub_node->graph != NULL;
+ }
+ case DEPSNODE_TYPE_PARAMETERS:
+ case DEPSNODE_TYPE_ANIMATION:
+ case DEPSNODE_TYPE_TRANSFORM:
+ case DEPSNODE_TYPE_PROXY:
+ case DEPSNODE_TYPE_GEOMETRY:
+ case DEPSNODE_TYPE_SEQUENCER:
+ case DEPSNODE_TYPE_EVAL_POSE:
+ case DEPSNODE_TYPE_BONE:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ return !comp_node->operations.empty();
+ }
+ default:
+ return false;
+ }
+}
+
+static bool deg_debug_graphviz_is_owner(const DepsNode *node,
+ const DepsNode *other)
+{
+ switch (node->tclass) {
+ case DEPSNODE_CLASS_COMPONENT:
+ {
+ ComponentDepsNode *comp_node = (ComponentDepsNode *)node;
+ if (comp_node->owner == other)
+ return true;
+ break;
+ }
+ case DEPSNODE_CLASS_OPERATION:
+ {
+ OperationDepsNode *op_node = (OperationDepsNode *)node;
+ if (op_node->owner == other)
+ return true;
+ else if (op_node->owner->owner == other)
+ return true;
+ break;
+ }
+ default: break;
+ }
+ return false;
+}
+
+static void deg_debug_graphviz_node_relations(const DebugContext &ctx,
+ const DepsNode *node)
+{
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->inlinks, rel)
+ {
+ const DepsNode *tail = rel->to; /* same as node */
+ const DepsNode *head = rel->from;
+ deg_debug_fprintf(ctx, "// %s -> %s\n",
+ head->identifier().c_str(),
+ tail->identifier().c_str());
+ deg_debug_fprintf(ctx, "\"node_%p\"", head);
+ deg_debug_fprintf(ctx, " -> ");
+ deg_debug_fprintf(ctx, "\"node_%p\"", tail);
+
+ deg_debug_fprintf(ctx, "[");
+ deg_debug_fprintf(ctx, "label=\"%s\"", rel->name);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",color="); deg_debug_graphviz_relation_color(ctx, rel);
+ /* NOTE: edge from node to own cluster is not possible and gives graphviz
+ * warning, avoid this here by just linking directly to the invisible
+ * placeholder node
+ */
+ if (deg_debug_graphviz_is_cluster(tail) && !deg_debug_graphviz_is_owner(head, tail)) {
+ deg_debug_fprintf(ctx, ",ltail=\"cluster_%p\"", tail);
+ }
+ if (deg_debug_graphviz_is_cluster(head) && !deg_debug_graphviz_is_owner(tail, head)) {
+ deg_debug_fprintf(ctx, ",lhead=\"cluster_%p\"", head);
+ }
+ deg_debug_fprintf(ctx, "];" NL);
+ deg_debug_fprintf(ctx, NL);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+#if 0
+ if (node->tclass == DEPSNODE_CLASS_COMPONENT) {
+ const ComponentDepsNode *comp_node = (const ComponentDepsNode *)node;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_ID_REF) {
+ const IDDepsNode *id_node = (const IDDepsNode *)node;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ const ComponentDepsNode *comp = it->second;
+ deg_debug_graphviz_node_relations(ctx, comp);
+ }
+ }
+ else if (node->type == DEPSNODE_TYPE_SUBGRAPH) {
+ SubgraphDepsNode *sub_node = (SubgraphDepsNode *)node;
+ if (sub_node->graph) {
+ deg_debug_graphviz_graph_relations(ctx, sub_node->graph);
+ }
+ }
+#endif
+}
+
+static void deg_debug_graphviz_graph_nodes(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+ if (graph->root_node) {
+ deg_debug_graphviz_node(ctx, graph->root_node);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *node = it->second;
+ deg_debug_graphviz_node(ctx, node);
+ }
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node(ctx, time_source);
+ }
+}
+
+static void deg_debug_graphviz_graph_relations(const DebugContext &ctx,
+ const Depsgraph *graph)
+{
+#if 0
+ if (graph->root_node) {
+ deg_debug_graphviz_node_relations(ctx, graph->root_node);
+ }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ DepsNode *id_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, id_node);
+ }
+#else
+ /* XXX not in use yet */
+// for (Depsgraph::OperationNodes::const_iterator it = graph->all_opnodes.begin();
+// it != graph->all_opnodes.end();
+// ++it)
+// {
+// OperationDepsNode *op_node = *it;
+// deg_debug_graphviz_node_relations(ctx, op_node);
+// }
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ deg_debug_graphviz_node_relations(ctx, op_node);
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ deg_debug_graphviz_node_relations(ctx, time_source);
+ }
+#endif
+}
+
+void DEG_debug_graphviz(const Depsgraph *graph, FILE *f, const char *label, bool show_eval)
+{
+#if 0 /* generate shaded color set */
+ static char colors[][3] = {{0xa6, 0xce, 0xe3},{0x1f, 0x78, 0xb4},{0xb2, 0xdf, 0x8a},{0x33, 0xa0, 0x2c},
+ {0xfb, 0x9a, 0x99},{0xe3, 0x1a, 0x1c},{0xfd, 0xbf, 0x6f},{0xff, 0x7f, 0x00},
+ {0xca, 0xb2, 0xd6},{0x6a, 0x3d, 0x9a},{0xff, 0xff, 0x99},{0xb1, 0x59, 0x28}};
+ int i;
+ const float factor = 0.666f;
+ for (i=0; i < 12; ++i)
+ printf("\"#%x%x%x\"\n", (char)(colors[i][0] * factor), (char)(colors[i][1] * factor), (char)(colors[i][2] * factor));
+#endif
+
+ if (!graph) {
+ return;
+ }
+
+ DebugContext ctx;
+ ctx.file = f;
+ ctx.show_tags = show_eval;
+ ctx.show_eval_priority = show_eval;
+
+ deg_debug_fprintf(ctx, "digraph depgraph {" NL);
+ deg_debug_fprintf(ctx, "rankdir=LR;" NL);
+ deg_debug_fprintf(ctx, "graph [");
+ deg_debug_fprintf(ctx, "compound=true");
+ deg_debug_fprintf(ctx, ",labelloc=\"t\"");
+ deg_debug_fprintf(ctx, ",fontsize=%f", deg_debug_graphviz_graph_label_size);
+ deg_debug_fprintf(ctx, ",fontname=\"%s\"", deg_debug_graphviz_fontname);
+ deg_debug_fprintf(ctx, ",label=\"%s\"", label);
+ deg_debug_fprintf(ctx, ",splines=ortho");
+ deg_debug_fprintf(ctx, ",overlap=scalexy"); // XXX: only when using neato
+ deg_debug_fprintf(ctx, "];" NL);
+
+ deg_debug_graphviz_graph_nodes(ctx, graph);
+ deg_debug_graphviz_graph_relations(ctx, graph);
+
+ deg_debug_graphviz_legend(ctx);
+
+ deg_debug_fprintf(ctx, "}" NL);
+}
+
+#undef NL
+
+/* ************************************************ */
+
+static string get_component_name(eDepsNode_Type type, const string &name = "")
+{
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ if (name.empty()) {
+ return string(factory->tname());
+ }
+ else {
+ return string(factory->tname()) + " | " + name;
+ }
+}
+
+static void times_clear(DepsgraphStatsTimes &times)
+{
+ times.duration_last = 0.0f;
+}
+
+static void times_add(DepsgraphStatsTimes &times, float time)
+{
+ times.duration_last += time;
+}
+
+void DepsgraphDebug::eval_begin(const EvaluationContext *UNUSED(eval_ctx))
+{
+ /* TODO(sergey): Stats are currently globally disabled. */
+ /* verify_stats(); */
+ reset_stats();
+}
+
+void DepsgraphDebug::eval_end(const EvaluationContext *UNUSED(eval_ctx))
+{
+ WM_main_add_notifier(NC_SPACE | ND_SPACE_INFO_REPORT, NULL);
+}
+
+void DepsgraphDebug::eval_step(const EvaluationContext *UNUSED(eval_ctx),
+ const char *message)
+{
+#ifdef DEG_DEBUG_BUILD
+ if (deg_debug_eval_cb)
+ deg_debug_eval_cb(deg_debug_eval_userdata, message);
+#else
+ (void)message; /* Ignored. */
+#endif
+}
+
+void DepsgraphDebug::task_started(Depsgraph *graph,
+ const OperationDepsNode *node)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_clear(id_stats->times);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_clear(comp_stats->times);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+void DepsgraphDebug::task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time)
+{
+ if (stats) {
+ BLI_spin_lock(&graph->lock);
+
+ ComponentDepsNode *comp = node->owner;
+ ID *id = comp->owner->id;
+
+ DepsgraphStatsID *id_stats = get_id_stats(id, true);
+ times_add(id_stats->times, time);
+
+ /* XXX TODO use something like: if (id->flag & ID_DEG_DETAILS) {...} */
+ if (0) {
+ /* XXX component name usage needs cleanup! currently mixes identifier and description strings! */
+ DepsgraphStatsComponent *comp_stats = get_component_stats(id, get_component_name(comp->type, comp->name), true);
+ times_add(comp_stats->times, time);
+ }
+
+ BLI_spin_unlock(&graph->lock);
+ }
+}
+
+/* ********** */
+/* Statistics */
+
+DepsgraphStats *DepsgraphDebug::stats = NULL;
+
+/* GHash callback */
+static void deg_id_stats_free(void *val)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)val;
+
+ if (id_stats) {
+ BLI_freelistN(&id_stats->components);
+ MEM_freeN(id_stats);
+ }
+}
+
+void DepsgraphDebug::stats_init()
+{
+ if (!stats) {
+ stats = (DepsgraphStats *)MEM_callocN(sizeof(DepsgraphStats), "Depsgraph Stats");
+ stats->id_stats = BLI_ghash_new(BLI_ghashutil_ptrhash, BLI_ghashutil_ptrcmp, "Depsgraph ID Stats Hash");
+ }
+}
+
+void DepsgraphDebug::stats_free()
+{
+ if (stats) {
+ BLI_ghash_free(stats->id_stats, NULL, deg_id_stats_free);
+ MEM_freeN(stats);
+ stats = NULL;
+ }
+}
+
+void DepsgraphDebug::verify_stats()
+{
+ stats_init();
+}
+
+void DepsgraphDebug::reset_stats()
+{
+ if (!stats) {
+ return;
+ }
+
+ /* XXX this doesn't work, will immediately clear all info,
+ * since most depsgraph updates have none or very few updates to handle.
+ *
+ * Could consider clearing only zero-user ID blocks here
+ */
+// BLI_ghash_clear(stats->id_stats, NULL, deg_id_stats_free);
+}
+
+DepsgraphStatsID *DepsgraphDebug::get_id_stats(ID *id, bool create)
+{
+ DepsgraphStatsID *id_stats = (DepsgraphStatsID *)BLI_ghash_lookup(stats->id_stats, id);
+
+ if (!id_stats && create) {
+ id_stats = (DepsgraphStatsID *)MEM_callocN(sizeof(DepsgraphStatsID), "Depsgraph ID Stats");
+ id_stats->id = id;
+
+ BLI_ghash_insert(stats->id_stats, id, id_stats);
+ }
+
+ return id_stats;
+}
+
+DepsgraphStatsComponent *DepsgraphDebug::get_component_stats(DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create)
+{
+ DepsgraphStatsComponent *comp_stats;
+ for (comp_stats = (DepsgraphStatsComponent *)id_stats->components.first;
+ comp_stats != NULL;
+ comp_stats = comp_stats->next) {
+ if (STREQ(comp_stats->name, name.c_str()))
+ break;
+ }
+ if (!comp_stats && create) {
+ comp_stats = (DepsgraphStatsComponent *)MEM_callocN(sizeof(DepsgraphStatsComponent), "Depsgraph Component Stats");
+ BLI_strncpy(comp_stats->name, name.c_str(), sizeof(comp_stats->name));
+ BLI_addtail(&id_stats->components, comp_stats);
+ }
+ return comp_stats;
+}
+
+/* ------------------------------------------------ */
+
+DepsgraphStats *DEG_stats(void)
+{
+ return DepsgraphDebug::stats;
+}
+
+void DEG_stats_verify()
+{
+ DepsgraphDebug::verify_stats();
+}
+
+DepsgraphStatsID *DEG_stats_id(ID *id)
+{
+ if (!DepsgraphDebug::stats) {
+ return NULL;
+ }
+ return DepsgraphDebug::get_id_stats(id, false);
+}
+
+bool DEG_debug_compare(const struct Depsgraph *graph1,
+ const struct Depsgraph *graph2)
+{
+ BLI_assert(graph1 != NULL);
+ BLI_assert(graph2 != NULL);
+ if (graph1->operations.size() != graph2->operations.size()) {
+ return false;
+ }
+ /* TODO(sergey): Currently we only do real stupid check,
+ * which is fast but which isn't 100% reliable.
+ *
+ * Would be cool to make it more robust, but it's good enough
+ * for now. Also, proper graph check is actually NP-complex
+ * problem..
+ */
+ return true;
+}
+
+bool DEG_debug_scene_relations_validate(Main *bmain,
+ Scene *scene)
+{
+ Depsgraph *depsgraph = DEG_graph_new();
+ bool valid = true;
+ DEG_graph_build_from_scene(depsgraph, bmain, scene);
+ if (!DEG_debug_compare(depsgraph, scene->depsgraph)) {
+ fprintf(stderr, "ERROR! Depsgraph wasn't tagged for update when it should have!\n");
+ BLI_assert(!"This should not happen!");
+ valid = false;
+ }
+ DEG_graph_free(depsgraph);
+ return valid;
+}
+
+bool DEG_debug_consistency_check(Depsgraph *graph)
+{
+ /* Validate links exists in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->outlinks.begin();
+ tmp_rel != node->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->to->inlinks.begin();
+ tmp_rel != rel->to->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in outgoing direction but not in incoming (%d vs. %d).\n",
+ counter1, counter2);
+ return false;
+ }
+ }
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+
+ int counter1 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = node->inlinks.begin();
+ tmp_rel != node->inlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter1;
+ }
+ }
+
+ int counter2 = 0;
+ for (OperationDepsNode::Relations::const_iterator tmp_rel = rel->from->outlinks.begin();
+ tmp_rel != rel->from->outlinks.end();
+ ++tmp_rel)
+ {
+ if (*tmp_rel == rel) {
+ ++counter2;
+ }
+ }
+
+ if (counter1 != counter2) {
+ printf("Relation exists in incoming direction but not in outcoming (%d vs. %d).\n",
+ counter1, counter2);
+ }
+ }
+ }
+
+ /* Validate node valency calculated in both directions. */
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ node->num_links_pending = 0;
+ node->done = 0;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ if (node->done) {
+ printf("Node %s is twice in the operations!\n",
+ node->identifier().c_str());
+ return false;
+ }
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->num_links_pending < to->inlinks.size());
+ ++to->num_links_pending;
+ }
+ }
+ node->done = 1;
+ }
+
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ int num_links_pending = 0;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ ++num_links_pending;
+ }
+ }
+ if (node->num_links_pending != num_links_pending) {
+ printf("Valency mismatch: %s, %u != %d\n",
+ node->identifier().c_str(),
+ node->num_links_pending, num_links_pending);
+ printf("Number of inlinks: %d\n", (int)node->inlinks.size());
+ return false;
+ }
+ }
+ return true;
+}
+
+/* ------------------------------------------------ */
+
+/**
+ * Obtain simple statistics about the complexity of the depsgraph
+ * \param[out] r_outer The number of outer nodes in the graph
+ * \param[out] r_operations The number of operation nodes in the graph
+ * \param[out] r_relations The number of relations between (executable) nodes in the graph
+ */
+void DEG_stats_simple(const Depsgraph *graph, size_t *r_outer,
+ size_t *r_operations, size_t *r_relations)
+{
+ /* number of operations */
+ if (r_operations) {
+ /* All operations should be in this list, allowing us to count the total
+ * number of nodes.
+ */
+ *r_operations = graph->operations.size();
+ }
+
+ /* Count number of outer nodes and/or relations between these. */
+ if (r_outer || r_relations) {
+ size_t tot_outer = 0;
+ size_t tot_rels = 0;
+
+ for (Depsgraph::IDNodeMap::const_iterator it = graph->id_hash.begin();
+ it != graph->id_hash.end();
+ ++it)
+ {
+ IDDepsNode *id_node = it->second;
+ tot_outer++;
+ for (IDDepsNode::ComponentMap::const_iterator it = id_node->components.begin();
+ it != id_node->components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ tot_outer++;
+ for (ComponentDepsNode::OperationMap::const_iterator it = comp_node->operations.begin();
+ it != comp_node->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op_node = it->second;
+ tot_rels += op_node->inlinks.size();
+ }
+ }
+ }
+
+ TimeSourceDepsNode *time_source = graph->find_time_source(NULL);
+ if (time_source != NULL) {
+ tot_rels += time_source->inlinks.size();
+ }
+
+ if (r_relations) *r_relations = tot_rels;
+ if (r_outer) *r_outer = tot_outer;
+ }
+}
+
diff --git a/source/blender/depsgraph/intern/depsgraph_debug.h b/source/blender/depsgraph/intern/depsgraph_debug.h
new file mode 100644
index 00000000000..aed36f6add6
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_debug.h
@@ -0,0 +1,83 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DEPSGRAPH_DEBUG_H__
+#define __DEPSGRAPH_DEBUG_H__
+
+#include "depsgraph_types.h"
+
+extern "C" {
+#include "BKE_global.h"
+}
+
+struct DepsgraphStats;
+struct DepsgraphStatsID;
+struct DepsgraphStatsComponent;
+struct DepsgraphSettings;
+struct EvaluationContext;
+struct OperationDepsNode;
+
+struct Depsgraph;
+
+struct DepsgraphDebug {
+ static DepsgraphStats *stats;
+
+ static void stats_init();
+ static void stats_free();
+
+ static void verify_stats();
+ static void reset_stats();
+
+ static void eval_begin(const EvaluationContext *eval_ctx);
+ static void eval_end(const EvaluationContext *eval_ctx);
+ static void eval_step(const EvaluationContext *eval_ctx,
+ const char *message);
+
+ static void task_started(Depsgraph *graph, const OperationDepsNode *node);
+ static void task_completed(Depsgraph *graph,
+ const OperationDepsNode *node,
+ double time);
+
+ static DepsgraphStatsID *get_id_stats(ID *id, bool create);
+ static DepsgraphStatsComponent *get_component_stats(DepsgraphStatsID *id_stats,
+ const string &name,
+ bool create);
+ static DepsgraphStatsComponent *get_component_stats(ID *id,
+ const string &name,
+ bool create)
+ {
+ return get_component_stats(get_id_stats(id, create), name, create);
+ }
+};
+
+#define DEG_DEBUG_PRINTF(...) \
+ { \
+ if (G.debug & G_DEBUG_DEPSGRAPH) { \
+ fprintf(stderr, __VA_ARGS__); \
+ } \
+ } \
+
+#endif /* __DEPSGRAPH_DEBUG_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_eval.cc b/source/blender/depsgraph/intern/depsgraph_eval.cc
new file mode 100644
index 00000000000..11fd02376a3
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_eval.cc
@@ -0,0 +1,386 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Evaluation engine entrypoints for Depsgraph Engine
+ */
+
+#include "MEM_guardedalloc.h"
+
+#include "PIL_time.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_task.h"
+
+#include "BKE_depsgraph.h"
+#include "BKE_scene.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "atomic_ops.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_debug.h"
+
+#ifdef WITH_LEGACY_DEPSGRAPH
+static bool use_legacy_depsgraph = true;
+#endif
+
+bool DEG_depsgraph_use_legacy(void)
+{
+#ifdef DISABLE_NEW_DEPSGRAPH
+ return true;
+#elif defined(WITH_LEGACY_DEPSGRAPH)
+ return use_legacy_depsgraph;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+ return false;
+#endif
+}
+
+void DEG_depsgraph_switch_to_legacy(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = true;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+void DEG_depsgraph_switch_to_new(void)
+{
+#ifdef WITH_LEGACY_DEPSGRAPH
+ use_legacy_depsgraph = false;
+#else
+ BLI_assert(!"Should not be used with new depsgraph");
+#endif
+}
+
+/* ****************** */
+/* Evaluation Context */
+
+/* Create new evaluation context. */
+EvaluationContext *DEG_evaluation_context_new(int mode)
+{
+ EvaluationContext *eval_ctx =
+ (EvaluationContext *)MEM_callocN(sizeof(EvaluationContext),
+ "EvaluationContext");
+ eval_ctx->mode = mode;
+ return eval_ctx;
+}
+
+/**
+ * Initialize evaluation context.
+ * Used by the areas which currently overrides the context or doesn't have
+ * access to a proper one.
+ */
+void DEG_evaluation_context_init(EvaluationContext *eval_ctx, int mode)
+{
+ eval_ctx->mode = mode;
+}
+
+/* Free evaluation context. */
+void DEG_evaluation_context_free(EvaluationContext *eval_ctx)
+{
+ MEM_freeN(eval_ctx);
+}
+
+/* ********************** */
+/* Evaluation Entrypoints */
+
+/* Forward declarations. */
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers);
+
+struct DepsgraphEvalState {
+ EvaluationContext *eval_ctx;
+ Depsgraph *graph;
+ int layers;
+};
+
+static void deg_task_run_func(TaskPool *pool,
+ void *taskdata,
+ int UNUSED(threadid))
+{
+ DepsgraphEvalState *state = (DepsgraphEvalState *)BLI_task_pool_userdata(pool);
+ OperationDepsNode *node = (OperationDepsNode *)taskdata;
+
+ if (!node->is_noop()) {
+ /* Get context. */
+ // TODO: who initialises this? "Init" operations aren't able to initialise it!!!
+ /* TODO(sergey): Wedon't use component contexts at this moment. */
+ /* ComponentDepsNode *comp = node->owner; */
+ BLI_assert(node->owner != NULL);
+
+ /* Take note of current time. */
+ double start_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_started(state->graph, node);
+
+ /* Should only be the case for NOOPs, which never get to this point. */
+ BLI_assert(node->evaluate);
+
+ /* Perform operation. */
+ node->evaluate(state->eval_ctx);
+
+ /* Note how long this took. */
+ double end_time = PIL_check_seconds_timer();
+ DepsgraphDebug::task_completed(state->graph,
+ node,
+ end_time - start_time);
+ }
+
+ schedule_children(pool, state->graph, node, state->layers);
+}
+
+static void calculate_pending_parents(Depsgraph *graph, int layers)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ IDDepsNode *id_node = node->owner->owner;
+
+ node->num_links_pending = 0;
+ node->scheduled = false;
+
+ /* count number of inputs that need updates */
+ if ((id_node->layers & layers) != 0 &&
+ (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION &&
+ (rel->flag & DEPSREL_FLAG_CYCLIC) == 0)
+ {
+ OperationDepsNode *from = (OperationDepsNode *)rel->from;
+ IDDepsNode *id_from_node = from->owner->owner;
+ if ((id_from_node->layers & layers) != 0 &&
+ (from->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ ++node->num_links_pending;
+ }
+ }
+ }
+ }
+ }
+}
+
+static void calculate_eval_priority(OperationDepsNode *node)
+{
+ if (node->done) {
+ return;
+ }
+ node->done = 1;
+
+ if (node->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ /* XXX standard cost of a node, could be estimated somewhat later on */
+ const float cost = 1.0f;
+ /* NOOP nodes have no cost */
+ node->eval_priority = node->is_noop() ? cost : 0.0f;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ BLI_assert(to->type == DEPSNODE_TYPE_OPERATION);
+ calculate_eval_priority(to);
+ node->eval_priority += to->eval_priority;
+ }
+ }
+ else {
+ node->eval_priority = 0.0f;
+ }
+}
+
+static void schedule_graph(TaskPool *pool,
+ Depsgraph *graph,
+ const int layers)
+{
+ BLI_spin_lock(&graph->lock);
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ if ((node->flag & DEPSOP_FLAG_NEEDS_UPDATE) &&
+ node->num_links_pending == 0 &&
+ (id_node->layers & layers) != 0)
+ {
+ BLI_task_pool_push(pool, deg_task_run_func, node, false, TASK_PRIORITY_LOW);
+ node->scheduled = true;
+ }
+ }
+ BLI_spin_unlock(&graph->lock);
+}
+
+static void schedule_children(TaskPool *pool,
+ Depsgraph *graph,
+ OperationDepsNode *node,
+ const int layers)
+{
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *child = (OperationDepsNode *)rel->to;
+ BLI_assert(child->type == DEPSNODE_TYPE_OPERATION);
+
+ if (child->scheduled) {
+ /* Happens when having cyclic dependencies. */
+ continue;
+ }
+
+ IDDepsNode *id_child = child->owner->owner;
+ if ((id_child->layers & layers) != 0 &&
+ (child->flag & DEPSOP_FLAG_NEEDS_UPDATE) != 0)
+ {
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ BLI_assert(child->num_links_pending > 0);
+ atomic_sub_uint32(&child->num_links_pending, 1);
+ }
+
+ if (child->num_links_pending == 0) {
+ BLI_spin_lock(&graph->lock);
+ bool need_schedule = !child->scheduled;
+ child->scheduled = true;
+ BLI_spin_unlock(&graph->lock);
+
+ if (need_schedule) {
+ BLI_task_pool_push(pool, deg_task_run_func, child, false, TASK_PRIORITY_LOW);
+ }
+ }
+ }
+ }
+}
+
+/**
+ * Evaluate all nodes tagged for updating,
+ * \warning This is usually done as part of main loop, but may also be
+ * called from frame-change update.
+ *
+ * \note Time sources should be all valid!
+ */
+void DEG_evaluate_on_refresh_ex(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ const int layers)
+{
+ /* Generate base evaluation context, upon which all the others are derived. */
+ // TODO: this needs both main and scene access...
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* Set time for the current graph evaluation context. */
+ TimeSourceDepsNode *time_src = graph->find_time_source();
+ eval_ctx->ctime = time_src->cfra;
+
+ /* XXX could use a separate pool for each eval context */
+ DepsgraphEvalState state;
+ state.eval_ctx = eval_ctx;
+ state.graph = graph;
+ state.layers = layers;
+
+ TaskScheduler *task_scheduler = BLI_task_scheduler_get();
+ TaskPool *task_pool = BLI_task_pool_create(task_scheduler, &state);
+
+ calculate_pending_parents(graph, layers);
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* Calculate priority for operation nodes. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ calculate_eval_priority(node);
+ }
+
+ DepsgraphDebug::eval_begin(eval_ctx);
+
+ schedule_graph(task_pool, graph, layers);
+
+ BLI_task_pool_work_and_wait(task_pool);
+ BLI_task_pool_free(task_pool);
+
+ DepsgraphDebug::eval_end(eval_ctx);
+
+ /* Clear any uncleared tags - just in case. */
+ DEG_graph_clear_tags(graph);
+}
+
+/* Evaluate all nodes tagged for updating. */
+void DEG_evaluate_on_refresh(EvaluationContext *eval_ctx,
+ Depsgraph *graph,
+ Scene *scene)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = BKE_scene_frame_get(scene);;
+
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, graph->layers);
+}
+
+/* Frame-change happened for root scene that graph belongs to. */
+void DEG_evaluate_on_framechange(EvaluationContext *eval_ctx,
+ Main *bmain,
+ Depsgraph *graph,
+ float ctime,
+ const int layers)
+{
+ /* Update time on primary timesource. */
+ TimeSourceDepsNode *tsrc = graph->find_time_source();
+ tsrc->cfra = ctime;
+
+ tsrc->tag_update(graph);
+
+ DEG_graph_flush_updates(bmain, graph);
+
+ /* Perform recalculation updates. */
+ DEG_evaluate_on_refresh_ex(eval_ctx, graph, layers);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_intern.h b/source/blender/depsgraph/intern/depsgraph_intern.h
new file mode 100644
index 00000000000..70d452bf221
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_intern.h
@@ -0,0 +1,164 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * API's for internal use in the Depsgraph
+ * - Also, defines for "Node Type Info"
+ */
+
+#ifndef __DEPSGRAPH_INTERN_H__
+#define __DEPSGRAPH_INTERN_H__
+
+#include <cstdlib>
+
+#include "MEM_guardedalloc.h"
+
+#include "depsgraph.h"
+#include "depsnode.h"
+
+struct Main;
+struct Group;
+struct Scene;
+
+/* Graph Building ======================================================== */
+
+/**
+ * Build depsgraph for the given group, and dump results in given graph container
+ * This is usually used for building subgraphs for groups to use...
+ */
+void DEG_graph_build_from_group(Depsgraph *graph, struct Main *bmain, struct Group *group);
+
+/* Build subgraph for group */
+DepsNode *DEG_graph_build_group_subgraph(Depsgraph *graph_main, struct Main *bmain, struct Group *group);
+
+/* Graph Copying ========================================================= */
+/* (Part of the Filtering API) */
+
+/**
+ * Depsgraph Copying Context (dcc)
+ *
+ * Keeps track of node relationships/links/etc. during the copy
+ * operation so that they can be safely remapped...
+ */
+typedef struct DepsgraphCopyContext {
+ struct GHash *nodes_hash; /* <DepsNode, DepsNode> mapping from src node to dst node */
+ struct GHash *rels_hash; // XXX: same for relationships?
+
+ // XXX: filtering criteria...
+} DepsgraphCopyContext;
+
+/* Internal Filtering API ---------------------------------------------- */
+
+/* Create filtering context */
+// XXX: needs params for conditions?
+DepsgraphCopyContext *DEG_filter_init(void);
+
+/* Free filtering context once filtering is done */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc);
+
+
+/* Data Copy Operations ------------------------------------------------ */
+
+/**
+ * Make a (deep) copy of provided node and it's little subgraph
+ * \warning Newly created node is not added to the existing graph
+ * \param dcc: Context info for helping resolve links
+ */
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src);
+
+/* Node Types Handling ================================================= */
+
+/* "Typeinfo" for Node Types ------------------------------------------- */
+
+/* Typeinfo Struct (nti) */
+struct DepsNodeFactory {
+ virtual eDepsNode_Type type() const = 0;
+ virtual eDepsNode_Class tclass() const = 0;
+ virtual const char *tname() const = 0;
+
+ virtual DepsNode *create_node(const ID *id, const string &subdata, const string &name) const = 0;
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const = 0;
+};
+
+template <class NodeType>
+struct DepsNodeFactoryImpl : public DepsNodeFactory {
+ eDepsNode_Type type() const { return NodeType::typeinfo.type; }
+ eDepsNode_Class tclass() const { return NodeType::typeinfo.tclass; }
+ const char *tname() const { return NodeType::typeinfo.tname; }
+
+ DepsNode *create_node(const ID *id, const string &subdata, const string &name) const
+ {
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+
+ if (!name.empty())
+ /* set name if provided ... */
+ node->name = name;
+ else
+ /* ... otherwise use default type name */
+ node->name = tname();
+
+ node->init(id, subdata);
+
+ return node;
+ }
+
+ virtual DepsNode *copy_node(DepsgraphCopyContext *dcc, const DepsNode *copy) const
+ {
+ BLI_assert(copy->type == type());
+ DepsNode *node = OBJECT_GUARDED_NEW(NodeType);
+
+ /* populate base node settings */
+ node->type = type();
+ node->tclass = tclass();
+ // XXX: need to review the name here, as we can't have exact duplicates...
+ node->name = copy->name;
+
+ node->copy(dcc, static_cast<const NodeType *>(copy));
+
+ return node;
+ }
+};
+
+/* Typeinfo Management -------------------------------------------------- */
+
+/* Register typeinfo */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory);
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type);
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node);
+
+/* Editors Integration -------------------------------------------------- */
+
+void deg_editors_id_update(struct Main *bmain, struct ID *id);
+
+void deg_editors_scene_update(struct Main *bmain, struct Scene *scene, bool updated);
+
+#endif /* __DEPSGRAPH_INTERN_H__ */
diff --git a/source/blender/depsgraph/intern/depsgraph_query.cc b/source/blender/depsgraph/intern/depsgraph_query.cc
new file mode 100644
index 00000000000..aa6f5ef3ea1
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_query.cc
@@ -0,0 +1,213 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of Querying and Filtering API's
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "BKE_main.h"
+
+#include "DEG_depsgraph_query.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+#include "depsnode.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* ************************* */
+/* Low-Level Graph Traversal */
+
+#if 0
+/* Prepare for graph traversal, by tagging nodes, etc. */
+static void DEG_graph_traverse_begin(Depsgraph * /*graph*/)
+{
+ /* go over all nodes, initialising the valence counts */
+ // XXX: this will end up being O(|V|), which is bad when we're just updating a few nodes...
+}
+
+/* Perform a traversal of graph from given starting node (in execution order) */
+// TODO: additional flags for controlling the process?
+void DEG_graph_traverse_from_node(Depsgraph *graph, OperationDepsNode *start_node,
+ DEG_FilterPredicate filter, void *filter_data,
+ DEG_NodeOperation op, void *operation_data)
+{
+ DepsgraphQueue *q;
+
+ /* sanity checks */
+ if (ELEM(NULL, graph, start_node, op))
+ return;
+
+ /* add node as starting node to be evaluated, with value of 0 */
+ q = DEG_queue_new();
+
+ start_node->num_links_pending = 0;
+ DEG_queue_push(q, start_node, 0.0f);
+
+ /* while we still have nodes in the queue, grab and work on next one */
+ do {
+ /* grab item at front of queue */
+ // XXX: in practice, we may need to wait until one becomes available...
+ OperationDepsNode *node = (OperationDepsNode *)DEG_queue_pop(q);
+
+ /* perform operation on node */
+ op(graph, node, operation_data);
+
+ /* schedule up operations which depend on this */
+ DEPSNODE_RELATIONS_ITER_BEGIN(node->outlinks, rel)
+ {
+ /* ensure that relationship is not tagged for ignoring (i.e. cyclic, etc.) */
+ // TODO: cyclic refs should probably all get clustered towards the end, so that we can just stop on the first one
+ if ((rel->flag & DEPSREL_FLAG_CYCLIC) == 0) {
+ OperationDepsNode *child_node = (OperationDepsNode *)rel->to;
+
+ /* only visit node if the filtering function agrees */
+ if ((filter == NULL) || filter(graph, child_node, filter_data)) {
+ /* schedule up node... */
+ child_node->num_links_pending--;
+ DEG_queue_push(q, child_node, (float)child_node->num_links_pending);
+ }
+ }
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+ } while (DEG_queue_is_empty(q) == false);
+
+ /* cleanup */
+ DEG_queue_free(q);
+}
+#endif
+
+/* ************************************************************** */
+/* Filtering API - Basically, making a copy of the existing graph */
+
+/* Create filtering context */
+// TODO: allow passing in a number of criteria?
+DepsgraphCopyContext *DEG_filter_init()
+{
+ DepsgraphCopyContext *dcc = (DepsgraphCopyContext *)MEM_callocN(sizeof(DepsgraphCopyContext), "DepsgraphCopyContext");
+
+ /* init hashes for easy lookups */
+ dcc->nodes_hash = BLI_ghash_ptr_new("Depsgraph Filter NodeHash");
+ dcc->rels_hash = BLI_ghash_ptr_new("Depsgraph Filter Relationship Hash"); // XXX?
+
+ /* store filtering criteria? */
+ // xxx...
+
+ return dcc;
+}
+
+/* Cleanup filtering context */
+void DEG_filter_cleanup(DepsgraphCopyContext *dcc)
+{
+ /* sanity check */
+ if (dcc == NULL)
+ return;
+
+ /* free hashes - contents are weren't copied, so are ok... */
+ BLI_ghash_free(dcc->nodes_hash, NULL, NULL);
+ BLI_ghash_free(dcc->rels_hash, NULL, NULL);
+
+ /* clear filtering criteria */
+ // ...
+
+ /* free dcc itself */
+ MEM_freeN(dcc);
+}
+
+/* -------------------------------------------------- */
+
+/* Create a copy of provided node */
+// FIXME: the handling of sub-nodes and links will need to be subject to filtering options...
+// XXX: perhaps this really shouldn't be exposed, as it will just be a sub-step of the evaluation process?
+DepsNode *DEG_copy_node(DepsgraphCopyContext *dcc, const DepsNode *src)
+{
+ /* sanity check */
+ if (src == NULL)
+ return NULL;
+
+ DepsNodeFactory *factory = DEG_get_node_factory(src->type);
+ BLI_assert(factory != NULL);
+ DepsNode *dst = factory->copy_node(dcc, src);
+
+ /* add this node-pair to the hash... */
+ BLI_ghash_insert(dcc->nodes_hash, (DepsNode *)src, dst);
+
+#if 0 /* XXX TODO */
+ /* now, fix up any links in standard "node header" (i.e. DepsNode struct, that all
+ * all others are derived from) that are now corrupt
+ */
+ {
+ /* relationships to other nodes... */
+ // FIXME: how to handle links? We may only have partial set of all nodes still?
+ // XXX: the exact details of how to handle this are really part of the querying API...
+
+ // XXX: BUT, for copying subgraphs, we'll need to define an API for doing this stuff anyways
+ // (i.e. for resolving and patching over links that exist within subtree...)
+ dst->inlinks.clear();
+ dst->outlinks.clear();
+
+ /* clear traversal data */
+ dst->num_links_pending = 0;
+ dst->lasttime = 0;
+ }
+
+ /* fix links */
+ // XXX...
+#endif
+
+ /* return copied node */
+ return dst;
+}
+
+bool DEG_id_type_tagged(Main *bmain, short idtype)
+{
+ return bmain->id_tag_update[((unsigned char *)&idtype)[0]] != 0;
+}
+
+short DEG_get_eval_flags_for_id(Depsgraph *graph, ID *id)
+{
+ if (graph == NULL) {
+ /* Happens when converting objects to mesh from a python script
+ * after modifying scene graph.
+ *
+ * Currently harmless because it's only called for temporary
+ * objects which are out of the DAG anyway.
+ */
+ return 0;
+ }
+
+ IDDepsNode *id_node = graph->find_id_node(id);
+ if (id_node == NULL) {
+ /* TODO(sergey): Does it mean we need to check set scene? */
+ return 0;
+ }
+
+ return id_node->eval_flags;
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.cc b/source/blender/depsgraph/intern/depsgraph_queue.cc
new file mode 100644
index 00000000000..45290c50706
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.cc
@@ -0,0 +1,173 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Implementation of special queue type for use in Depsgraph traversals
+ */
+
+#include <stdlib.h>
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_heap.h"
+#include "BLI_ghash.h"
+} /* extern "C" */
+
+#include "depsgraph_queue.h"
+
+/* ****************************** */
+/* Depsgraph Queue implementation */
+
+/* Data Management ----------------------------------------- */
+
+DepsgraphQueue *DEG_queue_new(void)
+{
+ DepsgraphQueue *q = (DepsgraphQueue *)MEM_callocN(sizeof(DepsgraphQueue), "DEG_queue_new()");
+
+ /* init data structures for use here */
+ q->pending_heap = BLI_heap_new();
+ q->pending_hash = BLI_ghash_ptr_new("DEG Queue Pending Hash");
+
+ q->ready_heap = BLI_heap_new();
+
+ /* init settings */
+ q->idx = 0;
+ q->tot = 0;
+
+ /* return queue */
+ return q;
+}
+
+void DEG_queue_free(DepsgraphQueue *q)
+{
+ /* free data structures */
+ BLI_assert(BLI_heap_size(q->pending_heap) == 0);
+ BLI_assert(BLI_heap_size(q->ready_heap) == 0);
+ BLI_assert(BLI_ghash_size(q->pending_hash) == 0);
+
+ BLI_heap_free(q->pending_heap, NULL);
+ BLI_heap_free(q->ready_heap, NULL);
+ BLI_ghash_free(q->pending_hash, NULL, NULL);
+
+ /* free queue itself */
+ MEM_freeN(q);
+}
+
+/* Statistics --------------------------------------------- */
+
+/* Get the number of nodes which are we should visit, but are not able to yet */
+size_t DEG_queue_num_pending(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->pending_heap);
+}
+
+/* Get the number of nodes which are now ready to be visited */
+size_t DEG_queue_num_ready(DepsgraphQueue *q)
+{
+ return BLI_heap_size(q->ready_heap);
+}
+
+/* Get total size of queue */
+size_t DEG_queue_size(DepsgraphQueue *q)
+{
+ return DEG_queue_num_pending(q) + DEG_queue_num_ready(q);
+}
+
+/* Check if queue has any items in it (still passing through) */
+bool DEG_queue_is_empty(DepsgraphQueue *q)
+{
+ return DEG_queue_size(q) == 0;
+}
+
+/* Queue Operations --------------------------------------- */
+
+/**
+ * Add DepsNode to the queue
+ * \param dnode: ``(DepsNode *)`` node to add to the queue
+ * Each node is only added once to the queue; Subsequent pushes
+ * merely update its status (e.g. moving it from "pending" to "ready")
+ * \param cost: new "num_links_pending" count for node *after* it has encountered
+ * via an outlink from the node currently being visited
+ * (i.e. we're one of the dependencies which may now be able to be processed)
+ */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost)
+{
+ HeapNode *hnode = NULL;
+
+ /* Shortcut: Directly add to ready if node isn't waiting on anything now... */
+ if (cost == 0) {
+ /* node is now ready to be visited - schedule it up for such */
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* remove from pending queue - we're moving it to the scheduling queue */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+
+ BLI_ghash_remove(q->pending_hash, dnode, NULL, NULL);
+ }
+
+ /* schedule up node using latest count (of ready nodes) */
+ BLI_heap_insert(q->ready_heap, (float)q->idx, dnode);
+ q->idx++;
+ }
+ else {
+ /* node is still waiting on some other ancestors,
+ * so add it to the pending heap in the meantime...
+ */
+ // XXX: is this even necessary now?
+ if (BLI_ghash_haskey(q->pending_hash, dnode)) {
+ /* just update cost on pending node */
+ hnode = (HeapNode *)BLI_ghash_lookup(q->pending_hash, dnode);
+ BLI_heap_remove(q->pending_heap, hnode);
+ BLI_heap_insert(q->pending_heap, cost, hnode);
+ }
+ else {
+ /* add new node to pending queue, and increase size of overall queue */
+ hnode = BLI_heap_insert(q->pending_heap, cost, dnode);
+ q->tot++;
+ }
+ }
+}
+
+/* Grab a "ready" node from the queue */
+void *DEG_queue_pop(DepsgraphQueue *q)
+{
+ /* sanity check: if there are no "ready" nodes,
+ * start pulling from "pending" to keep things moving,
+ * but throw a warning so that we know that something's up here...
+ */
+ if (BLI_heap_is_empty(q->ready_heap)) {
+ // XXX: this should never happen
+ // XXX: if/when it does happen, we may want instead to just wait until something pops up here...
+ printf("DepsgraphHeap Warning: No more ready nodes available. Trying from pending (idx = %d, tot = %d, pending = %d, ready = %d)\n",
+ (int)q->idx, (int)q->tot, (int)DEG_queue_num_pending(q), (int)DEG_queue_num_ready(q));
+
+ return BLI_heap_popmin(q->pending_heap);
+ }
+ else {
+ /* only grab "ready" nodes */
+ return BLI_heap_popmin(q->ready_heap);
+ }
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_queue.h b/source/blender/depsgraph/intern/depsgraph_queue.h
new file mode 100644
index 00000000000..bd294d4655e
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_queue.h
@@ -0,0 +1,87 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Defines for special queue type for use in Depsgraph traversals
+ */
+
+#ifndef __DEPSGRAPH_QUEUE_H__
+#define __DEPSGRAPH_QUEUE_H__
+
+struct DepsNode;
+
+struct Heap;
+struct GHash;
+
+/* *********************************************** */
+/* Dependency Graph Traversal Queue
+ *
+ * There are two parts to this:
+ * a) "Pending" Nodes - This part contains the set of nodes
+ * which are related to those which have been visited
+ * previously, but are not yet ready to actually be visited.
+ * b) "Scheduled" Nodes - These are the nodes whose ancestors
+ * have all been evaluated already, which means that any
+ * or all of them can be picked (in practically in order) to
+ * be visited immediately.
+ *
+ * Internally, the queue makes sure that each node in the graph
+ * only gets added to the queue once. This is because there can
+ * be multiple inlinks to each node given the way that the relations
+ * work.
+ */
+
+/* Depsgraph Queue Type */
+typedef struct DepsgraphQueue {
+ /* Pending */
+ struct Heap *pending_heap; /* (valence:int, DepsNode*) */
+ struct GHash *pending_hash; /* (DepsNode* : HeapNode*>) */
+
+ /* Ready to be visited - fifo */
+ struct Heap *ready_heap; /* (idx:int, DepsNode*) */
+
+ /* Size/Order counts */
+ size_t idx; /* total number of nodes which are/have been ready so far (including those already visited) */
+ size_t tot; /* total number of nodes which have passed through queue; mainly for debug */
+} DepsgraphQueue;
+
+/* ************************** */
+/* Depsgraph Queue Operations */
+
+/* Data management */
+DepsgraphQueue *DEG_queue_new(void);
+void DEG_queue_free(DepsgraphQueue *q);
+
+/* Statistics */
+size_t DEG_queue_num_pending(DepsgraphQueue *q);
+size_t DEG_queue_num_ready(DepsgraphQueue *q);
+
+size_t DEG_queue_size(DepsgraphQueue *q);
+bool DEG_queue_is_empty(DepsgraphQueue *q);
+
+/* Operations */
+void DEG_queue_push(DepsgraphQueue *q, void *dnode, float cost = 0.0f);
+void *DEG_queue_pop(DepsgraphQueue *q);
+
+#endif /* DEPSGRAPH_QUEUE_H */
diff --git a/source/blender/depsgraph/intern/depsgraph_tag.cc b/source/blender/depsgraph/intern/depsgraph_tag.cc
new file mode 100644
index 00000000000..2f8cdfc1fd5
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_tag.cc
@@ -0,0 +1,490 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Core routines for how the Depsgraph works
+ */
+
+#include <stdio.h>
+#include <cstring>
+#include <queue>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+#include "DNA_particle_types.h"
+#include "DNA_screen_types.h"
+#include "DNA_windowmanager_types.h"
+
+#include "BKE_library.h"
+#include "BKE_main.h"
+#include "BKE_node.h"
+
+#define new new_
+#include "BKE_screen.h"
+#undef new
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_debug.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********************** */
+/* Update Tagging/Flushing */
+
+/* Data-Based Tagging ------------------------------- */
+
+static void lib_id_recalc_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+static void lib_id_recalc_data_tag(Main *bmain, ID *id)
+{
+ id->flag |= LIB_ID_RECALC_DATA;
+ DEG_id_type_tag(bmain, GS(id->name));
+}
+
+static void lib_id_recalc_tag_flag(Main *bmain, ID *id, int flag)
+{
+ if (flag) {
+ /* This bit of code ensures legacy object->recalc flags
+ * are still filled in the same way as it was expected
+ * with the old dependency graph.
+ *
+ * This is because some areas like motion paths and likely
+ * some other physics baking process are doing manual scene
+ * update on all the frames, trying to minimize number of
+ * updates.
+ *
+ * But this flag will also let us to re-construct entry
+ * nodes for update after relations update and after layer
+ * visibility changes.
+ */
+ short idtype = GS(id->name);
+ if (idtype == ID_OB) {
+ Object *object = (Object *)id;
+ object->recalc |= (flag & OB_RECALC_ALL);
+ }
+
+ if (flag & OB_RECALC_OB)
+ lib_id_recalc_tag(bmain, id);
+ if (flag & (OB_RECALC_DATA | PSYS_RECALC))
+ lib_id_recalc_data_tag(bmain, id);
+ }
+ else {
+ lib_id_recalc_tag(bmain, id);
+ }
+}
+
+/* Tag all nodes in ID-block for update.
+ * This is a crude measure, but is most convenient for old code.
+ */
+void DEG_graph_id_tag_update(Main *bmain, Depsgraph *graph, ID *id)
+{
+ IDDepsNode *node = graph->find_id_node(id);
+ lib_id_recalc_tag(bmain, id);
+ if (node != NULL) {
+ node->tag_update(graph);
+ }
+}
+
+/* Tag nodes related to a specific piece of data */
+void DEG_graph_data_tag_update(Depsgraph *graph, const PointerRNA *ptr)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, NULL);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag nodes related to a specific property. */
+void DEG_graph_property_tag_update(Depsgraph *graph,
+ const PointerRNA *ptr,
+ const PropertyRNA *prop)
+{
+ DepsNode *node = graph->find_node_from_pointer(ptr, prop);
+ if (node) {
+ node->tag_update(graph);
+ }
+ else {
+ printf("Missing node in %s\n", __func__);
+ BLI_assert(!"Shouldn't happens since it'll miss crucial update.");
+ }
+}
+
+/* Tag given ID for an update in all the dependency graphs. */
+void DEG_id_tag_update(ID *id, short flag)
+{
+ DEG_id_tag_update_ex(G.main, id, flag);
+}
+
+void DEG_id_tag_update_ex(Main *bmain, ID *id, short flag)
+{
+ if(id == NULL) {
+ /* Ideally should not happen, but old depsgraph allowed this. */
+ return;
+ }
+ DEG_DEBUG_PRINTF("%s: id=%s flag=%d\n", __func__, id->name, flag);
+ lib_id_recalc_tag_flag(bmain, id, flag);
+ for (Scene *scene = (Scene *)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene *)scene->id.next)
+ {
+ if (scene->depsgraph) {
+ Depsgraph *graph = scene->depsgraph;
+ if (flag == 0) {
+ /* TODO(sergey): Currently blender is still tagging IDs
+ * for recalc just using flag=0. This isn't totally correct
+ * but we'd better deal with such cases and don't fail.
+ */
+ DEG_graph_id_tag_update(bmain, graph, id);
+ continue;
+ }
+ if (flag & OB_RECALC_DATA && GS(id->name) == ID_OB) {
+ Object *object = (Object*)id;
+ if (object->data != NULL) {
+ DEG_graph_id_tag_update(bmain,
+ graph,
+ (ID*)object->data);
+ }
+ }
+ if (flag & (OB_RECALC_OB|OB_RECALC_DATA)) {
+ DEG_graph_id_tag_update(bmain, graph, id);
+ }
+ }
+ }
+}
+
+/* Tag given ID type for update. */
+void DEG_id_type_tag(Main *bmain, short idtype)
+{
+ if (idtype == ID_NT) {
+ /* Stupid workaround so parent datablocks of nested nodetree get looped
+ * over when we loop over tagged datablock types.
+ */
+ DEG_id_type_tag(bmain, ID_MA);
+ DEG_id_type_tag(bmain, ID_TE);
+ DEG_id_type_tag(bmain, ID_LA);
+ DEG_id_type_tag(bmain, ID_WO);
+ DEG_id_type_tag(bmain, ID_SCE);
+ }
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ bmain->id_tag_update[((unsigned char *)&idtype)[0]] = 1;
+}
+
+/* Update Flushing ---------------------------------- */
+
+/* FIFO queue for tagged nodes that need flushing */
+/* XXX This may get a dedicated implementation later if needed - lukas */
+typedef std::queue<OperationDepsNode*> FlushQueue;
+
+/* Flush updates from tagged nodes outwards until all affected nodes are tagged. */
+void DEG_graph_flush_updates(Main *bmain, Depsgraph *graph)
+{
+ /* sanity check */
+ if (graph == NULL)
+ return;
+
+ /* Nothing to update, early out. */
+ if (graph->entry_tags.size() == 0) {
+ return;
+ }
+
+ /* TODO(sergey): With a bit of flag magic we can get rid of this
+ * extra loop.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->scheduled = false;
+ }
+
+ FlushQueue queue;
+ /* Starting from the tagged "entry" nodes, flush outwards... */
+ /* NOTE: Also need to ensure that for each of these, there is a path back to
+ * root, or else they won't be done.
+ * NOTE: Count how many nodes we need to handle - entry nodes may be
+ * component nodes which don't count for this purpose!
+ */
+ for (Depsgraph::EntryTags::const_iterator it = graph->entry_tags.begin();
+ it != graph->entry_tags.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ queue.push(node);
+ deg_editors_id_update(bmain, id_node->id);
+ node->scheduled = true;
+ }
+
+ while (!queue.empty()) {
+ OperationDepsNode *node = queue.front();
+ queue.pop();
+
+ IDDepsNode *id_node = node->owner->owner;
+ lib_id_recalc_tag(bmain, id_node->id);
+ /* TODO(sergey): For until we've got proper data nodes in the graph. */
+ lib_id_recalc_data_tag(bmain, id_node->id);
+
+ ID *id = id_node->id;
+ /* This code is used to preserve those areas which does direct
+ * object update,
+ *
+ * Plus it ensures visibility changes and relations and layers
+ * visibility update has proper flags to work with.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ ComponentDepsNode *comp_node = node->owner;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ object->recalc |= OB_RECALC_TIME;
+ }
+ else if (comp_node->type == DEPSNODE_TYPE_TRANSFORM) {
+ object->recalc |= OB_RECALC_OB;
+ }
+ else {
+ object->recalc |= OB_RECALC_DATA;
+ }
+ }
+
+ /* Flush to nodes along links... */
+ for (OperationDepsNode::Relations::const_iterator it = node->outlinks.begin();
+ it != node->outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ OperationDepsNode *to_node = (OperationDepsNode *)rel->to;
+ if (to_node->scheduled == false) {
+ to_node->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ queue.push(to_node);
+ to_node->scheduled = true;
+ deg_editors_id_update(bmain, id_node->id);
+ }
+ }
+
+ /* TODO(sergey): For until incremental updates are possible
+ * witin a component at least we tag the whole component
+ * for update.
+ */
+ for (ComponentDepsNode::OperationMap::iterator it = node->owner->operations.begin();
+ it != node->owner->operations.end();
+ ++it)
+ {
+ OperationDepsNode *op = it->second;
+ op->flag |= DEPSOP_FLAG_NEEDS_UPDATE;
+ }
+ }
+}
+
+/* Recursively push updates out to all nodes dependent on this,
+ * until all affected are tagged and/or scheduled up for eval
+ */
+void DEG_ids_flush_tagged(Main *bmain)
+{
+ for (Scene *scene = (Scene*)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene*)scene->id.next)
+ {
+ /* TODO(sergey): Only visible scenes? */
+ if (scene->depsgraph != NULL) {
+ DEG_graph_flush_updates(bmain, scene->depsgraph);
+ }
+ }
+}
+
+/* Clear tags from all operation nodes. */
+void DEG_graph_clear_tags(Depsgraph *graph)
+{
+ /* Go over all operation nodes, clearing tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+
+ /* Clear node's "pending update" settings. */
+ node->flag &= ~(DEPSOP_FLAG_DIRECTLY_MODIFIED | DEPSOP_FLAG_NEEDS_UPDATE);
+ /* Reset so that it can be bumped up again. */
+ node->num_links_pending = 0;
+ node->scheduled = false;
+ }
+
+ /* Clear any entry tags which haven't been flushed. */
+ graph->entry_tags.clear();
+}
+
+/* Update dependency graph when visible scenes/layers changes. */
+void DEG_graph_on_visible_update(Main *bmain, Scene *scene)
+{
+ Depsgraph *graph = scene->depsgraph;
+ wmWindowManager *wm = (wmWindowManager *)bmain->wm.first;
+ int old_layers = graph->layers;
+ if (wm != NULL) {
+ BKE_main_id_flag_listbase(&bmain->scene, LIB_DOIT, true);
+ graph->layers = 0;
+ for (wmWindow *win = (wmWindow *)wm->windows.first;
+ win != NULL;
+ win = (wmWindow *)win->next)
+ {
+ Scene *scene = win->screen->scene;
+ if (scene->id.flag & LIB_DOIT) {
+ graph->layers |= BKE_screen_visible_layers(win->screen, scene);
+ scene->id.flag &= ~LIB_DOIT;
+ }
+ }
+ }
+ else {
+ /* All the layers for background render for now. */
+ graph->layers = (1 << 20) - 1;
+ }
+ if (old_layers != graph->layers) {
+ /* Tag all objects which becomes visible (or which becomes needed for dependencies)
+ * for recalc.
+ *
+ * This is mainly needed on file load only, after that updates of invisible objects
+ * will be stored in the pending list.
+ */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ IDDepsNode *id_node = node->owner->owner;
+ ID *id = id_node->id;
+ if ((id->flag & LIB_ID_RECALC_ALL) != 0 ||
+ (id_node->layers & scene->lay_updated) == 0)
+ {
+ id_node->tag_update(graph);
+ }
+ /* A bit of magic: if object->recalc is set it means somebody tagged
+ * it for update. If corresponding ID recalc flags are zero it means
+ * graph has been evaluated after that and the recalc was skipped
+ * because of visibility check.
+ */
+ if (GS(id->name) == ID_OB) {
+ Object *object = (Object *)id;
+ if ((id->flag & LIB_ID_RECALC_ALL) == 0 &&
+ (object->recalc & OB_RECALC_ALL) != 0)
+ {
+ id_node->tag_update(graph);
+ ComponentDepsNode *anim_comp =
+ id_node->find_component(DEPSNODE_TYPE_ANIMATION);
+ if (anim_comp != NULL && object->recalc & OB_RECALC_TIME) {
+ anim_comp->tag_update(graph);
+ }
+ }
+ }
+ }
+ }
+ scene->lay_updated |= graph->layers;
+}
+
+void DEG_on_visible_update(Main *bmain, const bool UNUSED(do_time))
+{
+ for (Scene *scene = (Scene*)bmain->scene.first;
+ scene != NULL;
+ scene = (Scene*)scene->id.next)
+ {
+ if (scene->depsgraph != NULL) {
+ DEG_graph_on_visible_update(bmain, scene);
+ }
+ }
+}
+
+/* Check if something was changed in the database and inform
+ * editors about this.
+ */
+void DEG_ids_check_recalc(Main *bmain, Scene *scene, bool time)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ int a;
+ bool updated = false;
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID*)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ updated = true;
+ break;
+ }
+ }
+
+ deg_editors_scene_update(bmain, scene, (updated || time));
+}
+
+void DEG_ids_clear_recalc(Main *bmain)
+{
+ ListBase *lbarray[MAX_LIBARRAY];
+ bNodeTree *ntree;
+ int a;
+
+ /* TODO(sergey): Re-implement POST_UPDATE_HANDLER_WORKAROUND using entry_tags
+ * and id_tags storage from the new dependency graph.
+ */
+
+ /* Loop over all ID types. */
+ a = set_listbasepointers(bmain, lbarray);
+ while (a--) {
+ ListBase *lb = lbarray[a];
+ ID *id = (ID *)lb->first;
+
+ /* We tag based on first ID type character to avoid
+ * looping over all ID's in case there are no tags.
+ */
+ if (id && bmain->id_tag_update[(unsigned char)id->name[0]]) {
+ for (; id; id = (ID *)id->next) {
+ id->flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+
+ /* Some ID's contain semi-datablock nodetree */
+ ntree = ntreeFromID(id);
+ if (ntree != NULL) {
+ ntree->id.flag &= ~(LIB_ID_RECALC | LIB_ID_RECALC_DATA);
+ }
+ }
+ }
+ }
+
+ memset(bmain->id_tag_update, 0, sizeof(bmain->id_tag_update));
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_type_defines.cc b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
new file mode 100644
index 00000000000..67c632d4125
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_type_defines.cc
@@ -0,0 +1,98 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Defines and code for core node types
+ */
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+
+#include "DEG_depsgraph.h"
+} /* extern "C" */
+
+#include "depsgraph_intern.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* ************ */
+/* External API */
+
+/* Global type registry */
+
+/**
+ * \note For now, this is a hashtable not array, since the core node types
+ * currently do not have contiguous ID values. Using a hash here gives us
+ * more flexibility, albeit using more memory and also sacrificing a little
+ * speed. Later on, when things stabilise we may turn this back to an array
+ * since there are only just a few node types that an array would cope fine...
+ */
+static GHash *_depsnode_typeinfo_registry = NULL;
+
+/* Registration ------------------------------------------- */
+
+/* Register node type */
+void DEG_register_node_typeinfo(DepsNodeFactory *factory)
+{
+ BLI_assert(factory != NULL);
+ BLI_ghash_insert(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(factory->type()), factory);
+}
+
+/* Register all node types */
+void DEG_register_node_types(void)
+{
+ /* initialise registry */
+ _depsnode_typeinfo_registry = BLI_ghash_int_new("Depsgraph Node Type Registry");
+
+ /* register node types */
+ DEG_register_base_depsnodes();
+ DEG_register_component_depsnodes();
+ DEG_register_operation_depsnodes();
+}
+
+/* Free registry on exit */
+void DEG_free_node_types(void)
+{
+ BLI_ghash_free(_depsnode_typeinfo_registry, NULL, NULL);
+}
+
+/* Getters ------------------------------------------------- */
+
+/* Get typeinfo for specified type */
+DepsNodeFactory *DEG_get_node_factory(const eDepsNode_Type type)
+{
+ /* look up type - at worst, it doesn't exist in table yet, and we fail */
+ return (DepsNodeFactory *)BLI_ghash_lookup(_depsnode_typeinfo_registry, SET_INT_IN_POINTER(type));
+}
+
+/* Get typeinfo for provided node */
+DepsNodeFactory *DEG_node_get_factory(const DepsNode *node)
+{
+ if (!node)
+ return NULL;
+
+ return DEG_get_node_factory(node->type);
+}
diff --git a/source/blender/depsgraph/intern/depsgraph_types.h b/source/blender/depsgraph/intern/depsgraph_types.h
new file mode 100644
index 00000000000..2a84f4587af
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsgraph_types.h
@@ -0,0 +1,169 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ *
+ * Datatypes for internal use in the Depsgraph
+ *
+ * All of these datatypes are only really used within the "core" depsgraph.
+ * In particular, node types declared here form the structure of operations
+ * in the graph.
+ */
+
+#ifndef __DEPSGRAPH_TYPES_H__
+#define __DEPSGRAPH_TYPES_H__
+
+#include "depsgraph_util_function.h"
+
+/* TODO(sergey): Ideally we'll just use char* and statically allocated strings
+ * to avoid any possible overhead caused by string (re)allocation/formatting.
+ */
+#include <string>
+#include <vector>
+
+using std::string;
+using std::vector;
+
+struct bAction;
+struct ChannelDriver;
+struct ModifierData;
+struct PointerRNA;
+struct EvaluationContext;
+struct FCurve;
+
+/* Evaluation Operation for atomic operation */
+// XXX: move this to another header that can be exposed?
+typedef function<void(struct EvaluationContext*)> DepsEvalOperationCb;
+
+/* Metatype of Nodes - The general "level" in the graph structure the node serves */
+typedef enum eDepsNode_Class {
+ DEPSNODE_CLASS_GENERIC = 0, /* Types generally unassociated with user-visible entities, but needed for graph functioning */
+
+ DEPSNODE_CLASS_COMPONENT = 1, /* [Outer Node] An "aspect" of evaluating/updating an ID-Block, requiring certain types of evaluation behaviours */
+ DEPSNODE_CLASS_OPERATION = 2, /* [Inner Node] A glorified function-pointer/callback for scheduling up evaluation operations for components, subject to relationship requirements */
+} eDepsNode_Class;
+
+/* Types of Nodes */
+typedef enum eDepsNode_Type {
+ DEPSNODE_TYPE_UNDEFINED = -1, /* fallback type for invalid return value */
+
+ DEPSNODE_TYPE_OPERATION = 0, /* Inner Node (Operation) */
+
+ /* Generic Types */
+ DEPSNODE_TYPE_ROOT = 1, /* "Current Scene" - basically whatever kicks off the evaluation process */
+ DEPSNODE_TYPE_TIMESOURCE = 2, /* Time-Source */
+
+ DEPSNODE_TYPE_ID_REF = 3, /* ID-Block reference - used as landmarks/collection point for components, but not usually part of main graph */
+ DEPSNODE_TYPE_SUBGRAPH = 4, /* Isolated sub-graph - used for keeping instanced data separate from instances using them */
+
+ /* Outer Types */
+ DEPSNODE_TYPE_PARAMETERS = 11, /* Parameters Component - Default when nothing else fits (i.e. just SDNA property setting) */
+ DEPSNODE_TYPE_PROXY = 12, /* Generic "Proxy-Inherit" Component */ // XXX: Also for instancing of subgraphs?
+ DEPSNODE_TYPE_ANIMATION = 13, /* Animation Component */ // XXX: merge in with parameters?
+ DEPSNODE_TYPE_TRANSFORM = 14, /* Transform Component (Parenting/Constraints) */
+ DEPSNODE_TYPE_GEOMETRY = 15, /* Geometry Component (DerivedMesh/Displist) */
+ DEPSNODE_TYPE_SEQUENCER = 16, /* Sequencer Component (Scene Only) */
+
+ /* Evaluation-Related Outer Types (with Subdata) */
+ DEPSNODE_TYPE_EVAL_POSE = 21, /* Pose Component - Owner/Container of Bones Eval */
+ DEPSNODE_TYPE_BONE = 22, /* Bone Component - Child/Subcomponent of Pose */
+
+ DEPSNODE_TYPE_EVAL_PARTICLES = 23, /* Particle Systems Component */
+ DEPSNODE_TYPE_SHADING = 24, /* Material Shading Component */
+} eDepsNode_Type;
+
+/* Identifiers for common operations (as an enum) */
+typedef enum eDepsOperation_Code {
+#define DEF_DEG_OPCODE(label) DEG_OPCODE_##label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+} eDepsOperation_Code;
+
+/* String defines for these opcodes, defined in depsnode_operation.cpp */
+extern const char *DEG_OPNAMES[];
+
+
+/* Type of operation */
+typedef enum eDepsOperation_Type {
+ /* Primary operation types */
+ DEPSOP_TYPE_INIT = 0, /* initialise evaluation data */
+ DEPSOP_TYPE_EXEC = 1, /* standard evaluation step */
+ DEPSOP_TYPE_POST = 2, /* cleanup evaluation data + flush results */
+
+ /* Additional operation types */
+ DEPSOP_TYPE_OUT = 3, /* indicator for outputting a temporary result that other components can use */ // XXX?
+ DEPSOP_TYPE_SIM = 4, /* indicator for things like IK Solvers and Rigidbody Sim steps which modify final results of separate entities at once */
+ DEPSOP_TYPE_REBUILD = 5, /* rebuild internal evaluation data - used for Rigidbody Reset and Armature Rebuild-On-Load */
+} eDepsOperation_Type;
+
+/* Types of relationships between nodes
+ *
+ * This is used to provide additional hints to use when filtering
+ * the graph, so that we can go without doing more extensive
+ * data-level checks...
+ */
+typedef enum eDepsRelation_Type {
+ /* reationship type unknown/irrelevant */
+ DEPSREL_TYPE_STANDARD = 0,
+
+ /* root -> active scene or entity (screen, image, etc.) */
+ DEPSREL_TYPE_ROOT_TO_ACTIVE,
+
+ /* general datablock dependency */
+ DEPSREL_TYPE_DATABLOCK,
+
+ /* time dependency */
+ DEPSREL_TYPE_TIME,
+
+ /* component depends on results of another */
+ DEPSREL_TYPE_COMPONENT_ORDER,
+
+ /* relationship is just used to enforce ordering of operations
+ * (e.g. "init()" callback done before "exec() and "cleanup()")
+ */
+ DEPSREL_TYPE_OPERATION,
+
+ /* relationship results from a property driver affecting property */
+ DEPSREL_TYPE_DRIVER,
+
+ /* relationship is something driver depends on */
+ DEPSREL_TYPE_DRIVER_TARGET,
+
+ /* relationship is used for transform stack
+ * (e.g. parenting, user transforms, constraints)
+ */
+ DEPSREL_TYPE_TRANSFORM,
+
+ /* relationship is used for geometry evaluation
+ * (e.g. metaball "motherball" or modifiers)
+ */
+ DEPSREL_TYPE_GEOMETRY_EVAL,
+
+ /* relationship is used to trigger a post-change validity updates */
+ DEPSREL_TYPE_UPDATE,
+
+ /* relationship is used to trigger editor/screen updates */
+ DEPSREL_TYPE_UPDATE_UI,
+} eDepsRelation_Type;
+
+#endif /* __DEPSGRAPH_TYPES_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode.cc b/source/blender/depsgraph/intern/depsnode.cc
new file mode 100644
index 00000000000..8d21f6e0034
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.cc
@@ -0,0 +1,308 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "BLI_utildefines.h"
+
+extern "C" {
+#include "DNA_ID.h"
+#include "DNA_anim_types.h"
+
+#include "BKE_animsys.h"
+
+#include "DEG_depsgraph.h"
+}
+
+#include "depsnode.h" /* own include */
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *************** */
+/* Node Management */
+
+/* Add ------------------------------------------------ */
+
+DepsNode::TypeInfo::TypeInfo(eDepsNode_Type type, const char *tname)
+{
+ this->type = type;
+ if (type == DEPSNODE_TYPE_OPERATION)
+ this->tclass = DEPSNODE_CLASS_OPERATION;
+ else if (type < DEPSNODE_TYPE_PARAMETERS)
+ this->tclass = DEPSNODE_CLASS_GENERIC;
+ else
+ this->tclass = DEPSNODE_CLASS_COMPONENT;
+ this->tname = tname;
+}
+
+DepsNode::DepsNode()
+{
+ this->name[0] = '\0';
+}
+
+DepsNode::~DepsNode()
+{
+ /* free links
+ * note: deleting relations will remove them from the node relations set,
+ * but only touch the same position as we are using here, which is safe.
+ */
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->inlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+
+ DEPSNODE_RELATIONS_ITER_BEGIN(this->outlinks, rel)
+ {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ DEPSNODE_RELATIONS_ITER_END;
+}
+
+
+/* Generic identifier for Depsgraph Nodes. */
+string DepsNode::identifier() const
+{
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + " : " + name;
+}
+
+/* ************* */
+/* Generic Nodes */
+
+/* Time Source Node ============================================== */
+
+void TimeSourceDepsNode::tag_update(Depsgraph *graph)
+{
+ for (DepsNode::Relations::const_iterator it = outlinks.begin();
+ it != outlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+ DepsNode *node = rel->to;
+ node->tag_update(graph);
+ }
+}
+
+
+/* Root Node ============================================== */
+
+RootDepsNode::~RootDepsNode()
+{
+ OBJECT_GUARDED_DELETE(time_source, TimeSourceDepsNode);
+}
+
+TimeSourceDepsNode *RootDepsNode::add_time_source(const string &name)
+{
+ if (!time_source) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_TIMESOURCE);
+ time_source = (TimeSourceDepsNode *)factory->create_node(NULL, "", name);
+ /*time_source->owner = this;*/ // XXX
+ }
+ return time_source;
+}
+
+DEG_DEPSNODE_DEFINE(RootDepsNode, DEPSNODE_TYPE_ROOT, "Root DepsNode");
+static DepsNodeFactoryImpl<RootDepsNode> DNTI_ROOT;
+
+/* Time Source Node ======================================= */
+
+DEG_DEPSNODE_DEFINE(TimeSourceDepsNode, DEPSNODE_TYPE_TIMESOURCE, "Time Source");
+static DepsNodeFactoryImpl<TimeSourceDepsNode> DNTI_TIMESOURCE;
+
+/* ID Node ================================================ */
+
+/* Initialize 'id' node - from pointer data given. */
+void IDDepsNode::init(const ID *id, const string &UNUSED(subdata))
+{
+ /* Store ID-pointer. */
+ BLI_assert(id != NULL);
+ this->id = (ID *)id;
+ this->layers = (1 << 20) - 1;
+ this->eval_flags = 0;
+
+ /* NOTE: components themselves are created if/when needed.
+ * This prevents problems with components getting added
+ * twice if an ID-Ref needs to be created to house it...
+ */
+}
+
+/* Free 'id' node. */
+IDDepsNode::~IDDepsNode()
+{
+ clear_components();
+}
+
+/* Copy 'id' node. */
+void IDDepsNode::copy(DepsgraphCopyContext *dcc, const IDDepsNode *src)
+{
+ (void)src; /* Ignored. */
+ /* Iterate over items in original hash, adding them to new hash. */
+ for (IDDepsNode::ComponentMap::const_iterator it = this->components.begin();
+ it != this->components.end();
+ ++it)
+ {
+ /* Get current <type : component> mapping. */
+ ComponentIDKey c_key = it->first;
+ DepsNode *old_component = it->second;
+
+ /* Make a copy of component. */
+ ComponentDepsNode *component = (ComponentDepsNode *)DEG_copy_node(dcc, old_component);
+
+ /* Add new node to hash... */
+ this->components[c_key] = component;
+ }
+
+ // TODO: perform a second loop to fix up links?
+ BLI_assert(!"Not expected to be used");
+}
+
+ComponentDepsNode *IDDepsNode::find_component(eDepsNode_Type type,
+ const string &name) const
+{
+ ComponentIDKey key(type, name);
+ ComponentMap::const_iterator it = components.find(key);
+ return it != components.end() ? it->second : NULL;
+}
+
+ComponentDepsNode *IDDepsNode::add_component(eDepsNode_Type type,
+ const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (!comp_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(type);
+ comp_node = (ComponentDepsNode *)factory->create_node(this->id, "", name);
+
+ /* Register. */
+ this->components[key] = comp_node;
+ comp_node->owner = this;
+ }
+ return comp_node;
+}
+
+void IDDepsNode::remove_component(eDepsNode_Type type, const string &name)
+{
+ ComponentIDKey key(type, name);
+ ComponentDepsNode *comp_node = find_component(type, name);
+ if (comp_node) {
+ /* Unregister. */
+ this->components.erase(key);
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+}
+
+void IDDepsNode::clear_components()
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ OBJECT_GUARDED_DELETE(comp_node, ComponentDepsNode);
+ }
+ components.clear();
+}
+
+void IDDepsNode::tag_update(Depsgraph *graph)
+{
+ for (ComponentMap::const_iterator it = components.begin();
+ it != components.end();
+ ++it)
+ {
+ ComponentDepsNode *comp_node = it->second;
+ /* TODO(sergey): What about drievrs? */
+ bool do_component_tag = comp_node->type != DEPSNODE_TYPE_ANIMATION;
+ if (comp_node->type == DEPSNODE_TYPE_ANIMATION) {
+ AnimData *adt = BKE_animdata_from_id(id);
+ BLI_assert(adt != NULL);
+ if (adt->recalc & ADT_RECALC_ANIM) {
+ do_component_tag = true;
+ }
+ }
+ if (do_component_tag) {
+ comp_node->tag_update(graph);
+ }
+ }
+}
+
+DEG_DEPSNODE_DEFINE(IDDepsNode, DEPSNODE_TYPE_ID_REF, "ID Node");
+static DepsNodeFactoryImpl<IDDepsNode> DNTI_ID_REF;
+
+/* Subgraph Node ========================================== */
+
+/* Initialize 'subgraph' node - from pointer data given. */
+void SubgraphDepsNode::init(const ID *id, const string &UNUSED(subdata))
+{
+ /* Store ID-ref if provided. */
+ this->root_id = (ID *)id;
+
+ /* NOTE: graph will need to be added manually,
+ * as we don't have any way of passing this down.
+ */
+}
+
+/* Free 'subgraph' node */
+SubgraphDepsNode::~SubgraphDepsNode()
+{
+ /* Only free if graph not shared, of if this node is the first
+ * reference to it...
+ */
+ // XXX: prune these flags a bit...
+ if ((this->flag & SUBGRAPH_FLAG_FIRSTREF) || !(this->flag & SUBGRAPH_FLAG_SHARED)) {
+ /* Free the referenced graph. */
+ DEG_graph_free(this->graph);
+ this->graph = NULL;
+ }
+}
+
+/* Copy 'subgraph' node - Assume that the subgraph doesn't get copied for now... */
+void SubgraphDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const SubgraphDepsNode * /*src*/)
+{
+ //const SubgraphDepsNode *src_node = (const SubgraphDepsNode *)src;
+ //SubgraphDepsNode *dst_node = (SubgraphDepsNode *)dst;
+
+ /* for now, subgraph itself isn't copied... */
+ BLI_assert(!"Not expected to be used");
+}
+
+DEG_DEPSNODE_DEFINE(SubgraphDepsNode, DEPSNODE_TYPE_SUBGRAPH, "Subgraph Node");
+static DepsNodeFactoryImpl<SubgraphDepsNode> DNTI_SUBGRAPH;
+
+
+void DEG_register_base_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_ROOT);
+ DEG_register_node_typeinfo(&DNTI_TIMESOURCE);
+
+ DEG_register_node_typeinfo(&DNTI_ID_REF);
+ DEG_register_node_typeinfo(&DNTI_SUBGRAPH);
+}
diff --git a/source/blender/depsgraph/intern/depsnode.h b/source/blender/depsgraph/intern/depsnode.h
new file mode 100644
index 00000000000..067bd771e87
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode.h
@@ -0,0 +1,243 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DEPSNODE_H__
+#define __DEPSNODE_H__
+
+#include "depsgraph_types.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct Scene;
+
+struct Depsgraph;
+struct DepsRelation;
+struct DepsgraphCopyContext;
+struct OperationDepsNode;
+
+/* *********************************** */
+/* Base-Defines for Nodes in Depsgraph */
+
+/* All nodes in Depsgraph are descended from this. */
+struct DepsNode {
+ /* Helper class for static typeinfo in subclasses. */
+ struct TypeInfo {
+ TypeInfo(eDepsNode_Type type, const char *tname);
+
+ eDepsNode_Type type;
+ eDepsNode_Class tclass;
+ const char *tname;
+ };
+
+ /* Identifier - mainly for debugging purposes. */
+ string name;
+
+ /* Structural type of node. */
+ eDepsNode_Type type;
+
+ /* Type of data/behaviour represented by node... */
+ eDepsNode_Class tclass;
+
+ /* Relationships between nodes
+ * The reason why all depsgraph nodes are descended from this type (apart
+ * from basic serialization benefits - from the typeinfo) is that we can have
+ * relationships between these nodes!
+ */
+ typedef unordered_set<DepsRelation *> Relations;
+
+ /* Nodes which this one depends on. */
+ Relations inlinks;
+
+ /* Nodes which depend on this one. */
+ Relations outlinks;
+
+ /* Generic tag for traversal algorithms */
+ int done;
+
+ /* Methods. */
+
+ DepsNode();
+ virtual ~DepsNode();
+
+ virtual string identifier() const;
+ string full_identifier() const;
+
+ virtual void init(const ID * /*id*/,
+ const string &/*subdata*/) {}
+ virtual void copy(DepsgraphCopyContext * /*dcc*/,
+ const DepsNode * /*src*/) {}
+
+ virtual void tag_update(Depsgraph * /*graph*/) {}
+
+ virtual OperationDepsNode *get_entry_operation() { return NULL; }
+ virtual OperationDepsNode *get_exit_operation() { return NULL; }
+};
+
+/* Macros for common static typeinfo. */
+#define DEG_DEPSNODE_DECLARE \
+ static const DepsNode::TypeInfo typeinfo
+#define DEG_DEPSNODE_DEFINE(NodeType, type_, tname_) \
+ const DepsNode::TypeInfo NodeType::typeinfo = DepsNode::TypeInfo(type_, tname_)
+
+/* Generic Nodes ======================= */
+
+struct ComponentDepsNode;
+struct IDDepsNode;
+
+/* Time Source Node. */
+struct TimeSourceDepsNode : public DepsNode {
+ /* New "current time". */
+ float cfra;
+
+ /* time-offset relative to the "official" time source that this one has. */
+ float offset;
+
+ // TODO: evaluate() operation needed
+
+ void tag_update(Depsgraph *graph);
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Root Node. */
+struct RootDepsNode : public DepsNode {
+ ~RootDepsNode();
+
+ TimeSourceDepsNode *add_time_source(const string &name = "");
+
+ /* scene that this corresponds to */
+ Scene *scene;
+
+ /* Entrypoint node for time-changed. */
+ TimeSourceDepsNode *time_source;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* ID-Block Reference */
+struct IDDepsNode : public DepsNode {
+ struct ComponentIDKey {
+ ComponentIDKey(eDepsNode_Type type, const string &name = "")
+ : type(type), name(name) {}
+
+ bool operator== (const ComponentIDKey &other) const
+ {
+ return type == other.type && name == other.name;
+ }
+
+ eDepsNode_Type type;
+ string name;
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentIDKey is
+ * a nested type ...
+ *
+ * http://stackoverflow.com/a/951245
+ */
+ struct component_key_hash {
+ bool operator() (const ComponentIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.type), hash<string>()(key.name));
+ }
+ };
+
+ typedef unordered_map<ComponentIDKey,
+ ComponentDepsNode*,
+ component_key_hash> ComponentMap;
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const IDDepsNode *src);
+ ~IDDepsNode();
+
+ ComponentDepsNode *find_component(eDepsNode_Type type,
+ const string &name = "") const;
+ ComponentDepsNode *add_component(eDepsNode_Type type,
+ const string &name = "");
+ void remove_component(eDepsNode_Type type, const string &name = "");
+ void clear_components();
+
+ void tag_update(Depsgraph *graph);
+
+ /* ID Block referenced. */
+ ID *id;
+
+ /* Hash to make it faster to look up components. */
+ ComponentMap components;
+
+ /* Layers of this node with accumulated layers of it's output relations. */
+ int layers;
+
+ /* Additional flags needed for scene evaluation.
+ * TODO(sergey): Only needed for until really granual updates
+ * of all the entities.
+ */
+ int eval_flags;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Subgraph Reference. */
+struct SubgraphDepsNode : public DepsNode {
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const SubgraphDepsNode *src);
+ ~SubgraphDepsNode();
+
+ /* Instanced graph. */
+ Depsgraph *graph;
+
+ /* ID-block at root of subgraph (if applicable). */
+ ID *root_id;
+
+ /* Number of nodes which use/reference this subgraph - if just 1, it may be
+ * possible to merge into main,
+ */
+ size_t num_users;
+
+ /* (eSubgraphRef_Flag) assorted settings for subgraph node. */
+ int flag;
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Flags for subgraph node */
+typedef enum eSubgraphRef_Flag {
+ /* Subgraph referenced is shared with another reference, so shouldn't
+ * free on exit.
+ */
+ SUBGRAPH_FLAG_SHARED = (1 << 0),
+
+ /* Node is first reference to subgraph, so it can be freed when we are
+ * removed.
+ */
+ SUBGRAPH_FLAG_FIRSTREF = (1 << 1),
+} eSubgraphRef_Flag;
+
+void DEG_register_base_depsnodes();
+
+#endif /* __DEPSNODE_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_component.cc b/source/blender/depsgraph/intern/depsnode_component.cc
new file mode 100644
index 00000000000..969b0891e15
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.cc
@@ -0,0 +1,314 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_object_types.h"
+
+#include "BKE_action.h"
+} /* extern "C" */
+
+#include "depsnode_component.h" /* own include */
+#include "depsnode_operation.h"
+#include "depsgraph_intern.h"
+
+/* *********** */
+/* Outer Nodes */
+
+/* Standard Component Methods ============================= */
+
+ComponentDepsNode::ComponentDepsNode() :
+ entry_operation(NULL),
+ exit_operation(NULL)
+{
+}
+
+/* Initialize 'component' node - from pointer data given */
+void ComponentDepsNode::init(const ID * /*id*/,
+ const string & /*subdata*/)
+{
+ /* hook up eval context? */
+ // XXX: maybe this needs a special API?
+}
+
+/* Copy 'component' node */
+void ComponentDepsNode::copy(DepsgraphCopyContext * /*dcc*/,
+ const ComponentDepsNode * /*src*/)
+{
+#if 0 // XXX: remove all this
+ /* duplicate list of operation nodes */
+ this->operations.clear();
+
+ for (OperationMap::const_iterator it = src->operations.begin(); it != src->operations.end(); ++it) {
+ const string &pchan_name = it->first;
+ OperationDepsNode *src_op = it->second;
+
+ /* recursive copy */
+ DepsNodeFactory *factory = DEG_node_get_factory(src_op);
+ OperationDepsNode *dst_op = (OperationDepsNode *)factory->copy_node(dcc, src_op);
+ this->operations[pchan_name] = dst_op;
+
+ /* fix links... */
+ // ...
+ }
+
+ /* copy evaluation contexts */
+ //
+#endif
+ BLI_assert(!"Not expected to be called");
+}
+
+/* Free 'component' node */
+ComponentDepsNode::~ComponentDepsNode()
+{
+ clear_operations();
+}
+
+string ComponentDepsNode::identifier() const
+{
+ string &idname = this->owner->name;
+
+ char typebuf[7];
+ sprintf(typebuf, "(%d)", type);
+
+ return string(typebuf) + name + " : " + idname;
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ else {
+ fprintf(stderr, "%s: find_operation(%s) failed\n",
+ this->identifier().c_str(), key.identifier().c_str());
+ BLI_assert(!"Request for non-existing operation, should not happen");
+ return NULL;
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::find_operation(eDepsOperation_Code opcode, const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return find_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(OperationIDKey key) const
+{
+ OperationMap::const_iterator it = this->operations.find(key);
+ if (it != this->operations.end()) {
+ return it->second;
+ }
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::has_operation(eDepsOperation_Code opcode,
+ const string &name) const
+{
+ OperationIDKey key(opcode, name);
+ return has_operation(key);
+}
+
+OperationDepsNode *ComponentDepsNode::add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = has_operation(opcode, name);
+ if (!op_node) {
+ DepsNodeFactory *factory = DEG_get_node_factory(DEPSNODE_TYPE_OPERATION);
+ op_node = (OperationDepsNode *)factory->create_node(this->owner->id, "", name);
+
+ /* register opnode in this component's operation set */
+ OperationIDKey key(opcode, name);
+ this->operations[key] = op_node;
+
+ /* set as entry/exit node of component (if appropriate) */
+ if (optype == DEPSOP_TYPE_INIT) {
+ BLI_assert(this->entry_operation == NULL);
+ this->entry_operation = op_node;
+ }
+ else if (optype == DEPSOP_TYPE_POST) {
+ // XXX: review whether DEPSOP_TYPE_OUT is better than DEPSOP_TYPE_POST, or maybe have both?
+ BLI_assert(this->exit_operation == NULL);
+ this->exit_operation = op_node;
+ }
+
+ /* set backlink */
+ op_node->owner = this;
+ }
+ else {
+ fprintf(stderr, "add_operation: Operation already exists - %s has %s at %p\n",
+ this->identifier().c_str(), op_node->identifier().c_str(), op_node);
+ BLI_assert(!"Should not happen!");
+ }
+
+ /* attach extra data */
+ op_node->evaluate = op;
+ op_node->optype = optype;
+ op_node->opcode = opcode;
+ op_node->name = name;
+
+ return op_node;
+}
+
+void ComponentDepsNode::remove_operation(eDepsOperation_Code opcode, const string &name)
+{
+ OperationDepsNode *op_node = find_operation(opcode, name);
+ if (op_node) {
+ /* unregister */
+ this->operations.erase(OperationIDKey(opcode, name));
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+}
+
+void ComponentDepsNode::clear_operations()
+{
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ OBJECT_GUARDED_DELETE(op_node, OperationDepsNode);
+ }
+ operations.clear();
+}
+
+void ComponentDepsNode::tag_update(Depsgraph *graph)
+{
+ OperationDepsNode *entry_op = get_entry_operation();
+ if (entry_op != NULL && entry_op->flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ for (OperationMap::const_iterator it = operations.begin(); it != operations.end(); ++it) {
+ OperationDepsNode *op_node = it->second;
+ op_node->tag_update(graph);
+ }
+}
+
+OperationDepsNode *ComponentDepsNode::get_entry_operation()
+{
+ if (entry_operation)
+ return entry_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+OperationDepsNode *ComponentDepsNode::get_exit_operation()
+{
+ if (exit_operation)
+ return exit_operation;
+ else if (operations.size() == 1)
+ return operations.begin()->second;
+ return NULL;
+}
+
+/* Parameter Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParametersComponentDepsNode, DEPSNODE_TYPE_PARAMETERS, "Parameters Component");
+static DepsNodeFactoryImpl<ParametersComponentDepsNode> DNTI_PARAMETERS;
+
+/* Animation Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(AnimationComponentDepsNode, DEPSNODE_TYPE_ANIMATION, "Animation Component");
+static DepsNodeFactoryImpl<AnimationComponentDepsNode> DNTI_ANIMATION;
+
+/* Transform Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(TransformComponentDepsNode, DEPSNODE_TYPE_TRANSFORM, "Transform Component");
+static DepsNodeFactoryImpl<TransformComponentDepsNode> DNTI_TRANSFORM;
+
+/* Proxy Component Defines ================================ */
+
+DEG_DEPSNODE_DEFINE(ProxyComponentDepsNode, DEPSNODE_TYPE_PROXY, "Proxy Component");
+static DepsNodeFactoryImpl<ProxyComponentDepsNode> DNTI_PROXY;
+
+/* Geometry Component Defines ============================= */
+
+DEG_DEPSNODE_DEFINE(GeometryComponentDepsNode, DEPSNODE_TYPE_GEOMETRY, "Geometry Component");
+static DepsNodeFactoryImpl<GeometryComponentDepsNode> DNTI_GEOMETRY;
+
+/* Sequencer Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(SequencerComponentDepsNode, DEPSNODE_TYPE_SEQUENCER, "Sequencer Component");
+static DepsNodeFactoryImpl<SequencerComponentDepsNode> DNTI_SEQUENCER;
+
+/* Pose Component ========================================= */
+
+DEG_DEPSNODE_DEFINE(PoseComponentDepsNode, DEPSNODE_TYPE_EVAL_POSE, "Pose Eval Component");
+static DepsNodeFactoryImpl<PoseComponentDepsNode> DNTI_EVAL_POSE;
+
+/* Bone Component ========================================= */
+
+/* Initialize 'bone component' node - from pointer data given */
+void BoneComponentDepsNode::init(const ID *id, const string &subdata)
+{
+ /* generic component-node... */
+ ComponentDepsNode::init(id, subdata);
+
+ /* name of component comes is bone name */
+ /* TODO(sergey): This sets name to an empty string because subdata is
+ * empty. Is it a bug?
+ */
+ //this->name = subdata;
+
+ /* bone-specific node data */
+ Object *ob = (Object *)id;
+ this->pchan = BKE_pose_channel_find_name(ob->pose, subdata.c_str());
+}
+
+DEG_DEPSNODE_DEFINE(BoneComponentDepsNode, DEPSNODE_TYPE_BONE, "Bone Component");
+static DepsNodeFactoryImpl<BoneComponentDepsNode> DNTI_BONE;
+
+/* Particles Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ParticlesComponentDepsNode, DEPSNODE_TYPE_EVAL_PARTICLES, "Particles Component");
+static DepsNodeFactoryImpl<ParticlesComponentDepsNode> DNTI_EVAL_PARTICLES;
+
+/* Shading Component Defines ============================ */
+
+DEG_DEPSNODE_DEFINE(ShadingComponentDepsNode, DEPSNODE_TYPE_SHADING, "Shading Component");
+static DepsNodeFactoryImpl<ShadingComponentDepsNode> DNTI_SHADING;
+
+
+/* Node Types Register =================================== */
+
+void DEG_register_component_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_PARAMETERS);
+ DEG_register_node_typeinfo(&DNTI_PROXY);
+ DEG_register_node_typeinfo(&DNTI_ANIMATION);
+ DEG_register_node_typeinfo(&DNTI_TRANSFORM);
+ DEG_register_node_typeinfo(&DNTI_GEOMETRY);
+ DEG_register_node_typeinfo(&DNTI_SEQUENCER);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_POSE);
+ DEG_register_node_typeinfo(&DNTI_BONE);
+
+ DEG_register_node_typeinfo(&DNTI_EVAL_PARTICLES);
+ DEG_register_node_typeinfo(&DNTI_SHADING);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_component.h b/source/blender/depsgraph/intern/depsnode_component.h
new file mode 100644
index 00000000000..06a18b60abb
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_component.h
@@ -0,0 +1,197 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DEPSNODE_COMPONENT_H__
+#define __DEPSNODE_COMPONENT_H__
+
+#include "depsnode.h"
+
+#include "depsgraph_util_hash.h"
+#include "depsgraph_util_map.h"
+#include "depsgraph_util_set.h"
+
+struct ID;
+struct bPoseChannel;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+struct EvaluationContext;
+struct OperationDepsNode;
+struct BoneComponentDepsNode;
+
+
+/* ID Component - Base type for all components */
+struct ComponentDepsNode : public DepsNode {
+ /* Key used to look up operations within a component */
+ struct OperationIDKey
+ {
+ eDepsOperation_Code opcode;
+ string name;
+
+
+ OperationIDKey() :
+ opcode(DEG_OPCODE_OPERATION), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode) :
+ opcode(opcode), name("")
+ {}
+ OperationIDKey(eDepsOperation_Code opcode, const string &name) :
+ opcode(opcode), name(name)
+ {}
+
+ string identifier() const
+ {
+ char codebuf[5];
+ sprintf(codebuf, "%d", opcode);
+
+ return string("OperationIDKey(") + codebuf + ", " + name + ")";
+ }
+
+ bool operator==(const OperationIDKey &other) const
+ {
+ return (opcode == other.opcode) && (name == other.name);
+ }
+ };
+
+ /* XXX can't specialize std::hash for this purpose, because ComponentKey is a nested type ...
+ * http://stackoverflow.com/a/951245
+ */
+ struct operation_key_hash {
+ bool operator() (const OperationIDKey &key) const
+ {
+ return hash_combine(hash<int>()(key.opcode), hash<string>()(key.name));
+ }
+ };
+
+ /* Typedef for container of operations */
+ typedef unordered_map<OperationIDKey, OperationDepsNode *, operation_key_hash> OperationMap;
+
+
+ ComponentDepsNode();
+ ~ComponentDepsNode();
+
+ void init(const ID *id, const string &subdata);
+ void copy(DepsgraphCopyContext *dcc, const ComponentDepsNode *src);
+
+ string identifier() const;
+
+ /* Find an existing operation, will throw an assert() if it does not exist. */
+ OperationDepsNode *find_operation(OperationIDKey key) const;
+ OperationDepsNode *find_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /* Check operation exists and return it. */
+ OperationDepsNode *has_operation(OperationIDKey key) const;
+ OperationDepsNode *has_operation(eDepsOperation_Code opcode, const string &name) const;
+
+ /**
+ * Create a new node for representing an operation and add this to graph
+ * \warning If an existing node is found, it will be modified. This helps when node may
+ * have been partially created earlier (e.g. parent ref before parent item is added)
+ *
+ * \param type: Operation node type (corresponding to context/component that it operates in)
+ * \param optype: Role that operation plays within component (i.e. where in eval process)
+ * \param op: The operation to perform
+ * \param name: Identifier for operation - used to find/locate it again
+ */
+ OperationDepsNode *add_operation(eDepsOperation_Type optype, DepsEvalOperationCb op, eDepsOperation_Code opcode, const string &name);
+
+ void remove_operation(eDepsOperation_Code opcode, const string &name);
+ void clear_operations();
+
+ void tag_update(Depsgraph *graph);
+
+ /* Evaluation Context Management .................. */
+
+ /* Initialize component's evaluation context used for the specified purpose */
+ virtual bool eval_context_init(EvaluationContext * /*eval_ctx*/) { return false; }
+ /* Free data in component's evaluation context which is used for the specified purpose
+ * NOTE: this does not free the actual context in question
+ */
+ virtual void eval_context_free(EvaluationContext * /*eval_ctx*/) {}
+
+ OperationDepsNode *get_entry_operation();
+ OperationDepsNode *get_exit_operation();
+
+ IDDepsNode *owner;
+
+ OperationMap operations; /* inner nodes for this component */
+ OperationDepsNode *entry_operation;
+ OperationDepsNode *exit_operation;
+
+ // XXX: a poll() callback to check if component's first node can be started?
+};
+
+/* ---------------------------------------- */
+
+struct ParametersComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct AnimationComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct TransformComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ProxyComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct GeometryComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct SequencerComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct PoseComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+/* Bone Component */
+struct BoneComponentDepsNode : public ComponentDepsNode {
+ void init(const ID *id, const string &subdata);
+
+ struct bPoseChannel *pchan; /* the bone that this component represents */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ParticlesComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+struct ShadingComponentDepsNode : public ComponentDepsNode {
+ DEG_DEPSNODE_DECLARE;
+};
+
+
+void DEG_register_component_depsnodes();
+
+#endif /* __DEPSNODE_COMPONENT_H__ */
diff --git a/source/blender/depsgraph/intern/depsnode_opcodes.h b/source/blender/depsgraph/intern/depsnode_opcodes.h
new file mode 100644
index 00000000000..48db2b79e66
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_opcodes.h
@@ -0,0 +1,141 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/* == OpCodes for OperationDepsNodes ==
+ * This file defines all the "operation codes" (opcodes) used to identify
+ * common operation node types. The intention of these defines is to have
+ * a fast and reliable way of identifying the relevant nodes within a component
+ * without having to use fragile dynamic strings.
+ *
+ * This file is meant to be used like UI_icons.h. That is, before including
+ * the file, the host file must define the DEG_OPCODE(_label) macro, which
+ * is responsible for converting the define into whatever form is suitable.
+ * Therefore, it intentionally doesn't have header guards.
+ */
+
+
+/* Example macro define: */
+/* #define DEF_DEG_OPCODE(label) DEG_OPCODE_##label, */
+
+/* Generic Operations ------------------------------ */
+
+/* Placeholder for operations which don't need special mention */
+DEF_DEG_OPCODE(OPERATION)
+
+// XXX: Placeholder while porting depsgraph code
+DEF_DEG_OPCODE(PLACEHOLDER)
+
+DEF_DEG_OPCODE(NOOP)
+
+/* Animation, Drivers, etc. ------------------------ */
+
+/* NLA + Action */
+DEF_DEG_OPCODE(ANIMATION)
+
+/* Driver */
+DEF_DEG_OPCODE(DRIVER)
+
+/* Proxy Inherit? */
+//DEF_DEG_OPCODE(PROXY)
+
+/* Transform --------------------------------------- */
+
+/* Transform entry point - local transforms only */
+DEF_DEG_OPCODE(TRANSFORM_LOCAL)
+
+/* Parenting */
+DEF_DEG_OPCODE(TRANSFORM_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINT)
+//DEF_DEG_OPCODE(TRANSFORM_CONSTRAINTS_DONE)
+
+/* Rigidbody Sim - Perform Sim */
+DEF_DEG_OPCODE(RIGIDBODY_REBUILD)
+DEF_DEG_OPCODE(RIGIDBODY_SIM)
+
+/* Rigidbody Sim - Copy Results to Object */
+DEF_DEG_OPCODE(TRANSFORM_RIGIDBODY)
+
+/* Transform exitpoint */
+DEF_DEG_OPCODE(TRANSFORM_FINAL)
+
+/* XXX: ubereval is for temporary porting purposes only */
+DEF_DEG_OPCODE(OBJECT_UBEREVAL)
+
+/* Geometry ---------------------------------------- */
+
+/* XXX: Placeholder - UberEval */
+DEF_DEG_OPCODE(GEOMETRY_UBEREVAL)
+
+/* Modifier */
+DEF_DEG_OPCODE(GEOMETRY_MODIFIER)
+
+/* Curve Objects - Path Calculation (used for path-following tools) */
+DEF_DEG_OPCODE(GEOMETRY_PATH)
+
+/* Pose -------------------------------------------- */
+
+/* Init IK Trees, etc. */
+DEF_DEG_OPCODE(POSE_INIT)
+
+/* Free IK Trees + Compute Deform Matrices */
+DEF_DEG_OPCODE(POSE_DONE)
+
+/* IK/Spline Solvers */
+DEF_DEG_OPCODE(POSE_IK_SOLVER)
+DEF_DEG_OPCODE(POSE_SPLINE_IK_SOLVER)
+
+/* Bone -------------------------------------------- */
+
+/* Bone local transforms - Entrypoint */
+DEF_DEG_OPCODE(BONE_LOCAL)
+
+/* Pose-space conversion (includes parent + restpose) */
+DEF_DEG_OPCODE(BONE_POSE_PARENT)
+
+/* Constraints */
+DEF_DEG_OPCODE(BONE_CONSTRAINTS)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_INIT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINT)
+//DEF_DEG_OPCODE(BONE_CONSTRAINTS_DONE)
+
+/* Bone transforms are ready
+ * - "READY" This (internal) noop is used to signal that all pre-IK operations are done.
+ * Its role is to help mediate situations where cyclic relations may otherwise form
+ * (i.e. one bone in chain targetting another in same chain)
+ * - "DONE" This noop is used to signal that the bone's final pose transform can be read by others
+ */
+// TODO: deform mats could get calculated in the final_transform ops...
+DEF_DEG_OPCODE(BONE_READY)
+DEF_DEG_OPCODE(BONE_DONE)
+
+/* Particles --------------------------------------- */
+
+/* XXX: placeholder - Particle System eval */
+DEF_DEG_OPCODE(PSYS_EVAL)
diff --git a/source/blender/depsgraph/intern/depsnode_operation.cc b/source/blender/depsgraph/intern/depsnode_operation.cc
new file mode 100644
index 00000000000..de8755f7ae9
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.cc
@@ -0,0 +1,100 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "MEM_guardedalloc.h"
+
+extern "C" {
+#include "BLI_utildefines.h"
+} /* extern "C" */
+
+#include "depsnode_operation.h" /* own include */
+#include "depsnode_component.h"
+#include "depsgraph.h"
+#include "depsgraph_intern.h"
+
+/* ******************************************************************* */
+/* OpNode Identifiers Array - Exported to other depsgraph files too... */
+
+/* identifiers for operations */
+const char *DEG_OPNAMES[] = {
+#define DEF_DEG_OPCODE(label) #label,
+#include "depsnode_opcodes.h"
+#undef DEF_DEG_OPCODE
+
+ "<Invalid>"
+};
+
+/* *********** */
+/* Inner Nodes */
+
+OperationDepsNode::OperationDepsNode() :
+ eval_priority(0.0f),
+ flag(0)
+{
+}
+
+OperationDepsNode::~OperationDepsNode()
+{
+}
+
+string OperationDepsNode::identifier() const
+{
+ BLI_assert((opcode > 0) && (opcode < ARRAY_SIZE(DEG_OPNAMES)));
+ return string(DEG_OPNAMES[opcode]) + "(" + name + ")";
+}
+
+/* Full node identifier, including owner name.
+ * used for logging and debug prints.
+ */
+string OperationDepsNode::full_identifier() const
+{
+ string owner_str = "";
+ if (owner->type == DEPSNODE_TYPE_BONE) {
+ owner_str = owner->owner->name + "." + owner->name;
+ }
+ else {
+ owner_str = owner->owner->name;
+ }
+ return owner_str + "." + identifier();
+}
+
+void OperationDepsNode::tag_update(Depsgraph *graph)
+{
+ if (flag & DEPSOP_FLAG_NEEDS_UPDATE) {
+ return;
+ }
+ /* Tag for update, but also note that this was the source of an update. */
+ flag |= (DEPSOP_FLAG_NEEDS_UPDATE | DEPSOP_FLAG_DIRECTLY_MODIFIED);
+ graph->add_entry_tag(this);
+}
+
+DEG_DEPSNODE_DEFINE(OperationDepsNode, DEPSNODE_TYPE_OPERATION, "Operation");
+static DepsNodeFactoryImpl<OperationDepsNode> DNTI_OPERATION;
+
+void DEG_register_operation_depsnodes()
+{
+ DEG_register_node_typeinfo(&DNTI_OPERATION);
+}
diff --git a/source/blender/depsgraph/intern/depsnode_operation.h b/source/blender/depsgraph/intern/depsnode_operation.h
new file mode 100644
index 00000000000..2b70ff0a8dc
--- /dev/null
+++ b/source/blender/depsgraph/intern/depsnode_operation.h
@@ -0,0 +1,86 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2013 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Joshua Leung
+ * Contributor(s): None Yet
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __DEPSNODE_OPERATION_H__
+#define __DEPSNODE_OPERATION_H__
+
+#include "depsnode.h"
+
+struct ID;
+
+struct Depsgraph;
+struct DepsgraphCopyContext;
+
+/* Flags for Depsgraph Nodes */
+typedef enum eDepsOperation_Flag {
+ /* node needs to be updated */
+ DEPSOP_FLAG_NEEDS_UPDATE = (1 << 0),
+
+ /* node was directly modified, causing need for update */
+ /* XXX: intention is to make it easier to tell when we just need to take subgraphs */
+ DEPSOP_FLAG_DIRECTLY_MODIFIED = (1 << 1),
+
+ /* Operation is evaluated using CPython; has GIL and security implications... */
+ DEPSOP_FLAG_USES_PYTHON = (1 << 2),
+} eDepsOperation_Flag;
+
+/* Atomic Operation - Base type for all operations */
+struct OperationDepsNode : public DepsNode {
+
+
+ OperationDepsNode();
+ ~OperationDepsNode();
+
+ string identifier() const;
+ string full_identifier() const;
+
+ void tag_update(Depsgraph *graph);
+
+ bool is_noop() const { return (bool)evaluate == false; }
+
+ OperationDepsNode *get_entry_operation() { return this; }
+ OperationDepsNode *get_exit_operation() { return this; }
+
+ ComponentDepsNode *owner; /* component that contains the operation */
+
+ DepsEvalOperationCb evaluate; /* callback for operation */
+
+
+ uint32_t num_links_pending; /* how many inlinks are we still waiting on before we can be evaluated... */
+ float eval_priority;
+ bool scheduled;
+
+ short optype; /* (eDepsOperation_Type) stage of evaluation */
+ int opcode; /* (eDepsOperation_Code) identifier for the operation being performed */
+
+ int flag; /* (eDepsOperation_Flag) extra settings affecting evaluation */
+
+ DEG_DEPSNODE_DECLARE;
+};
+
+void DEG_register_operation_depsnodes();
+
+#endif /* __DEPSNODE_OPERATION_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.cc b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
new file mode 100644
index 00000000000..5a171d190cd
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.cc
@@ -0,0 +1,134 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ */
+
+#include <cstdio>
+#include <cstdlib>
+#include <stack>
+
+extern "C" {
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_cycle.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+struct StackEntry {
+ OperationDepsNode *node;
+ StackEntry *from;
+ DepsRelation *via_relation;
+};
+
+void deg_graph_detect_cycles(Depsgraph *graph)
+{
+ /* Not is not visited at all during traversal. */
+ const int NODE_NOT_VISITED = 0;
+ /* Node has been visited during traversal and not in current stack. */
+ const int NODE_VISITED = 1;
+ /* Node has been visited during traversal and is in current stack. */
+ const int NODE_IN_STACK = 2;
+
+ std::stack<StackEntry> traversal_stack;
+ for (Depsgraph::OperationNodes::const_iterator it_op = graph->operations.begin();
+ it_op != graph->operations.end();
+ ++it_op)
+ {
+ OperationDepsNode *node = *it_op;
+ bool has_inlinks = false;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->inlinks.begin();
+ it_rel != node->inlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->from->type == DEPSNODE_TYPE_OPERATION) {
+ has_inlinks = true;
+ }
+ }
+ if (has_inlinks == false) {
+ StackEntry entry;
+ entry.node = node;
+ entry.from = NULL;
+ entry.via_relation = NULL;
+ traversal_stack.push(entry);
+ node->done = NODE_IN_STACK;
+ }
+ else {
+ node->done = NODE_NOT_VISITED;
+ }
+ }
+
+ while (!traversal_stack.empty()) {
+ StackEntry &entry = traversal_stack.top();
+ OperationDepsNode *node = entry.node;
+ bool all_child_traversed = true;
+ for (OperationDepsNode::Relations::const_iterator it_rel = node->outlinks.begin();
+ it_rel != node->outlinks.end();
+ ++it_rel)
+ {
+ DepsRelation *rel = *it_rel;
+ if (rel->to->type == DEPSNODE_TYPE_OPERATION) {
+ OperationDepsNode *to = (OperationDepsNode *)rel->to;
+ if (to->done == NODE_IN_STACK) {
+ printf("Dependency cycle detected:\n");
+ printf(" '%s' depends on '%s' through '%s'\n",
+ to->full_identifier().c_str(),
+ node->full_identifier().c_str(),
+ rel->name);
+
+ StackEntry *current = &entry;
+ while (current->node != to) {
+ BLI_assert(current != NULL);
+ printf(" '%s' depends on '%s' through '%s'\n",
+ current->node->full_identifier().c_str(),
+ current->from->node->full_identifier().c_str(),
+ current->via_relation->name);
+ current = current->from;
+ }
+ /* TODO(sergey): So called roussian rlette cycle solver. */
+ rel->flag |= DEPSREL_FLAG_CYCLIC;
+ }
+ else if (to->done == NODE_NOT_VISITED) {
+ StackEntry new_entry;
+ new_entry.node = to;
+ new_entry.from = &entry;
+ new_entry.via_relation = rel;
+ traversal_stack.push(new_entry);
+ to->done = NODE_IN_STACK;
+ all_child_traversed = false;
+ break;
+ }
+ }
+ }
+ if (all_child_traversed) {
+ node->done = NODE_VISITED;
+ traversal_stack.pop();
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_cycle.h b/source/blender/depsgraph/util/depsgraph_util_cycle.h
new file mode 100644
index 00000000000..f827d85c16a
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_cycle.h
@@ -0,0 +1,31 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Sergey Sharybin
+ */
+
+#ifndef __DEPSGRAPH_UTIL_CYCLE_H__
+#define __DEPSGRAPH_UTIL_CYCLE_H__
+
+struct Depsgraph;
+
+void deg_graph_detect_cycles(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_CYCLE_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_function.h b/source/blender/depsgraph/util/depsgraph_util_function.h
new file mode 100644
index 00000000000..f62efd76267
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_function.h
@@ -0,0 +1,106 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Lukas Toenne
+ * Contributor(s):
+ */
+
+#ifndef __DEPSGRAPH_UTIL_FUNCTION_H__
+#define __DEPSGRAPH_UTIL_FUNCTION_H__
+
+#if (__cplusplus > 199711L) || (defined(_MSC_VER) && _MSC_VER >= 1800)
+
+#include <functional>
+
+using std::function;
+using namespace std::placeholders;
+#define function_bind std::bind
+
+#elif defined(HAVE_BOOST_FUNCTION_BINDINGS)
+
+#include <boost/bind.hpp>
+#include <boost/function.hpp>
+
+using boost::function;
+#define function_bind boost::bind
+
+#else
+
+#pragma message("No available function binding implementation. Using stub instead, disabling new depsgraph")
+
+#ifndef WITH_LEGACY_DEPSGRAPH
+# error "Unable to build new depsgraph and legacy one is disabled."
+#endif
+
+#define DISABLE_NEW_DEPSGRAPH
+
+#include <cstdlib>
+
+template<typename T>
+class function {
+public:
+ function() {};
+ function(void *) {}
+ operator bool() const { return false; }
+ bool operator== (void*) { return false; }
+
+ template<typename T1>
+ void operator() (T1) {
+ BLI_assert(!"Should not be used");
+ }
+};
+
+class Wrap {
+public:
+ Wrap() {}
+ template <typename T>
+ Wrap(T /*arg*/) {}
+};
+
+template <typename T>
+void *function_bind(T func,
+ Wrap arg1 = Wrap(),
+ Wrap arg2 = Wrap(),
+ Wrap arg3 = Wrap(),
+ Wrap arg4 = Wrap(),
+ Wrap arg5 = Wrap(),
+ Wrap arg6 = Wrap(),
+ Wrap arg7 = Wrap())
+{
+ BLI_assert(!"Should not be used");
+ (void)func;
+ (void)arg1;
+ (void)arg2;
+ (void)arg3;
+ (void)arg4;
+ (void)arg5;
+ (void)arg6;
+ (void)arg7;
+ return NULL;
+}
+
+#define _1 Wrap()
+#define _2 Wrap()
+#define _3 Wrap()
+#define _4 Wrap()
+
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_SET_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_hash.h b/source/blender/depsgraph/util/depsgraph_util_hash.h
new file mode 100644
index 00000000000..0f5a85b3526
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_hash.h
@@ -0,0 +1,66 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ */
+
+#ifndef __DEPSGRAPH_UTIL_HASH_H__
+#define __DEPSGRAPH_UTIL_HASH_H__
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# define DEG_HASH_NAMESPACE_BEGIN
+# define DEG_HASH_NAMESPACE_END
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std {
+# define DEG_HASH_NAMESPACE_END }
+using std::hash;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+# define DEG_HASH_NAMESPACE_BEGIN namespace std { namespace tr1 {
+# define DEG_HASH_NAMESPACE_END } }
+using std::tr1::hash;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+/* XXX this might require 2 different variants for sizeof(size_t) (32 vs 64 bit) */
+inline size_t hash_combine(size_t hash_a, size_t hash_b)
+{
+ return hash_a ^ (hash_b + 0x9e3779b9 + (hash_a << 6) + (hash_a >> 2));
+}
+
+#endif /* __DEPSGRAPH_UTIL_HASH_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_map.h b/source/blender/depsgraph/util/depsgraph_util_map.h
new file mode 100644
index 00000000000..2951641431b
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_map.h
@@ -0,0 +1,61 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ */
+
+#ifndef __DEPSGRAPH_UTIL_MAP_H__
+#define __DEPSGRAPH_UTIL_MAP_H__
+
+#include <map>
+
+#include "depsgraph_util_hash.h"
+
+using std::map;
+using std::pair;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <map>
+typedef std::map unordered_map;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_map>
+using std::unordered_map;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_map>
+using std::tr1::unordered_map;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_MAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
new file mode 100644
index 00000000000..36bd72108ed
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.cc
@@ -0,0 +1,132 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#include "depsgraph_util_pchanmap.h"
+
+#include <stdio.h>
+#include <string.h>
+
+extern "C" {
+#include "BLI_utildefines.h"
+#include "BLI_ghash.h"
+}
+
+static void free_rootpchanmap_valueset(void *val)
+{
+ /* Just need to free the set itself - the names stored are all references. */
+ GSet *values = (GSet *)val;
+ BLI_gset_free(values, NULL);
+}
+
+RootPChanMap::RootPChanMap()
+{
+ /* Just create empty map. */
+ m_map = BLI_ghash_str_new("RootPChanMap");
+}
+
+RootPChanMap::~RootPChanMap()
+{
+ /* Free the map, and all the value sets. */
+ BLI_ghash_free(m_map, NULL, free_rootpchanmap_valueset);
+}
+
+/* Debug contents of map */
+void RootPChanMap::print_debug()
+{
+ GHashIterator it1;
+ GSetIterator it2;
+
+ printf("Root PChan Map:\n");
+ GHASH_ITER(it1, m_map) {
+ const char *item = (const char *)BLI_ghashIterator_getKey(&it1);
+ GSet *values = (GSet *)BLI_ghashIterator_getValue(&it1);
+
+ printf(" %s : { ", item);
+ GSET_ITER(it2, values) {
+ const char *val = (const char *)BLI_gsetIterator_getKey(&it2);
+ printf("%s, ", val);
+ }
+ printf("}\n");
+ }
+}
+
+/* Add a mapping. */
+void RootPChanMap::add_bone(const char *bone, const char *root)
+{
+ if (BLI_ghash_haskey(m_map, bone)) {
+ /* Add new entry, but only add the root if it doesn't already
+ * exist in there.
+ */
+ GSet *values = (GSet *)BLI_ghash_lookup(m_map, bone);
+ BLI_gset_add(values, (void *)root);
+ }
+ else {
+ /* Create new set and mapping. */
+ GSet *values = BLI_gset_new(BLI_ghashutil_strhash_p,
+ BLI_ghashutil_strcmp,
+ "RootPChanMap Value Set");
+ BLI_ghash_insert(m_map, (void *)bone, (void *)values);
+
+ /* Add new entry now. */
+ BLI_gset_insert(values, (void *)root);
+ }
+}
+
+/* Check if there's a common root bone between two bones. */
+bool RootPChanMap::has_common_root(const char *bone1, const char *bone2)
+{
+ /* Ensure that both are in the map... */
+ if (BLI_ghash_haskey(m_map, bone1) == false) {
+ //fprintf("RootPChanMap: bone1 '%s' not found (%s => %s)\n", bone1, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ if (BLI_ghash_haskey(m_map, bone2) == false) {
+ //fprintf("RootPChanMap: bone2 '%s' not found (%s => %s)\n", bone2, bone1, bone2);
+ //print_debug();
+ return false;
+ }
+
+ GSet *bone1_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone1);
+ GSet *bone2_roots = (GSet *)BLI_ghash_lookup(m_map, (void *)bone2);
+
+ GSetIterator it1, it2;
+ GSET_ITER(it1, bone1_roots) {
+ GSET_ITER(it2, bone2_roots) {
+ const char *v1 = (const char *)BLI_gsetIterator_getKey(&it1);
+ const char *v2 = (const char *)BLI_gsetIterator_getKey(&it2);
+
+ if (strcmp(v1, v2) == 0) {
+ //fprintf("RootPchanMap: %s in common for %s => %s\n", v1, bone1, bone2);
+ return true;
+ }
+ }
+ }
+
+ //fprintf("RootPChanMap: No common root found (%s => %s)\n", bone1, bone2);
+ return false;
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_pchanmap.h b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
new file mode 100644
index 00000000000..5d27d84c0da
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_pchanmap.h
@@ -0,0 +1,55 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Sergey Sharybin
+ * Contributor(s): Joshua Leung
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef ___DEPSGRAPH_UTIL_PCHANMAP_H__
+#define ___DEPSGRAPH_UTIL_PCHANMAP_H__
+
+struct RootPChanMap {
+ /* ctor and dtor - Create and free the internal map respectively. */
+ RootPChanMap();
+ ~RootPChanMap();
+
+ /* Debug contents of map. */
+ void print_debug();
+
+ /* Add a mapping. */
+ void add_bone(const char *bone, const char *root);
+
+ /* Check if there's a common root bone between two bones. */
+ bool has_common_root(const char *bone1, const char *bone2);
+
+private:
+ /* The actual map:
+ * - Keys are "strings" (const char *) - not dynamically allocated.
+ * - Values are "sets" (const char *) - not dynamically allocated.
+ *
+ * We don't use the C++ maps here, as it's more convenient to use
+ * Blender's GHash and be able to compare by-value instead of by-ref.
+ */
+ struct GHash *m_map;
+};
+
+#endif /* __DEPSGRAPH_UTIL_PCHANMAP_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_set.h b/source/blender/depsgraph/util/depsgraph_util_set.h
new file mode 100644
index 00000000000..09fa5313920
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_set.h
@@ -0,0 +1,60 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2014 Blender Foundation.
+ * All rights reserved.
+ *
+ * Original Author: Brecht van Lommel
+ * Contributor(s): Lukas Toenne
+ */
+
+#ifndef __DEPSGRAPH_UTIL_SET_H__
+#define __DEPSGRAPH_UTIL_SET_H__
+
+#include <set>
+
+#include "depsgraph_util_hash.h"
+
+using std::set;
+
+#if defined(DEG_NO_UNORDERED_MAP)
+# include <set>
+typedef std::set unordered_set;
+#endif
+
+#if defined(DEG_TR1_UNORDERED_MAP)
+# include <tr1/unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP)
+# include <unordered_set>
+using std::unordered_set;
+#endif
+
+#if defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE)
+# include <unordered_set>
+using std::tr1::unordered_set;
+#endif
+
+#if !defined(DEG_NO_UNORDERED_MAP) && !defined(DEG_TR1_UNORDERED_MAP) && \
+ !defined(DEG_STD_UNORDERED_MAP) && !defined(DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE) // NOLINT
+# error One of: DEG_NO_UNORDERED_MAP, DEG_TR1_UNORDERED_MAP,\
+ DEG_STD_UNORDERED_MAP, DEG_STD_UNORDERED_MAP_IN_TR1_NAMESPACE must be defined! // NOLINT
+#endif
+
+#endif /* __DEPSGRAPH_UTIL_SET_H__ */
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.cc b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
new file mode 100644
index 00000000000..9411d013c44
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.cc
@@ -0,0 +1,133 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne
+ * Sergey Sharybin,
+ */
+
+extern "C" {
+#include "MEM_guardedalloc.h"
+
+#include "BLI_utildefines.h"
+
+#include "DNA_ID.h"
+
+#include "RNA_access.h"
+#include "RNA_types.h"
+}
+
+#include "depsgraph_util_transitive.h"
+#include "depsgraph.h"
+#include "depsnode.h"
+#include "depsnode_component.h"
+#include "depsnode_operation.h"
+
+/* -------------------------------------------------- */
+
+/* Performs a transitive reduction to remove redundant relations.
+ * http://en.wikipedia.org/wiki/Transitive_reduction
+ *
+ * XXX The current implementation is somewhat naive and has O(V*E) worst case
+ * runtime.
+ * A more optimized algorithm can be implemented later, e.g.
+ *
+ * http://www.sciencedirect.com/science/article/pii/0304397588900321/pdf?md5=3391e309b708b6f9cdedcd08f84f4afc&pid=1-s2.0-0304397588900321-main.pdf
+ *
+ * Care has to be taken to make sure the algorithm can handle the cyclic case
+ * too! (unless we can to prevent this case early on).
+ */
+
+enum {
+ OP_VISITED = 1,
+ OP_REACHABLE = 2,
+};
+
+static void deg_graph_tag_paths_recursive(DepsNode *node)
+{
+ if (node->done & OP_VISITED)
+ return;
+ node->done |= OP_VISITED;
+
+ for (OperationDepsNode::Relations::const_iterator it = node->inlinks.begin();
+ it != node->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ /* Do this only in inlinks loop, so the target node does not get
+ * flagged.
+ */
+ rel->from->done |= OP_REACHABLE;
+ }
+}
+
+void deg_graph_transitive_reduction(Depsgraph *graph)
+{
+ for (Depsgraph::OperationNodes::const_iterator it_target = graph->operations.begin();
+ it_target != graph->operations.end();
+ ++it_target)
+ {
+ OperationDepsNode *target = *it_target;
+
+ /* Clear tags. */
+ for (Depsgraph::OperationNodes::const_iterator it = graph->operations.begin();
+ it != graph->operations.end();
+ ++it)
+ {
+ OperationDepsNode *node = *it;
+ node->done = 0;
+ }
+
+ /* mark nodes from which we can reach the target
+ * start with children, so the target node and direct children are not
+ * flagged.
+ */
+ target->done |= OP_VISITED;
+ for (OperationDepsNode::Relations::const_iterator it = target->inlinks.begin();
+ it != target->inlinks.end();
+ ++it)
+ {
+ DepsRelation *rel = *it;
+
+ deg_graph_tag_paths_recursive(rel->from);
+ }
+
+ /* Eemove redundant paths to the target. */
+ for (DepsNode::Relations::const_iterator it_rel = target->inlinks.begin();
+ it_rel != target->inlinks.end();
+ )
+ {
+ DepsRelation *rel = *it_rel;
+ /* Increment in advance, so we can safely remove the relation. */
+ ++it_rel;
+
+ if (rel->from->type == DEPSNODE_TYPE_TIMESOURCE) {
+ /* HACK: time source nodes don't get "done" flag set/cleared. */
+ /* TODO: there will be other types in future, so iterators above
+ * need modifying.
+ */
+ }
+ else if (rel->from->done & OP_REACHABLE) {
+ OBJECT_GUARDED_DELETE(rel, DepsRelation);
+ }
+ }
+ }
+}
diff --git a/source/blender/depsgraph/util/depsgraph_util_transitive.h b/source/blender/depsgraph/util/depsgraph_util_transitive.h
new file mode 100644
index 00000000000..8995c18eca0
--- /dev/null
+++ b/source/blender/depsgraph/util/depsgraph_util_transitive.h
@@ -0,0 +1,32 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2015 Blender Foundation.
+ * All rights reserved.
+ *
+ * Contributor(s): Lukas Toenne
+ * Sergey Sharybin,
+ */
+
+#ifndef __DEPSGRAPH_UTIL_TRANSITIVE_H__
+#define __DEPSGRAPH_UTIL_TRANSITIVE_H__
+
+struct Depsgraph;
+
+void deg_graph_transitive_reduction(Depsgraph *graph);
+
+#endif /* __DEPSGRAPH_UTIL_TRANSITIVE_H__ */
diff --git a/source/blender/editors/space_view3d/CMakeLists.txt b/source/blender/editors/space_view3d/CMakeLists.txt
index ab69e67361d..d8d29d63686 100644
--- a/source/blender/editors/space_view3d/CMakeLists.txt
+++ b/source/blender/editors/space_view3d/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../../makesrna
../../render/extern/include
../../windowmanager
+ ../../depsgraph
../../../../intern/guardedalloc
../../../../intern/glew-mx
../../../../intern/smoke/extern
diff --git a/source/blender/editors/space_view3d/SConscript b/source/blender/editors/space_view3d/SConscript
index a21da940906..78f24948070 100644
--- a/source/blender/editors/space_view3d/SConscript
+++ b/source/blender/editors/space_view3d/SConscript
@@ -48,6 +48,7 @@ incs = [
'../../makesrna',
'../../render/extern/include',
'../../windowmanager',
+ '../../depsgraph',
]
if env['WITH_BF_PYTHON']:
diff --git a/source/blender/editors/space_view3d/space_view3d.c b/source/blender/editors/space_view3d/space_view3d.c
index bd070ea25fb..096d9e8a40a 100644
--- a/source/blender/editors/space_view3d/space_view3d.c
+++ b/source/blender/editors/space_view3d/space_view3d.c
@@ -74,6 +74,8 @@
# include "BPY_extern.h"
#endif
+#include "DEG_depsgraph.h"
+
#include "view3d_intern.h" /* own include */
/* ******************** manage regions ********************* */
@@ -931,7 +933,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
(ob && (ob->mode == OB_MODE_TEXTURE_PAINT)) ||
(v3d->drawtype == OB_TEXTURE &&
(scene->gm.matmode == GAME_MAT_GLSL ||
- BKE_scene_use_new_shading_nodes(scene))))
+ BKE_scene_use_new_shading_nodes(scene))) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
@@ -954,7 +957,8 @@ static void view3d_main_area_listener(bScreen *sc, ScrArea *sa, ARegion *ar, wmN
switch (wmn->data) {
case ND_LIGHTING:
if ((v3d->drawtype == OB_MATERIAL) ||
- (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)))
+ (v3d->drawtype == OB_TEXTURE && (scene->gm.matmode == GAME_MAT_GLSL)) ||
+ !DEG_depsgraph_use_legacy())
{
ED_region_tag_redraw(ar);
}
diff --git a/source/blender/editors/transform/CMakeLists.txt b/source/blender/editors/transform/CMakeLists.txt
index 0c360474b78..0bc38f81dd7 100644
--- a/source/blender/editors/transform/CMakeLists.txt
+++ b/source/blender/editors/transform/CMakeLists.txt
@@ -55,6 +55,10 @@ if(WITH_INTERNATIONAL)
add_definitions(-DWITH_INTERNATIONAL)
endif()
+if(WITH_LEGACY_DEPSGRAPH)
+ add_definitions(-DWITH_LEGACY_DEPSGRAPH)
+endif()
+
add_definitions(${GL_DEFINITIONS})
blender_add_lib(bf_editor_transform "${SRC}" "${INC}" "${INC_SYS}")
diff --git a/source/blender/editors/transform/SConscript b/source/blender/editors/transform/SConscript
index e249856b747..1a2e9ab074a 100644
--- a/source/blender/editors/transform/SConscript
+++ b/source/blender/editors/transform/SConscript
@@ -50,4 +50,7 @@ defs = env['BF_GL_DEFINITIONS']
if env['WITH_BF_INTERNATIONAL']:
defs.append('WITH_INTERNATIONAL')
+if env['WITH_BF_LEGACY_DEPSGRAPH']:
+ defs.append('WITH_LEGACY_DEPSGRAPH')
+
env.BlenderLib ( 'bf_editors_transform', sources, incs, defs, libtype=['core'], priority=[40] )
diff --git a/source/blender/editors/transform/transform_conversions.c b/source/blender/editors/transform/transform_conversions.c
index 9efbc1bc549..4da3fa8a959 100644
--- a/source/blender/editors/transform/transform_conversions.c
+++ b/source/blender/editors/transform/transform_conversions.c
@@ -5362,7 +5362,9 @@ static void set_trans_object_base_flags(TransInfo *t)
}
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
@@ -5439,7 +5441,9 @@ static int count_proportional_objects(TransInfo *t)
/* all recalc flags get flushed to all layers, so a layer flip later on works fine */
DAG_scene_relations_update(G.main, t->scene);
+#ifdef WITH_LEGACY_DEPSGRAPH
DAG_scene_flush_update(G.main, t->scene, -1, 0);
+#endif
/* and we store them temporal in base (only used for transform code) */
/* this because after doing updates, the object->recalc is cleared */
diff --git a/source/blender/makesdna/DNA_scene_types.h b/source/blender/makesdna/DNA_scene_types.h
index a40b8aff08e..fe346eecec5 100644
--- a/source/blender/makesdna/DNA_scene_types.h
+++ b/source/blender/makesdna/DNA_scene_types.h
@@ -1401,6 +1401,7 @@ typedef struct Scene {
void *fps_info; /* (runtime) info/cache used for presenting playback framerate info to the user */
/* none of the dependency graph vars is mean to be saved */
+ struct Depsgraph *depsgraph;
struct DagForest *theDag;
short dagflags;
short recalc; /* recalc = counterpart of ob->recalc */
diff --git a/source/blender/makesrna/SConscript b/source/blender/makesrna/SConscript
index e366c9bbe2b..f8eb2e1807c 100644
--- a/source/blender/makesrna/SConscript
+++ b/source/blender/makesrna/SConscript
@@ -47,6 +47,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../bmesh',
+ '../depsgraph',
'../editors/include',
'../gpu',
'../ikplugin',
diff --git a/source/blender/makesrna/intern/CMakeLists.txt b/source/blender/makesrna/intern/CMakeLists.txt
index 69c5955c454..e878e0877d2 100644
--- a/source/blender/makesrna/intern/CMakeLists.txt
+++ b/source/blender/makesrna/intern/CMakeLists.txt
@@ -45,6 +45,7 @@ set(DEFSRC
rna_context.c
rna_controller.c
rna_curve.c
+ rna_depsgraph.c
rna_dynamicpaint.c
rna_fcurve.c
rna_fluidsim.c
@@ -307,6 +308,7 @@ blender_include_dirs(
../../blenlib
../../bmesh
../../blenfont
+ ../../depsgraph
../../gpu
../../imbuf
../../ikplugin
diff --git a/source/blender/makesrna/intern/SConscript b/source/blender/makesrna/intern/SConscript
index 3d190fc6a13..afa4ab3a67d 100644
--- a/source/blender/makesrna/intern/SConscript
+++ b/source/blender/makesrna/intern/SConscript
@@ -66,6 +66,7 @@ incs = [
'../../blenkernel',
'../../blenlib',
'../../bmesh',
+ '../../depsgraph',
'../../editors/include',
'../../gpu',
'../../ikplugin',
diff --git a/source/blender/makesrna/intern/makesrna.c b/source/blender/makesrna/intern/makesrna.c
index 829a70ef166..dfd0f13ec1a 100644
--- a/source/blender/makesrna/intern/makesrna.c
+++ b/source/blender/makesrna/intern/makesrna.c
@@ -3293,6 +3293,7 @@ static RNAProcessItem PROCESS_ITEMS[] = {
{"rna_context.c", NULL, RNA_def_context},
{"rna_controller.c", "rna_controller_api.c", RNA_def_controller},
{"rna_curve.c", "rna_curve_api.c", RNA_def_curve},
+ {"rna_depsgraph.c", NULL, RNA_def_depsgraph},
{"rna_dynamicpaint.c", NULL, RNA_def_dynamic_paint},
{"rna_fcurve.c", "rna_fcurve_api.c", RNA_def_fcurve},
{"rna_fluidsim.c", NULL, RNA_def_fluidsim},
diff --git a/source/blender/makesrna/intern/rna_depsgraph.c b/source/blender/makesrna/intern/rna_depsgraph.c
new file mode 100644
index 00000000000..8ac1e2acc60
--- /dev/null
+++ b/source/blender/makesrna/intern/rna_depsgraph.c
@@ -0,0 +1,112 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributor(s): Blender Foundation (2014).
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+/** \file blender/makesrna/intern/rna_depsgraph.c
+ * \ingroup RNA
+ */
+
+#include <stdlib.h>
+
+#include "BLI_utildefines.h"
+#include "BLI_path_util.h"
+
+#include "RNA_define.h"
+#include "RNA_enum_types.h"
+
+#include "rna_internal.h"
+
+#include "DEG_depsgraph.h"
+
+#include "BKE_depsgraph.h"
+
+#ifdef RNA_RUNTIME
+
+#include "BKE_report.h"
+
+#include "DEG_depsgraph_debug.h"
+
+static void rna_Depsgraph_debug_graphviz(Depsgraph *graph, const char *filename)
+{
+ FILE *f = fopen(filename, "w");
+ if (f == NULL)
+ return;
+
+ DEG_debug_graphviz(graph, f, "Depsgraph", false);
+
+ fclose(f);
+}
+
+static void rna_Depsgraph_debug_rebuild(Depsgraph *UNUSED(graph), Main *bmain)
+{
+ Scene *sce;
+ DAG_relations_tag_update(bmain);
+ for (sce = bmain->scene.first; sce; sce = sce->id.next) {
+ DAG_scene_relations_rebuild(bmain, sce);
+ DEG_graph_on_visible_update(bmain, sce);
+ }
+}
+
+static void rna_Depsgraph_debug_stats(Depsgraph *graph, ReportList *reports)
+{
+ size_t outer, ops, rels;
+
+ DEG_stats_simple(graph, &outer, &ops, &rels);
+
+ // XXX: report doesn't seem to work
+ printf("Approx %lu Operations, %lu Relations, %lu Outer Nodes\n",
+ ops, rels, outer);
+
+ BKE_reportf(reports, RPT_WARNING, "Approx. %lu Operations, %lu Relations, %lu Outer Nodes",
+ ops, rels, outer);
+}
+
+#else
+
+static void rna_def_depsgraph(BlenderRNA *brna)
+{
+ StructRNA *srna;
+ FunctionRNA *func;
+ PropertyRNA *parm;
+
+ srna = RNA_def_struct(brna, "Depsgraph", NULL);
+ RNA_def_struct_ui_text(srna, "Dependency Graph", "");
+
+ func = RNA_def_function(srna, "debug_graphviz", "rna_Depsgraph_debug_graphviz");
+ parm = RNA_def_string_file_path(func, "filename", NULL, FILE_MAX, "File Name",
+ "File in which to store graphviz debug output");
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "debug_rebuild", "rna_Depsgraph_debug_rebuild");
+ RNA_def_function_flag(func, FUNC_USE_MAIN);
+ RNA_def_property_flag(parm, PROP_REQUIRED);
+
+ func = RNA_def_function(srna, "debug_stats", "rna_Depsgraph_debug_stats");
+ RNA_def_function_ui_description(func, "Report the number of elements in the Dependency Graph");
+ RNA_def_function_flag(func, FUNC_USE_REPORTS);
+}
+
+void RNA_def_depsgraph(BlenderRNA *brna)
+{
+ rna_def_depsgraph(brna);
+}
+
+#endif
diff --git a/source/blender/makesrna/intern/rna_internal.h b/source/blender/makesrna/intern/rna_internal.h
index 01303225f38..eab14be9085 100644
--- a/source/blender/makesrna/intern/rna_internal.h
+++ b/source/blender/makesrna/intern/rna_internal.h
@@ -140,6 +140,7 @@ void RNA_def_constraint(struct BlenderRNA *brna);
void RNA_def_context(struct BlenderRNA *brna);
void RNA_def_controller(struct BlenderRNA *brna);
void RNA_def_curve(struct BlenderRNA *brna);
+void RNA_def_depsgraph(struct BlenderRNA *brna);
void RNA_def_dynamic_paint(struct BlenderRNA *brna);
void RNA_def_fluidsim(struct BlenderRNA *brna);
void RNA_def_fcurve(struct BlenderRNA *brna);
diff --git a/source/blender/makesrna/intern/rna_object_api.c b/source/blender/makesrna/intern/rna_object_api.c
index 9fe44511c8c..2a3688c49f2 100644
--- a/source/blender/makesrna/intern/rna_object_api.c
+++ b/source/blender/makesrna/intern/rna_object_api.c
@@ -87,6 +87,8 @@ static EnumPropertyItem space_items[] = {
#include "MEM_guardedalloc.h"
+#include "DEG_depsgraph.h"
+
/* Convert a given matrix from a space to another (using the object and/or a bone as reference). */
static void rna_Scene_mat_convert_space(Object *ob, ReportList *reports, bPoseChannel *pchan,
float *mat, float *mat_ret, int from, int to)
@@ -191,8 +193,8 @@ static void dupli_render_particle_set(Scene *scene, Object *ob, int level, int e
static void rna_Object_create_duplilist(Object *ob, ReportList *reports, Scene *sce, int settings)
{
bool for_render = (settings == DAG_EVAL_RENDER);
- EvaluationContext eval_ctx = {0};
- eval_ctx.mode = settings;
+ EvaluationContext eval_ctx;
+ DEG_evaluation_context_init(&eval_ctx, settings);
if (!(ob->transflag & OB_DUPLI)) {
BKE_report(reports, RPT_ERROR, "Object does not have duplis");
diff --git a/source/blender/makesrna/intern/rna_scene.c b/source/blender/makesrna/intern/rna_scene.c
index d7dfa827493..00114d1125c 100644
--- a/source/blender/makesrna/intern/rna_scene.c
+++ b/source/blender/makesrna/intern/rna_scene.c
@@ -6525,6 +6525,11 @@ void RNA_def_scene(BlenderRNA *brna)
RNA_def_property_struct_type(prop, "ColorManagedSequencerColorspaceSettings");
RNA_def_property_ui_text(prop, "Sequencer Color Space Settings", "Settings of color space sequencer is working in");
+ /* Dependency Graph */
+ prop = RNA_def_property(srna, "depsgraph", PROP_POINTER, PROP_NONE);
+ RNA_def_property_struct_type(prop, "Depsgraph");
+ RNA_def_property_ui_text(prop, "Dependency Graph", "Dependencies in the scene data");
+
/* Nestled Data */
/* *** Non-Animated *** */
RNA_define_animate_sdna(false);
diff --git a/source/blender/modifiers/CMakeLists.txt b/source/blender/modifiers/CMakeLists.txt
index 1de3fc9eac0..fde0c773ef0 100644
--- a/source/blender/modifiers/CMakeLists.txt
+++ b/source/blender/modifiers/CMakeLists.txt
@@ -30,6 +30,7 @@ set(INC
../blenkernel
../blenlib
../blenfont
+ ../depsgraph
../makesdna
../makesrna
../bmesh
diff --git a/source/blender/modifiers/SConscript b/source/blender/modifiers/SConscript
index b4c8299250e..a7d17609ab7 100644
--- a/source/blender/modifiers/SConscript
+++ b/source/blender/modifiers/SConscript
@@ -40,6 +40,7 @@ incs = [
'../include',
'../blenlib',
'../blenfont',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../blenkernel',
diff --git a/source/blender/modifiers/intern/MOD_armature.c b/source/blender/modifiers/intern/MOD_armature.c
index 52a47c3e041..9ce31cebb66 100644
--- a/source/blender/modifiers/intern/MOD_armature.c
+++ b/source/blender/modifiers/intern/MOD_armature.c
@@ -115,6 +115,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArmatureModifierData *amd = (ArmatureModifierData *)md;
+ if (amd->object != NULL) {
+ DEG_add_object_relation(node, amd->object, DEG_OB_COMP_EVAL_POSE, "Armature Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -208,6 +220,7 @@ ModifierTypeInfo modifierType_Armature = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_array.c b/source/blender/modifiers/intern/MOD_array.c
index 44660b15c3c..efb77f73ec9 100644
--- a/source/blender/modifiers/intern/MOD_array.c
+++ b/source/blender/modifiers/intern/MOD_array.c
@@ -135,6 +135,28 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ArrayModifierData *amd = (ArrayModifierData *)md;
+ if (amd->start_cap != NULL) {
+ DEG_add_object_relation(node, amd->start_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier Start Cap");
+ }
+ if (amd->end_cap != NULL) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_TRANSFORM, "Hook Modifier End Cap");
+ }
+ if (amd->curve_ob) {
+ DEG_add_object_relation(node, amd->end_cap, DEG_OB_COMP_GEOMETRY, "Hook Modifier Curve");
+ DEG_add_special_eval_flag(scene->depsgraph, &amd->curve_ob->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+ if (amd->offset_ob != NULL) {
+ DEG_add_object_relation(node, amd->offset_ob, DEG_OB_COMP_TRANSFORM, "Hook Modifier Offset");
+ }
+}
+
static float vertarray_size(const MVert *mvert, int numVerts, int axis)
{
int i;
@@ -771,6 +793,7 @@ ModifierTypeInfo modifierType_Array = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_bevel.c b/source/blender/modifiers/intern/MOD_bevel.c
index 1dca18dce37..c2b5a29939f 100644
--- a/source/blender/modifiers/intern/MOD_bevel.c
+++ b/source/blender/modifiers/intern/MOD_bevel.c
@@ -213,6 +213,7 @@ ModifierTypeInfo modifierType_Bevel = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_boolean.c b/source/blender/modifiers/intern/MOD_boolean.c
index ee3bc7140a8..eb54a3c4e9c 100644
--- a/source/blender/modifiers/intern/MOD_boolean.c
+++ b/source/blender/modifiers/intern/MOD_boolean.c
@@ -89,6 +89,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ BooleanModifierData *bmd = (BooleanModifierData *)md;
+ if (bmd->object != NULL) {
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+ DEG_add_object_relation(node, bmd->object, DEG_OB_COMP_GEOMETRY, "Boolean Modifier");
+ }
+ /* We need own transformation as well. */
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Boolean Modifier");
+}
+
#ifdef WITH_MOD_BOOLEAN
static DerivedMesh *get_quick_derivedMesh(DerivedMesh *derivedData, DerivedMesh *dm, int operation)
{
@@ -193,6 +208,7 @@ ModifierTypeInfo modifierType_Boolean = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_build.c b/source/blender/modifiers/intern/MOD_build.c
index 96337c33373..507fad466a3 100644
--- a/source/blender/modifiers/intern/MOD_build.c
+++ b/source/blender/modifiers/intern/MOD_build.c
@@ -329,6 +329,7 @@ ModifierTypeInfo modifierType_Build = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_cast.c b/source/blender/modifiers/intern/MOD_cast.c
index 3bdc62e124c..7c3d65a5c9a 100644
--- a/source/blender/modifiers/intern/MOD_cast.c
+++ b/source/blender/modifiers/intern/MOD_cast.c
@@ -121,6 +121,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CastModifierData *cmd = (CastModifierData *)md;
+ if (cmd->object != NULL) {
+ DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_TRANSFORM, "Cast Modifier");
+ }
+}
+
static void sphere_do(
CastModifierData *cmd, Object *ob, DerivedMesh *dm,
float (*vertexCos)[3], int numVerts)
@@ -500,6 +512,7 @@ ModifierTypeInfo modifierType_Cast = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_cloth.c b/source/blender/modifiers/intern/MOD_cloth.c
index 392112e4b4a..25fd54d1d3e 100644
--- a/source/blender/modifiers/intern/MOD_cloth.c
+++ b/source/blender/modifiers/intern/MOD_cloth.c
@@ -140,6 +140,27 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ ClothModifierData *clmd = (ClothModifierData *)md;
+ if (clmd != NULL) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ CollisionModifierData *coll_clmd = (CollisionModifierData *)modifiers_findByType(ob1, eModifierType_Collision);
+ if (coll_clmd) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Cloth Modifier");
+ }
+ }
+ }
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
CustomDataMask dataMask = 0;
@@ -251,6 +272,7 @@ ModifierTypeInfo modifierType_Cloth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_collision.c b/source/blender/modifiers/intern/MOD_collision.c
index 130e332ef69..931f82c98e9 100644
--- a/source/blender/modifiers/intern/MOD_collision.c
+++ b/source/blender/modifiers/intern/MOD_collision.c
@@ -241,6 +241,7 @@ ModifierTypeInfo modifierType_Collision = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_correctivesmooth.c b/source/blender/modifiers/intern/MOD_correctivesmooth.c
index 162f45b4e91..d5b4daca3b7 100644
--- a/source/blender/modifiers/intern/MOD_correctivesmooth.c
+++ b/source/blender/modifiers/intern/MOD_correctivesmooth.c
@@ -760,6 +760,7 @@ ModifierTypeInfo modifierType_CorrectiveSmooth = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_curve.c b/source/blender/modifiers/intern/MOD_curve.c
index d53bac390a6..1488296caf9 100644
--- a/source/blender/modifiers/intern/MOD_curve.c
+++ b/source/blender/modifiers/intern/MOD_curve.c
@@ -45,6 +45,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -108,6 +109,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ CurveModifierData *cmd = (CurveModifierData *)md;
+ if (cmd->object != NULL) {
+ /* TODO(sergey): Need to do the same eval_flags trick for path
+ * as happening in legacy depsgraph callback.
+ */
+ /* TODO(sergey): Currently path is evaluated as a part of modifier stack,
+ * might be changed in the future.
+ */
+ DEG_add_object_relation(node, cmd->object, DEG_OB_COMP_GEOMETRY, "Curve Modifier");
+ DEG_add_special_eval_flag(scene->depsgraph, &cmd->object->id, DAG_EVAL_NEED_CURVE_PATH);
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -156,6 +176,7 @@ ModifierTypeInfo modifierType_Curve = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_datatransfer.c b/source/blender/modifiers/intern/MOD_datatransfer.c
index d13ca6e5bb7..57d119f5481 100644
--- a/source/blender/modifiers/intern/MOD_datatransfer.c
+++ b/source/blender/modifiers/intern/MOD_datatransfer.c
@@ -147,6 +147,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
+ if (dtmd->ob_source != NULL) {
+ DEG_add_object_relation(node, dtmd->ob_source, DEG_OB_COMP_GEOMETRY, "DataTransfer Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
DataTransferModifierData *dtmd = (DataTransferModifierData *) md;
@@ -235,6 +247,7 @@ ModifierTypeInfo modifierType_DataTransfer = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_decimate.c b/source/blender/modifiers/intern/MOD_decimate.c
index 542c75f3276..7c13774ee99 100644
--- a/source/blender/modifiers/intern/MOD_decimate.c
+++ b/source/blender/modifiers/intern/MOD_decimate.c
@@ -224,6 +224,7 @@ ModifierTypeInfo modifierType_Decimate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_displace.c b/source/blender/modifiers/intern/MOD_displace.c
index e377445fed8..2921472fe99 100644
--- a/source/blender/modifiers/intern/MOD_displace.c
+++ b/source/blender/modifiers/intern/MOD_displace.c
@@ -171,6 +171,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DisplaceModifierData *dmd = (DisplaceModifierData *)md;
+ if (dmd->map_object != NULL && dmd->texmapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, dmd->map_object, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+ if (dmd->texmapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "Displace Modifier");
+ }
+}
+
/* dm must be a CDDerivedMesh */
static void displaceModifier_do(
DisplaceModifierData *dmd, Object *ob,
@@ -302,6 +317,7 @@ ModifierTypeInfo modifierType_Displace = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_dynamicpaint.c b/source/blender/modifiers/intern/MOD_dynamicpaint.c
index c6999468dc3..95bc4706dc9 100644
--- a/source/blender/modifiers/intern/MOD_dynamicpaint.c
+++ b/source/blender/modifiers/intern/MOD_dynamicpaint.c
@@ -38,6 +38,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
@@ -135,6 +136,26 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ DynamicPaintModifierData *pmd = (DynamicPaintModifierData *)md;
+ /* Add relation from canvases to all brush objects. */
+ if (pmd->canvas != NULL) {
+ Base *base = scene->base.first;
+ for (; base; base = base->next) {
+ DynamicPaintModifierData *pmd2 =
+ (DynamicPaintModifierData *)modifiers_findByType(base->object, eModifierType_DynamicPaint);
+ if (pmd2 && pmd2->brush && ob != base->object) {
+ DEG_add_object_relation(node, base->object, DEG_OB_COMP_TRANSFORM, "Dynamic Paint Brush");
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -187,6 +208,7 @@ ModifierTypeInfo modifierType_DynamicPaint = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_edgesplit.c b/source/blender/modifiers/intern/MOD_edgesplit.c
index fa29921b325..4441edb299b 100644
--- a/source/blender/modifiers/intern/MOD_edgesplit.c
+++ b/source/blender/modifiers/intern/MOD_edgesplit.c
@@ -158,6 +158,7 @@ ModifierTypeInfo modifierType_EdgeSplit = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_explode.c b/source/blender/modifiers/intern/MOD_explode.c
index 32a6303d19d..fa16ebbb5da 100644
--- a/source/blender/modifiers/intern/MOD_explode.c
+++ b/source/blender/modifiers/intern/MOD_explode.c
@@ -1058,6 +1058,7 @@ ModifierTypeInfo modifierType_Explode = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_fluidsim.c b/source/blender/modifiers/intern/MOD_fluidsim.c
index 9f05d357299..8d2774a346f 100644
--- a/source/blender/modifiers/intern/MOD_fluidsim.c
+++ b/source/blender/modifiers/intern/MOD_fluidsim.c
@@ -44,6 +44,7 @@
#include "BKE_modifier.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "MOD_fluidsim_util.h"
#include "MEM_guardedalloc.h"
@@ -126,6 +127,32 @@ static void updateDepgraph(
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ FluidsimModifierData *fluidmd = (FluidsimModifierData *) md;
+ if (fluidmd && fluidmd->fss) {
+ if (fluidmd->fss->type == OB_FLUIDSIM_DOMAIN) {
+ Base *base;
+ for (base = scene->base.first; base; base = base->next) {
+ Object *ob1 = base->object;
+ if (ob1 != ob) {
+ FluidsimModifierData *fluidmdtmp =
+ (FluidsimModifierData *)modifiers_findByType(ob1, eModifierType_Fluidsim);
+
+ /* Only put dependencies from NON-DOMAIN fluids in here. */
+ if (fluidmdtmp && fluidmdtmp->fss && (fluidmdtmp->fss->type != OB_FLUIDSIM_DOMAIN)) {
+ DEG_add_object_relation(node, ob1, DEG_OB_COMP_TRANSFORM, "Fluidsim Object");
+ }
+ }
+ }
+ }
+ }
+}
+
static bool dependsOnTime(ModifierData *UNUSED(md))
{
return true;
@@ -154,6 +181,7 @@ ModifierTypeInfo modifierType_Fluidsim = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_hook.c b/source/blender/modifiers/intern/MOD_hook.c
index 10223d3880e..3a10fabbb8e 100644
--- a/source/blender/modifiers/intern/MOD_hook.c
+++ b/source/blender/modifiers/intern/MOD_hook.c
@@ -129,6 +129,25 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ HookModifierData *hmd = (HookModifierData *)md;
+ if (hmd->object != NULL) {
+ if (hmd->subtarget[0]) {
+ /* TODO(sergey): Hpw do we add relation to bone here? */
+ //DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_EVAL_POSE, "Hook Modifier");
+ DEG_add_bone_relation(node, hmd->object, hmd->subtarget, DEG_OB_COMP_BONE, "Hook Modifier");
+ }
+ else {
+ DEG_add_object_relation(node, hmd->object, DEG_OB_COMP_TRANSFORM, "Hook Modifier");
+ }
+ }
+}
+
struct HookData_cb {
float (*vertexCos)[3];
@@ -403,6 +422,7 @@ ModifierTypeInfo modifierType_Hook = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_laplaciandeform.c b/source/blender/modifiers/intern/MOD_laplaciandeform.c
index a4f6d005d94..c3cfafb7e27 100644
--- a/source/blender/modifiers/intern/MOD_laplaciandeform.c
+++ b/source/blender/modifiers/intern/MOD_laplaciandeform.c
@@ -862,6 +862,7 @@ ModifierTypeInfo modifierType_LaplacianDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_laplaciansmooth.c b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
index 93cd92196b2..a142d18a6d3 100644
--- a/source/blender/modifiers/intern/MOD_laplaciansmooth.c
+++ b/source/blender/modifiers/intern/MOD_laplaciansmooth.c
@@ -716,6 +716,7 @@ ModifierTypeInfo modifierType_LaplacianSmooth = {
/* freeData */ NULL,
/* isDisabled */ is_disabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_lattice.c b/source/blender/modifiers/intern/MOD_lattice.c
index 60caf523a97..b8975beaf83 100644
--- a/source/blender/modifiers/intern/MOD_lattice.c
+++ b/source/blender/modifiers/intern/MOD_lattice.c
@@ -107,6 +107,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ LatticeModifierData *lmd = (LatticeModifierData *)md;
+ if (lmd->object != NULL) {
+ DEG_add_object_relation(node, lmd->object, DEG_OB_COMP_GEOMETRY, "Lattice Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -155,6 +167,7 @@ ModifierTypeInfo modifierType_Lattice = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mask.c b/source/blender/modifiers/intern/MOD_mask.c
index e77225f3617..06fbab65d7b 100644
--- a/source/blender/modifiers/intern/MOD_mask.c
+++ b/source/blender/modifiers/intern/MOD_mask.c
@@ -50,6 +50,7 @@
#include "BKE_deform.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
#include "BLI_strict_flags.h"
@@ -94,6 +95,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MaskModifierData *mmd = (MaskModifierData *)md;
+ if (mmd->ob_arm) {
+ bArmature *arm = (bArmature *)mmd->ob_arm->data;
+ /* Tag relationship in depsgraph, but also on the armature. */
+ /* TODO(sergey): Is it a proper relation here? */
+ DEG_add_object_relation(node, mmd->ob_arm, DEG_OB_COMP_TRANSFORM, "Mask Modifier");
+ arm->flag |= ARM_HAS_VIZ_DEPS;
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob,
DerivedMesh *dm,
ModifierApplyFlag UNUSED(flag))
@@ -385,6 +402,7 @@ ModifierTypeInfo modifierType_Mask = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_meshcache.c b/source/blender/modifiers/intern/MOD_meshcache.c
index db50d49f790..92926ed9424 100644
--- a/source/blender/modifiers/intern/MOD_meshcache.c
+++ b/source/blender/modifiers/intern/MOD_meshcache.c
@@ -313,6 +313,7 @@ ModifierTypeInfo modifierType_MeshCache = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_meshdeform.c b/source/blender/modifiers/intern/MOD_meshdeform.c
index 3ceed4a970d..22148d1f5ae 100644
--- a/source/blender/modifiers/intern/MOD_meshdeform.c
+++ b/source/blender/modifiers/intern/MOD_meshdeform.c
@@ -139,6 +139,19 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MeshDeformModifierData *mmd = (MeshDeformModifierData *)md;
+ if (mmd->object != NULL) {
+ /* TODO(sergey): Do we need transform component here? */
+ DEG_add_object_relation(node, mmd->object, DEG_OB_COMP_GEOMETRY, "Mesh Deform Modifier");
+ }
+}
+
static float meshdeform_dynamic_bind(MeshDeformModifierData *mmd, float (*dco)[3], float vec[3])
{
MDefCell *cell;
@@ -521,6 +534,7 @@ ModifierTypeInfo modifierType_MeshDeform = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_mirror.c b/source/blender/modifiers/intern/MOD_mirror.c
index 73bc61e5519..d3080ca235a 100644
--- a/source/blender/modifiers/intern/MOD_mirror.c
+++ b/source/blender/modifiers/intern/MOD_mirror.c
@@ -43,7 +43,9 @@
#include "BKE_deform.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -88,6 +90,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ MirrorModifierData *mmd = (MirrorModifierData *)md;
+ if (mmd->mirror_ob != NULL) {
+ DEG_add_object_relation(node, mmd->mirror_ob, DEG_OB_COMP_TRANSFORM, "Mirror Modifier");
+ }
+}
+
static DerivedMesh *doMirrorOnAxis(MirrorModifierData *mmd,
Object *ob,
DerivedMesh *dm,
@@ -361,6 +375,7 @@ ModifierTypeInfo modifierType_Mirror = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_multires.c b/source/blender/modifiers/intern/MOD_multires.c
index 4754813a744..90ad1bdfdc2 100644
--- a/source/blender/modifiers/intern/MOD_multires.c
+++ b/source/blender/modifiers/intern/MOD_multires.c
@@ -162,6 +162,7 @@ ModifierTypeInfo modifierType_Multires = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_none.c b/source/blender/modifiers/intern/MOD_none.c
index 579f65a9c50..d9d9ba2966d 100644
--- a/source/blender/modifiers/intern/MOD_none.c
+++ b/source/blender/modifiers/intern/MOD_none.c
@@ -68,6 +68,7 @@ ModifierTypeInfo modifierType_None = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_normal_edit.c b/source/blender/modifiers/intern/MOD_normal_edit.c
index 8315f61c132..87d75c6f1a7 100644
--- a/source/blender/modifiers/intern/MOD_normal_edit.c
+++ b/source/blender/modifiers/intern/MOD_normal_edit.c
@@ -481,6 +481,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ NormalEditModifierData *smd = (NormalEditModifierData *) md;
+ if (smd->target) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "NormalEdit Modifier");
+ }
+}
+
static DerivedMesh *applyModifier(ModifierData *md, Object *ob, DerivedMesh *dm, ModifierApplyFlag UNUSED(flag))
{
return normalEditModifier_do((NormalEditModifierData *)md, ob, dm);
@@ -508,6 +520,7 @@ ModifierTypeInfo modifierType_NormalEdit = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_ocean.c b/source/blender/modifiers/intern/MOD_ocean.c
index 4cbe0967b01..913c2f25c15 100644
--- a/source/blender/modifiers/intern/MOD_ocean.c
+++ b/source/blender/modifiers/intern/MOD_ocean.c
@@ -580,6 +580,7 @@ ModifierTypeInfo modifierType_Ocean = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_particleinstance.c b/source/blender/modifiers/intern/MOD_particleinstance.c
index 29ba7dda5db..cb6234d50b7 100644
--- a/source/blender/modifiers/intern/MOD_particleinstance.c
+++ b/source/blender/modifiers/intern/MOD_particleinstance.c
@@ -51,7 +51,7 @@
#include "BKE_pointcache.h"
#include "depsgraph_private.h"
-
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -127,6 +127,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ParticleInstanceModifierData *pimd = (ParticleInstanceModifierData *) md;
+ if (pimd->ob != NULL) {
+ DEG_add_object_relation(node, pimd->ob, DEG_OB_COMP_TRANSFORM, "Particle Instance Modifier");
+ }
+}
+
static void foreachObjectLink(ModifierData *md, Object *ob,
ObjectWalkFunc walk, void *userData)
{
@@ -448,6 +460,7 @@ ModifierTypeInfo modifierType_ParticleInstance = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_particlesystem.c b/source/blender/modifiers/intern/MOD_particlesystem.c
index 9860daeda4c..de1b11eddd9 100644
--- a/source/blender/modifiers/intern/MOD_particlesystem.c
+++ b/source/blender/modifiers/intern/MOD_particlesystem.c
@@ -206,6 +206,7 @@ ModifierTypeInfo modifierType_ParticleSystem = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_remesh.c b/source/blender/modifiers/intern/MOD_remesh.c
index 6d76dc51ac7..9df064db44d 100644
--- a/source/blender/modifiers/intern/MOD_remesh.c
+++ b/source/blender/modifiers/intern/MOD_remesh.c
@@ -232,6 +232,7 @@ ModifierTypeInfo modifierType_Remesh = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_screw.c b/source/blender/modifiers/intern/MOD_screw.c
index a9160189a7b..4fa86527334 100644
--- a/source/blender/modifiers/intern/MOD_screw.c
+++ b/source/blender/modifiers/intern/MOD_screw.c
@@ -46,6 +46,8 @@
#include "BKE_cdderivedmesh.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
@@ -1074,6 +1076,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ScrewModifierData *ltmd = (ScrewModifierData *)md;
+ if (ltmd->ob_axis != NULL) {
+ DEG_add_object_relation(node, ltmd->ob_axis, DEG_OB_COMP_TRANSFORM, "Screw Modifier");
+ }
+}
+
static void foreachObjectLink(
ModifierData *md, Object *ob,
void (*walk)(void *userData, Object *ob, Object **obpoin),
@@ -1107,6 +1121,7 @@ ModifierTypeInfo modifierType_Screw = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_shapekey.c b/source/blender/modifiers/intern/MOD_shapekey.c
index f3327a03f2c..a543aac74b9 100644
--- a/source/blender/modifiers/intern/MOD_shapekey.c
+++ b/source/blender/modifiers/intern/MOD_shapekey.c
@@ -138,6 +138,7 @@ ModifierTypeInfo modifierType_ShapeKey = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_shrinkwrap.c b/source/blender/modifiers/intern/MOD_shrinkwrap.c
index fd583c43d6e..91be0c40059 100644
--- a/source/blender/modifiers/intern/MOD_shrinkwrap.c
+++ b/source/blender/modifiers/intern/MOD_shrinkwrap.c
@@ -159,6 +159,23 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
DAG_RL_OB_DATA | DAG_RL_DATA_DATA, "Shrinkwrap Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
+ if (smd->target != NULL) {
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->target, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+ if (smd->auxTarget != NULL) {
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_TRANSFORM, "Shrinkwrap Modifier");
+ DEG_add_object_relation(node, smd->auxTarget, DEG_OB_COMP_GEOMETRY, "Shrinkwrap Modifier");
+ }
+}
+
static bool dependsOnNormals(ModifierData *md)
{
ShrinkwrapModifierData *smd = (ShrinkwrapModifierData *)md;
@@ -191,6 +208,7 @@ ModifierTypeInfo modifierType_Shrinkwrap = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_simpledeform.c b/source/blender/modifiers/intern/MOD_simpledeform.c
index 0e1cb125a47..706a296f5a1 100644
--- a/source/blender/modifiers/intern/MOD_simpledeform.c
+++ b/source/blender/modifiers/intern/MOD_simpledeform.c
@@ -298,6 +298,18 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
dag_add_relation(forest, dag_get_node(forest, smd->origin), obNode, DAG_RL_OB_DATA, "SimpleDeform Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ SimpleDeformModifierData *smd = (SimpleDeformModifierData *)md;
+ if (smd->origin != NULL) {
+ DEG_add_object_relation(node, smd->origin, DEG_OB_COMP_TRANSFORM, "SimpleDeform Modifier");
+ }
+}
+
static void deformVerts(ModifierData *md, Object *ob,
DerivedMesh *derivedData,
float (*vertexCos)[3],
@@ -362,6 +374,7 @@ ModifierTypeInfo modifierType_SimpleDeform = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_skin.c b/source/blender/modifiers/intern/MOD_skin.c
index 5ebb3f98f6c..6c096224b58 100644
--- a/source/blender/modifiers/intern/MOD_skin.c
+++ b/source/blender/modifiers/intern/MOD_skin.c
@@ -1937,6 +1937,7 @@ ModifierTypeInfo modifierType_Skin = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smoke.c b/source/blender/modifiers/intern/MOD_smoke.c
index 74409498ca3..657c4e09d96 100644
--- a/source/blender/modifiers/intern/MOD_smoke.c
+++ b/source/blender/modifiers/intern/MOD_smoke.c
@@ -53,6 +53,7 @@
#include "BKE_smoke.h"
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -227,6 +228,111 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void update_depsgraph_flow_coll_object_new(struct DepsNodeHandle *node,
+ Object *object2)
+{
+ SmokeModifierData *smd;
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ smd = (SmokeModifierData *)modifiers_findByType(object2, eModifierType_Smoke);
+ if (smd && (((smd->type & MOD_SMOKE_TYPE_FLOW) && smd->flow) ||
+ ((smd->type & MOD_SMOKE_TYPE_COLL) && smd->coll)))
+ {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Smoke Flow/Coll");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Smoke Flow/Coll");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_flow_coll_object_new(node, go->ob);
+ }
+ }
+}
+
+static void update_depsgraph_field_source_object_new(struct DepsNodeHandle *node,
+ Object *object,
+ Object *object2)
+{
+ if ((object2->id.flag & LIB_DOIT) == 0) {
+ return;
+ }
+ object2->id.flag &= ~LIB_DOIT;
+ if (object2->pd && object2->pd->forcefield == PFIELD_SMOKEFLOW && object2->pd->f_source == object) {
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_TRANSFORM, "Field Source Object");
+ DEG_add_object_relation(node, object2, DEG_OB_COMP_GEOMETRY, "Field Source Object");
+ }
+ if ((object2->transflag & OB_DUPLIGROUP) && object2->dup_group) {
+ GroupObject *go;
+ for (go = object2->dup_group->gobject.first;
+ go != NULL;
+ go = go->next)
+ {
+ if (go->ob == NULL) {
+ continue;
+ }
+ update_depsgraph_field_source_object_new(node, object, go->ob);
+ }
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *bmain,
+ struct Scene *scene,
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ SmokeModifierData *smd = (SmokeModifierData *)md;
+ Base *base;
+ if (smd && (smd->type & MOD_SMOKE_TYPE_DOMAIN) && smd->domain) {
+ if (smd->domain->fluid_group || smd->domain->coll_group) {
+ GroupObject *go = NULL;
+ if (smd->domain->fluid_group != NULL) {
+ for (go = smd->domain->fluid_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_FLOW) && smd2->flow) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Flow");
+ }
+ }
+ }
+ }
+ if (smd->domain->coll_group != NULL) {
+ for (go = smd->domain->coll_group->gobject.first; go; go = go->next) {
+ if (go->ob != NULL) {
+ SmokeModifierData *smd2 = (SmokeModifierData *)modifiers_findByType(go->ob, eModifierType_Smoke);
+ /* Check for initialized smoke object. */
+ if (smd2 && (smd2->type & MOD_SMOKE_TYPE_COLL) && smd2->coll) {
+ DEG_add_object_relation(node, go->ob, DEG_OB_COMP_TRANSFORM, "Smoke Coll");
+ }
+ }
+ }
+ }
+ }
+ else {
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ base = scene->base.first;
+ for (; base; base = base->next) {
+ update_depsgraph_flow_coll_object_new(node, base->object);
+ }
+ }
+ /* add relation to all "smoke flow" force fields */
+ base = scene->base.first;
+ BKE_main_id_tag_listbase(&bmain->object, true);
+ for (; base; base = base->next) {
+ update_depsgraph_field_source_object_new(node, ob, base->object);
+ }
+ }
+}
+
static void foreachIDLink(ModifierData *md, Object *ob,
IDWalkFunc walk, void *userData)
{
@@ -268,6 +374,7 @@ ModifierTypeInfo modifierType_Smoke = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_smooth.c b/source/blender/modifiers/intern/MOD_smooth.c
index d1ad8f1fcfc..d45c8528510 100644
--- a/source/blender/modifiers/intern/MOD_smooth.c
+++ b/source/blender/modifiers/intern/MOD_smooth.c
@@ -262,6 +262,7 @@ ModifierTypeInfo modifierType_Smooth = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_softbody.c b/source/blender/modifiers/intern/MOD_softbody.c
index 5f5347a46b0..d958badc33c 100644
--- a/source/blender/modifiers/intern/MOD_softbody.c
+++ b/source/blender/modifiers/intern/MOD_softbody.c
@@ -80,6 +80,7 @@ ModifierTypeInfo modifierType_Softbody = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_solidify.c b/source/blender/modifiers/intern/MOD_solidify.c
index fdba8e54a98..ca2dcfec3a3 100644
--- a/source/blender/modifiers/intern/MOD_solidify.c
+++ b/source/blender/modifiers/intern/MOD_solidify.c
@@ -961,6 +961,7 @@ ModifierTypeInfo modifierType_Solidify = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_subsurf.c b/source/blender/modifiers/intern/MOD_subsurf.c
index 7ada058d883..2a62a9e6081 100644
--- a/source/blender/modifiers/intern/MOD_subsurf.c
+++ b/source/blender/modifiers/intern/MOD_subsurf.c
@@ -159,6 +159,7 @@ ModifierTypeInfo modifierType_Subsurf = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_surface.c b/source/blender/modifiers/intern/MOD_surface.c
index 1c462f12f9f..3d998f2d95a 100644
--- a/source/blender/modifiers/intern/MOD_surface.c
+++ b/source/blender/modifiers/intern/MOD_surface.c
@@ -186,6 +186,7 @@ ModifierTypeInfo modifierType_Surface = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_triangulate.c b/source/blender/modifiers/intern/MOD_triangulate.c
index 592ab4194ec..194a46b6f28 100644
--- a/source/blender/modifiers/intern/MOD_triangulate.c
+++ b/source/blender/modifiers/intern/MOD_triangulate.c
@@ -119,6 +119,7 @@ ModifierTypeInfo modifierType_Triangulate = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/modifiers/intern/MOD_util.h b/source/blender/modifiers/intern/MOD_util.h
index 5a1f1fc876a..b74ff9c2a25 100644
--- a/source/blender/modifiers/intern/MOD_util.h
+++ b/source/blender/modifiers/intern/MOD_util.h
@@ -31,6 +31,8 @@
/* so modifier types match their defines */
#include "MOD_modifiertypes.h"
+#include "DEG_depsgraph_build.h"
+
struct DerivedMesh;
struct MDeformVert;
struct ModifierData;
diff --git a/source/blender/modifiers/intern/MOD_uvproject.c b/source/blender/modifiers/intern/MOD_uvproject.c
index 113f1654d02..1b1474ee666 100644
--- a/source/blender/modifiers/intern/MOD_uvproject.c
+++ b/source/blender/modifiers/intern/MOD_uvproject.c
@@ -51,7 +51,9 @@
#include "MOD_modifiertypes.h"
#include "MEM_guardedalloc.h"
+
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
static void initData(ModifierData *md)
{
@@ -122,6 +124,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVProjectModifierData *umd = (UVProjectModifierData *)md;
+ int i;
+ for (i = 0; i < umd->num_projectors; ++i) {
+ if (umd->projectors[i] != NULL) {
+ DEG_add_object_relation(node, umd->projectors[i], DEG_OB_COMP_TRANSFORM, "UV Project Modifier");
+ }
+ }
+}
+
typedef struct Projector {
Object *ob; /* object this projector is derived from */
float projmat[4][4]; /* projection matrix */
@@ -369,6 +386,7 @@ ModifierTypeInfo modifierType_UVProject = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_uvwarp.c b/source/blender/modifiers/intern/MOD_uvwarp.c
index f41705d1aac..3c4ca66485d 100644
--- a/source/blender/modifiers/intern/MOD_uvwarp.c
+++ b/source/blender/modifiers/intern/MOD_uvwarp.c
@@ -229,6 +229,30 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
uv_warp_deps_object_bone(forest, obNode, umd->object_dst, umd->bone_dst);
}
+static void uv_warp_deps_object_bone_new(struct DepsNodeHandle *node,
+ Object *object,
+ const char *bonename)
+{
+ if (object != NULL) {
+ if (bonename[0])
+ DEG_add_object_relation(node, object, DEG_OB_COMP_EVAL_POSE, "UVWarp Modifier");
+ else
+ DEG_add_object_relation(node, object, DEG_OB_COMP_TRANSFORM, "UVWarp Modifier");
+ }
+}
+
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ UVWarpModifierData *umd = (UVWarpModifierData *) md;
+
+ uv_warp_deps_object_bone_new(node, umd->object_src, umd->bone_src);
+ uv_warp_deps_object_bone_new(node, umd->object_dst, umd->bone_dst);
+}
+
ModifierTypeInfo modifierType_UVWarp = {
/* name */ "UVWarp",
/* structName */ "UVWarpModifierData",
@@ -249,6 +273,7 @@ ModifierTypeInfo modifierType_UVWarp = {
/* freeData */ NULL,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_warp.c b/source/blender/modifiers/intern/MOD_warp.c
index 9d496724ba1..ae2dbd4a37c 100644
--- a/source/blender/modifiers/intern/MOD_warp.c
+++ b/source/blender/modifiers/intern/MOD_warp.c
@@ -157,6 +157,22 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WarpModifierData *wmd = (WarpModifierData *) md;
+ if (wmd->object_from != NULL && wmd->object_to != NULL) {
+ DEG_add_object_relation(node, wmd->object_from, DEG_OB_COMP_TRANSFORM, "Warp Modifier from");
+ DEG_add_object_relation(node, wmd->object_to, DEG_OB_COMP_TRANSFORM, "Warp Modifier to");
+ }
+ if ((wmd->texmapping == MOD_DISP_MAP_OBJECT) && wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Warp Modifier map");
+ }
+}
+
static void warpModifier_do(WarpModifierData *wmd, Object *ob,
DerivedMesh *dm, float (*vertexCos)[3], int numVerts)
{
@@ -372,6 +388,7 @@ ModifierTypeInfo modifierType_Warp = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wave.c b/source/blender/modifiers/intern/MOD_wave.c
index 7fd830dabd4..5b98f221489 100644
--- a/source/blender/modifiers/intern/MOD_wave.c
+++ b/source/blender/modifiers/intern/MOD_wave.c
@@ -153,6 +153,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
}
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *UNUSED(ob),
+ struct DepsNodeHandle *node)
+{
+ WaveModifierData *wmd = (WaveModifierData *)md;
+ if (wmd->objectcenter != NULL) {
+ DEG_add_object_relation(node, wmd->objectcenter, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+ if (wmd->map_object != NULL) {
+ DEG_add_object_relation(node, wmd->map_object, DEG_OB_COMP_TRANSFORM, "Wave Modifier");
+ }
+}
+
static CustomDataMask requiredDataMask(Object *UNUSED(ob), ModifierData *md)
{
WaveModifierData *wmd = (WaveModifierData *)md;
@@ -381,6 +396,7 @@ ModifierTypeInfo modifierType_Wave = {
/* freeData */ freeData,
/* isDisabled */ NULL,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgedit.c b/source/blender/modifiers/intern/MOD_weightvgedit.c
index c4734ccd7a8..cba077a2f8d 100644
--- a/source/blender/modifiers/intern/MOD_weightvgedit.c
+++ b/source/blender/modifiers/intern/MOD_weightvgedit.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -162,6 +164,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGEdit Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGEditModifierData *wmd = (WeightVGEditModifierData *)md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGEdit Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGEditModifierData *wmd = (WeightVGEditModifierData *) md;
@@ -292,6 +309,7 @@ ModifierTypeInfo modifierType_WeightVGEdit = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgmix.c b/source/blender/modifiers/intern/MOD_weightvgmix.c
index 266cfcc59a6..3d60c4a8b8b 100644
--- a/source/blender/modifiers/intern/MOD_weightvgmix.c
+++ b/source/blender/modifiers/intern/MOD_weightvgmix.c
@@ -43,6 +43,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -211,6 +213,21 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGMix Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGMix Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGMixModifierData *wmd = (WeightVGMixModifierData *) md;
@@ -422,6 +439,7 @@ ModifierTypeInfo modifierType_WeightVGMix = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_weightvgproximity.c b/source/blender/modifiers/intern/MOD_weightvgproximity.c
index 390475b57f5..033516016d3 100644
--- a/source/blender/modifiers/intern/MOD_weightvgproximity.c
+++ b/source/blender/modifiers/intern/MOD_weightvgproximity.c
@@ -46,6 +46,8 @@
#include "BKE_texture.h" /* Texture masking. */
#include "depsgraph_private.h"
+#include "DEG_depsgraph_build.h"
+
#include "MEM_guardedalloc.h"
#include "MOD_weightvg_util.h"
@@ -338,6 +340,24 @@ static void updateDepgraph(ModifierData *md, DagForest *forest,
"WeightVGProximity Modifier");
}
+static void updateDepsgraph(ModifierData *md,
+ struct Main *UNUSED(bmain),
+ struct Scene *UNUSED(scene),
+ Object *ob,
+ struct DepsNodeHandle *node)
+{
+ WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *)md;
+ if (wmd->proximity_ob_target != NULL) {
+ DEG_add_object_relation(node, wmd->proximity_ob_target, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_map_obj != NULL && wmd->mask_tex_mapping == MOD_DISP_MAP_OBJECT) {
+ DEG_add_object_relation(node, wmd->mask_tex_map_obj, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+ if (wmd->mask_tex_mapping == MOD_DISP_MAP_GLOBAL) {
+ DEG_add_object_relation(node, ob, DEG_OB_COMP_TRANSFORM, "WeightVGProximity Modifier");
+ }
+}
+
static bool isDisabled(ModifierData *md, int UNUSED(useRenderParams))
{
WeightVGProximityModifierData *wmd = (WeightVGProximityModifierData *) md;
@@ -566,6 +586,7 @@ ModifierTypeInfo modifierType_WeightVGProximity = {
/* freeData */ freeData,
/* isDisabled */ isDisabled,
/* updateDepgraph */ updateDepgraph,
+ /* updateDepsgraph */ updateDepsgraph,
/* dependsOnTime */ dependsOnTime,
/* dependsOnNormals */ NULL,
/* foreachObjectLink */ foreachObjectLink,
diff --git a/source/blender/modifiers/intern/MOD_wireframe.c b/source/blender/modifiers/intern/MOD_wireframe.c
index aa5e6116516..fe21757d5c2 100644
--- a/source/blender/modifiers/intern/MOD_wireframe.c
+++ b/source/blender/modifiers/intern/MOD_wireframe.c
@@ -133,6 +133,7 @@ ModifierTypeInfo modifierType_Wireframe = {
/* freeData */ NULL,
/* isDisabled */ isDisabled,
/* updateDepgraph */ NULL,
+ /* updateDepsgraph */ NULL,
/* dependsOnTime */ NULL,
/* dependsOnNormals */ dependsOnNormals,
/* foreachObjectLink */ NULL,
diff --git a/source/blender/render/CMakeLists.txt b/source/blender/render/CMakeLists.txt
index 36b9f8ae362..4b54ddf7225 100644
--- a/source/blender/render/CMakeLists.txt
+++ b/source/blender/render/CMakeLists.txt
@@ -31,6 +31,7 @@ set(INC
../blenkernel
../blenlib
../imbuf
+ ../depsgraph
../makesdna
../makesrna
../physics
diff --git a/source/blender/render/SConscript b/source/blender/render/SConscript
index 0cbf188525b..4a9f32bc1ac 100644
--- a/source/blender/render/SConscript
+++ b/source/blender/render/SConscript
@@ -38,6 +38,7 @@ incs = [
'../blenkernel',
'../blenlib',
'../imbuf',
+ '../depsgraph',
'../makesdna',
'../makesrna',
'../physics',
diff --git a/source/blender/render/intern/source/pipeline.c b/source/blender/render/intern/source/pipeline.c
index 7f08e576747..bdf67434725 100644
--- a/source/blender/render/intern/source/pipeline.c
+++ b/source/blender/render/intern/source/pipeline.c
@@ -84,6 +84,8 @@
# include "FRS_freestyle.h"
#endif
+#include "DEG_depsgraph.h"
+
/* internal */
#include "render_result.h"
#include "render_types.h"
@@ -467,8 +469,7 @@ Render *RE_NewRender(const char *name)
BLI_strncpy(re->name, name, RE_MAXNAME);
BLI_rw_mutex_init(&re->resultmutex);
BLI_rw_mutex_init(&re->partsmutex);
- re->eval_ctx = MEM_callocN(sizeof(EvaluationContext), "re->eval_ctx");
- re->eval_ctx->mode = DAG_EVAL_RENDER;
+ re->eval_ctx = DEG_evaluation_context_new(DAG_EVAL_RENDER);
}
RE_InitRenderCB(re);
diff --git a/source/blenderplayer/CMakeLists.txt b/source/blenderplayer/CMakeLists.txt
index 25ee4f2ef21..1136524da04 100644
--- a/source/blenderplayer/CMakeLists.txt
+++ b/source/blenderplayer/CMakeLists.txt
@@ -106,6 +106,7 @@ endif()
bf_intern_ghostndof3dconnexion
bf_rna
bf_blenkernel
+ bf_depsgraph
bf_physics
bf_intern_rigidbody
bf_blenloader
diff --git a/source/creator/CMakeLists.txt b/source/creator/CMakeLists.txt
index c0b0c2eadb6..ffaf6f42b18 100644
--- a/source/creator/CMakeLists.txt
+++ b/source/creator/CMakeLists.txt
@@ -31,6 +31,7 @@ blender_include_dirs(
../blender/blenlib
../blender/blenkernel
../blender/blenloader
+ ../blender/depsgraph
../blender/editors/include
../blender/makesrna
../blender/imbuf
diff --git a/source/creator/creator.c b/source/creator/creator.c
index 721e43cda4d..e2d7bda3a21 100644
--- a/source/creator/creator.c
+++ b/source/creator/creator.c
@@ -93,6 +93,8 @@
#include "BKE_image.h"
#include "BKE_particle.h"
+#include "DEG_depsgraph.h"
+
#include "IMB_imbuf.h" /* for IMB_init */
#ifdef WITH_PYTHON
@@ -357,6 +359,10 @@ static int print_help(int UNUSED(argc), const char **UNUSED(argv), void *data)
printf("Other Options:\n");
BLI_argsPrintOtherDoc(ba);
+ printf("\n");
+ printf("Experimental features:\n");
+ BLI_argsPrintArgDoc(ba, "--enable-new-depsgraph");
+
printf("Argument Parsing:\n");
printf("\targuments must be separated by white space. eg\n");
printf("\t\t\"blender -ba test.blend\"\n");
@@ -929,6 +935,12 @@ static int set_threads(int argc, const char **argv, void *UNUSED(data))
}
}
+static int depsgraph_use_new(int UNUSED(argc), const char **UNUSED(argv), void *UNUSED(data))
+{
+ DEG_depsgraph_switch_to_new();
+ return 0;
+}
+
static int set_verbosity(int argc, const char **argv, void *UNUSED(data))
{
if (argc > 1) {
@@ -1494,6 +1506,8 @@ static void setupArguments(bContext *C, bArgs *ba, SYS_SystemHandle *syshandle)
BLI_argsAdd(ba, 1, NULL, "--debug-depsgraph", "\n\tEnable debug messages from dependency graph", debug_mode_generic, (void *)G_DEBUG_DEPSGRAPH);
BLI_argsAdd(ba, 1, NULL, "--debug-gpumem", "\n\tEnable GPU memory stats in status bar", debug_mode_generic, (void *)G_DEBUG_GPU_MEM);
+ BLI_argsAdd(ba, 1, NULL, "--enable-new-depsgraph", "\n\tUse new dependency graph", depsgraph_use_new, NULL);
+
BLI_argsAdd(ba, 1, NULL, "--verbose", "<verbose>\n\tSet logging verbosity level.", set_verbosity, NULL);
BLI_argsAdd(ba, 1, NULL, "--factory-startup", "\n\tSkip reading the "STRINGIFY (BLENDER_STARTUP_FILE)" in the users home directory", set_factory_startup, NULL);