/* helper call for armature_bone_rename */
static void constraint_bone_name_fix(Object *ob, ListBase *conlist, const char *oldname, const char *newname)
{
	bConstraint *curcon;
	bConstraintTarget *ct;
	
	for (curcon = conlist->first; curcon; curcon = curcon->next) {
		const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
		ListBase targets = {NULL, NULL};
		
		/* constraint targets */
		if (cti && cti->get_constraint_targets) {
			cti->get_constraint_targets(curcon, &targets);
			
			for (ct = targets.first; ct; ct = ct->next) {
				if (ct->tar == ob) {
					if (STREQ(ct->subtarget, oldname)) {
						BLI_strncpy(ct->subtarget, newname, MAXBONENAME);
					}
				}
			}
			
			if (cti->flush_constraint_targets)
				cti->flush_constraint_targets(curcon, &targets, 0);
		}
		
		/* action constraints */
		if (curcon->type == CONSTRAINT_TYPE_ACTION) {
			bActionConstraint *actcon = (bActionConstraint *)curcon->data;
			BKE_action_fix_paths_rename(&ob->id, actcon->act, "pose.bones", oldname, newname, 0, 0, 1);
		}
	}
}
void AnimationExporter::make_anim_frames_from_targets(Object *ob, std::vector<float> &frames )
{
	ListBase *conlist = get_active_constraints(ob);
	if (conlist == NULL) return;
	bConstraint *con;
	for (con = (bConstraint *)conlist->first; con; con = con->next) {
		ListBase targets = {NULL, NULL};
		
		bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
		
		if (!validateConstraints(con)) continue;

		if (cti && cti->get_constraint_targets) {
			bConstraintTarget *ct;
			Object *obtar;
			/* get targets 
			 *  - constraints should use ct->matrix, not directly accessing values
			 *	- ct->matrix members have not yet been calculated here! 
			 */
			cti->get_constraint_targets(con, &targets);

			for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
				obtar = ct->tar;

				if (obtar)
					find_frames(obtar, frames);
			}

			if (cti->flush_constraint_targets)
				cti->flush_constraint_targets(con, &targets, 1);
		}
	}
}
void AnimationExporter::calc_ob_mat_at_time(Object *ob, float ctime , float mat[][4])
{
	ListBase *conlist = get_active_constraints(ob);
	bConstraint *con;
	for (con = (bConstraint *)conlist->first; con; con = con->next) {
		ListBase targets = {NULL, NULL};
		
		bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
		
		if (cti && cti->get_constraint_targets) {
			bConstraintTarget *ct;
			Object *obtar;
			cti->get_constraint_targets(con, &targets);
			for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
				obtar = ct->tar;

				if (obtar) {
					BKE_animsys_evaluate_animdata(scene, &obtar->id, obtar->adt, ctime, ADT_RECALC_ANIM);
					BKE_object_where_is_calc_time(scene, obtar, ctime);
				}
			}

			if (cti->flush_constraint_targets)
				cti->flush_constraint_targets(con, &targets, 1);
		}
	}
	BKE_object_where_is_calc_time(scene, ob, ctime);
	copy_m4_m4(mat, ob->obmat);
}
static void object_solver_inverted_matrix(Scene *scene, Object *ob, float invmat[4][4])
{
  bool found = false;
  for (bConstraint *con = ob->constraints.first; con != NULL; con = con->next) {
    const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
    if (cti == NULL) {
      continue;
    }
    if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
      bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
      if (!found) {
        Object *cam = data->camera ? data->camera : scene->camera;
        BKE_object_where_is_calc_mat4(cam, invmat);
      }
      mul_m4_m4m4(invmat, invmat, data->invmat);
      found = true;
    }
  }
  if (found) {
    invert_m4(invmat);
  }
  else {
    unit_m4(invmat);
  }
}
Exemple #5
0
static void joined_armature_fix_links_constraints(
        Object *tarArm, Object *srcArm, bPoseChannel *pchan, EditBone *curbone,
        ListBase *lb)
{
	bConstraint *con;

	for (con = lb->first; con; con = con->next) {
		bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
		ListBase targets = {NULL, NULL};
		bConstraintTarget *ct;

		/* constraint targets */
		if (cti && cti->get_constraint_targets) {
			cti->get_constraint_targets(con, &targets);

			for (ct = targets.first; ct; ct = ct->next) {
				if (ct->tar == srcArm) {
					if (ct->subtarget[0] == '\0') {
						ct->tar = tarArm;
					}
					else if (STREQ(ct->subtarget, pchan->name)) {
						ct->tar = tarArm;
						BLI_strncpy(ct->subtarget, curbone->name, sizeof(ct->subtarget));
					}
				}
			}

			if (cti->flush_constraint_targets)
				cti->flush_constraint_targets(con, &targets, 0);
		}

		/* action constraint? (pose constraints only) */
		if (con->type == CONSTRAINT_TYPE_ACTION) {
			bActionConstraint *data = con->data; // XXX old animation system
			bAction *act;
			bActionChannel *achan;

			if (data->act) {
				act = data->act;

				for (achan = act->chanbase.first; achan; achan = achan->next) {
					if (STREQ(achan->name, pchan->name)) {
						BLI_strncpy(achan->name, curbone->name, sizeof(achan->name));
					}
				}
			}
		}

	}
}
bool AnimationExporter::validateConstraints(bConstraint *con)
{
	bool valid = true;
	bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
	/* these we can skip completely (invalid constraints...) */
	if (cti == NULL) valid = false;
	if (con->flag & (CONSTRAINT_DISABLE | CONSTRAINT_OFF)) valid = false;
	/* these constraints can't be evaluated anyway */
	if (cti->evaluate_constraint == NULL) valid = false;
	/* influence == 0 should be ignored */
	if (con->enforce == 0.0f) valid = false;

	return valid;
}
static Object *object_solver_camera(Scene *scene, Object *ob)
{
  for (bConstraint *con = ob->constraints.first; con != NULL; con = con->next) {
    const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
    if (cti == NULL) {
      continue;
    }
    if (cti->type == CONSTRAINT_TYPE_OBJECTSOLVER) {
      bObjectSolverConstraint *data = (bObjectSolverConstraint *)con->data;
      return (data->camera != NULL) ? data->camera : scene->camera;
    }
  }
  return NULL;
}
Exemple #8
0
static int pose_select_constraint_target_exec(bContext *C, wmOperator *UNUSED(op))
{
	Object *ob = BKE_object_pose_armature_get(CTX_data_active_object(C));
	bArmature *arm = (bArmature *)ob->data;
	bConstraint *con;
	int found = 0;
	
	CTX_DATA_BEGIN (C, bPoseChannel *, pchan, visible_pose_bones)
	{
		if (pchan->bone->flag & BONE_SELECTED) {
			for (con = pchan->constraints.first; con; con = con->next) {
				bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
				ListBase targets = {NULL, NULL};
				bConstraintTarget *ct;
				
				if (cti && cti->get_constraint_targets) {
					cti->get_constraint_targets(con, &targets);
					
					for (ct = targets.first; ct; ct = ct->next) {
						if ((ct->tar == ob) && (ct->subtarget[0])) {
							bPoseChannel *pchanc = BKE_pose_channel_find_name(ob->pose, ct->subtarget);
							if ((pchanc) && !(pchanc->bone->flag & BONE_UNSELECTABLE)) {
								pchanc->bone->flag |= BONE_SELECTED | BONE_TIPSEL | BONE_ROOTSEL;
								found = 1;
							}
						}
					}
					
					if (cti->flush_constraint_targets)
						cti->flush_constraint_targets(con, &targets, 1);
				}
			}
		}
	}
	CTX_DATA_END;
	
	if (!found)
		return OPERATOR_CANCELLED;
	
	/* updates */
	WM_event_add_notifier(C, NC_OBJECT | ND_BONE_SELECT, ob);
	
	if (arm->flag & ARM_HAS_VIZ_DEPS) {
		/* mask modifier ('armature' mode), etc. */
		DAG_id_tag_update(&ob->id, OB_RECALC_DATA);
	}
	
	return OPERATOR_FINISHED;
}
/*
 * Note: When duplicating cross objects, editbones here is the list of bones
 * from the SOURCE object but ob is the DESTINATION object
 * */
void updateDuplicateSubtargetObjects(EditBone *dupBone, ListBase *editbones, Object *src_ob, Object *dst_ob)
{
	/* If an edit bone has been duplicated, lets
	 * update it's constraints if the subtarget
	 * they point to has also been duplicated
	 */
	EditBone     *oldtarget, *newtarget;
	bPoseChannel *pchan;
	bConstraint  *curcon;
	ListBase     *conlist;
	
	if ((pchan = BKE_pose_channel_verify(dst_ob->pose, dupBone->name))) {
		if ((conlist = &pchan->constraints)) {
			for (curcon = conlist->first; curcon; curcon = curcon->next) {
				/* does this constraint have a subtarget in
				 * this armature?
				 */
				const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(curcon);
				ListBase targets = {NULL, NULL};
				bConstraintTarget *ct;
				
				if (cti && cti->get_constraint_targets) {
					cti->get_constraint_targets(curcon, &targets);
					
					for (ct = targets.first; ct; ct = ct->next) {
						if ((ct->tar == src_ob) && (ct->subtarget[0])) {
							ct->tar = dst_ob; /* update target */ 
							oldtarget = get_named_editbone(editbones, ct->subtarget);
							if (oldtarget) {
								/* was the subtarget bone duplicated too? If
								 * so, update the constraint to point at the 
								 * duplicate of the old subtarget.
								 */
								if (oldtarget->temp.ebone) {
									newtarget = oldtarget->temp.ebone;
									BLI_strncpy(ct->subtarget, newtarget->name, sizeof(ct->subtarget));
								}
							}
						}
					}
					
					if (cti->flush_constraint_targets)
						cti->flush_constraint_targets(curcon, &targets, 0);
				}
			}
		}
	}
}
void BL_ArmatureObject::LoadConstraints(KX_BlenderSceneConverter* converter)
{
	// first delete any existing constraint (should not have any)
	while (!m_controlledConstraints.Empty()) {
		BL_ArmatureConstraint* constraint = m_controlledConstraints.Remove();
		delete constraint;
	}
	m_constraintNumber = 0;

	// list all the constraint and convert them to BL_ArmatureConstraint
	// get the persistent pose structure
	bPoseChannel* pchan;
	bConstraint* pcon;
	const bConstraintTypeInfo* cti;
	Object* blendtarget;
	KX_GameObject* gametarget;
	KX_GameObject* gamesubtarget;

	// and locate the constraint
	for (pchan = (bPoseChannel *)m_pose->chanbase.first; pchan; pchan = pchan->next) {
		for (pcon = (bConstraint *)pchan->constraints.first; pcon; pcon = pcon->next) {
			if (pcon->flag & CONSTRAINT_DISABLE)
				continue;
			// which constraint should we support?
			switch (pcon->type) {
			case CONSTRAINT_TYPE_TRACKTO:
			case CONSTRAINT_TYPE_DAMPTRACK:
			case CONSTRAINT_TYPE_KINEMATIC:
			case CONSTRAINT_TYPE_ROTLIKE:
			case CONSTRAINT_TYPE_LOCLIKE:
			case CONSTRAINT_TYPE_MINMAX:
			case CONSTRAINT_TYPE_SIZELIKE:
			case CONSTRAINT_TYPE_LOCKTRACK:
			case CONSTRAINT_TYPE_STRETCHTO:
			case CONSTRAINT_TYPE_CLAMPTO:
			case CONSTRAINT_TYPE_TRANSFORM:
			case CONSTRAINT_TYPE_DISTLIMIT:
			case CONSTRAINT_TYPE_TRANSLIKE:
				cti = BKE_constraint_typeinfo_get(pcon);
				gametarget = gamesubtarget = NULL;
				if (cti && cti->get_constraint_targets) {
					ListBase listb = { NULL, NULL };
					cti->get_constraint_targets(pcon, &listb);
					if (listb.first) {
						bConstraintTarget* target = (bConstraintTarget*)listb.first;
						if (target->tar && target->tar != m_objArma) {
							// only remember external objects, self target is handled automatically
							blendtarget = target->tar;
							gametarget = converter->FindGameObject(blendtarget);
						}
						if (target->next != NULL) {
							// secondary target
							target = target->next;
							if (target->tar && target->tar != m_objArma) {
								// only track external object
								blendtarget = target->tar;
								gamesubtarget = converter->FindGameObject(blendtarget);
							}
						}
					}
					if (cti->flush_constraint_targets)
						cti->flush_constraint_targets(pcon, &listb, 1);
				}
				BL_ArmatureConstraint* constraint = new BL_ArmatureConstraint(this, pchan, pcon, gametarget, gamesubtarget);
				m_controlledConstraints.AddBack(constraint);
				m_constraintNumber++;
			}
		}
	}

	// If we have constraints, make sure we get treated as an "animated" object
	if (m_constraintNumber > 0)
		GetActionManager();
}
Exemple #11
0
/**
 * Selectively remove pose channels.
 */
void BKE_pose_channels_remove(
        Object *ob,
        bool (*filter_fn)(const char *bone_name, void *user_data), void *user_data)
{
	/* Erase any associated pose channel, along with any references to them */
	if (ob->pose) {
		bPoseChannel *pchan, *pchan_next;
		bConstraint *con;

		for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan_next) {
			pchan_next = pchan->next;

			if (filter_fn(pchan->name, user_data)) {
				/* Bone itself is being removed */
				BKE_pose_channel_free(pchan);
				if (ob->pose->chanhash) {
					BLI_ghash_remove(ob->pose->chanhash, pchan->name, NULL, NULL);
				}
				BLI_freelinkN(&ob->pose->chanbase, pchan);
			}
			else {
				/* Maybe something the bone references is being removed instead? */
				for (con = pchan->constraints.first; con; con = con->next) {
					const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
					ListBase targets = {NULL, NULL};
					bConstraintTarget *ct;

					if (cti && cti->get_constraint_targets) {
						cti->get_constraint_targets(con, &targets);

						for (ct = targets.first; ct; ct = ct->next) {
							if (ct->tar == ob) {
								if (ct->subtarget[0]) {
									if (filter_fn(ct->subtarget, user_data)) {
										con->flag |= CONSTRAINT_DISABLE;
										ct->subtarget[0] = 0;
									}
								}
							}
						}

						if (cti->flush_constraint_targets)
							cti->flush_constraint_targets(con, &targets, 0);
					}
				}
				
				if (pchan->bbone_prev) {
					if (filter_fn(pchan->bbone_prev->name, user_data))
						pchan->bbone_prev = NULL;
				}
				if (pchan->bbone_next) {
					if (filter_fn(pchan->bbone_next->name, user_data))
						pchan->bbone_next = NULL;
				}
				
				if (pchan->custom_tx) {
					if (filter_fn(pchan->custom_tx->name, user_data))
						pchan->custom_tx = NULL;
				}
			}
		}
	}
}
Exemple #12
0
/* Helper function for armature separating - link fixing */
static void separated_armature_fix_links(Object *origArm, Object *newArm)
{
	Object *ob;
	bPoseChannel *pchan;
	bConstraint *con;
	ListBase *opchans, *npchans;
	
	/* get reference to list of bones in original and new armatures  */
	opchans = &origArm->pose->chanbase;
	npchans = &newArm->pose->chanbase;
	
	/* let's go through all objects in database */
	for (ob = G.main->object.first; ob; ob = ob->id.next) {
		/* do some object-type specific things */
		if (ob->type == OB_ARMATURE) {
			for (pchan = ob->pose->chanbase.first; pchan; pchan = pchan->next) {
				for (con = pchan->constraints.first; con; con = con->next) {
					bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
					ListBase targets = {NULL, NULL};
					bConstraintTarget *ct;
					
					/* constraint targets */
					if (cti && cti->get_constraint_targets) {
						cti->get_constraint_targets(con, &targets);
						
						for (ct = targets.first; ct; ct = ct->next) {
							/* any targets which point to original armature are redirected to the new one only if:
							 *	- the target isn't origArm/newArm itself
							 *	- the target is one that can be found in newArm/origArm
							 */
							if (ct->subtarget[0] != 0) {
								if (ct->tar == origArm) {
									if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
										ct->tar = newArm;
									}
								}
								else if (ct->tar == newArm) {
									if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
										ct->tar = origArm;
									}
								}
							}
						}

						if (cti->flush_constraint_targets) {
							cti->flush_constraint_targets(con, &targets, 0);
						}
					}
				}
			}
		}
			
		/* fix object-level constraints */
		if (ob != origArm) {
			for (con = ob->constraints.first; con; con = con->next) {
				bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
				ListBase targets = {NULL, NULL};
				bConstraintTarget *ct;
				
				/* constraint targets */
				if (cti && cti->get_constraint_targets) {
					cti->get_constraint_targets(con, &targets);
					
					for (ct = targets.first; ct; ct = ct->next) {
						/* any targets which point to original armature are redirected to the new one only if:
						 *	- the target isn't origArm/newArm itself
						 *	- the target is one that can be found in newArm/origArm
						 */
						if (ct->subtarget[0] != '\0') {
							if (ct->tar == origArm) {
								if (BLI_findstring(npchans, ct->subtarget, offsetof(bPoseChannel, name))) {
									ct->tar = newArm;
								}
							}
							else if (ct->tar == newArm) {
								if (BLI_findstring(opchans, ct->subtarget, offsetof(bPoseChannel, name))) {
									ct->tar = origArm;
								}
							}
						}
					}
					
					if (cti->flush_constraint_targets) {
						cti->flush_constraint_targets(con, &targets, 0);
					}
				}
			}
		}
		
		/* See if an object is parented to this armature */
		if (ob->parent && (ob->parent == origArm)) {
			/* Is object parented to a bone of this src armature? */
			if ((ob->partype == PARBONE) && (ob->parsubstr[0] != '\0')) {
				if (BLI_findstring(npchans, ob->parsubstr, offsetof(bPoseChannel, name))) {
					ob->parent = newArm;
				}
			}
		}
	}
}
void SceneExporter::writeNodes(Object *ob, Scene *sce)
{
	// Add associated armature first if available
	bool armature_exported = false;
	Object *ob_arm = bc_get_assigned_armature(ob);
	if (ob_arm != NULL) {
		armature_exported = bc_is_in_Export_set(this->export_settings->export_set, ob_arm);
		if (armature_exported && bc_is_marked(ob_arm)) {
			bc_remove_mark(ob_arm);
			writeNodes(ob_arm, sce);
			armature_exported = true;
		}
	}

	COLLADASW::Node colladaNode(mSW);
	colladaNode.setNodeId(translate_id(id_name(ob)));
	colladaNode.setNodeName(translate_id(id_name(ob)));
	colladaNode.setType(COLLADASW::Node::NODE);

	colladaNode.start();

	std::list<Object *> child_objects;

	// list child objects
	LinkNode *node;
	for (node=this->export_settings->export_set; node; node=node->next) {
		// cob - child object
		Object *cob = (Object *)node->link;

		if (cob->parent == ob) {
			switch (cob->type) {
				case OB_MESH:
				case OB_CAMERA:
				case OB_LAMP:
				case OB_EMPTY:
				case OB_ARMATURE:
					if (bc_is_marked(cob))
						child_objects.push_back(cob);
					break;
			}
		}
	}

	if (ob->type == OB_MESH && armature_exported)
		// for skinned mesh we write obmat in <bind_shape_matrix>
		TransformWriter::add_node_transform_identity(colladaNode);
	else {
		TransformWriter::add_node_transform_ob(colladaNode, ob, this->transformation_type);
	}

	// <instance_geometry>
	if (ob->type == OB_MESH) {
		bool instance_controller_created = false;
		if (armature_exported) {
			instance_controller_created = arm_exporter->add_instance_controller(ob);
		}
		if (!instance_controller_created) {
			COLLADASW::InstanceGeometry instGeom(mSW);
			instGeom.setUrl(COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_geometry_id(ob, this->export_settings->use_object_instantiation)));
			instGeom.setName(translate_id(id_name(ob)));
			InstanceWriter::add_material_bindings(instGeom.getBindMaterial(), ob, this->export_settings->active_uv_only);

			instGeom.add();
		}
	}

	// <instance_controller>
	else if (ob->type == OB_ARMATURE) {
		arm_exporter->add_armature_bones(ob, sce, this, child_objects);
	}

	// <instance_camera>
	else if (ob->type == OB_CAMERA) {
		COLLADASW::InstanceCamera instCam(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_camera_id(ob)));
		instCam.add();
	}

	// <instance_light>
	else if (ob->type == OB_LAMP) {
		COLLADASW::InstanceLight instLa(mSW, COLLADASW::URI(COLLADABU::Utils::EMPTY_STRING, get_light_id(ob)));
		instLa.add();
	}

	// empty object
	else if (ob->type == OB_EMPTY) { // TODO: handle groups (OB_DUPLIGROUP
		if ((ob->transflag & OB_DUPLIGROUP) == OB_DUPLIGROUP && ob->dup_group) {
			GroupObject *go = NULL;
			Group *gr = ob->dup_group;
			/* printf("group detected '%s'\n", gr->id.name + 2); */
			for (go = (GroupObject *)(gr->gobject.first); go; go = go->next) {
				printf("\t%s\n", go->ob->id.name);
			}
		}
	}

	if (ob->type == OB_ARMATURE) {
		colladaNode.end();
	}

	if (BLI_listbase_is_empty(&ob->constraints) == false) {
		bConstraint *con = (bConstraint *) ob->constraints.first;
		while (con) {
			std::string con_name(translate_id(con->name));
			std::string con_tag = con_name + "_constraint";
			printf("%s\n", con_name.c_str());
			printf("%s\n\n", con_tag.c_str());
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"type",con->type);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"enforce",con->enforce);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"flag",con->flag);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"headtail",con->headtail);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"own_space",con->ownspace);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"rot_error",con->rot_error);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"tar_space",con->tarspace);
			colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"lin_error",con->lin_error);
			
			//not ideal: add the target object name as another parameter. 
			//No real mapping in the .dae
			//Need support for multiple target objects also.
			const bConstraintTypeInfo *cti = BKE_constraint_typeinfo_get(con);
			ListBase targets = {NULL, NULL};
			if (cti && cti->get_constraint_targets) {
			
				bConstraintTarget *ct;
				Object *obtar;
			
				cti->get_constraint_targets(con, &targets);

				for (ct = (bConstraintTarget *)targets.first; ct; ct = ct->next) {
					obtar = ct->tar;
					std::string tar_id((obtar) ? id_name(obtar) : "");
					colladaNode.addExtraTechniqueChildParameter("blender",con_tag,"target_id",tar_id);
				}

				if (cti->flush_constraint_targets)
					cti->flush_constraint_targets(con, &targets, 1);

			}

			con = con->next;
		}
	}

	for (std::list<Object *>::iterator i = child_objects.begin(); i != child_objects.end(); ++i) {
		if (bc_is_marked(*i)) {
			bc_remove_mark(*i);
			writeNodes(*i, sce);
		}
	}

	if (ob->type != OB_ARMATURE)
		colladaNode.end();
}