Depsgraph: Initial support of armatures for copy-on-write

This commit makes simple cases to work, for example:

- IK solver to an external object
- Object with Armature modifier, "parented" to the deforming armature
  (via animation).

More complicated setups (like agent rig) are crashing still.
This commit is contained in:
Sergey Sharybin
2017-07-14 14:56:54 +02:00
parent 0ea4bb51df
commit 92f3b4ac64
4 changed files with 204 additions and 99 deletions

View File

@@ -445,39 +445,41 @@ void DepsgraphNodeBuilder::build_object(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_object_transform(Scene *scene, Object *ob)
{
OperationDepsNode *op_node;
Scene *scene_cow = get_cow_datablock(scene);
Object *ob_cow = get_cow_datablock(ob);
/* local transforms (from transform channels - loc/rot/scale + deltas) */
op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_local_transform, _1, scene, ob),
function_bind(BKE_object_eval_local_transform,
_1,
scene_cow, ob_cow),
DEG_OPCODE_TRANSFORM_LOCAL);
op_node->set_as_entry();
/* object parent */
if (ob->parent) {
if (ob->parent != NULL) {
add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_parent, _1, scene, ob),
function_bind(BKE_object_eval_parent,
_1,
scene_cow, ob_cow),
DEG_OPCODE_TRANSFORM_PARENT);
}
/* object constraints */
if (ob->constraints.first) {
if (ob->constraints.first != NULL) {
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.
*/
/* Rest of transformation update. */
add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_uber_transform, _1, scene, ob),
function_bind(BKE_object_eval_uber_transform,
_1,
scene_cow, ob_cow),
DEG_OPCODE_OBJECT_UBEREVAL);
/* object transform is done */
op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_done, _1, ob),
function_bind(BKE_object_eval_done, _1, ob_cow),
DEG_OPCODE_TRANSFORM_FINAL);
op_node->set_as_exit();
}
@@ -503,7 +505,9 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
{
/* create node for constraint stack */
add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_object_eval_constraints, _1, scene, ob),
function_bind(BKE_object_eval_constraints, _1,
get_cow_datablock(scene),
get_cow_datablock(ob)),
DEG_OPCODE_TRANSFORM_CONSTRAINTS);
}
@@ -514,23 +518,29 @@ void DepsgraphNodeBuilder::build_object_constraints(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_animdata(ID *id)
{
AnimData *adt = BKE_animdata_from_id(id);
if (adt == NULL)
if (adt == NULL) {
return;
}
ID *id_cow = get_cow_id(id);
/* animation */
if (adt->action || adt->nla_tracks.first || adt->drivers.first) {
// XXX: Hook up specific update callbacks for special properties which may need it...
// 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 */
/* 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, DEG_NODE_TYPE_ANIMATION,
function_bind(BKE_animsys_eval_animdata, _1, id),
function_bind(BKE_animsys_eval_animdata, _1, id_cow),
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)
/* 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 */
@@ -549,6 +559,7 @@ void DepsgraphNodeBuilder::build_animdata(ID *id)
OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
{
ChannelDriver *driver = fcu->driver;
ID *id_cow = get_cow_id(id);
/* Create data node for this driver */
/* TODO(sergey): Avoid creating same operation multiple times,
@@ -562,9 +573,10 @@ OperationDepsNode *DepsgraphNodeBuilder::build_driver(ID *id, FCurve *fcu)
fcu->array_index);
if (driver_op == NULL) {
/* TODO(sergey): Shall we use COW of fcu itself here? */
driver_op = add_operation_node(id,
DEG_NODE_TYPE_PARAMETERS,
function_bind(BKE_animsys_eval_driver, _1, id, fcu),
function_bind(BKE_animsys_eval_driver, _1, id_cow, fcu),
DEG_OPCODE_DRIVER,
fcu->rna_path ? fcu->rna_path : "",
fcu->array_index);
@@ -608,43 +620,49 @@ void DepsgraphNodeBuilder::build_world(World *world)
void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
{
RigidBodyWorld *rbw = scene->rigidbody_world;
Scene *scene_cow = get_cow_datablock(scene);
/**
* 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)
* 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
* 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? */
/* 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, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_rigidbody_rebuild_sim, _1, scene),
DEG_OPCODE_RIGIDBODY_REBUILD);
/*OperationDepsNode *init_node =*/ add_operation_node(
&scene->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_rigidbody_rebuild_sim, _1, scene_cow),
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, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_rigidbody_eval_simulation, _1, scene),
DEG_OPCODE_RIGIDBODY_SIM);
OperationDepsNode *sim_node = add_operation_node(
&scene->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_rigidbody_eval_simulation, _1, scene_cow),
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...
/* 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) {
LINKLIST_FOREACH (GroupObject *, go, &rbw->group->gobject) {
@@ -654,9 +672,13 @@ void DepsgraphNodeBuilder::build_rigidbody(Scene *scene)
continue;
/* 2) create operation for flushing results */
/* object's transform component - where the rigidbody operation lives */
/* object's transform component - where the rigidbody operation
* lives. */
add_operation_node(&ob->id, DEG_NODE_TYPE_TRANSFORM,
function_bind(BKE_rigidbody_object_sync_transforms, _1, scene, ob),
function_bind(BKE_rigidbody_object_sync_transforms,
_1,
scene_cow,
get_cow_datablock(ob)),
DEG_OPCODE_TRANSFORM_RIGIDBODY);
}
}
@@ -683,6 +705,10 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
ComponentDepsNode *psys_comp =
add_component_node(&ob->id, DEG_NODE_TYPE_EVAL_PARTICLES);
/* TODO(sergey): Need to get COW of PSYS. */
Scene *scene_cow = get_cow_datablock(scene);
Object *ob_cow = get_cow_datablock(ob);
/* particle systems */
LINKLIST_FOREACH (ParticleSystem *, psys, &ob->particlesystem) {
ParticleSettings *part = psys->part;
@@ -696,8 +722,8 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
add_operation_node(psys_comp,
function_bind(BKE_particle_system_eval,
_1,
scene,
ob,
scene_cow,
ob_cow,
psys),
DEG_OPCODE_PSYS_EVAL,
psys->name);
@@ -709,13 +735,16 @@ void DepsgraphNodeBuilder::build_particles(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_cloth(Scene *scene, Object *object)
{
Scene *scene_cow = get_cow_datablock(scene);
Object *object_cow = get_cow_datablock(object);
ComponentDepsNode *cache_comp = add_component_node(&object->id,
DEG_NODE_TYPE_CACHE);
add_operation_node(cache_comp,
function_bind(BKE_object_eval_cloth,
_1,
scene,
object),
scene_cow,
object_cow),
DEG_OPCODE_PLACEHOLDER,
"Cloth Modifier");
}
@@ -734,7 +763,10 @@ void DepsgraphNodeBuilder::build_shapekeys(Key *key)
void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
{
ID *obdata = (ID *)ob->data;
ID *obdata_cow = get_cow_id(obdata);
OperationDepsNode *op_node;
Scene *scene_cow = get_cow_datablock(scene);
Object *object_cow = get_cow_datablock(ob);
/* TODO(sergey): This way using this object's properties as driver target
* works fine.
@@ -759,8 +791,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_object_eval_uber_data,
_1,
(Scene *)get_cow_id(&scene->id),
(Object *)get_cow_id(&ob->id)),
scene_cow,
object_cow),
DEG_OPCODE_GEOMETRY_UBEREVAL);
op_node->set_as_exit();
@@ -785,7 +817,8 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
if (ob->type == OB_MESH) {
add_operation_node(&ob->id,
DEG_NODE_TYPE_SHADING,
function_bind(BKE_object_eval_update_shading, _1, ob),
function_bind(BKE_object_eval_update_shading, _1,
object_cow),
DEG_OPCODE_SHADING);
}
@@ -827,7 +860,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_mesh_eval_geometry,
_1,
(Mesh *)obdata),
(Mesh *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
@@ -846,7 +879,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_mball_eval_geometry,
_1,
(MetaBall *)obdata),
(MetaBall *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
@@ -864,7 +897,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_curve_eval_geometry,
_1,
(Curve *)obdata),
(Curve *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();
@@ -875,7 +908,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_curve_eval_path,
_1,
(Curve *)obdata),
(Curve *)obdata_cow),
DEG_OPCODE_GEOMETRY_PATH,
"Path");
}
@@ -903,7 +936,7 @@ void DepsgraphNodeBuilder::build_obdata_geom(Scene *scene, Object *ob)
DEG_NODE_TYPE_GEOMETRY,
function_bind(BKE_lattice_eval_geometry,
_1,
(Lattice *)obdata),
(Lattice *)obdata_cow),
DEG_OPCODE_PLACEHOLDER,
"Geometry Eval");
op_node->set_as_entry();

View File

@@ -75,6 +75,11 @@ struct DepsgraphNodeBuilder {
ID *get_cow_id(const ID *id_orig) const;
template<typename T>
T *get_cow_datablock(const T *orig) const {
return (T *)get_cow_id(&orig->id);
}
IDDepsNode *add_id_node(ID *id);
TimeSourceDepsNode *add_time_source();

View File

@@ -46,6 +46,7 @@ extern "C" {
#include "DNA_armature_types.h"
#include "DNA_constraint_types.h"
#include "DNA_object_types.h"
#include "DNA_scene_types.h"
#include "BKE_action.h"
#include "BKE_armature.h"
@@ -55,6 +56,7 @@ extern "C" {
#include "DEG_depsgraph_build.h"
#include "intern/builder/deg_builder.h"
#include "intern/eval/deg_eval_copy_on_write.h"
#include "intern/nodes/deg_node.h"
#include "intern/nodes/deg_node_component.h"
#include "intern/nodes/deg_node_operation.h"
@@ -64,16 +66,25 @@ extern "C" {
namespace DEG {
void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene, Object *ob, bPoseChannel *pchan)
void DepsgraphNodeBuilder::build_pose_constraints(Scene *scene,
Object *ob,
bPoseChannel *pchan)
{
/* create node for constraint stack */
add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_constraints_evaluate, _1, scene, ob, pchan),
function_bind(BKE_pose_constraints_evaluate,
_1,
get_cow_datablock(scene),
get_cow_datablock(ob),
pchan),
DEG_OPCODE_BONE_CONSTRAINTS);
}
/* IK Solver Eval Steps */
void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
void DepsgraphNodeBuilder::build_ik_pose(Scene *scene,
Object *ob,
bPoseChannel *pchan,
bConstraint *con)
{
bKinematicConstraint *data = (bKinematicConstraint *)con->data;
@@ -88,12 +99,18 @@ void DepsgraphNodeBuilder::build_ik_pose(Scene *scene, Object *ob, bPoseChannel
/* Operation node for evaluating/running IK Solver. */
add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
function_bind(BKE_pose_iktree_evaluate, _1, scene, ob, rootchan),
function_bind(BKE_pose_iktree_evaluate, _1,
get_cow_datablock(scene),
get_cow_datablock(ob),
rootchan),
DEG_OPCODE_POSE_IK_SOLVER);
}
/* Spline IK Eval Steps */
void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseChannel *pchan, bConstraint *con)
void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene,
Object *ob,
bPoseChannel *pchan,
bConstraint *con)
{
bSplineIKConstraint *data = (bSplineIKConstraint *)con->data;
@@ -101,30 +118,55 @@ void DepsgraphNodeBuilder::build_splineik_pose(Scene *scene, Object *ob, bPoseCh
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.
* Store the "root bone" of this chain in the solver, so it knows where to
* start.
*/
add_operation_node(&ob->id, DEG_NODE_TYPE_EVAL_POSE, rootchan->name,
function_bind(BKE_pose_splineik_evaluate, _1, scene, ob, rootchan),
function_bind(BKE_pose_splineik_evaluate,
_1,
get_cow_datablock(scene),
get_cow_datablock(ob),
rootchan),
DEG_OPCODE_POSE_SPLINE_IK_SOLVER);
}
/* Pose/Armature Bones Graph */
void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *object)
{
bArmature *arm = (bArmature *)ob->data;
bArmature *armature = (bArmature *)object->data;
const bool armature_tag = armature->id.tag;
#ifdef WITH_COPY_ON_WRITE
/* NOTE: We need to expand both object and armature, so this way we can
* safely create object level pose.
*/
Scene *scene_cow = get_cow_datablock(scene);
IDDepsNode *object_id_node = add_id_node(&object->id);
Object *object_cow = (Object *)deg_expand_copy_on_write_datablock(
m_graph, object_id_node);
IDDepsNode *armature_id_node = add_id_node(&armature->id);
bArmature *armature_cow = (bArmature *)deg_expand_copy_on_write_datablock(
m_graph, armature_id_node);
#else
Scene *scene_cow = scene;
Object *object_cow = object;
bArmature *armature_cow = armature;
#endif
OperationDepsNode *op_node;
/* animation and/or drivers linking posebones to base-armature used to define them
/* 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...
* 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.
*/
if ((arm->id.tag & LIB_TAG_DOIT) == 0) {
build_animdata(&arm->id);
if ((armature_tag & LIB_TAG_DOIT) == 0) {
build_animdata(&armature->id);
/* Make sure pose is up-to-date with armature updates. */
add_operation_node(&arm->id,
add_operation_node(&armature->id,
DEG_NODE_TYPE_PARAMETERS,
NULL,
DEG_OPCODE_PLACEHOLDER,
@@ -132,22 +174,22 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
}
/* Rebuild pose if not up to date. */
if (ob->pose == NULL || (ob->pose->flag & POSE_RECALC)) {
BKE_pose_rebuild(ob, arm);
if (object_cow->pose == NULL || (object->pose->flag & POSE_RECALC)) {
BKE_pose_rebuild(object_cow, armature_cow);
/* 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;
if (object_cow->adt) {
object_cow->adt->recalc |= ADT_RECALC_ANIM;
}
}
/* speed optimization for animation lookups */
if (ob->pose) {
BKE_pose_channels_hash_make(ob->pose);
if (ob->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(ob->pose);
if (object_cow->pose != NULL) {
BKE_pose_channels_hash_make(object_cow->pose);
if (object_cow->pose->flag & POSE_CONSTRAINTS_NEED_UPDATE_FLAGS) {
BKE_pose_update_constraint_flags(object_cow->pose);
}
}
@@ -168,47 +210,59 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
* - 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/
* - 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 */
op_node = add_operation_node(&ob->id,
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
function_bind(BKE_pose_eval_init, _1, scene, ob, ob->pose),
function_bind(BKE_pose_eval_init,
_1,
scene_cow,
object_cow,
object_cow->pose),
DEG_OPCODE_POSE_INIT);
op_node->set_as_entry();
op_node = add_operation_node(&ob->id,
op_node = add_operation_node(&object->id,
DEG_NODE_TYPE_EVAL_POSE,
function_bind(BKE_pose_eval_flush, _1, scene, ob, ob->pose),
function_bind(BKE_pose_eval_flush,
_1,
scene_cow,
object_cow,
object_cow->pose),
DEG_OPCODE_POSE_DONE);
op_node->set_as_exit();
/* bones */
LINKLIST_FOREACH (bPoseChannel *, pchan, &ob->pose->chanbase) {
LINKLIST_FOREACH (bPoseChannel *, pchan, &object_cow->pose->chanbase) {
/* node for bone eval */
op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name, NULL,
DEG_OPCODE_BONE_LOCAL);
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE,
pchan->name, NULL, DEG_OPCODE_BONE_LOCAL);
op_node->set_as_entry();
add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_eval_bone, _1, scene, ob, pchan),
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_eval_bone, _1,
scene_cow,
object_cow,
pchan),
DEG_OPCODE_BONE_POSE_PARENT);
add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
NULL, /* NOTE: dedicated noop for easier relationship construction */
/* NOTE: Dedicated noop for easier relationship construction. */
add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
NULL,
DEG_OPCODE_BONE_READY);
op_node = add_operation_node(&ob->id, DEG_NODE_TYPE_BONE, pchan->name,
op_node = add_operation_node(&object->id, DEG_NODE_TYPE_BONE, pchan->name,
function_bind(BKE_pose_bone_done, _1, pchan),
DEG_OPCODE_BONE_DONE);
op_node->set_as_exit();
/* constraints */
if (pchan->constraints.first != NULL) {
build_pose_constraints(scene, ob, pchan);
build_pose_constraints(scene, object, pchan);
}
/**
@@ -219,17 +273,18 @@ void DepsgraphNodeBuilder::build_rig(Scene *scene, Object *ob)
* 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...
* - Care is needed to ensure that multi-headed trees work out the same
* as in ik-tree building
* - Animated chain-lengths are a problem.
*/
LINKLIST_FOREACH (bConstraint *, con, &pchan->constraints) {
switch (con->type) {
case CONSTRAINT_TYPE_KINEMATIC:
build_ik_pose(scene, ob, pchan, con);
build_ik_pose(scene, object, pchan, con);
break;
case CONSTRAINT_TYPE_SPLINEIK:
build_splineik_pose(scene, ob, pchan, con);
build_splineik_pose(scene, object, pchan, con);
break;
default:

View File

@@ -308,11 +308,22 @@ int foreach_libblock_remap_callback(void *user_data,
}
/* Check whether given ID is expanded or still a shallow copy. */
BLI_INLINE bool check_datablock_expanded(ID *id_cow)
BLI_INLINE bool check_datablock_expanded(const ID *id_cow)
{
return (id_cow->name[0] != '\0');
}
/* Check whether datablock was already expanded during depsgraph
* construction.
*/
static bool check_datablock_expanded_at_construction(const ID *id_orig)
{
const short id_type = GS(id_orig->name);
return (id_type == ID_SCE) ||
(id_type == ID_OB && ((Object *)id_orig)->type == OB_ARMATURE) ||
(id_type == ID_AR);
}
/* Do some special treatment of data transfer from original ID to it's
* CoW complementary part.
*
@@ -423,6 +434,7 @@ void update_copy_on_write_datablock(const Depsgraph *depsgraph,
// - Active render engine.
// - Something else?
}
// TODO(sergey): Other ID types here.
}
/* This callback is used to validate that all nested ID datablocks are
@@ -549,7 +561,7 @@ ID *deg_update_copy_on_write_datablock(const Depsgraph *depsgraph,
* construction time. This datablocks must never change pointers of their
* nested data since it is used for function bindings.
*/
if (GS(id_orig->name) == ID_SCE) {
if (check_datablock_expanded_at_construction(id_orig)) {
BLI_assert(check_datablock_expanded(id_cow) == true);
update_copy_on_write_datablock(depsgraph, id_orig, id_cow);
return id_cow;